954e348871528595bc69db40f60be31c3910c1ba
[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 ULONG CmpTraceLevel = 0;
33
34 extern LONG CmpFlushStarveWriters;
35 extern BOOLEAN CmFirstTime;
36
37 /* FUNCTIONS ******************************************************************/
38
39 BOOLEAN
40 NTAPI
41 CmpLinkKeyToHive(
42 _In_z_ PWSTR LinkKeyName,
43 _In_z_ PWSTR TargetKeyName)
44 {
45 OBJECT_ATTRIBUTES ObjectAttributes;
46 UNICODE_STRING LinkKeyName_U;
47 HANDLE TargetKeyHandle;
48 ULONG Disposition;
49 NTSTATUS Status;
50 PAGED_CODE();
51
52 /* Initialize the object attributes */
53 RtlInitUnicodeString(&LinkKeyName_U, LinkKeyName);
54 InitializeObjectAttributes(&ObjectAttributes,
55 &LinkKeyName_U,
56 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
57 NULL,
58 NULL);
59
60 /* Create the link key */
61 Status = ZwCreateKey(&TargetKeyHandle,
62 KEY_CREATE_LINK,
63 &ObjectAttributes,
64 0,
65 NULL,
66 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
67 &Disposition);
68 if (!NT_SUCCESS(Status))
69 {
70 DPRINT1("CM: CmpLinkKeyToHive: couldn't create %S Status = 0x%lx\n",
71 LinkKeyName, Status);
72 return FALSE;
73 }
74
75 /* Check if the new key was actually created */
76 if (Disposition != REG_CREATED_NEW_KEY)
77 {
78 DPRINT1("CM: CmpLinkKeyToHive: %S already exists!\n", LinkKeyName);
79 ZwClose(TargetKeyHandle);
80 return FALSE;
81 }
82
83 /* Set the target key name as link target */
84 Status = ZwSetValueKey(TargetKeyHandle,
85 &CmSymbolicLinkValueName,
86 0,
87 REG_LINK,
88 TargetKeyName,
89 wcslen(TargetKeyName) * sizeof(WCHAR));
90
91 /* Close the link key handle */
92 ObCloseHandle(TargetKeyHandle, KernelMode);
93
94 if (!NT_SUCCESS(Status))
95 {
96 DPRINT1("CM: CmpLinkKeyToHive: couldn't create symbolic link for %S\n",
97 TargetKeyName);
98 return FALSE;
99 }
100
101 return TRUE;
102 }
103
104 VOID
105 NTAPI
106 CmpDeleteKeyObject(PVOID DeletedObject)
107 {
108 PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)DeletedObject;
109 PCM_KEY_CONTROL_BLOCK Kcb;
110 REG_KEY_HANDLE_CLOSE_INFORMATION KeyHandleCloseInfo;
111 REG_POST_OPERATION_INFORMATION PostOperationInfo;
112 NTSTATUS Status;
113 PAGED_CODE();
114
115 /* First off, prepare the handle close information callback */
116 PostOperationInfo.Object = KeyBody;
117 KeyHandleCloseInfo.Object = KeyBody;
118 Status = CmiCallRegisteredCallbacks(RegNtPreKeyHandleClose,
119 &KeyHandleCloseInfo);
120 if (!NT_SUCCESS(Status))
121 {
122 /* If we failed, notify the post routine */
123 PostOperationInfo.Status = Status;
124 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose, &PostOperationInfo);
125 return;
126 }
127
128 /* Acquire hive lock */
129 CmpLockRegistry();
130
131 /* Make sure this is a valid key body */
132 if (KeyBody->Type == CM_KEY_BODY_TYPE)
133 {
134 /* Get the KCB */
135 Kcb = KeyBody->KeyControlBlock;
136 if (Kcb)
137 {
138 /* Delist the key */
139 DelistKeyBodyFromKCB(KeyBody, FALSE);
140
141 /* Dereference the KCB */
142 CmpDelayDerefKeyControlBlock(Kcb);
143 }
144 }
145
146 /* Release the registry lock */
147 CmpUnlockRegistry();
148
149 /* Do the post callback */
150 PostOperationInfo.Status = STATUS_SUCCESS;
151 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose, &PostOperationInfo);
152 }
153
154 VOID
155 NTAPI
156 CmpCloseKeyObject(IN PEPROCESS Process OPTIONAL,
157 IN PVOID Object,
158 IN ACCESS_MASK GrantedAccess,
159 IN ULONG ProcessHandleCount,
160 IN ULONG SystemHandleCount)
161 {
162 PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)Object;
163 PAGED_CODE();
164
165 /* Don't do anything if we're not the last handle */
166 if (SystemHandleCount > 1) return;
167
168 /* Make sure we're a valid key body */
169 if (KeyBody->Type == CM_KEY_BODY_TYPE)
170 {
171 /* Don't do anything if we don't have a notify block */
172 if (!KeyBody->NotifyBlock) return;
173
174 /* This shouldn't happen yet */
175 ASSERT(FALSE);
176 }
177 }
178
179 NTSTATUS
180 NTAPI
181 CmpQueryKeyName(IN PVOID ObjectBody,
182 IN BOOLEAN HasName,
183 IN OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
184 IN ULONG Length,
185 OUT PULONG ReturnLength,
186 IN KPROCESSOR_MODE PreviousMode)
187 {
188 PUNICODE_STRING KeyName;
189 ULONG BytesToCopy;
190 NTSTATUS Status = STATUS_SUCCESS;
191 PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)ObjectBody;
192 PCM_KEY_CONTROL_BLOCK Kcb = KeyBody->KeyControlBlock;
193
194 /* Acquire hive lock */
195 CmpLockRegistry();
196
197 /* Lock KCB shared */
198 CmpAcquireKcbLockShared(Kcb);
199
200 /* Check if it's a deleted block */
201 if (Kcb->Delete)
202 {
203 /* Release the locks */
204 CmpReleaseKcbLock(Kcb);
205 CmpUnlockRegistry();
206
207 /* Let the caller know it's deleted */
208 return STATUS_KEY_DELETED;
209 }
210
211 /* Get the name */
212 KeyName = CmpConstructName(Kcb);
213
214 /* Release the locks */
215 CmpReleaseKcbLock(Kcb);
216 CmpUnlockRegistry();
217
218 /* Check if we got the name */
219 if (!KeyName) return STATUS_INSUFFICIENT_RESOURCES;
220
221 /* Set the returned length */
222 *ReturnLength = KeyName->Length + sizeof(OBJECT_NAME_INFORMATION) + sizeof(WCHAR);
223
224 /* Calculate amount of bytes to copy into the buffer */
225 BytesToCopy = KeyName->Length + sizeof(WCHAR);
226
227 /* Check if the provided buffer is too small to fit even anything */
228 if ((Length <= sizeof(OBJECT_NAME_INFORMATION)) ||
229 ((Length < (*ReturnLength)) && (BytesToCopy < sizeof(WCHAR))))
230 {
231 /* Free the buffer allocated by CmpConstructName */
232 ExFreePoolWithTag(KeyName, TAG_CM);
233
234 /* Return buffer length failure without writing anything there because nothing fits */
235 return STATUS_INFO_LENGTH_MISMATCH;
236 }
237
238 /* Check if the provided buffer can be partially written */
239 if (Length < (*ReturnLength))
240 {
241 /* Yes, indicate so in the return status */
242 Status = STATUS_INFO_LENGTH_MISMATCH;
243
244 /* Calculate amount of bytes which the provided buffer could handle */
245 BytesToCopy = Length - sizeof(OBJECT_NAME_INFORMATION);
246 }
247
248 /* Remove the null termination character from the size */
249 BytesToCopy -= sizeof(WCHAR);
250
251 /* Fill in the result */
252 _SEH2_TRY
253 {
254 /* Return data to user */
255 ObjectNameInfo->Name.Buffer = (PWCHAR)(ObjectNameInfo + 1);
256 ObjectNameInfo->Name.MaximumLength = KeyName->Length;
257 ObjectNameInfo->Name.Length = KeyName->Length;
258
259 /* Copy string content*/
260 RtlCopyMemory(ObjectNameInfo->Name.Buffer,
261 KeyName->Buffer,
262 BytesToCopy);
263
264 /* Null terminate it */
265 ObjectNameInfo->Name.Buffer[BytesToCopy / sizeof(WCHAR)] = 0;
266 }
267 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
268 {
269 /* Get the status */
270 Status = _SEH2_GetExceptionCode();
271 }
272 _SEH2_END;
273
274 /* Free the buffer allocated by CmpConstructName */
275 ExFreePoolWithTag(KeyName, TAG_CM);
276
277 /* Return status */
278 return Status;
279 }
280
281 NTSTATUS
282 NTAPI
283 CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName,
284 IN ULONG HiveFlags,
285 OUT PCMHIVE *Hive,
286 IN OUT PBOOLEAN New,
287 IN ULONG CheckFlags)
288 {
289 ULONG HiveDisposition, LogDisposition;
290 HANDLE FileHandle = NULL, LogHandle = NULL;
291 NTSTATUS Status;
292 ULONG Operation, FileType;
293 PCMHIVE NewHive;
294 PAGED_CODE();
295
296 /* Assume failure */
297 *Hive = NULL;
298
299 /* Open or create the hive files */
300 Status = CmpOpenHiveFiles(HiveName,
301 L".LOG",
302 &FileHandle,
303 &LogHandle,
304 &HiveDisposition,
305 &LogDisposition,
306 *New,
307 FALSE,
308 TRUE,
309 NULL);
310 if (!NT_SUCCESS(Status)) return Status;
311
312 /* Check if we have a log handle */
313 FileType = (LogHandle) ? HFILE_TYPE_LOG : HFILE_TYPE_PRIMARY;
314
315 /* Check if we created or opened the hive */
316 if (HiveDisposition == FILE_CREATED)
317 {
318 /* Do a create operation */
319 Operation = HINIT_CREATE;
320 *New = TRUE;
321 }
322 else
323 {
324 /* Open it as a file */
325 Operation = HINIT_FILE;
326 *New = FALSE;
327 }
328
329 /* Check if we're sharing hives */
330 if (CmpShareSystemHives)
331 {
332 /* Then force using the primary hive */
333 FileType = HFILE_TYPE_PRIMARY;
334 if (LogHandle)
335 {
336 /* Get rid of the log handle */
337 ZwClose(LogHandle);
338 LogHandle = NULL;
339 }
340 }
341
342 /* Check if we're too late */
343 if (HvShutdownComplete)
344 {
345 /* Fail */
346 ZwClose(FileHandle);
347 if (LogHandle) ZwClose(LogHandle);
348 return STATUS_TOO_LATE;
349 }
350
351 /* Initialize the hive */
352 Status = CmpInitializeHive((PCMHIVE*)&NewHive,
353 Operation,
354 HiveFlags,
355 FileType,
356 NULL,
357 FileHandle,
358 LogHandle,
359 NULL,
360 HiveName,
361 CheckFlags);
362 if (!NT_SUCCESS(Status))
363 {
364 /* Fail */
365 ZwClose(FileHandle);
366 if (LogHandle) ZwClose(LogHandle);
367 return Status;
368 }
369
370 /* Success, return hive */
371 *Hive = NewHive;
372
373 /* HACK: ROS: Init root key cell and prepare the hive */
374 if (Operation == HINIT_CREATE) CmCreateRootNode(&NewHive->Hive, L"");
375
376 /* Duplicate the hive name */
377 NewHive->FileFullPath.Buffer = ExAllocatePoolWithTag(PagedPool,
378 HiveName->Length,
379 TAG_CM);
380 if (NewHive->FileFullPath.Buffer)
381 {
382 /* Copy the string */
383 RtlCopyMemory(NewHive->FileFullPath.Buffer,
384 HiveName->Buffer,
385 HiveName->Length);
386 NewHive->FileFullPath.Length = HiveName->Length;
387 NewHive->FileFullPath.MaximumLength = HiveName->MaximumLength;
388 }
389
390 /* Return success */
391 return STATUS_SUCCESS;
392 }
393
394 NTSTATUS
395 NTAPI
396 INIT_FUNCTION
397 CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
398 {
399 OBJECT_ATTRIBUTES ObjectAttributes;
400 UNICODE_STRING KeyName, ValueName = { 0, 0, NULL };
401 HANDLE KeyHandle = NULL;
402 NTSTATUS Status;
403 ASSERT(LoaderBlock != NULL);
404
405 /* Setup attributes for loader options */
406 RtlInitUnicodeString(&KeyName,
407 L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\"
408 L"Control");
409 InitializeObjectAttributes(&ObjectAttributes,
410 &KeyName,
411 OBJ_CASE_INSENSITIVE,
412 NULL,
413 NULL);
414 Status = NtOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
415 if (!NT_SUCCESS(Status)) goto Quickie;
416
417 /* Key opened, now write to the key */
418 RtlInitUnicodeString(&KeyName, L"SystemStartOptions");
419 Status = ZwSetValueKey(KeyHandle,
420 &KeyName,
421 0,
422 REG_SZ,
423 CmpLoadOptions.Buffer,
424 CmpLoadOptions.Length);
425 if (!NT_SUCCESS(Status)) goto Quickie;
426
427 /* Setup value name for system boot device in ARC format */
428 RtlInitUnicodeString(&KeyName, L"SystemBootDevice");
429 RtlCreateUnicodeStringFromAsciiz(&ValueName, LoaderBlock->ArcBootDeviceName);
430 Status = ZwSetValueKey(KeyHandle,
431 &KeyName,
432 0,
433 REG_SZ,
434 ValueName.Buffer,
435 ValueName.Length);
436
437 Quickie:
438 /* Free the buffers */
439 RtlFreeUnicodeString(&ValueName);
440
441 /* Close the key and return */
442 if (KeyHandle) NtClose(KeyHandle);
443
444 /* Return the status */
445 return (ExpInTextModeSetup ? STATUS_SUCCESS : Status);
446 }
447
448 NTSTATUS
449 NTAPI
450 INIT_FUNCTION
451 CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
452 {
453 UNICODE_STRING ConfigName = RTL_CONSTANT_STRING(L"Control\\IDConfigDB");
454 UNICODE_STRING SelectName =
455 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\Select");
456 UNICODE_STRING KeyName;
457 OBJECT_ATTRIBUTES ObjectAttributes;
458 CHAR ValueInfoBuffer[128];
459 PKEY_VALUE_FULL_INFORMATION ValueInfo;
460 CHAR Buffer[128];
461 WCHAR UnicodeBuffer[128];
462 HANDLE SelectHandle, KeyHandle, ConfigHandle = NULL, ProfileHandle = NULL;
463 HANDLE ParentHandle = NULL;
464 ULONG ControlSet, HwProfile;
465 ANSI_STRING TempString;
466 NTSTATUS Status;
467 ULONG ResultLength, Disposition;
468 PLOADER_PARAMETER_EXTENSION LoaderExtension;
469 PAGED_CODE();
470
471 /* Open the select key */
472 InitializeObjectAttributes(&ObjectAttributes,
473 &SelectName,
474 OBJ_CASE_INSENSITIVE,
475 NULL,
476 NULL);
477 Status = ZwOpenKey(&SelectHandle, KEY_READ, &ObjectAttributes);
478 if (!NT_SUCCESS(Status))
479 {
480 /* ReactOS Hack: Hard-code current to 001 for SetupLdr */
481 if (!LoaderBlock->RegistryBase)
482 {
483 /* Build the ControlSet001 key */
484 RtlInitUnicodeString(&KeyName,
485 L"\\Registry\\Machine\\System\\ControlSet001");
486 InitializeObjectAttributes(&ObjectAttributes,
487 &KeyName,
488 OBJ_CASE_INSENSITIVE,
489 NULL,
490 NULL);
491 Status = ZwCreateKey(&KeyHandle,
492 KEY_ALL_ACCESS,
493 &ObjectAttributes,
494 0,
495 NULL,
496 0,
497 &Disposition);
498 if (!NT_SUCCESS(Status))
499 return Status;
500
501 /* We 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 = ZwCreateKey(&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 = ZwSetValueKey(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 ZwClose(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 = ZwSetValueKey(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 CmpLinkKeyToHive(L"\\Registry\\User\\S-1-5-18",
1475 L"\\Registry\\User\\.Default");
1476 }
1477
1478 BOOLEAN
1479 NTAPI
1480 INIT_FUNCTION
1481 CmInitSystem1(VOID)
1482 {
1483 OBJECT_ATTRIBUTES ObjectAttributes;
1484 UNICODE_STRING KeyName;
1485 HANDLE KeyHandle;
1486 NTSTATUS Status;
1487 PCMHIVE HardwareHive;
1488 PSECURITY_DESCRIPTOR SecurityDescriptor;
1489 PAGED_CODE();
1490
1491 /* Check if this is PE-boot */
1492 if (InitIsWinPEMode)
1493 {
1494 /* Set registry to PE mode */
1495 CmpMiniNTBoot = TRUE;
1496 CmpShareSystemHives = TRUE;
1497 }
1498
1499 /* Initialize the hive list and lock */
1500 InitializeListHead(&CmpHiveListHead);
1501 ExInitializePushLock(&CmpHiveListHeadLock);
1502 ExInitializePushLock(&CmpLoadHiveLock);
1503
1504 /* Initialize registry lock */
1505 ExInitializeResourceLite(&CmpRegistryLock);
1506
1507 /* Initialize the cache */
1508 CmpInitializeCache();
1509
1510 /* Initialize allocation and delayed dereferencing */
1511 CmpInitCmPrivateAlloc();
1512 CmpInitCmPrivateDelayAlloc();
1513 CmpInitDelayDerefKCBEngine();
1514
1515 /* Initialize callbacks */
1516 CmpInitCallback();
1517
1518 /* Initialize self healing */
1519 KeInitializeGuardedMutex(&CmpSelfHealQueueLock);
1520 InitializeListHead(&CmpSelfHealQueueListHead);
1521
1522 /* Save the current process and lock the registry */
1523 CmpSystemProcess = PsGetCurrentProcess();
1524
1525 /* Create the key object types */
1526 Status = CmpCreateObjectTypes();
1527 if (!NT_SUCCESS(Status))
1528 {
1529 /* Bugcheck */
1530 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 1, Status, 0);
1531 }
1532
1533 /* Build the master hive */
1534 Status = CmpInitializeHive((PCMHIVE*)&CmiVolatileHive,
1535 HINIT_CREATE,
1536 HIVE_VOLATILE,
1537 HFILE_TYPE_PRIMARY,
1538 NULL,
1539 NULL,
1540 NULL,
1541 NULL,
1542 NULL,
1543 0);
1544 if (!NT_SUCCESS(Status))
1545 {
1546 /* Bugcheck */
1547 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 2, Status, 0);
1548 }
1549
1550 /* Create the \REGISTRY key node */
1551 if (!CmpCreateRegistryRoot())
1552 {
1553 /* Bugcheck */
1554 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 3, 0, 0);
1555 }
1556
1557 /* Create the default security descriptor */
1558 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
1559
1560 /* Create '\Registry\Machine' key. */
1561 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE");
1562 InitializeObjectAttributes(&ObjectAttributes,
1563 &KeyName,
1564 OBJ_CASE_INSENSITIVE,
1565 NULL,
1566 SecurityDescriptor);
1567 Status = NtCreateKey(&KeyHandle,
1568 KEY_READ | KEY_WRITE,
1569 &ObjectAttributes,
1570 0,
1571 NULL,
1572 0,
1573 NULL);
1574 if (!NT_SUCCESS(Status))
1575 {
1576 /* Bugcheck */
1577 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 5, Status, 0);
1578 }
1579
1580 /* Close the handle */
1581 NtClose(KeyHandle);
1582
1583 /* Create '\Registry\User' key. */
1584 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\USER");
1585 InitializeObjectAttributes(&ObjectAttributes,
1586 &KeyName,
1587 OBJ_CASE_INSENSITIVE,
1588 NULL,
1589 SecurityDescriptor);
1590 Status = NtCreateKey(&KeyHandle,
1591 KEY_READ | KEY_WRITE,
1592 &ObjectAttributes,
1593 0,
1594 NULL,
1595 0,
1596 NULL);
1597 if (!NT_SUCCESS(Status))
1598 {
1599 /* Bugcheck */
1600 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 6, Status, 0);
1601 }
1602
1603 /* Close the handle */
1604 NtClose(KeyHandle);
1605
1606 /* Initialize the system hive */
1607 if (!CmpInitializeSystemHive(KeLoaderBlock))
1608 {
1609 /* Bugcheck */
1610 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 7, 0, 0);
1611 }
1612
1613 /* Create the 'CurrentControlSet' link. */
1614 Status = CmpCreateControlSet(KeLoaderBlock);
1615 if (!NT_SUCCESS(Status))
1616 {
1617 /* Bugcheck */
1618 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 8, Status, 0);
1619 }
1620
1621 /* Create the hardware hive */
1622 Status = CmpInitializeHive((PCMHIVE*)&HardwareHive,
1623 HINIT_CREATE,
1624 HIVE_VOLATILE,
1625 HFILE_TYPE_PRIMARY,
1626 NULL,
1627 NULL,
1628 NULL,
1629 NULL,
1630 NULL,
1631 0);
1632 if (!NT_SUCCESS(Status))
1633 {
1634 /* Bugcheck */
1635 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 11, Status, 0);
1636 }
1637
1638 /* Add the hive to the hive list */
1639 CmpMachineHiveList[0].CmHive = (PCMHIVE)HardwareHive;
1640
1641 /* Attach it to the machine key */
1642 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE");
1643 Status = CmpLinkHiveToMaster(&KeyName,
1644 NULL,
1645 (PCMHIVE)HardwareHive,
1646 TRUE,
1647 SecurityDescriptor);
1648 if (!NT_SUCCESS(Status))
1649 {
1650 /* Bugcheck */
1651 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 12, Status, 0);
1652 }
1653
1654 /* Add to HiveList key */
1655 CmpAddToHiveFileList(HardwareHive);
1656
1657 /* Free the security descriptor */
1658 ExFreePoolWithTag(SecurityDescriptor, TAG_CM);
1659
1660 /* Fill out the Hardware key with the ARC Data from the Loader */
1661 Status = CmpInitializeHardwareConfiguration(KeLoaderBlock);
1662 if (!NT_SUCCESS(Status))
1663 {
1664 /* Bugcheck */
1665 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 13, Status, 0);
1666 }
1667
1668 /* Initialize machine-dependent information into the registry */
1669 Status = CmpInitializeMachineDependentConfiguration(KeLoaderBlock);
1670 if (!NT_SUCCESS(Status))
1671 {
1672 /* Bugcheck */
1673 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 14, Status, 0);
1674 }
1675
1676 /* Initialize volatile registry settings */
1677 Status = CmpSetSystemValues(KeLoaderBlock);
1678 if (!NT_SUCCESS(Status))
1679 {
1680 /* Bugcheck */
1681 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 15, Status, 0);
1682 }
1683
1684 /* Free the load options */
1685 ExFreePoolWithTag(CmpLoadOptions.Buffer, TAG_CM);
1686
1687 /* If we got here, all went well */
1688 return TRUE;
1689 }
1690
1691 VOID
1692 NTAPI
1693 INIT_FUNCTION
1694 CmpFreeDriverList(IN PHHIVE Hive,
1695 IN PLIST_ENTRY DriverList)
1696 {
1697 PLIST_ENTRY NextEntry, OldEntry;
1698 PBOOT_DRIVER_NODE DriverNode;
1699 PAGED_CODE();
1700
1701 /* Parse the current list */
1702 NextEntry = DriverList->Flink;
1703 while (NextEntry != DriverList)
1704 {
1705 /* Get the driver node */
1706 DriverNode = CONTAINING_RECORD(NextEntry, BOOT_DRIVER_NODE, ListEntry.Link);
1707
1708 /* Get the next entry now, since we're going to free it later */
1709 OldEntry = NextEntry;
1710 NextEntry = NextEntry->Flink;
1711
1712 /* Was there a name? */
1713 if (DriverNode->Name.Buffer)
1714 {
1715 /* Free it */
1716 CmpFree(DriverNode->Name.Buffer, DriverNode->Name.Length);
1717 }
1718
1719 /* Was there a registry path? */
1720 if (DriverNode->ListEntry.RegistryPath.Buffer)
1721 {
1722 /* Free it */
1723 CmpFree(DriverNode->ListEntry.RegistryPath.Buffer,
1724 DriverNode->ListEntry.RegistryPath.MaximumLength);
1725 }
1726
1727 /* Was there a file path? */
1728 if (DriverNode->ListEntry.FilePath.Buffer)
1729 {
1730 /* Free it */
1731 CmpFree(DriverNode->ListEntry.FilePath.Buffer,
1732 DriverNode->ListEntry.FilePath.MaximumLength);
1733 }
1734
1735 /* Now free the node, and move on */
1736 CmpFree(OldEntry, sizeof(BOOT_DRIVER_NODE));
1737 }
1738 }
1739
1740 PUNICODE_STRING*
1741 NTAPI
1742 INIT_FUNCTION
1743 CmGetSystemDriverList(VOID)
1744 {
1745 LIST_ENTRY DriverList;
1746 OBJECT_ATTRIBUTES ObjectAttributes;
1747 NTSTATUS Status;
1748 PCM_KEY_BODY KeyBody;
1749 PHHIVE Hive;
1750 HCELL_INDEX RootCell, ControlCell;
1751 HANDLE KeyHandle;
1752 UNICODE_STRING KeyName;
1753 PLIST_ENTRY NextEntry;
1754 ULONG i;
1755 PUNICODE_STRING* ServicePath = NULL;
1756 BOOLEAN Success, AutoSelect;
1757 PBOOT_DRIVER_LIST_ENTRY DriverEntry;
1758 PAGED_CODE();
1759
1760 /* Initialize the driver list */
1761 InitializeListHead(&DriverList);
1762
1763 /* Open the system hive key */
1764 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System");
1765 InitializeObjectAttributes(&ObjectAttributes,
1766 &KeyName,
1767 OBJ_CASE_INSENSITIVE,
1768 NULL,
1769 NULL);
1770 Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
1771 if (!NT_SUCCESS(Status)) return NULL;
1772
1773 /* Reference the key object to get the root hive/cell to access directly */
1774 Status = ObReferenceObjectByHandle(KeyHandle,
1775 KEY_QUERY_VALUE,
1776 CmpKeyObjectType,
1777 KernelMode,
1778 (PVOID*)&KeyBody,
1779 NULL);
1780 if (!NT_SUCCESS(Status))
1781 {
1782 /* Fail */
1783 NtClose(KeyHandle);
1784 return NULL;
1785 }
1786
1787 /* Do all this under the registry lock */
1788 CmpLockRegistryExclusive();
1789
1790 /* Get the hive and key cell */
1791 Hive = KeyBody->KeyControlBlock->KeyHive;
1792 RootCell = KeyBody->KeyControlBlock->KeyCell;
1793
1794 /* Open the current control set key */
1795 RtlInitUnicodeString(&KeyName, L"Current");
1796 ControlCell = CmpFindControlSet(Hive, RootCell, &KeyName, &AutoSelect);
1797 if (ControlCell == HCELL_NIL) goto EndPath;
1798
1799 /* Find all system drivers */
1800 Success = CmpFindDrivers(Hive, ControlCell, SystemLoad, NULL, &DriverList);
1801 if (!Success) goto EndPath;
1802
1803 /* Sort by group/tag */
1804 if (!CmpSortDriverList(Hive, ControlCell, &DriverList)) goto EndPath;
1805
1806 /* Remove circular dependencies (cycles) and sort */
1807 if (!CmpResolveDriverDependencies(&DriverList)) goto EndPath;
1808
1809 /* Loop the list to count drivers */
1810 for (i = 0, NextEntry = DriverList.Flink;
1811 NextEntry != &DriverList;
1812 i++, NextEntry = NextEntry->Flink);
1813
1814 /* Allocate the array */
1815 ServicePath = ExAllocatePool(NonPagedPool, (i + 1) * sizeof(PUNICODE_STRING));
1816 if (!ServicePath) KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0);
1817
1818 /* Loop the driver list */
1819 for (i = 0, NextEntry = DriverList.Flink;
1820 NextEntry != &DriverList;
1821 i++, NextEntry = NextEntry->Flink)
1822 {
1823 /* Get the entry */
1824 DriverEntry = CONTAINING_RECORD(NextEntry, BOOT_DRIVER_LIST_ENTRY, Link);
1825
1826 /* Allocate the path for the caller and duplicate the registry path */
1827 ServicePath[i] = ExAllocatePool(NonPagedPool, sizeof(UNICODE_STRING));
1828 RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1829 &DriverEntry->RegistryPath,
1830 ServicePath[i]);
1831 }
1832
1833 /* Terminate the list */
1834 ServicePath[i] = NULL;
1835
1836 EndPath:
1837 /* Free the driver list if we had one */
1838 if (!IsListEmpty(&DriverList)) CmpFreeDriverList(Hive, &DriverList);
1839
1840 /* Unlock the registry */
1841 CmpUnlockRegistry();
1842
1843 /* Close the key handle and dereference the object, then return the path */
1844 ObDereferenceObject(KeyBody);
1845 NtClose(KeyHandle);
1846 return ServicePath;
1847 }
1848
1849 VOID
1850 NTAPI
1851 CmpLockRegistryExclusive(VOID)
1852 {
1853 /* Enter a critical region and lock the registry */
1854 KeEnterCriticalRegion();
1855 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
1856
1857 /* Sanity check */
1858 ASSERT(CmpFlushStarveWriters == 0);
1859 RtlGetCallersAddress(&CmpRegistryLockCaller, &CmpRegistryLockCallerCaller);
1860 }
1861
1862 VOID
1863 NTAPI
1864 CmpLockRegistry(VOID)
1865 {
1866 /* Enter a critical region */
1867 KeEnterCriticalRegion();
1868
1869 /* Check if we have to starve writers */
1870 if (CmpFlushStarveWriters)
1871 {
1872 /* Starve exlusive waiters */
1873 ExAcquireSharedStarveExclusive(&CmpRegistryLock, TRUE);
1874 }
1875 else
1876 {
1877 /* Just grab the lock */
1878 ExAcquireResourceSharedLite(&CmpRegistryLock, TRUE);
1879 }
1880 }
1881
1882 BOOLEAN
1883 NTAPI
1884 CmpTestRegistryLock(VOID)
1885 {
1886 /* Test the lock */
1887 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock) ? FALSE : TRUE;
1888 }
1889
1890 BOOLEAN
1891 NTAPI
1892 CmpTestRegistryLockExclusive(VOID)
1893 {
1894 /* Test the lock */
1895 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock) ? FALSE : TRUE;
1896 }
1897
1898 VOID
1899 NTAPI
1900 CmpLockHiveFlusherExclusive(IN PCMHIVE Hive)
1901 {
1902 /* Lock the flusher. We should already be in a critical section */
1903 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive);
1904 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) &&
1905 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0));
1906 ExAcquireResourceExclusiveLite(Hive->FlusherLock, TRUE);
1907 }
1908
1909 VOID
1910 NTAPI
1911 CmpLockHiveFlusherShared(IN PCMHIVE Hive)
1912 {
1913 /* Lock the flusher. We should already be in a critical section */
1914 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive);
1915 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) &&
1916 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0));
1917 ExAcquireResourceSharedLite(Hive->FlusherLock, TRUE);
1918 }
1919
1920 VOID
1921 NTAPI
1922 CmpUnlockHiveFlusher(IN PCMHIVE Hive)
1923 {
1924 /* Sanity check */
1925 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive);
1926 CMP_ASSERT_FLUSH_LOCK(Hive);
1927
1928 /* Release the lock */
1929 ExReleaseResourceLite(Hive->FlusherLock);
1930 }
1931
1932 BOOLEAN
1933 NTAPI
1934 CmpTestHiveFlusherLockShared(IN PCMHIVE Hive)
1935 {
1936 /* Test the lock */
1937 return !ExIsResourceAcquiredSharedLite(Hive->FlusherLock) ? FALSE : TRUE;
1938 }
1939
1940 BOOLEAN
1941 NTAPI
1942 CmpTestHiveFlusherLockExclusive(IN PCMHIVE Hive)
1943 {
1944 /* Test the lock */
1945 return !ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) ? FALSE : TRUE;
1946 }
1947
1948 VOID
1949 NTAPI
1950 CmpUnlockRegistry(VOID)
1951 {
1952 /* Sanity check */
1953 CMP_ASSERT_REGISTRY_LOCK();
1954
1955 /* Check if we should flush the registry */
1956 if (CmpFlushOnLockRelease)
1957 {
1958 /* The registry should be exclusively locked for this */
1959 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
1960
1961 /* Flush the registry */
1962 CmpDoFlushAll(TRUE);
1963 CmpFlushOnLockRelease = FALSE;
1964 }
1965 else
1966 {
1967 /* Lazy flush the registry */
1968 CmpLazyFlush();
1969 }
1970
1971 /* Release the lock and leave the critical region */
1972 ExReleaseResourceLite(&CmpRegistryLock);
1973 KeLeaveCriticalRegion();
1974 }
1975
1976 VOID
1977 NTAPI
1978 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1,
1979 IN ULONG ConvKey2)
1980 {
1981 ULONG Index1, Index2;
1982
1983 /* Sanity check */
1984 CMP_ASSERT_REGISTRY_LOCK();
1985
1986 /* Get hash indexes */
1987 Index1 = GET_HASH_INDEX(ConvKey1);
1988 Index2 = GET_HASH_INDEX(ConvKey2);
1989
1990 /* See which one is highest */
1991 if (Index1 < Index2)
1992 {
1993 /* Grab them in the proper order */
1994 CmpAcquireKcbLockExclusiveByKey(ConvKey1);
1995 CmpAcquireKcbLockExclusiveByKey(ConvKey2);
1996 }
1997 else
1998 {
1999 /* Grab the second one first, then the first */
2000 CmpAcquireKcbLockExclusiveByKey(ConvKey2);
2001 if (Index1 != Index2) CmpAcquireKcbLockExclusiveByKey(ConvKey1);
2002 }
2003 }
2004
2005 VOID
2006 NTAPI
2007 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1,
2008 IN ULONG ConvKey2)
2009 {
2010 ULONG Index1, Index2;
2011
2012 /* Sanity check */
2013 CMP_ASSERT_REGISTRY_LOCK();
2014
2015 /* Get hash indexes */
2016 Index1 = GET_HASH_INDEX(ConvKey1);
2017 Index2 = GET_HASH_INDEX(ConvKey2);
2018 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey2).Owner == KeGetCurrentThread()) ||
2019 (CmpTestRegistryLockExclusive()));
2020
2021 /* See which one is highest */
2022 if (Index1 < Index2)
2023 {
2024 /* Grab them in the proper order */
2025 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1).Owner == KeGetCurrentThread()) ||
2026 (CmpTestRegistryLockExclusive()));
2027 CmpReleaseKcbLockByKey(ConvKey2);
2028 CmpReleaseKcbLockByKey(ConvKey1);
2029 }
2030 else
2031 {
2032 /* Release the first one first, then the second */
2033 if (Index1 != Index2)
2034 {
2035 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1).Owner == KeGetCurrentThread()) ||
2036 (CmpTestRegistryLockExclusive()));
2037 CmpReleaseKcbLockByKey(ConvKey1);
2038 }
2039 CmpReleaseKcbLockByKey(ConvKey2);
2040 }
2041 }
2042
2043 VOID
2044 NTAPI
2045 CmShutdownSystem(VOID)
2046 {
2047 /* Kill the workers */
2048 if (!CmFirstTime) CmpShutdownWorkers();
2049
2050 /* Flush all hives */
2051 CmpLockRegistryExclusive();
2052 CmpDoFlushAll(TRUE);
2053 CmpUnlockRegistry();
2054 }
2055
2056 VOID
2057 NTAPI
2058 CmpSetVersionData(VOID)
2059 {
2060 OBJECT_ATTRIBUTES ObjectAttributes;
2061 UNICODE_STRING KeyName;
2062 UNICODE_STRING ValueName;
2063 UNICODE_STRING ValueData;
2064 HANDLE SoftwareKeyHandle = NULL;
2065 HANDLE MicrosoftKeyHandle = NULL;
2066 HANDLE WindowsNtKeyHandle = NULL;
2067 HANDLE CurrentVersionKeyHandle = NULL;
2068 WCHAR Buffer[128];
2069 NTSTATUS Status;
2070
2071 /* Open the 'CurrentVersion' key */
2072 RtlInitUnicodeString(&KeyName,
2073 L"\\REGISTRY\\MACHINE\\SOFTWARE");
2074
2075 InitializeObjectAttributes(&ObjectAttributes,
2076 &KeyName,
2077 OBJ_CASE_INSENSITIVE,
2078 NULL,
2079 NULL);
2080
2081 Status = NtCreateKey(&SoftwareKeyHandle,
2082 KEY_CREATE_SUB_KEY,
2083 &ObjectAttributes,
2084 0,
2085 NULL,
2086 0,
2087 NULL);
2088 if (!NT_SUCCESS(Status))
2089 {
2090 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status);
2091 return;
2092 }
2093
2094 /* Open the 'CurrentVersion' key */
2095 RtlInitUnicodeString(&KeyName,
2096 L"Microsoft");
2097
2098 InitializeObjectAttributes(&ObjectAttributes,
2099 &KeyName,
2100 OBJ_CASE_INSENSITIVE,
2101 SoftwareKeyHandle,
2102 NULL);
2103
2104 Status = NtCreateKey(&MicrosoftKeyHandle,
2105 KEY_CREATE_SUB_KEY,
2106 &ObjectAttributes,
2107 0,
2108 NULL,
2109 0,
2110 NULL);
2111 if (!NT_SUCCESS(Status))
2112 {
2113 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status);
2114 goto done;
2115 }
2116
2117 /* Open the 'CurrentVersion' key */
2118 RtlInitUnicodeString(&KeyName,
2119 L"Windows NT");
2120
2121 InitializeObjectAttributes(&ObjectAttributes,
2122 &KeyName,
2123 OBJ_CASE_INSENSITIVE,
2124 MicrosoftKeyHandle,
2125 NULL);
2126
2127 Status = NtCreateKey(&WindowsNtKeyHandle,
2128 KEY_CREATE_SUB_KEY,
2129 &ObjectAttributes,
2130 0,
2131 NULL,
2132 0,
2133 NULL);
2134 if (!NT_SUCCESS(Status))
2135 {
2136 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status);
2137 goto done;
2138 }
2139
2140 /* Open the 'CurrentVersion' key */
2141 RtlInitUnicodeString(&KeyName,
2142 L"CurrentVersion");
2143
2144 InitializeObjectAttributes(&ObjectAttributes,
2145 &KeyName,
2146 OBJ_CASE_INSENSITIVE,
2147 WindowsNtKeyHandle,
2148 NULL);
2149
2150 Status = NtCreateKey(&CurrentVersionKeyHandle,
2151 KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
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 done;
2161 }
2162
2163 /* Set the 'CurrentType' value */
2164 RtlInitUnicodeString(&ValueName,
2165 L"CurrentType");
2166
2167 #ifdef CONFIG_SMP
2168 wcscpy(Buffer, L"Multiprocessor");
2169 #else
2170 wcscpy(Buffer, L"Uniprocessor");
2171 #endif
2172
2173 wcscat(Buffer, L" ");
2174
2175 #if (DBG == 1)
2176 wcscat(Buffer, L"Checked");
2177 #else
2178 wcscat(Buffer, L"Free");
2179 #endif
2180
2181 RtlInitUnicodeString(&ValueData,
2182 Buffer);
2183
2184 ZwSetValueKey(CurrentVersionKeyHandle,
2185 &ValueName,
2186 0,
2187 REG_SZ,
2188 ValueData.Buffer,
2189 ValueData.Length + sizeof(WCHAR));
2190
2191 done:;
2192 /* Close the keys */
2193 if (CurrentVersionKeyHandle != NULL)
2194 NtClose(CurrentVersionKeyHandle);
2195
2196 if (WindowsNtKeyHandle != NULL)
2197 NtClose(WindowsNtKeyHandle);
2198
2199 if (MicrosoftKeyHandle != NULL)
2200 NtClose(MicrosoftKeyHandle);
2201
2202 if (SoftwareKeyHandle != NULL)
2203 NtClose(SoftwareKeyHandle);
2204 }
2205
2206 /* EOF */