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