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