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