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