3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/cm/registry.c
6 * PURPOSE: Registry functions
8 * PROGRAMMERS: Rex Jolliff
15 #include <internal/debug.h>
19 /* GLOBALS ******************************************************************/
21 POBJECT_TYPE CmiKeyType
= NULL
;
22 PREGISTRY_HIVE CmiVolatileHive
= NULL
;
24 LIST_ENTRY CmiHiveListHead
;
26 ERESOURCE CmiRegistryLock
;
28 KTIMER CmiWorkerTimer
;
29 LIST_ENTRY CmiKeyObjectListHead
;
32 volatile BOOLEAN CmiHiveSyncEnabled
= FALSE
;
33 volatile BOOLEAN CmiHiveSyncPending
= FALSE
;
35 KTIMER CmiHiveSyncTimer
;
37 static GENERIC_MAPPING CmiKeyMapping
=
38 {KEY_READ
, KEY_WRITE
, KEY_EXECUTE
, KEY_ALL_ACCESS
};
43 CmiCheckKey(BOOLEAN Verbose
,
47 CmiCreateCurrentControlSetLink(VOID
);
50 CmiHiveSyncDpcRoutine(PKDPC Dpc
,
51 PVOID DeferredContext
,
52 PVOID SystemArgument1
,
53 PVOID SystemArgument2
);
55 extern LIST_ENTRY CmiCallbackHead
;
56 extern FAST_MUTEX CmiCallbackLock
;
58 /* FUNCTIONS ****************************************************************/
61 CmiCheckSubKeys(BOOLEAN Verbose
,
64 OBJECT_ATTRIBUTES ObjectAttributes
;
65 PKEY_NODE_INFORMATION KeyInfo
;
66 WCHAR KeyBuffer
[MAX_PATH
];
67 UNICODE_STRING KeyPath
;
78 BufferSize
= sizeof(KEY_NODE_INFORMATION
) + 4096;
79 KeyInfo
= ExAllocatePool(PagedPool
, BufferSize
);
81 Status
= ZwEnumerateKey(Key
,
87 if (!NT_SUCCESS(Status
))
90 if (Status
== STATUS_NO_MORE_ENTRIES
)
91 Status
= STATUS_SUCCESS
;
97 KeyInfo
->NameLength
/ sizeof(WCHAR
));
101 DbgPrint("Key: %S\n", Name
);
104 /* FIXME: Check info. */
108 wcscpy(KeyBuffer
, L
"\\Registry\\");
109 wcscat(KeyBuffer
, Name
);
111 RtlInitUnicodeString(&KeyPath
, KeyBuffer
);
113 InitializeObjectAttributes(&ObjectAttributes
,
115 OBJ_CASE_INSENSITIVE
,
119 Status
= ZwOpenKey(&SubKey
,
123 ASSERT(NT_SUCCESS(Status
));
125 CmiCheckKey(Verbose
, SubKey
);
132 ASSERT(NT_SUCCESS(Status
));
137 CmiCheckValues(BOOLEAN Verbose
,
140 PKEY_NODE_INFORMATION ValueInfo
;
141 WCHAR Name
[MAX_PATH
];
150 BufferSize
= sizeof(KEY_NODE_INFORMATION
) + 4096;
151 ValueInfo
= ExAllocatePool(PagedPool
, BufferSize
);
153 Status
= ZwEnumerateValueKey(Key
,
159 if (!NT_SUCCESS(Status
))
161 ExFreePool(ValueInfo
);
162 if (Status
== STATUS_NO_MORE_ENTRIES
)
163 Status
= STATUS_SUCCESS
;
169 ValueInfo
->NameLength
/ sizeof(WCHAR
));
173 DbgPrint("Value: %S\n", Name
);
176 /* FIXME: Check info. */
178 ExFreePool(ValueInfo
);
183 ASSERT(NT_SUCCESS(Status
));
188 CmiCheckKey(BOOLEAN Verbose
,
191 CmiCheckValues(Verbose
, Key
);
192 CmiCheckSubKeys(Verbose
, Key
);
197 CmiCheckByName(BOOLEAN Verbose
,
200 OBJECT_ATTRIBUTES ObjectAttributes
;
201 WCHAR KeyPathBuffer
[MAX_PATH
];
202 UNICODE_STRING KeyPath
;
206 wcscpy(KeyPathBuffer
, L
"\\Registry\\");
207 wcscat(KeyPathBuffer
, KeyName
);
209 RtlInitUnicodeString(&KeyPath
, KeyPathBuffer
);
211 InitializeObjectAttributes(&ObjectAttributes
,
213 OBJ_CASE_INSENSITIVE
,
217 Status
= ZwOpenKey(&Key
,
223 if (!NT_SUCCESS(Status
))
225 DbgPrint("KeyPath %wZ Status: %.08x", KeyPath
, Status
);
226 DbgPrint("KeyPath %S Status: %.08x", KeyPath
.Buffer
, Status
);
227 ASSERT(NT_SUCCESS(Status
));
231 CmiCheckKey(Verbose
, Key
);
238 CmiCheckRegistry(BOOLEAN Verbose
)
241 DbgPrint("Checking registry internals\n");
243 CmiCheckByName(Verbose
, L
"Machine");
244 CmiCheckByName(Verbose
, L
"User");
248 CmiWorkerThread(PVOID Param
)
251 PLIST_ENTRY CurrentEntry
;
252 PKEY_OBJECT CurrentKey
;
258 Status
= KeWaitForSingleObject(&CmiWorkerTimer
,
263 if (Status
== STATUS_SUCCESS
)
265 DPRINT("CmiWorkerThread\n");
267 /* Acquire hive lock */
268 KeEnterCriticalRegion();
269 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
274 CurrentEntry
= CmiKeyObjectListHead
.Blink
;
275 while (CurrentEntry
!= &CmiKeyObjectListHead
)
277 CurrentKey
= CONTAINING_RECORD(CurrentEntry
, KEY_OBJECT
, ListEntry
);
278 if (CurrentKey
->TimeStamp
+ 120 > CmiTimer
)
280 /* The object was accessed in the last 10min */
283 if (1 == ObGetObjectPointerCount(CurrentKey
) &&
284 !(CurrentKey
->Flags
& KO_MARKED_FOR_DELETE
))
286 ObDereferenceObject(CurrentKey
);
287 CurrentEntry
= CmiKeyObjectListHead
.Blink
;
292 CurrentEntry
= CurrentEntry
->Blink
;
295 ExReleaseResourceLite(&CmiRegistryLock
);
296 KeLeaveCriticalRegion();
298 DPRINT("Removed %d key objects\n", Count
);
311 CmInitHives(BOOLEAN SetupBoot
)
315 /* Load Registry Hives. This one can be missing. */
316 if (CachedModules
[SystemRegistry
]) {
317 BaseAddress
= (PCHAR
)CachedModules
[SystemRegistry
]->ModStart
;
318 CmImportSystemHive(BaseAddress
,
319 CachedModules
[SystemRegistry
]->ModEnd
- (ULONG_PTR
)BaseAddress
);
322 BaseAddress
= (PCHAR
)CachedModules
[HardwareRegistry
]->ModStart
;
323 CmImportHardwareHive(BaseAddress
,
324 CachedModules
[HardwareRegistry
]->ModEnd
- (ULONG_PTR
)BaseAddress
);
327 /* Create dummy keys if no hardware hive was found */
328 CmImportHardwareHive (NULL
, 0);
330 /* Initialize volatile registry settings */
331 if (SetupBoot
== FALSE
) CmInit2((PCHAR
)KeLoaderBlock
.CommandLine
);
336 CmInitializeRegistry(VOID
)
338 OBJECT_ATTRIBUTES ObjectAttributes
;
339 UNICODE_STRING KeyName
;
342 PSECURITY_CELL RootSecurityCell
;
344 HANDLE RootKeyHandle
;
347 LARGE_INTEGER DueTime
;
350 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
353 DPRINT("Creating Registry Object Type\n");
355 /* Initialize the Key object type */
356 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
357 RtlInitUnicodeString(&Name
, L
"Key");
358 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
359 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(KEY_OBJECT
);
360 ObjectTypeInitializer
.GenericMapping
= CmiKeyMapping
;
361 ObjectTypeInitializer
.PoolType
= PagedPool
;
362 ObjectTypeInitializer
.ValidAccessMask
= KEY_ALL_ACCESS
;
363 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
364 ObjectTypeInitializer
.DeleteProcedure
= CmiObjectDelete
;
365 ObjectTypeInitializer
.ParseProcedure
= CmiObjectParse
;
366 ObjectTypeInitializer
.SecurityProcedure
= CmiObjectSecurity
;
367 ObjectTypeInitializer
.QueryNameProcedure
= CmiObjectQueryName
;
369 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &CmiKeyType
);
371 /* Initialize the hive list */
372 InitializeListHead(&CmiHiveListHead
);
374 /* Initialize registry lock */
375 ExInitializeResourceLite(&CmiRegistryLock
);
377 /* Initialize the key object list */
378 InitializeListHead(&CmiKeyObjectListHead
);
380 /* Initialize the worker timer */
381 KeInitializeTimerEx(&CmiWorkerTimer
, SynchronizationTimer
);
383 /* Initialize the worker thread */
384 Status
= PsCreateSystemThread(&ThreadHandle
,
391 if (!NT_SUCCESS(Status
))
396 /* Start the timer */
397 DueTime
.QuadPart
= -1;
398 KeSetTimerEx(&CmiWorkerTimer
, DueTime
, 5000, NULL
); /* 5sec */
400 /* Build volatile registry store */
401 Status
= CmiCreateVolatileHive (&CmiVolatileHive
);
402 ASSERT(NT_SUCCESS(Status
));
404 InitializeListHead(&CmiCallbackHead
);
405 ExInitializeFastMutex(&CmiCallbackLock
);
407 /* Create '\Registry' key. */
408 RtlInitUnicodeString(&KeyName
, REG_ROOT_KEY_NAME
);
409 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, 0, NULL
, NULL
);
410 Status
= ObCreateObject(KernelMode
,
419 ASSERT(NT_SUCCESS(Status
));
420 Status
= ObInsertObject(RootKey
,
426 ASSERT(NT_SUCCESS(Status
));
427 RootKey
->RegistryHive
= CmiVolatileHive
;
428 RootKey
->KeyCellOffset
= CmiVolatileHive
->HiveHeader
->RootKeyOffset
;
429 RootKey
->KeyCell
= CmiGetCell (CmiVolatileHive
, RootKey
->KeyCellOffset
, NULL
);
430 RootKey
->ParentKey
= RootKey
;
432 RootKey
->NumberOfSubKeys
= 0;
433 RootKey
->SubKeys
= NULL
;
434 RootKey
->SizeOfSubKeys
= 0;
435 InsertTailList(&CmiKeyObjectListHead
, &RootKey
->ListEntry
);
436 Status
= RtlpCreateUnicodeString(&RootKey
->Name
, L
"Registry", NonPagedPool
);
437 ASSERT(NT_SUCCESS(Status
));
440 Status
= CmiAllocateCell(CmiVolatileHive
,
441 0x10, //LONG CellSize,
442 (PVOID
*)&RootSecurityCell
,
443 &RootKey
->KeyCell
->SecurityKeyOffset
);
444 ASSERT(NT_SUCCESS(Status
));
446 /* Copy the security descriptor */
448 CmiVolatileHive
->RootSecurityCell
= RootSecurityCell
;
452 /* Create '\Registry\Machine' key. */
453 RtlInitUnicodeString(&KeyName
,
455 InitializeObjectAttributes(&ObjectAttributes
,
460 Status
= ZwCreateKey(&KeyHandle
,
467 ASSERT(NT_SUCCESS(Status
));
469 /* Create '\Registry\User' key. */
470 RtlInitUnicodeString(&KeyName
,
472 InitializeObjectAttributes(&ObjectAttributes
,
477 Status
= ZwCreateKey(&KeyHandle
,
484 ASSERT(NT_SUCCESS(Status
));
489 CmInit2(PCHAR CommandLine
)
492 BOOLEAN MiniNT
= FALSE
;
493 PWCHAR SystemBootDevice
;
494 PWCHAR SystemStartOptions
;
498 /* Create the 'CurrentControlSet' link. */
499 Status
= CmiCreateCurrentControlSetLink();
500 if (!NT_SUCCESS(Status
))
501 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
504 * Parse the system boot device.
507 SystemBootDevice
= ExAllocatePool(PagedPool
,
508 (strlen(CommandLine
) + 1) * sizeof(WCHAR
));
509 if (SystemBootDevice
== NULL
)
511 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
514 while (*CommandLine
!= 0 && *CommandLine
!= ' ')
515 SystemBootDevice
[Position
++] = *(CommandLine
++);
516 SystemBootDevice
[Position
++] = 0;
519 * Write the system boot device to registry.
521 Status
= RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
522 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
526 Position
* sizeof(WCHAR
));
527 if (!NT_SUCCESS(Status
))
529 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
533 * Parse the system start options.
536 SystemStartOptions
= SystemBootDevice
;
537 while ((CommandLine
= strchr(CommandLine
, '/')) != NULL
)
539 /* Skip over the slash */
542 /* Special options */
543 if (!_strnicmp(CommandLine
, "MININT", 6))
545 else if (!_strnicmp(CommandLine
, "DEBUGPORT=PICE", 14))
548 /* Add a space between the options */
550 SystemStartOptions
[Position
++] = L
' ';
552 /* Copy the command */
553 while (*CommandLine
!= 0 && *CommandLine
!= ' ')
554 SystemStartOptions
[Position
++] = *(CommandLine
++);
556 SystemStartOptions
[Position
++] = 0;
559 * Write the system start options to registry.
561 Status
= RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
562 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
563 L
"SystemStartOptions",
566 Position
* sizeof(WCHAR
));
567 if (!NT_SUCCESS(Status
))
569 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
573 * Create a CurrentControlSet\Control\MiniNT key that is used
574 * to detect WinPE/MiniNT systems.
578 Status
= RtlCreateRegistryKey(RTL_REGISTRY_CONTROL
, L
"MiniNT");
579 if (!NT_SUCCESS(Status
))
580 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
583 /* Set PICE 'Start' value to 1, if PICE debugging is enabled */
584 Status
= RtlWriteRegistryValue(
585 RTL_REGISTRY_SERVICES
,
591 if (!NT_SUCCESS(Status
))
592 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
594 ExFreePool(SystemBootDevice
);
599 CmiCreateCurrentControlSetLink(VOID
)
601 RTL_QUERY_REGISTRY_TABLE QueryTable
[5];
602 WCHAR TargetNameBuffer
[80];
603 ULONG TargetNameLength
;
604 UNICODE_STRING LinkName
= RTL_CONSTANT_STRING(
605 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
606 UNICODE_STRING LinkValue
= RTL_CONSTANT_STRING(L
"SymbolicLinkValue");
612 OBJECT_ATTRIBUTES ObjectAttributes
;
615 DPRINT("CmiCreateCurrentControlSetLink() called\n");
617 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
619 QueryTable
[0].Name
= L
"Current";
620 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
621 QueryTable
[0].EntryContext
= &CurrentSet
;
623 QueryTable
[1].Name
= L
"Default";
624 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
625 QueryTable
[1].EntryContext
= &DefaultSet
;
627 QueryTable
[2].Name
= L
"Failed";
628 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
629 QueryTable
[2].EntryContext
= &Failed
;
631 QueryTable
[3].Name
= L
"LastKnownGood";
632 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
633 QueryTable
[3].EntryContext
= &LastKnownGood
;
635 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
636 L
"\\Registry\\Machine\\SYSTEM\\Select",
640 if (!NT_SUCCESS(Status
))
645 DPRINT("Current %ld Default %ld\n", CurrentSet
, DefaultSet
);
647 swprintf(TargetNameBuffer
,
648 L
"\\Registry\\Machine\\SYSTEM\\ControlSet%03lu",
650 TargetNameLength
= wcslen(TargetNameBuffer
) * sizeof(WCHAR
);
652 DPRINT("Link target '%S'\n", TargetNameBuffer
);
654 InitializeObjectAttributes(&ObjectAttributes
,
656 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_OPENLINK
,
659 Status
= ZwCreateKey(&KeyHandle
,
660 KEY_ALL_ACCESS
| KEY_CREATE_LINK
,
664 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
666 if (!NT_SUCCESS(Status
))
668 DPRINT1("ZwCreateKey() failed (Status %lx)\n", Status
);
672 Status
= ZwSetValueKey(KeyHandle
,
676 (PVOID
)TargetNameBuffer
,
678 if (!NT_SUCCESS(Status
))
680 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
690 CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
691 IN PREGISTRY_HIVE RegistryHive
)
693 UNICODE_STRING RemainingPath
;
694 PKEY_OBJECT ParentKey
;
698 UNICODE_STRING ObjectName
;
699 OBJECT_CREATE_INFORMATION ObjectCreateInfo
;
701 DPRINT("CmiConnectHive(%p, %p) called.\n",
702 KeyObjectAttributes
, RegistryHive
);
704 /* Capture all the info */
705 DPRINT("Capturing Create Info\n");
706 Status
= ObpCaptureObjectAttributes(KeyObjectAttributes
,
712 if (!NT_SUCCESS(Status
))
714 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status
);
718 Status
= ObFindObject(&ObjectCreateInfo
,
723 ObpReleaseCapturedAttributes(&ObjectCreateInfo
,
727 if (!NT_SUCCESS(Status
))
732 DPRINT ("RemainingPath %wZ\n", &RemainingPath
);
734 if ((RemainingPath
.Buffer
== NULL
) || (RemainingPath
.Buffer
[0] == 0))
736 ObDereferenceObject (ParentKey
);
737 RtlFreeUnicodeString(&RemainingPath
);
738 return STATUS_OBJECT_NAME_COLLISION
;
741 /* Ignore leading backslash */
742 SubName
= RemainingPath
.Buffer
;
743 if (*SubName
== L
'\\')
746 /* If RemainingPath contains \ we must return error
747 because CmiConnectHive() can not create trees */
748 if (wcschr (SubName
, L
'\\') != NULL
)
750 ObDereferenceObject (ParentKey
);
751 RtlFreeUnicodeString(&RemainingPath
);
752 return STATUS_OBJECT_NAME_NOT_FOUND
;
755 DPRINT("RemainingPath %wZ ParentKey %p\n",
756 &RemainingPath
, ParentKey
);
758 Status
= ObCreateObject(KernelMode
,
768 if (!NT_SUCCESS(Status
))
770 DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status
);
771 ObDereferenceObject (ParentKey
);
772 RtlFreeUnicodeString(&RemainingPath
);
775 DPRINT("Inserting Key into Object Tree\n");
776 Status
= ObInsertObject((PVOID
)NewKey
,
782 DPRINT("Status %x\n", Status
);
783 NewKey
->RegistryHive
= RegistryHive
;
784 NewKey
->KeyCellOffset
= RegistryHive
->HiveHeader
->RootKeyOffset
;
785 NewKey
->KeyCell
= CmiGetCell (RegistryHive
, NewKey
->KeyCellOffset
, NULL
);
787 NewKey
->NumberOfSubKeys
= 0;
788 InsertTailList(&CmiKeyObjectListHead
, &NewKey
->ListEntry
);
789 if (NewKey
->KeyCell
->NumberOfSubKeys
!= 0)
791 NewKey
->SubKeys
= ExAllocatePool(NonPagedPool
,
792 NewKey
->KeyCell
->NumberOfSubKeys
* sizeof(ULONG
));
793 if (NewKey
->SubKeys
== NULL
)
795 DPRINT("ExAllocatePool() failed\n");
796 ObDereferenceObject (NewKey
);
797 ObDereferenceObject (ParentKey
);
798 RtlFreeUnicodeString(&RemainingPath
);
799 return STATUS_INSUFFICIENT_RESOURCES
;
804 NewKey
->SubKeys
= NULL
;
807 DPRINT ("SubName %S\n", SubName
);
809 Status
= RtlpCreateUnicodeString(&NewKey
->Name
,
810 SubName
, NonPagedPool
);
811 RtlFreeUnicodeString(&RemainingPath
);
812 if (!NT_SUCCESS(Status
))
814 DPRINT1("RtlpCreateUnicodeString() failed (Status %lx)\n", Status
);
815 if (NewKey
->SubKeys
!= NULL
)
817 ExFreePool (NewKey
->SubKeys
);
819 ObDereferenceObject (NewKey
);
820 ObDereferenceObject (ParentKey
);
821 return STATUS_INSUFFICIENT_RESOURCES
;
824 CmiAddKeyToList (ParentKey
, NewKey
);
825 ObDereferenceObject (ParentKey
);
827 VERIFY_KEY_OBJECT(NewKey
);
829 /* Note: Do not dereference NewKey here! */
831 return STATUS_SUCCESS
;
836 CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
837 OUT PREGISTRY_HIVE
*RegistryHive
)
839 PKEY_OBJECT KeyObject
;
843 PLIST_ENTRY CurrentEntry
;
844 PKEY_OBJECT CurrentKey
;
846 DPRINT("CmiDisconnectHive() called\n");
848 *RegistryHive
= NULL
;
850 Status
= ObOpenObjectByName (KeyObjectAttributes
,
854 STANDARD_RIGHTS_REQUIRED
,
857 if (!NT_SUCCESS(Status
))
859 DPRINT1 ("ObOpenObjectByName() failed (Status %lx)\n", Status
);
863 Status
= ObReferenceObjectByHandle (KeyHandle
,
864 STANDARD_RIGHTS_REQUIRED
,
870 if (!NT_SUCCESS(Status
))
872 DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status
);
875 DPRINT ("KeyObject %p Hive %p\n", KeyObject
, KeyObject
->RegistryHive
);
877 if (!(KeyObject
->KeyCell
->Flags
& REG_KEY_ROOT_CELL
))
879 DPRINT1 ("Key is not the Hive-Root-Key\n");
880 ObDereferenceObject (KeyObject
);
881 return STATUS_INVALID_PARAMETER
;
884 /* Acquire registry lock exclusively */
885 KeEnterCriticalRegion();
886 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
888 CurrentEntry
= CmiKeyObjectListHead
.Flink
;
889 while (CurrentEntry
!= &CmiKeyObjectListHead
)
891 CurrentKey
= CONTAINING_RECORD(CurrentEntry
, KEY_OBJECT
, ListEntry
);
892 if (1 == ObGetObjectPointerCount(CurrentKey
) &&
893 !(CurrentKey
->Flags
& KO_MARKED_FOR_DELETE
))
895 ObDereferenceObject(CurrentKey
);
896 CurrentEntry
= CmiKeyObjectListHead
.Flink
;
900 CurrentEntry
= CurrentEntry
->Flink
;
904 if (ObGetObjectHandleCount (KeyObject
) != 0 ||
905 ObGetObjectPointerCount (KeyObject
) != 2)
907 DPRINT1 ("Hive is still in use (hc %d, rc %d)\n", ObGetObjectHandleCount (KeyObject
), ObGetObjectPointerCount (KeyObject
));
908 ObDereferenceObject (KeyObject
);
910 /* Release registry lock */
911 ExReleaseResourceLite (&CmiRegistryLock
);
912 KeLeaveCriticalRegion();
914 return STATUS_UNSUCCESSFUL
;
917 Hive
= KeyObject
->RegistryHive
;
919 /* Dereference KeyObject twice to delete it */
920 ObDereferenceObject (KeyObject
);
921 ObDereferenceObject (KeyObject
);
923 *RegistryHive
= Hive
;
925 /* Release registry lock */
926 ExReleaseResourceLite (&CmiRegistryLock
);
927 KeLeaveCriticalRegion();
929 DPRINT ("CmiDisconnectHive() done\n");
931 return STATUS_SUCCESS
;
936 CmiInitControlSetLink (VOID
)
938 OBJECT_ATTRIBUTES ObjectAttributes
;
939 UNICODE_STRING ControlSetKeyName
= RTL_CONSTANT_STRING(
940 L
"\\Registry\\Machine\\SYSTEM\\ControlSet001");
941 UNICODE_STRING ControlSetLinkName
= RTL_CONSTANT_STRING(
942 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
943 UNICODE_STRING ControlSetValueName
= RTL_CONSTANT_STRING(L
"SymbolicLinkValue");
947 /* Create 'ControlSet001' key */
948 InitializeObjectAttributes (&ObjectAttributes
,
950 OBJ_CASE_INSENSITIVE
,
953 Status
= ZwCreateKey (&KeyHandle
,
958 REG_OPTION_NON_VOLATILE
,
960 if (!NT_SUCCESS(Status
))
962 DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status
);
967 /* Link 'CurrentControlSet' to 'ControlSet001' key */
968 InitializeObjectAttributes (&ObjectAttributes
,
970 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_OPENLINK
,
973 Status
= ZwCreateKey (&KeyHandle
,
974 KEY_ALL_ACCESS
| KEY_CREATE_LINK
,
978 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
980 if (!NT_SUCCESS(Status
))
982 DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status
);
986 Status
= ZwSetValueKey (KeyHandle
,
987 &ControlSetValueName
,
990 (PVOID
)ControlSetKeyName
.Buffer
,
991 ControlSetKeyName
.Length
);
992 if (!NT_SUCCESS(Status
))
994 DPRINT1 ("ZwSetValueKey() failed (Status %lx)\n", Status
);
998 return STATUS_SUCCESS
;
1003 CmiInitHives(BOOLEAN SetupBoot
)
1005 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
1006 OBJECT_ATTRIBUTES ObjectAttributes
;
1007 UNICODE_STRING FileName
;
1008 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE");
1009 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"InstallPath");
1014 WCHAR ConfigPath
[MAX_PATH
];
1021 DPRINT("CmiInitHives() called\n");
1023 if (SetupBoot
== TRUE
)
1025 InitializeObjectAttributes(&ObjectAttributes
,
1027 OBJ_CASE_INSENSITIVE
,
1030 Status
= ZwOpenKey(&KeyHandle
,
1033 if (!NT_SUCCESS(Status
))
1035 DPRINT1("ZwOpenKey() failed (Status %lx)\n", Status
);
1039 BufferSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4096;
1040 ValueInfo
= ExAllocatePool(PagedPool
,
1042 if (ValueInfo
== NULL
)
1045 return(STATUS_INSUFFICIENT_RESOURCES
);
1048 Status
= ZwQueryValueKey(KeyHandle
,
1050 KeyValuePartialInformation
,
1055 if (!NT_SUCCESS(Status
))
1057 ExFreePool(ValueInfo
);
1061 RtlCopyMemory(ConfigPath
,
1063 ValueInfo
->DataLength
);
1064 ConfigPath
[ValueInfo
->DataLength
/ sizeof(WCHAR
)] = (WCHAR
)0;
1065 ExFreePool(ValueInfo
);
1069 wcscpy(ConfigPath
, L
"\\SystemRoot");
1071 wcscat(ConfigPath
, L
"\\system32\\config");
1073 DPRINT("ConfigPath: %S\n", ConfigPath
);
1075 EndPtr
= ConfigPath
+ wcslen(ConfigPath
);
1079 /* FIXME: Save boot log */
1081 /* Connect the SYSTEM hive only if it has been created */
1082 if (SetupBoot
== TRUE
)
1084 wcscpy(EndPtr
, REG_SYSTEM_FILE_NAME
);
1085 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1087 RtlInitUnicodeString (&KeyName
,
1088 REG_SYSTEM_KEY_NAME
);
1089 InitializeObjectAttributes(&ObjectAttributes
,
1091 OBJ_CASE_INSENSITIVE
,
1095 RtlInitUnicodeString (&FileName
,
1097 Status
= CmiLoadHive (&ObjectAttributes
,
1100 if (!NT_SUCCESS(Status
))
1102 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status
);
1106 Status
= CmiInitControlSetLink ();
1107 if (!NT_SUCCESS(Status
))
1109 DPRINT1("CmiInitControlSetLink() failed (Status %lx)\n", Status
);
1114 /* Connect the SOFTWARE hive */
1115 wcscpy(EndPtr
, REG_SOFTWARE_FILE_NAME
);
1116 RtlInitUnicodeString (&FileName
,
1118 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1120 RtlInitUnicodeString (&KeyName
,
1121 REG_SOFTWARE_KEY_NAME
);
1122 InitializeObjectAttributes(&ObjectAttributes
,
1124 OBJ_CASE_INSENSITIVE
,
1128 Status
= CmiLoadHive (&ObjectAttributes
,
1131 if (!NT_SUCCESS(Status
))
1133 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1137 /* Connect the SAM hive */
1138 wcscpy(EndPtr
, REG_SAM_FILE_NAME
);
1139 RtlInitUnicodeString (&FileName
,
1141 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1143 RtlInitUnicodeString (&KeyName
,
1145 InitializeObjectAttributes(&ObjectAttributes
,
1147 OBJ_CASE_INSENSITIVE
,
1150 Status
= CmiLoadHive (&ObjectAttributes
,
1153 if (!NT_SUCCESS(Status
))
1155 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1159 /* Connect the SECURITY hive */
1160 wcscpy(EndPtr
, REG_SEC_FILE_NAME
);
1161 RtlInitUnicodeString (&FileName
,
1163 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1165 RtlInitUnicodeString (&KeyName
,
1167 InitializeObjectAttributes(&ObjectAttributes
,
1169 OBJ_CASE_INSENSITIVE
,
1172 Status
= CmiLoadHive (&ObjectAttributes
,
1175 if (!NT_SUCCESS(Status
))
1177 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1181 /* Connect the DEFAULT hive */
1182 wcscpy(EndPtr
, REG_DEFAULT_USER_FILE_NAME
);
1183 RtlInitUnicodeString (&FileName
,
1185 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1187 RtlInitUnicodeString (&KeyName
,
1188 REG_DEFAULT_USER_KEY_NAME
);
1189 InitializeObjectAttributes(&ObjectAttributes
,
1191 OBJ_CASE_INSENSITIVE
,
1194 Status
= CmiLoadHive (&ObjectAttributes
,
1197 if (!NT_SUCCESS(Status
))
1199 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1203 // CmiCheckRegistry(TRUE);
1205 /* Start automatic hive synchronization */
1206 KeInitializeDpc(&CmiHiveSyncDpc
,
1207 CmiHiveSyncDpcRoutine
,
1209 KeInitializeTimer(&CmiHiveSyncTimer
);
1210 CmiHiveSyncEnabled
= TRUE
;
1212 DPRINT("CmiInitHives() done\n");
1214 return(STATUS_SUCCESS
);
1219 CmShutdownRegistry(VOID
)
1221 PREGISTRY_HIVE Hive
;
1224 DPRINT("CmShutdownRegistry() called\n");
1226 /* Stop automatic hive synchronization */
1227 CmiHiveSyncEnabled
= FALSE
;
1229 /* Cancel pending hive synchronization */
1230 if (CmiHiveSyncPending
== TRUE
)
1232 KeCancelTimer(&CmiHiveSyncTimer
);
1233 CmiHiveSyncPending
= FALSE
;
1236 /* Acquire hive list lock exclusively */
1237 KeEnterCriticalRegion();
1238 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1240 Entry
= CmiHiveListHead
.Flink
;
1241 while (Entry
!= &CmiHiveListHead
)
1243 Hive
= CONTAINING_RECORD(Entry
, REGISTRY_HIVE
, HiveList
);
1245 if (!(IsNoFileHive(Hive
) || IsNoSynchHive(Hive
)))
1247 /* Flush non-volatile hive */
1248 CmiFlushRegistryHive(Hive
);
1251 Entry
= Entry
->Flink
;
1254 /* Release hive list lock */
1255 ExReleaseResourceLite(&CmiRegistryLock
);
1256 KeLeaveCriticalRegion();
1258 DPRINT("CmShutdownRegistry() done\n");
1263 CmiHiveSyncRoutine(PVOID DeferredContext
)
1265 PREGISTRY_HIVE Hive
;
1268 DPRINT("CmiHiveSyncRoutine() called\n");
1270 CmiHiveSyncPending
= FALSE
;
1272 /* Acquire hive list lock exclusively */
1273 KeEnterCriticalRegion();
1274 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1276 Entry
= CmiHiveListHead
.Flink
;
1277 while (Entry
!= &CmiHiveListHead
)
1279 Hive
= CONTAINING_RECORD(Entry
, REGISTRY_HIVE
, HiveList
);
1281 if (!(IsNoFileHive(Hive
) || IsNoSynchHive(Hive
)))
1283 /* Flush non-volatile hive */
1284 CmiFlushRegistryHive(Hive
);
1287 Entry
= Entry
->Flink
;
1290 /* Release hive list lock */
1291 ExReleaseResourceLite(&CmiRegistryLock
);
1292 KeLeaveCriticalRegion();
1294 DPRINT("DeferredContext 0x%p\n", DeferredContext
);
1295 ExFreePool(DeferredContext
);
1297 DPRINT("CmiHiveSyncRoutine() done\n");
1302 CmiHiveSyncDpcRoutine(PKDPC Dpc
,
1303 PVOID DeferredContext
,
1304 PVOID SystemArgument1
,
1305 PVOID SystemArgument2
)
1307 PWORK_QUEUE_ITEM WorkQueueItem
;
1309 WorkQueueItem
= ExAllocatePool(NonPagedPool
,
1310 sizeof(WORK_QUEUE_ITEM
));
1311 if (WorkQueueItem
== NULL
)
1313 DbgPrint("Failed to allocate work item\n");
1317 ExInitializeWorkItem(WorkQueueItem
,
1321 DPRINT("DeferredContext 0x%p\n", WorkQueueItem
);
1322 ExQueueWorkItem(WorkQueueItem
,
1330 LARGE_INTEGER Timeout
;
1332 DPRINT("CmiSyncHives() called\n");
1334 if (CmiHiveSyncEnabled
== FALSE
||
1335 CmiHiveSyncPending
== TRUE
)
1338 CmiHiveSyncPending
= TRUE
;
1340 Timeout
.QuadPart
= (LONGLONG
)-50000000;
1341 KeSetTimer(&CmiHiveSyncTimer
,