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
= CmFindObject(&ObjectCreateInfo
,
731 ObpReleaseCapturedAttributes(&ObjectCreateInfo
);
732 if (ObjectName
.Buffer
) ExFreePool(ObjectName
.Buffer
);
733 if (!NT_SUCCESS(Status
))
738 DPRINT ("RemainingPath %wZ\n", &RemainingPath
);
740 if ((RemainingPath
.Buffer
== NULL
) || (RemainingPath
.Buffer
[0] == 0))
742 ObDereferenceObject (ParentKey
);
743 RtlFreeUnicodeString(&RemainingPath
);
744 return STATUS_OBJECT_NAME_COLLISION
;
747 /* Ignore leading backslash */
748 SubName
= RemainingPath
.Buffer
;
749 if (*SubName
== L
'\\')
752 /* If RemainingPath contains \ we must return error
753 because CmiConnectHive() can not create trees */
754 if (wcschr (SubName
, L
'\\') != NULL
)
756 ObDereferenceObject (ParentKey
);
757 RtlFreeUnicodeString(&RemainingPath
);
758 return STATUS_OBJECT_NAME_NOT_FOUND
;
761 DPRINT("RemainingPath %wZ ParentKey %p\n",
762 &RemainingPath
, ParentKey
);
764 Status
= ObCreateObject(KernelMode
,
774 if (!NT_SUCCESS(Status
))
776 DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status
);
777 ObDereferenceObject (ParentKey
);
778 RtlFreeUnicodeString(&RemainingPath
);
781 DPRINT("Inserting Key into Object Tree\n");
782 Status
= ObInsertObject((PVOID
)NewKey
,
788 DPRINT("Status %x\n", Status
);
789 NewKey
->RegistryHive
= RegistryHive
;
790 NewKey
->KeyCellOffset
= RegistryHive
->HiveHeader
->RootKeyOffset
;
791 NewKey
->KeyCell
= CmiGetCell (RegistryHive
, NewKey
->KeyCellOffset
, NULL
);
793 NewKey
->NumberOfSubKeys
= 0;
794 InsertTailList(&CmiKeyObjectListHead
, &NewKey
->ListEntry
);
795 if (NewKey
->KeyCell
->NumberOfSubKeys
!= 0)
797 NewKey
->SubKeys
= ExAllocatePool(NonPagedPool
,
798 NewKey
->KeyCell
->NumberOfSubKeys
* sizeof(ULONG
));
799 if (NewKey
->SubKeys
== NULL
)
801 DPRINT("ExAllocatePool() failed\n");
802 ObDereferenceObject (NewKey
);
803 ObDereferenceObject (ParentKey
);
804 RtlFreeUnicodeString(&RemainingPath
);
805 return STATUS_INSUFFICIENT_RESOURCES
;
810 NewKey
->SubKeys
= NULL
;
813 DPRINT ("SubName %S\n", SubName
);
815 Status
= RtlpCreateUnicodeString(&NewKey
->Name
,
816 SubName
, NonPagedPool
);
817 RtlFreeUnicodeString(&RemainingPath
);
818 if (!NT_SUCCESS(Status
))
820 DPRINT1("RtlpCreateUnicodeString() failed (Status %lx)\n", Status
);
821 if (NewKey
->SubKeys
!= NULL
)
823 ExFreePool (NewKey
->SubKeys
);
825 ObDereferenceObject (NewKey
);
826 ObDereferenceObject (ParentKey
);
827 return STATUS_INSUFFICIENT_RESOURCES
;
830 CmiAddKeyToList (ParentKey
, NewKey
);
831 ObDereferenceObject (ParentKey
);
833 VERIFY_KEY_OBJECT(NewKey
);
835 /* Note: Do not dereference NewKey here! */
837 return STATUS_SUCCESS
;
842 CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
843 OUT PREGISTRY_HIVE
*RegistryHive
)
845 PKEY_OBJECT KeyObject
;
849 PLIST_ENTRY CurrentEntry
;
850 PKEY_OBJECT CurrentKey
;
852 DPRINT("CmiDisconnectHive() called\n");
854 *RegistryHive
= NULL
;
856 Status
= ObOpenObjectByName (KeyObjectAttributes
,
860 STANDARD_RIGHTS_REQUIRED
,
863 if (!NT_SUCCESS(Status
))
865 DPRINT1 ("ObOpenObjectByName() failed (Status %lx)\n", Status
);
869 Status
= ObReferenceObjectByHandle (KeyHandle
,
870 STANDARD_RIGHTS_REQUIRED
,
876 if (!NT_SUCCESS(Status
))
878 DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status
);
881 DPRINT ("KeyObject %p Hive %p\n", KeyObject
, KeyObject
->RegistryHive
);
883 if (!(KeyObject
->KeyCell
->Flags
& REG_KEY_ROOT_CELL
))
885 DPRINT1 ("Key is not the Hive-Root-Key\n");
886 ObDereferenceObject (KeyObject
);
887 return STATUS_INVALID_PARAMETER
;
890 /* Acquire registry lock exclusively */
891 KeEnterCriticalRegion();
892 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
894 CurrentEntry
= CmiKeyObjectListHead
.Flink
;
895 while (CurrentEntry
!= &CmiKeyObjectListHead
)
897 CurrentKey
= CONTAINING_RECORD(CurrentEntry
, KEY_OBJECT
, ListEntry
);
898 if (1 == ObGetObjectPointerCount(CurrentKey
) &&
899 !(CurrentKey
->Flags
& KO_MARKED_FOR_DELETE
))
901 ObDereferenceObject(CurrentKey
);
902 CurrentEntry
= CmiKeyObjectListHead
.Flink
;
906 CurrentEntry
= CurrentEntry
->Flink
;
910 if (ObGetObjectHandleCount (KeyObject
) != 0 ||
911 ObGetObjectPointerCount (KeyObject
) != 2)
913 DPRINT1 ("Hive is still in use (hc %d, rc %d)\n", ObGetObjectHandleCount (KeyObject
), ObGetObjectPointerCount (KeyObject
));
914 ObDereferenceObject (KeyObject
);
916 /* Release registry lock */
917 ExReleaseResourceLite (&CmiRegistryLock
);
918 KeLeaveCriticalRegion();
920 return STATUS_UNSUCCESSFUL
;
923 Hive
= KeyObject
->RegistryHive
;
925 /* Dereference KeyObject twice to delete it */
926 ObDereferenceObject (KeyObject
);
927 ObDereferenceObject (KeyObject
);
929 *RegistryHive
= Hive
;
931 /* Release registry lock */
932 ExReleaseResourceLite (&CmiRegistryLock
);
933 KeLeaveCriticalRegion();
935 DPRINT ("CmiDisconnectHive() done\n");
937 return STATUS_SUCCESS
;
942 CmiInitControlSetLink (VOID
)
944 OBJECT_ATTRIBUTES ObjectAttributes
;
945 UNICODE_STRING ControlSetKeyName
= RTL_CONSTANT_STRING(
946 L
"\\Registry\\Machine\\SYSTEM\\ControlSet001");
947 UNICODE_STRING ControlSetLinkName
= RTL_CONSTANT_STRING(
948 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
949 UNICODE_STRING ControlSetValueName
= RTL_CONSTANT_STRING(L
"SymbolicLinkValue");
953 /* Create 'ControlSet001' key */
954 InitializeObjectAttributes (&ObjectAttributes
,
956 OBJ_CASE_INSENSITIVE
,
959 Status
= ZwCreateKey (&KeyHandle
,
964 REG_OPTION_NON_VOLATILE
,
966 if (!NT_SUCCESS(Status
))
968 DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status
);
973 /* Link 'CurrentControlSet' to 'ControlSet001' key */
974 InitializeObjectAttributes (&ObjectAttributes
,
976 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_OPENLINK
,
979 Status
= ZwCreateKey (&KeyHandle
,
980 KEY_ALL_ACCESS
| KEY_CREATE_LINK
,
984 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
986 if (!NT_SUCCESS(Status
))
988 DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status
);
992 Status
= ZwSetValueKey (KeyHandle
,
993 &ControlSetValueName
,
996 (PVOID
)ControlSetKeyName
.Buffer
,
997 ControlSetKeyName
.Length
);
998 if (!NT_SUCCESS(Status
))
1000 DPRINT1 ("ZwSetValueKey() failed (Status %lx)\n", Status
);
1002 ZwClose (KeyHandle
);
1004 return STATUS_SUCCESS
;
1009 CmiInitHives(BOOLEAN SetupBoot
)
1011 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
1012 OBJECT_ATTRIBUTES ObjectAttributes
;
1013 UNICODE_STRING FileName
;
1014 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE");
1015 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"InstallPath");
1020 WCHAR ConfigPath
[MAX_PATH
];
1027 DPRINT("CmiInitHives() called\n");
1029 if (SetupBoot
== TRUE
)
1031 InitializeObjectAttributes(&ObjectAttributes
,
1033 OBJ_CASE_INSENSITIVE
,
1036 Status
= ZwOpenKey(&KeyHandle
,
1039 if (!NT_SUCCESS(Status
))
1041 DPRINT1("ZwOpenKey() failed (Status %lx)\n", Status
);
1045 BufferSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4096;
1046 ValueInfo
= ExAllocatePool(PagedPool
,
1048 if (ValueInfo
== NULL
)
1051 return(STATUS_INSUFFICIENT_RESOURCES
);
1054 Status
= ZwQueryValueKey(KeyHandle
,
1056 KeyValuePartialInformation
,
1061 if (!NT_SUCCESS(Status
))
1063 ExFreePool(ValueInfo
);
1067 RtlCopyMemory(ConfigPath
,
1069 ValueInfo
->DataLength
);
1070 ConfigPath
[ValueInfo
->DataLength
/ sizeof(WCHAR
)] = (WCHAR
)0;
1071 ExFreePool(ValueInfo
);
1075 wcscpy(ConfigPath
, L
"\\SystemRoot");
1077 wcscat(ConfigPath
, L
"\\system32\\config");
1079 DPRINT("ConfigPath: %S\n", ConfigPath
);
1081 EndPtr
= ConfigPath
+ wcslen(ConfigPath
);
1085 /* FIXME: Save boot log */
1087 /* Connect the SYSTEM hive only if it has been created */
1088 if (SetupBoot
== TRUE
)
1090 wcscpy(EndPtr
, REG_SYSTEM_FILE_NAME
);
1091 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1093 RtlInitUnicodeString (&KeyName
,
1094 REG_SYSTEM_KEY_NAME
);
1095 InitializeObjectAttributes(&ObjectAttributes
,
1097 OBJ_CASE_INSENSITIVE
,
1101 RtlInitUnicodeString (&FileName
,
1103 Status
= CmiLoadHive (&ObjectAttributes
,
1106 if (!NT_SUCCESS(Status
))
1108 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status
);
1112 Status
= CmiInitControlSetLink ();
1113 if (!NT_SUCCESS(Status
))
1115 DPRINT1("CmiInitControlSetLink() failed (Status %lx)\n", Status
);
1120 /* Connect the SOFTWARE hive */
1121 wcscpy(EndPtr
, REG_SOFTWARE_FILE_NAME
);
1122 RtlInitUnicodeString (&FileName
,
1124 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1126 RtlInitUnicodeString (&KeyName
,
1127 REG_SOFTWARE_KEY_NAME
);
1128 InitializeObjectAttributes(&ObjectAttributes
,
1130 OBJ_CASE_INSENSITIVE
,
1134 Status
= CmiLoadHive (&ObjectAttributes
,
1137 if (!NT_SUCCESS(Status
))
1139 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1143 /* Connect the SAM hive */
1144 wcscpy(EndPtr
, REG_SAM_FILE_NAME
);
1145 RtlInitUnicodeString (&FileName
,
1147 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1149 RtlInitUnicodeString (&KeyName
,
1151 InitializeObjectAttributes(&ObjectAttributes
,
1153 OBJ_CASE_INSENSITIVE
,
1156 Status
= CmiLoadHive (&ObjectAttributes
,
1159 if (!NT_SUCCESS(Status
))
1161 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1165 /* Connect the SECURITY hive */
1166 wcscpy(EndPtr
, REG_SEC_FILE_NAME
);
1167 RtlInitUnicodeString (&FileName
,
1169 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1171 RtlInitUnicodeString (&KeyName
,
1173 InitializeObjectAttributes(&ObjectAttributes
,
1175 OBJ_CASE_INSENSITIVE
,
1178 Status
= CmiLoadHive (&ObjectAttributes
,
1181 if (!NT_SUCCESS(Status
))
1183 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1187 /* Connect the DEFAULT hive */
1188 wcscpy(EndPtr
, REG_DEFAULT_USER_FILE_NAME
);
1189 RtlInitUnicodeString (&FileName
,
1191 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1193 RtlInitUnicodeString (&KeyName
,
1194 REG_DEFAULT_USER_KEY_NAME
);
1195 InitializeObjectAttributes(&ObjectAttributes
,
1197 OBJ_CASE_INSENSITIVE
,
1200 Status
= CmiLoadHive (&ObjectAttributes
,
1203 if (!NT_SUCCESS(Status
))
1205 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1209 // CmiCheckRegistry(TRUE);
1211 /* Start automatic hive synchronization */
1212 KeInitializeDpc(&CmiHiveSyncDpc
,
1213 CmiHiveSyncDpcRoutine
,
1215 KeInitializeTimer(&CmiHiveSyncTimer
);
1216 CmiHiveSyncEnabled
= TRUE
;
1218 DPRINT("CmiInitHives() done\n");
1220 return(STATUS_SUCCESS
);
1225 CmShutdownRegistry(VOID
)
1227 PREGISTRY_HIVE Hive
;
1230 DPRINT("CmShutdownRegistry() called\n");
1232 /* Stop automatic hive synchronization */
1233 CmiHiveSyncEnabled
= FALSE
;
1235 /* Cancel pending hive synchronization */
1236 if (CmiHiveSyncPending
== TRUE
)
1238 KeCancelTimer(&CmiHiveSyncTimer
);
1239 CmiHiveSyncPending
= FALSE
;
1242 /* Acquire hive list lock exclusively */
1243 KeEnterCriticalRegion();
1244 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1246 Entry
= CmiHiveListHead
.Flink
;
1247 while (Entry
!= &CmiHiveListHead
)
1249 Hive
= CONTAINING_RECORD(Entry
, REGISTRY_HIVE
, HiveList
);
1251 if (!(IsNoFileHive(Hive
) || IsNoSynchHive(Hive
)))
1253 /* Flush non-volatile hive */
1254 CmiFlushRegistryHive(Hive
);
1257 Entry
= Entry
->Flink
;
1260 /* Release hive list lock */
1261 ExReleaseResourceLite(&CmiRegistryLock
);
1262 KeLeaveCriticalRegion();
1264 DPRINT("CmShutdownRegistry() done\n");
1269 CmiHiveSyncRoutine(PVOID DeferredContext
)
1271 PREGISTRY_HIVE Hive
;
1274 DPRINT("CmiHiveSyncRoutine() called\n");
1276 CmiHiveSyncPending
= FALSE
;
1278 /* Acquire hive list lock exclusively */
1279 KeEnterCriticalRegion();
1280 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1282 Entry
= CmiHiveListHead
.Flink
;
1283 while (Entry
!= &CmiHiveListHead
)
1285 Hive
= CONTAINING_RECORD(Entry
, REGISTRY_HIVE
, HiveList
);
1287 if (!(IsNoFileHive(Hive
) || IsNoSynchHive(Hive
)))
1289 /* Flush non-volatile hive */
1290 CmiFlushRegistryHive(Hive
);
1293 Entry
= Entry
->Flink
;
1296 /* Release hive list lock */
1297 ExReleaseResourceLite(&CmiRegistryLock
);
1298 KeLeaveCriticalRegion();
1300 DPRINT("DeferredContext 0x%p\n", DeferredContext
);
1301 ExFreePool(DeferredContext
);
1303 DPRINT("CmiHiveSyncRoutine() done\n");
1308 CmiHiveSyncDpcRoutine(PKDPC Dpc
,
1309 PVOID DeferredContext
,
1310 PVOID SystemArgument1
,
1311 PVOID SystemArgument2
)
1313 PWORK_QUEUE_ITEM WorkQueueItem
;
1315 WorkQueueItem
= ExAllocatePool(NonPagedPool
,
1316 sizeof(WORK_QUEUE_ITEM
));
1317 if (WorkQueueItem
== NULL
)
1319 DbgPrint("Failed to allocate work item\n");
1323 ExInitializeWorkItem(WorkQueueItem
,
1327 DPRINT("DeferredContext 0x%p\n", WorkQueueItem
);
1328 ExQueueWorkItem(WorkQueueItem
,
1336 LARGE_INTEGER Timeout
;
1338 DPRINT("CmiSyncHives() called\n");
1340 if (CmiHiveSyncEnabled
== FALSE
||
1341 CmiHiveSyncPending
== TRUE
)
1344 CmiHiveSyncPending
= TRUE
;
1346 Timeout
.QuadPart
= (LONGLONG
)-50000000;
1347 KeSetTimer(&CmiHiveSyncTimer
,