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 #if defined (ALLOC_PRAGMA)
20 #pragma alloc_text(INIT, CmInitHives)
21 #pragma alloc_text(INIT, CmInitializeRegistry)
22 #pragma alloc_text(INIT, CmInit2)
26 /* GLOBALS ******************************************************************/
28 POBJECT_TYPE CmiKeyType
= NULL
;
29 PREGISTRY_HIVE CmiVolatileHive
= NULL
;
31 LIST_ENTRY CmiHiveListHead
;
33 ERESOURCE CmiRegistryLock
;
35 KTIMER CmiWorkerTimer
;
36 LIST_ENTRY CmiKeyObjectListHead
;
39 volatile BOOLEAN CmiHiveSyncEnabled
= FALSE
;
40 volatile BOOLEAN CmiHiveSyncPending
= FALSE
;
42 KTIMER CmiHiveSyncTimer
;
44 static GENERIC_MAPPING CmiKeyMapping
=
45 {KEY_READ
, KEY_WRITE
, KEY_EXECUTE
, KEY_ALL_ACCESS
};
50 CmiCheckKey(BOOLEAN Verbose
,
54 CmiCreateCurrentControlSetLink(VOID
);
57 CmiHiveSyncDpcRoutine(PKDPC Dpc
,
58 PVOID DeferredContext
,
59 PVOID SystemArgument1
,
60 PVOID SystemArgument2
);
62 extern LIST_ENTRY CmiCallbackHead
;
63 extern FAST_MUTEX CmiCallbackLock
;
65 /* FUNCTIONS ****************************************************************/
68 CmiCheckSubKeys(BOOLEAN Verbose
,
71 OBJECT_ATTRIBUTES ObjectAttributes
;
72 PKEY_NODE_INFORMATION KeyInfo
;
73 WCHAR KeyBuffer
[MAX_PATH
];
74 UNICODE_STRING KeyPath
;
85 BufferSize
= sizeof(KEY_NODE_INFORMATION
) + 4096;
86 KeyInfo
= ExAllocatePool(PagedPool
, BufferSize
);
88 Status
= ZwEnumerateKey(Key
,
94 if (!NT_SUCCESS(Status
))
97 if (Status
== STATUS_NO_MORE_ENTRIES
)
98 Status
= STATUS_SUCCESS
;
104 KeyInfo
->NameLength
/ sizeof(WCHAR
));
108 DbgPrint("Key: %S\n", Name
);
111 /* FIXME: Check info. */
115 wcscpy(KeyBuffer
, L
"\\Registry\\");
116 wcscat(KeyBuffer
, Name
);
118 RtlInitUnicodeString(&KeyPath
, KeyBuffer
);
120 InitializeObjectAttributes(&ObjectAttributes
,
122 OBJ_CASE_INSENSITIVE
,
126 Status
= ZwOpenKey(&SubKey
,
130 ASSERT(NT_SUCCESS(Status
));
132 CmiCheckKey(Verbose
, SubKey
);
139 ASSERT(NT_SUCCESS(Status
));
144 CmiCheckValues(BOOLEAN Verbose
,
147 PKEY_NODE_INFORMATION ValueInfo
;
148 WCHAR Name
[MAX_PATH
];
157 BufferSize
= sizeof(KEY_NODE_INFORMATION
) + 4096;
158 ValueInfo
= ExAllocatePool(PagedPool
, BufferSize
);
160 Status
= ZwEnumerateValueKey(Key
,
166 if (!NT_SUCCESS(Status
))
168 ExFreePool(ValueInfo
);
169 if (Status
== STATUS_NO_MORE_ENTRIES
)
170 Status
= STATUS_SUCCESS
;
176 ValueInfo
->NameLength
/ sizeof(WCHAR
));
180 DbgPrint("Value: %S\n", Name
);
183 /* FIXME: Check info. */
185 ExFreePool(ValueInfo
);
190 ASSERT(NT_SUCCESS(Status
));
195 CmiCheckKey(BOOLEAN Verbose
,
198 CmiCheckValues(Verbose
, Key
);
199 CmiCheckSubKeys(Verbose
, Key
);
204 CmiCheckByName(BOOLEAN Verbose
,
207 OBJECT_ATTRIBUTES ObjectAttributes
;
208 WCHAR KeyPathBuffer
[MAX_PATH
];
209 UNICODE_STRING KeyPath
;
213 wcscpy(KeyPathBuffer
, L
"\\Registry\\");
214 wcscat(KeyPathBuffer
, KeyName
);
216 RtlInitUnicodeString(&KeyPath
, KeyPathBuffer
);
218 InitializeObjectAttributes(&ObjectAttributes
,
220 OBJ_CASE_INSENSITIVE
,
224 Status
= ZwOpenKey(&Key
,
230 if (!NT_SUCCESS(Status
))
232 DbgPrint("KeyPath %wZ Status: %.08x", KeyPath
, Status
);
233 DbgPrint("KeyPath %S Status: %.08x", KeyPath
.Buffer
, Status
);
234 ASSERT(NT_SUCCESS(Status
));
238 CmiCheckKey(Verbose
, Key
);
245 CmiCheckRegistry(BOOLEAN Verbose
)
248 DbgPrint("Checking registry internals\n");
250 CmiCheckByName(Verbose
, L
"Machine");
251 CmiCheckByName(Verbose
, L
"User");
255 CmiWorkerThread(PVOID Param
)
258 PLIST_ENTRY CurrentEntry
;
259 PKEY_OBJECT CurrentKey
;
265 Status
= KeWaitForSingleObject(&CmiWorkerTimer
,
270 if (Status
== STATUS_SUCCESS
)
272 DPRINT("CmiWorkerThread\n");
274 /* Acquire hive lock */
275 KeEnterCriticalRegion();
276 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
281 CurrentEntry
= CmiKeyObjectListHead
.Blink
;
282 while (CurrentEntry
!= &CmiKeyObjectListHead
)
284 CurrentKey
= CONTAINING_RECORD(CurrentEntry
, KEY_OBJECT
, ListEntry
);
285 if (CurrentKey
->TimeStamp
+ 120 > CmiTimer
)
287 /* The object was accessed in the last 10min */
290 if (1 == ObGetObjectPointerCount(CurrentKey
) &&
291 !(CurrentKey
->Flags
& KO_MARKED_FOR_DELETE
))
293 ObDereferenceObject(CurrentKey
);
294 CurrentEntry
= CmiKeyObjectListHead
.Blink
;
299 CurrentEntry
= CurrentEntry
->Blink
;
302 ExReleaseResourceLite(&CmiRegistryLock
);
303 KeLeaveCriticalRegion();
305 DPRINT("Removed %d key objects\n", Count
);
318 CmInitHives(BOOLEAN SetupBoot
)
322 /* Load Registry Hives. This one can be missing. */
323 if (CachedModules
[SystemRegistry
]) {
324 BaseAddress
= (PCHAR
)CachedModules
[SystemRegistry
]->ModStart
;
325 CmImportSystemHive(BaseAddress
,
326 CachedModules
[SystemRegistry
]->ModEnd
- (ULONG_PTR
)BaseAddress
);
329 BaseAddress
= (PCHAR
)CachedModules
[HardwareRegistry
]->ModStart
;
330 CmImportHardwareHive(BaseAddress
,
331 CachedModules
[HardwareRegistry
]->ModEnd
- (ULONG_PTR
)BaseAddress
);
334 /* Create dummy keys if no hardware hive was found */
335 CmImportHardwareHive (NULL
, 0);
337 /* Initialize volatile registry settings */
338 if (SetupBoot
== FALSE
) CmInit2((PCHAR
)KeLoaderBlock
.CommandLine
);
343 CmInitializeRegistry(VOID
)
345 OBJECT_ATTRIBUTES ObjectAttributes
;
346 UNICODE_STRING KeyName
;
349 PSECURITY_CELL RootSecurityCell
;
351 HANDLE RootKeyHandle
;
354 LARGE_INTEGER DueTime
;
357 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
360 DPRINT("Creating Registry Object Type\n");
362 /* Initialize the Key object type */
363 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
364 RtlInitUnicodeString(&Name
, L
"Key");
365 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
366 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(KEY_OBJECT
);
367 ObjectTypeInitializer
.GenericMapping
= CmiKeyMapping
;
368 ObjectTypeInitializer
.PoolType
= PagedPool
;
369 ObjectTypeInitializer
.ValidAccessMask
= KEY_ALL_ACCESS
;
370 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
371 ObjectTypeInitializer
.DeleteProcedure
= CmiObjectDelete
;
372 ObjectTypeInitializer
.ParseProcedure
= CmiObjectParse
;
373 ObjectTypeInitializer
.SecurityProcedure
= CmiObjectSecurity
;
374 ObjectTypeInitializer
.QueryNameProcedure
= CmiObjectQueryName
;
376 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &CmiKeyType
);
378 /* Initialize the hive list */
379 InitializeListHead(&CmiHiveListHead
);
381 /* Initialize registry lock */
382 ExInitializeResourceLite(&CmiRegistryLock
);
384 /* Initialize the key object list */
385 InitializeListHead(&CmiKeyObjectListHead
);
387 /* Initialize the worker timer */
388 KeInitializeTimerEx(&CmiWorkerTimer
, SynchronizationTimer
);
390 /* Initialize the worker thread */
391 Status
= PsCreateSystemThread(&ThreadHandle
,
398 if (!NT_SUCCESS(Status
))
403 /* Start the timer */
404 DueTime
.QuadPart
= -1;
405 KeSetTimerEx(&CmiWorkerTimer
, DueTime
, 5000, NULL
); /* 5sec */
407 /* Build volatile registry store */
408 Status
= CmiCreateVolatileHive (&CmiVolatileHive
);
409 ASSERT(NT_SUCCESS(Status
));
411 InitializeListHead(&CmiCallbackHead
);
412 ExInitializeFastMutex(&CmiCallbackLock
);
414 /* Create '\Registry' key. */
415 RtlInitUnicodeString(&KeyName
, REG_ROOT_KEY_NAME
);
416 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, 0, NULL
, NULL
);
417 Status
= ObCreateObject(KernelMode
,
426 ASSERT(NT_SUCCESS(Status
));
427 Status
= ObInsertObject(RootKey
,
433 ASSERT(NT_SUCCESS(Status
));
434 RootKey
->RegistryHive
= CmiVolatileHive
;
435 RootKey
->KeyCellOffset
= CmiVolatileHive
->HiveHeader
->RootKeyOffset
;
436 RootKey
->KeyCell
= CmiGetCell (CmiVolatileHive
, RootKey
->KeyCellOffset
, NULL
);
437 RootKey
->ParentKey
= RootKey
;
439 RootKey
->NumberOfSubKeys
= 0;
440 RootKey
->SubKeys
= NULL
;
441 RootKey
->SizeOfSubKeys
= 0;
442 InsertTailList(&CmiKeyObjectListHead
, &RootKey
->ListEntry
);
443 Status
= RtlpCreateUnicodeString(&RootKey
->Name
, L
"Registry", NonPagedPool
);
444 ASSERT(NT_SUCCESS(Status
));
447 Status
= CmiAllocateCell(CmiVolatileHive
,
448 0x10, //LONG CellSize,
449 (PVOID
*)&RootSecurityCell
,
450 &RootKey
->KeyCell
->SecurityKeyOffset
);
451 ASSERT(NT_SUCCESS(Status
));
453 /* Copy the security descriptor */
455 CmiVolatileHive
->RootSecurityCell
= RootSecurityCell
;
459 /* Create '\Registry\Machine' key. */
460 RtlInitUnicodeString(&KeyName
,
462 InitializeObjectAttributes(&ObjectAttributes
,
467 Status
= ZwCreateKey(&KeyHandle
,
474 ASSERT(NT_SUCCESS(Status
));
476 /* Create '\Registry\User' key. */
477 RtlInitUnicodeString(&KeyName
,
479 InitializeObjectAttributes(&ObjectAttributes
,
484 Status
= ZwCreateKey(&KeyHandle
,
491 ASSERT(NT_SUCCESS(Status
));
496 CmInit2(PCHAR CommandLine
)
499 BOOLEAN MiniNT
= FALSE
;
500 PWCHAR SystemBootDevice
;
501 PWCHAR SystemStartOptions
;
505 /* Create the 'CurrentControlSet' link. */
506 Status
= CmiCreateCurrentControlSetLink();
507 if (!NT_SUCCESS(Status
))
508 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
511 * Parse the system boot device.
514 SystemBootDevice
= ExAllocatePool(PagedPool
,
515 (strlen(CommandLine
) + 1) * sizeof(WCHAR
));
516 if (SystemBootDevice
== NULL
)
518 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
521 while (*CommandLine
!= 0 && *CommandLine
!= ' ')
522 SystemBootDevice
[Position
++] = *(CommandLine
++);
523 SystemBootDevice
[Position
++] = 0;
526 * Write the system boot device to registry.
528 Status
= RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
529 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
533 Position
* sizeof(WCHAR
));
534 if (!NT_SUCCESS(Status
))
536 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
540 * Parse the system start options.
543 SystemStartOptions
= SystemBootDevice
;
544 while ((CommandLine
= strchr(CommandLine
, '/')) != NULL
)
546 /* Skip over the slash */
549 /* Special options */
550 if (!_strnicmp(CommandLine
, "MININT", 6))
552 else if (!_strnicmp(CommandLine
, "DEBUGPORT=PICE", 14))
555 /* Add a space between the options */
557 SystemStartOptions
[Position
++] = L
' ';
559 /* Copy the command */
560 while (*CommandLine
!= 0 && *CommandLine
!= ' ')
561 SystemStartOptions
[Position
++] = *(CommandLine
++);
563 SystemStartOptions
[Position
++] = 0;
566 * Write the system start options to registry.
568 Status
= RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
569 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
570 L
"SystemStartOptions",
573 Position
* sizeof(WCHAR
));
574 if (!NT_SUCCESS(Status
))
576 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
580 * Create a CurrentControlSet\Control\MiniNT key that is used
581 * to detect WinPE/MiniNT systems.
585 Status
= RtlCreateRegistryKey(RTL_REGISTRY_CONTROL
, L
"MiniNT");
586 if (!NT_SUCCESS(Status
))
587 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
590 /* Set PICE 'Start' value to 1, if PICE debugging is enabled */
591 Status
= RtlWriteRegistryValue(
592 RTL_REGISTRY_SERVICES
,
598 if (!NT_SUCCESS(Status
))
599 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
601 ExFreePool(SystemBootDevice
);
606 CmiCreateCurrentControlSetLink(VOID
)
608 RTL_QUERY_REGISTRY_TABLE QueryTable
[5];
609 WCHAR TargetNameBuffer
[80];
610 ULONG TargetNameLength
;
611 UNICODE_STRING LinkName
= RTL_CONSTANT_STRING(
612 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
613 UNICODE_STRING LinkValue
= RTL_CONSTANT_STRING(L
"SymbolicLinkValue");
619 OBJECT_ATTRIBUTES ObjectAttributes
;
622 DPRINT("CmiCreateCurrentControlSetLink() called\n");
624 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
626 QueryTable
[0].Name
= L
"Current";
627 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
628 QueryTable
[0].EntryContext
= &CurrentSet
;
630 QueryTable
[1].Name
= L
"Default";
631 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
632 QueryTable
[1].EntryContext
= &DefaultSet
;
634 QueryTable
[2].Name
= L
"Failed";
635 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
636 QueryTable
[2].EntryContext
= &Failed
;
638 QueryTable
[3].Name
= L
"LastKnownGood";
639 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
640 QueryTable
[3].EntryContext
= &LastKnownGood
;
642 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
643 L
"\\Registry\\Machine\\SYSTEM\\Select",
647 if (!NT_SUCCESS(Status
))
652 DPRINT("Current %ld Default %ld\n", CurrentSet
, DefaultSet
);
654 swprintf(TargetNameBuffer
,
655 L
"\\Registry\\Machine\\SYSTEM\\ControlSet%03lu",
657 TargetNameLength
= wcslen(TargetNameBuffer
) * sizeof(WCHAR
);
659 DPRINT("Link target '%S'\n", TargetNameBuffer
);
661 InitializeObjectAttributes(&ObjectAttributes
,
663 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_OPENLINK
,
666 Status
= ZwCreateKey(&KeyHandle
,
667 KEY_ALL_ACCESS
| KEY_CREATE_LINK
,
671 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
673 if (!NT_SUCCESS(Status
))
675 DPRINT1("ZwCreateKey() failed (Status %lx)\n", Status
);
679 Status
= ZwSetValueKey(KeyHandle
,
683 (PVOID
)TargetNameBuffer
,
685 if (!NT_SUCCESS(Status
))
687 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status
);
697 CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
698 IN PREGISTRY_HIVE RegistryHive
)
700 UNICODE_STRING RemainingPath
;
701 PKEY_OBJECT ParentKey
;
705 UNICODE_STRING ObjectName
;
706 OBJECT_CREATE_INFORMATION ObjectCreateInfo
;
708 DPRINT("CmiConnectHive(%p, %p) called.\n",
709 KeyObjectAttributes
, RegistryHive
);
711 /* Capture all the info */
712 DPRINT("Capturing Create Info\n");
713 Status
= ObpCaptureObjectAttributes(KeyObjectAttributes
,
718 if (!NT_SUCCESS(Status
))
720 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status
);
724 Status
= ObFindObject(&ObjectCreateInfo
,
729 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
730 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
731 if (!NT_SUCCESS(Status
))
736 DPRINT ("RemainingPath %wZ\n", &RemainingPath
);
738 if ((RemainingPath
.Buffer
== NULL
) || (RemainingPath
.Buffer
[0] == 0))
740 ObDereferenceObject (ParentKey
);
741 RtlFreeUnicodeString(&RemainingPath
);
742 return STATUS_OBJECT_NAME_COLLISION
;
745 /* Ignore leading backslash */
746 SubName
= RemainingPath
.Buffer
;
747 if (*SubName
== L
'\\')
750 /* If RemainingPath contains \ we must return error
751 because CmiConnectHive() can not create trees */
752 if (wcschr (SubName
, L
'\\') != NULL
)
754 ObDereferenceObject (ParentKey
);
755 RtlFreeUnicodeString(&RemainingPath
);
756 return STATUS_OBJECT_NAME_NOT_FOUND
;
759 DPRINT("RemainingPath %wZ ParentKey %p\n",
760 &RemainingPath
, ParentKey
);
762 Status
= ObCreateObject(KernelMode
,
772 if (!NT_SUCCESS(Status
))
774 DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status
);
775 ObDereferenceObject (ParentKey
);
776 RtlFreeUnicodeString(&RemainingPath
);
779 DPRINT("Inserting Key into Object Tree\n");
780 Status
= ObInsertObject((PVOID
)NewKey
,
786 DPRINT("Status %x\n", Status
);
787 NewKey
->RegistryHive
= RegistryHive
;
788 NewKey
->KeyCellOffset
= RegistryHive
->HiveHeader
->RootKeyOffset
;
789 NewKey
->KeyCell
= CmiGetCell (RegistryHive
, NewKey
->KeyCellOffset
, NULL
);
791 NewKey
->NumberOfSubKeys
= 0;
792 InsertTailList(&CmiKeyObjectListHead
, &NewKey
->ListEntry
);
793 if (NewKey
->KeyCell
->NumberOfSubKeys
!= 0)
795 NewKey
->SubKeys
= ExAllocatePool(NonPagedPool
,
796 NewKey
->KeyCell
->NumberOfSubKeys
* sizeof(ULONG
));
797 if (NewKey
->SubKeys
== NULL
)
799 DPRINT("ExAllocatePool() failed\n");
800 ObDereferenceObject (NewKey
);
801 ObDereferenceObject (ParentKey
);
802 RtlFreeUnicodeString(&RemainingPath
);
803 return STATUS_INSUFFICIENT_RESOURCES
;
808 NewKey
->SubKeys
= NULL
;
811 DPRINT ("SubName %S\n", SubName
);
813 Status
= RtlpCreateUnicodeString(&NewKey
->Name
,
814 SubName
, NonPagedPool
);
815 RtlFreeUnicodeString(&RemainingPath
);
816 if (!NT_SUCCESS(Status
))
818 DPRINT1("RtlpCreateUnicodeString() failed (Status %lx)\n", Status
);
819 if (NewKey
->SubKeys
!= NULL
)
821 ExFreePool (NewKey
->SubKeys
);
823 ObDereferenceObject (NewKey
);
824 ObDereferenceObject (ParentKey
);
825 return STATUS_INSUFFICIENT_RESOURCES
;
828 CmiAddKeyToList (ParentKey
, NewKey
);
829 ObDereferenceObject (ParentKey
);
831 VERIFY_KEY_OBJECT(NewKey
);
833 /* Note: Do not dereference NewKey here! */
835 return STATUS_SUCCESS
;
840 CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
841 OUT PREGISTRY_HIVE
*RegistryHive
)
843 PKEY_OBJECT KeyObject
;
847 PLIST_ENTRY CurrentEntry
;
848 PKEY_OBJECT CurrentKey
;
850 DPRINT("CmiDisconnectHive() called\n");
852 *RegistryHive
= NULL
;
854 Status
= ObOpenObjectByName (KeyObjectAttributes
,
858 STANDARD_RIGHTS_REQUIRED
,
861 if (!NT_SUCCESS(Status
))
863 DPRINT1 ("ObOpenObjectByName() failed (Status %lx)\n", Status
);
867 Status
= ObReferenceObjectByHandle (KeyHandle
,
868 STANDARD_RIGHTS_REQUIRED
,
874 if (!NT_SUCCESS(Status
))
876 DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status
);
879 DPRINT ("KeyObject %p Hive %p\n", KeyObject
, KeyObject
->RegistryHive
);
881 if (!(KeyObject
->KeyCell
->Flags
& REG_KEY_ROOT_CELL
))
883 DPRINT1 ("Key is not the Hive-Root-Key\n");
884 ObDereferenceObject (KeyObject
);
885 return STATUS_INVALID_PARAMETER
;
888 /* Acquire registry lock exclusively */
889 KeEnterCriticalRegion();
890 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
892 CurrentEntry
= CmiKeyObjectListHead
.Flink
;
893 while (CurrentEntry
!= &CmiKeyObjectListHead
)
895 CurrentKey
= CONTAINING_RECORD(CurrentEntry
, KEY_OBJECT
, ListEntry
);
896 if (1 == ObGetObjectPointerCount(CurrentKey
) &&
897 !(CurrentKey
->Flags
& KO_MARKED_FOR_DELETE
))
899 ObDereferenceObject(CurrentKey
);
900 CurrentEntry
= CmiKeyObjectListHead
.Flink
;
904 CurrentEntry
= CurrentEntry
->Flink
;
908 if (ObGetObjectHandleCount (KeyObject
) != 0 ||
909 ObGetObjectPointerCount (KeyObject
) != 2)
911 DPRINT1 ("Hive is still in use (hc %d, rc %d)\n", ObGetObjectHandleCount (KeyObject
), ObGetObjectPointerCount (KeyObject
));
912 ObDereferenceObject (KeyObject
);
914 /* Release registry lock */
915 ExReleaseResourceLite (&CmiRegistryLock
);
916 KeLeaveCriticalRegion();
918 return STATUS_UNSUCCESSFUL
;
921 Hive
= KeyObject
->RegistryHive
;
923 /* Dereference KeyObject twice to delete it */
924 ObDereferenceObject (KeyObject
);
925 ObDereferenceObject (KeyObject
);
927 *RegistryHive
= Hive
;
929 /* Release registry lock */
930 ExReleaseResourceLite (&CmiRegistryLock
);
931 KeLeaveCriticalRegion();
933 DPRINT ("CmiDisconnectHive() done\n");
935 return STATUS_SUCCESS
;
940 CmiInitControlSetLink (VOID
)
942 OBJECT_ATTRIBUTES ObjectAttributes
;
943 UNICODE_STRING ControlSetKeyName
= RTL_CONSTANT_STRING(
944 L
"\\Registry\\Machine\\SYSTEM\\ControlSet001");
945 UNICODE_STRING ControlSetLinkName
= RTL_CONSTANT_STRING(
946 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
947 UNICODE_STRING ControlSetValueName
= RTL_CONSTANT_STRING(L
"SymbolicLinkValue");
951 /* Create 'ControlSet001' key */
952 InitializeObjectAttributes (&ObjectAttributes
,
954 OBJ_CASE_INSENSITIVE
,
957 Status
= ZwCreateKey (&KeyHandle
,
962 REG_OPTION_NON_VOLATILE
,
964 if (!NT_SUCCESS(Status
))
966 DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status
);
971 /* Link 'CurrentControlSet' to 'ControlSet001' key */
972 InitializeObjectAttributes (&ObjectAttributes
,
974 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_OPENLINK
,
977 Status
= ZwCreateKey (&KeyHandle
,
978 KEY_ALL_ACCESS
| KEY_CREATE_LINK
,
982 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
984 if (!NT_SUCCESS(Status
))
986 DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status
);
990 Status
= ZwSetValueKey (KeyHandle
,
991 &ControlSetValueName
,
994 (PVOID
)ControlSetKeyName
.Buffer
,
995 ControlSetKeyName
.Length
);
996 if (!NT_SUCCESS(Status
))
998 DPRINT1 ("ZwSetValueKey() failed (Status %lx)\n", Status
);
1000 ZwClose (KeyHandle
);
1002 return STATUS_SUCCESS
;
1007 CmiInitHives(BOOLEAN SetupBoot
)
1009 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
1010 OBJECT_ATTRIBUTES ObjectAttributes
;
1011 UNICODE_STRING FileName
;
1012 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE");
1013 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"InstallPath");
1018 WCHAR ConfigPath
[MAX_PATH
];
1025 DPRINT("CmiInitHives() called\n");
1027 if (SetupBoot
== TRUE
)
1029 InitializeObjectAttributes(&ObjectAttributes
,
1031 OBJ_CASE_INSENSITIVE
,
1034 Status
= ZwOpenKey(&KeyHandle
,
1037 if (!NT_SUCCESS(Status
))
1039 DPRINT1("ZwOpenKey() failed (Status %lx)\n", Status
);
1043 BufferSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4096;
1044 ValueInfo
= ExAllocatePool(PagedPool
,
1046 if (ValueInfo
== NULL
)
1049 return(STATUS_INSUFFICIENT_RESOURCES
);
1052 Status
= ZwQueryValueKey(KeyHandle
,
1054 KeyValuePartialInformation
,
1059 if (!NT_SUCCESS(Status
))
1061 ExFreePool(ValueInfo
);
1065 RtlCopyMemory(ConfigPath
,
1067 ValueInfo
->DataLength
);
1068 ConfigPath
[ValueInfo
->DataLength
/ sizeof(WCHAR
)] = (WCHAR
)0;
1069 ExFreePool(ValueInfo
);
1073 wcscpy(ConfigPath
, L
"\\SystemRoot");
1075 wcscat(ConfigPath
, L
"\\system32\\config");
1077 DPRINT("ConfigPath: %S\n", ConfigPath
);
1079 EndPtr
= ConfigPath
+ wcslen(ConfigPath
);
1083 /* FIXME: Save boot log */
1085 /* Connect the SYSTEM hive only if it has been created */
1086 if (SetupBoot
== TRUE
)
1088 wcscpy(EndPtr
, REG_SYSTEM_FILE_NAME
);
1089 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1091 RtlInitUnicodeString (&KeyName
,
1092 REG_SYSTEM_KEY_NAME
);
1093 InitializeObjectAttributes(&ObjectAttributes
,
1095 OBJ_CASE_INSENSITIVE
,
1099 RtlInitUnicodeString (&FileName
,
1101 Status
= CmiLoadHive (&ObjectAttributes
,
1104 if (!NT_SUCCESS(Status
))
1106 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status
);
1110 Status
= CmiInitControlSetLink ();
1111 if (!NT_SUCCESS(Status
))
1113 DPRINT1("CmiInitControlSetLink() failed (Status %lx)\n", Status
);
1118 /* Connect the SOFTWARE hive */
1119 wcscpy(EndPtr
, REG_SOFTWARE_FILE_NAME
);
1120 RtlInitUnicodeString (&FileName
,
1122 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1124 RtlInitUnicodeString (&KeyName
,
1125 REG_SOFTWARE_KEY_NAME
);
1126 InitializeObjectAttributes(&ObjectAttributes
,
1128 OBJ_CASE_INSENSITIVE
,
1132 Status
= CmiLoadHive (&ObjectAttributes
,
1135 if (!NT_SUCCESS(Status
))
1137 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1141 /* Connect the SAM hive */
1142 wcscpy(EndPtr
, REG_SAM_FILE_NAME
);
1143 RtlInitUnicodeString (&FileName
,
1145 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1147 RtlInitUnicodeString (&KeyName
,
1149 InitializeObjectAttributes(&ObjectAttributes
,
1151 OBJ_CASE_INSENSITIVE
,
1154 Status
= CmiLoadHive (&ObjectAttributes
,
1157 if (!NT_SUCCESS(Status
))
1159 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1163 /* Connect the SECURITY hive */
1164 wcscpy(EndPtr
, REG_SEC_FILE_NAME
);
1165 RtlInitUnicodeString (&FileName
,
1167 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1169 RtlInitUnicodeString (&KeyName
,
1171 InitializeObjectAttributes(&ObjectAttributes
,
1173 OBJ_CASE_INSENSITIVE
,
1176 Status
= CmiLoadHive (&ObjectAttributes
,
1179 if (!NT_SUCCESS(Status
))
1181 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1185 /* Connect the DEFAULT hive */
1186 wcscpy(EndPtr
, REG_DEFAULT_USER_FILE_NAME
);
1187 RtlInitUnicodeString (&FileName
,
1189 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1191 RtlInitUnicodeString (&KeyName
,
1192 REG_DEFAULT_USER_KEY_NAME
);
1193 InitializeObjectAttributes(&ObjectAttributes
,
1195 OBJ_CASE_INSENSITIVE
,
1198 Status
= CmiLoadHive (&ObjectAttributes
,
1201 if (!NT_SUCCESS(Status
))
1203 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1207 // CmiCheckRegistry(TRUE);
1209 /* Start automatic hive synchronization */
1210 KeInitializeDpc(&CmiHiveSyncDpc
,
1211 CmiHiveSyncDpcRoutine
,
1213 KeInitializeTimer(&CmiHiveSyncTimer
);
1214 CmiHiveSyncEnabled
= TRUE
;
1216 DPRINT("CmiInitHives() done\n");
1218 return(STATUS_SUCCESS
);
1223 CmShutdownRegistry(VOID
)
1225 PREGISTRY_HIVE Hive
;
1228 DPRINT("CmShutdownRegistry() called\n");
1230 /* Stop automatic hive synchronization */
1231 CmiHiveSyncEnabled
= FALSE
;
1233 /* Cancel pending hive synchronization */
1234 if (CmiHiveSyncPending
== TRUE
)
1236 KeCancelTimer(&CmiHiveSyncTimer
);
1237 CmiHiveSyncPending
= FALSE
;
1240 /* Acquire hive list lock exclusively */
1241 KeEnterCriticalRegion();
1242 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1244 Entry
= CmiHiveListHead
.Flink
;
1245 while (Entry
!= &CmiHiveListHead
)
1247 Hive
= CONTAINING_RECORD(Entry
, REGISTRY_HIVE
, HiveList
);
1249 if (!(IsNoFileHive(Hive
) || IsNoSynchHive(Hive
)))
1251 /* Flush non-volatile hive */
1252 CmiFlushRegistryHive(Hive
);
1255 Entry
= Entry
->Flink
;
1258 /* Release hive list lock */
1259 ExReleaseResourceLite(&CmiRegistryLock
);
1260 KeLeaveCriticalRegion();
1262 DPRINT("CmShutdownRegistry() done\n");
1267 CmiHiveSyncRoutine(PVOID DeferredContext
)
1269 PREGISTRY_HIVE Hive
;
1272 DPRINT("CmiHiveSyncRoutine() called\n");
1274 CmiHiveSyncPending
= FALSE
;
1276 /* Acquire hive list lock exclusively */
1277 KeEnterCriticalRegion();
1278 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1280 Entry
= CmiHiveListHead
.Flink
;
1281 while (Entry
!= &CmiHiveListHead
)
1283 Hive
= CONTAINING_RECORD(Entry
, REGISTRY_HIVE
, HiveList
);
1285 if (!(IsNoFileHive(Hive
) || IsNoSynchHive(Hive
)))
1287 /* Flush non-volatile hive */
1288 CmiFlushRegistryHive(Hive
);
1291 Entry
= Entry
->Flink
;
1294 /* Release hive list lock */
1295 ExReleaseResourceLite(&CmiRegistryLock
);
1296 KeLeaveCriticalRegion();
1298 DPRINT("DeferredContext 0x%p\n", DeferredContext
);
1299 ExFreePool(DeferredContext
);
1301 DPRINT("CmiHiveSyncRoutine() done\n");
1306 CmiHiveSyncDpcRoutine(PKDPC Dpc
,
1307 PVOID DeferredContext
,
1308 PVOID SystemArgument1
,
1309 PVOID SystemArgument2
)
1311 PWORK_QUEUE_ITEM WorkQueueItem
;
1313 WorkQueueItem
= ExAllocatePool(NonPagedPool
,
1314 sizeof(WORK_QUEUE_ITEM
));
1315 if (WorkQueueItem
== NULL
)
1317 DbgPrint("Failed to allocate work item\n");
1321 ExInitializeWorkItem(WorkQueueItem
,
1325 DPRINT("DeferredContext 0x%p\n", WorkQueueItem
);
1326 ExQueueWorkItem(WorkQueueItem
,
1334 LARGE_INTEGER Timeout
;
1336 DPRINT("CmiSyncHives() called\n");
1338 if (CmiHiveSyncEnabled
== FALSE
||
1339 CmiHiveSyncPending
== TRUE
)
1342 CmiHiveSyncPending
= TRUE
;
1344 Timeout
.QuadPart
= (LONGLONG
)-50000000;
1345 KeSetTimer(&CmiHiveSyncTimer
,