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
);
335 CmInitializeRegistry(VOID
)
337 OBJECT_ATTRIBUTES ObjectAttributes
;
338 UNICODE_STRING KeyName
;
341 PSECURITY_CELL RootSecurityCell
;
343 HANDLE RootKeyHandle
;
346 LARGE_INTEGER DueTime
;
350 /* Initialize the Key object type */
351 CmiKeyType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
353 CmiKeyType
->Tag
= TAG('R', 'e', 'g', 'K');
354 CmiKeyType
->TotalObjects
= 0;
355 CmiKeyType
->TotalHandles
= 0;
356 CmiKeyType
->PeakObjects
= 0;
357 CmiKeyType
->PeakHandles
= 0;
358 CmiKeyType
->PagedPoolCharge
= 0;
359 CmiKeyType
->NonpagedPoolCharge
= sizeof(KEY_OBJECT
);
360 CmiKeyType
->Mapping
= &CmiKeyMapping
;
361 CmiKeyType
->Dump
= NULL
;
362 CmiKeyType
->Open
= NULL
;
363 CmiKeyType
->Close
= NULL
;
364 CmiKeyType
->Delete
= CmiObjectDelete
;
365 CmiKeyType
->Parse
= CmiObjectParse
;
366 CmiKeyType
->Security
= CmiObjectSecurity
;
367 CmiKeyType
->QueryName
= CmiObjectQueryName
;
368 CmiKeyType
->OkayToClose
= NULL
;
369 CmiKeyType
->Create
= CmiObjectCreate
;
370 CmiKeyType
->DuplicationNotify
= NULL
;
371 RtlInitUnicodeString(&CmiKeyType
->TypeName
, L
"Key");
373 ObpCreateTypeObject (CmiKeyType
);
375 /* Initialize the hive list */
376 InitializeListHead(&CmiHiveListHead
);
378 /* Initialize registry lock */
379 ExInitializeResourceLite(&CmiRegistryLock
);
381 /* Initialize the key object list */
382 InitializeListHead(&CmiKeyObjectListHead
);
384 /* Initialize the worker timer */
385 KeInitializeTimerEx(&CmiWorkerTimer
, SynchronizationTimer
);
387 /* Initialize the worker thread */
388 Status
= PsCreateSystemThread(&ThreadHandle
,
395 if (!NT_SUCCESS(Status
))
400 /* Start the timer */
401 DueTime
.QuadPart
= -1;
402 KeSetTimerEx(&CmiWorkerTimer
, DueTime
, 5000, NULL
); /* 5sec */
404 /* Build volatile registry store */
405 Status
= CmiCreateVolatileHive (&CmiVolatileHive
);
406 ASSERT(NT_SUCCESS(Status
));
408 InitializeListHead(&CmiCallbackHead
);
409 ExInitializeFastMutex(&CmiCallbackLock
);
411 /* Create '\Registry' key. */
412 RtlInitUnicodeString(&KeyName
, REG_ROOT_KEY_NAME
);
413 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, 0, NULL
, NULL
);
414 Status
= ObCreateObject(KernelMode
,
423 ASSERT(NT_SUCCESS(Status
));
424 Status
= ObInsertObject(RootKey
,
430 ASSERT(NT_SUCCESS(Status
));
431 RootKey
->RegistryHive
= CmiVolatileHive
;
432 RootKey
->KeyCellOffset
= CmiVolatileHive
->HiveHeader
->RootKeyOffset
;
433 RootKey
->KeyCell
= CmiGetCell (CmiVolatileHive
, RootKey
->KeyCellOffset
, NULL
);
434 RootKey
->ParentKey
= RootKey
;
436 RootKey
->NumberOfSubKeys
= 0;
437 RootKey
->SubKeys
= NULL
;
438 RootKey
->SizeOfSubKeys
= 0;
439 InsertTailList(&CmiKeyObjectListHead
, &RootKey
->ListEntry
);
440 Status
= RtlpCreateUnicodeString(&RootKey
->Name
, L
"Registry", NonPagedPool
);
441 ASSERT(NT_SUCCESS(Status
));
444 Status
= CmiAllocateCell(CmiVolatileHive
,
445 0x10, //LONG CellSize,
446 (PVOID
*)&RootSecurityCell
,
447 &RootKey
->KeyCell
->SecurityKeyOffset
);
448 ASSERT(NT_SUCCESS(Status
));
450 /* Copy the security descriptor */
452 CmiVolatileHive
->RootSecurityCell
= RootSecurityCell
;
456 /* Create '\Registry\Machine' key. */
457 RtlInitUnicodeString(&KeyName
,
459 InitializeObjectAttributes(&ObjectAttributes
,
464 Status
= ZwCreateKey(&KeyHandle
,
471 ASSERT(NT_SUCCESS(Status
));
473 /* Create '\Registry\User' key. */
474 RtlInitUnicodeString(&KeyName
,
476 InitializeObjectAttributes(&ObjectAttributes
,
481 Status
= ZwCreateKey(&KeyHandle
,
488 ASSERT(NT_SUCCESS(Status
));
493 CmInit2(PCHAR CommandLine
)
496 BOOLEAN MiniNT
= FALSE
;
497 PWCHAR SystemBootDevice
;
498 PWCHAR SystemStartOptions
;
502 /* Create the 'CurrentControlSet' link. */
503 Status
= CmiCreateCurrentControlSetLink();
504 if (!NT_SUCCESS(Status
))
505 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
508 * Parse the system boot device.
511 SystemBootDevice
= ExAllocatePool(PagedPool
,
512 (strlen(CommandLine
) + 1) * sizeof(WCHAR
));
513 if (SystemBootDevice
== NULL
)
515 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
518 while (*CommandLine
!= 0 && *CommandLine
!= ' ')
519 SystemBootDevice
[Position
++] = *(CommandLine
++);
520 SystemBootDevice
[Position
++] = 0;
523 * Write the system boot device to registry.
525 Status
= RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
526 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
530 Position
* sizeof(WCHAR
));
531 if (!NT_SUCCESS(Status
))
533 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
537 * Parse the system start options.
540 SystemStartOptions
= SystemBootDevice
;
541 while ((CommandLine
= strchr(CommandLine
, '/')) != NULL
)
543 /* Skip over the slash */
546 /* Special options */
547 if (!_strnicmp(CommandLine
, "MININT", 6))
549 else if (!_strnicmp(CommandLine
, "DEBUGPORT=PICE", 14))
552 /* Add a space between the options */
554 SystemStartOptions
[Position
++] = L
' ';
556 /* Copy the command */
557 while (*CommandLine
!= 0 && *CommandLine
!= ' ')
558 SystemStartOptions
[Position
++] = *(CommandLine
++);
560 SystemStartOptions
[Position
++] = 0;
563 * Write the system start options to registry.
565 Status
= RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE
,
566 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
567 L
"SystemStartOptions",
570 Position
* sizeof(WCHAR
));
571 if (!NT_SUCCESS(Status
))
573 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
577 * Create a CurrentControlSet\Control\MiniNT key that is used
578 * to detect WinPE/MiniNT systems.
582 Status
= RtlCreateRegistryKey(RTL_REGISTRY_CONTROL
, L
"MiniNT");
583 if (!NT_SUCCESS(Status
))
584 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
587 /* Set PICE 'Start' value to 1, if PICE debugging is enabled */
588 Status
= RtlWriteRegistryValue(
589 RTL_REGISTRY_SERVICES
,
595 if (!NT_SUCCESS(Status
))
596 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED
);
598 ExFreePool(SystemBootDevice
);
603 CmiCreateCurrentControlSetLink(VOID
)
605 RTL_QUERY_REGISTRY_TABLE QueryTable
[5];
606 WCHAR TargetNameBuffer
[80];
607 ULONG TargetNameLength
;
608 UNICODE_STRING LinkName
;
609 UNICODE_STRING LinkValue
;
615 OBJECT_ATTRIBUTES ObjectAttributes
;
618 DPRINT("CmiCreateCurrentControlSetLink() called\n");
620 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
622 QueryTable
[0].Name
= L
"Current";
623 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
624 QueryTable
[0].EntryContext
= &CurrentSet
;
626 QueryTable
[1].Name
= L
"Default";
627 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
628 QueryTable
[1].EntryContext
= &DefaultSet
;
630 QueryTable
[2].Name
= L
"Failed";
631 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
632 QueryTable
[2].EntryContext
= &Failed
;
634 QueryTable
[3].Name
= L
"LastKnownGood";
635 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
636 QueryTable
[3].EntryContext
= &LastKnownGood
;
638 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
639 L
"\\Registry\\Machine\\SYSTEM\\Select",
643 if (!NT_SUCCESS(Status
))
648 DPRINT("Current %ld Default %ld\n", CurrentSet
, DefaultSet
);
650 swprintf(TargetNameBuffer
,
651 L
"\\Registry\\Machine\\SYSTEM\\ControlSet%03lu",
653 TargetNameLength
= wcslen(TargetNameBuffer
) * sizeof(WCHAR
);
655 DPRINT("Link target '%S'\n", TargetNameBuffer
);
657 RtlRosInitUnicodeStringFromLiteral(&LinkName
,
658 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
659 InitializeObjectAttributes(&ObjectAttributes
,
661 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_OPENLINK
,
664 Status
= ZwCreateKey(&KeyHandle
,
665 KEY_ALL_ACCESS
| KEY_CREATE_LINK
,
669 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
671 if (!NT_SUCCESS(Status
))
673 DPRINT1("ZwCreateKey() failed (Status %lx)\n", Status
);
677 RtlRosInitUnicodeStringFromLiteral(&LinkValue
,
678 L
"SymbolicLinkValue");
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
;
706 DPRINT("CmiConnectHive(%p, %p) called.\n",
707 KeyObjectAttributes
, RegistryHive
);
709 Status
= ObFindObject(KeyObjectAttributes
,
713 if (!NT_SUCCESS(Status
))
718 DPRINT ("RemainingPath %wZ\n", &RemainingPath
);
720 if ((RemainingPath
.Buffer
== NULL
) || (RemainingPath
.Buffer
[0] == 0))
722 ObDereferenceObject (ParentKey
);
723 RtlFreeUnicodeString(&RemainingPath
);
724 return STATUS_OBJECT_NAME_COLLISION
;
727 /* Ignore leading backslash */
728 SubName
= RemainingPath
.Buffer
;
729 if (*SubName
== L
'\\')
732 /* If RemainingPath contains \ we must return error
733 because CmiConnectHive() can not create trees */
734 if (wcschr (SubName
, L
'\\') != NULL
)
736 ObDereferenceObject (ParentKey
);
737 RtlFreeUnicodeString(&RemainingPath
);
738 return STATUS_OBJECT_NAME_NOT_FOUND
;
741 DPRINT("RemainingPath %wZ ParentKey %p\n",
742 &RemainingPath
, ParentKey
);
744 Status
= ObCreateObject(KernelMode
,
753 if (!NT_SUCCESS(Status
))
755 DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status
);
756 ObDereferenceObject (ParentKey
);
757 RtlFreeUnicodeString(&RemainingPath
);
761 NewKey
->RegistryHive
= RegistryHive
;
762 NewKey
->KeyCellOffset
= RegistryHive
->HiveHeader
->RootKeyOffset
;
763 NewKey
->KeyCell
= CmiGetCell (RegistryHive
, NewKey
->KeyCellOffset
, NULL
);
765 NewKey
->NumberOfSubKeys
= 0;
766 InsertTailList(&CmiKeyObjectListHead
, &NewKey
->ListEntry
);
767 if (NewKey
->KeyCell
->NumberOfSubKeys
!= 0)
769 NewKey
->SubKeys
= ExAllocatePool(NonPagedPool
,
770 NewKey
->KeyCell
->NumberOfSubKeys
* sizeof(ULONG
));
771 if (NewKey
->SubKeys
== NULL
)
773 DPRINT("ExAllocatePool() failed\n");
774 ObDereferenceObject (NewKey
);
775 ObDereferenceObject (ParentKey
);
776 RtlFreeUnicodeString(&RemainingPath
);
777 return STATUS_INSUFFICIENT_RESOURCES
;
782 NewKey
->SubKeys
= NULL
;
785 DPRINT ("SubName %S\n", SubName
);
787 Status
= RtlpCreateUnicodeString(&NewKey
->Name
,
788 SubName
, NonPagedPool
);
789 RtlFreeUnicodeString(&RemainingPath
);
790 if (!NT_SUCCESS(Status
))
792 DPRINT1("RtlpCreateUnicodeString() failed (Status %lx)\n", Status
);
793 if (NewKey
->SubKeys
!= NULL
)
795 ExFreePool (NewKey
->SubKeys
);
797 ObDereferenceObject (NewKey
);
798 ObDereferenceObject (ParentKey
);
799 return STATUS_INSUFFICIENT_RESOURCES
;
802 CmiAddKeyToList (ParentKey
, NewKey
);
803 ObDereferenceObject (ParentKey
);
805 VERIFY_KEY_OBJECT(NewKey
);
807 /* Note: Do not dereference NewKey here! */
809 return STATUS_SUCCESS
;
814 CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
815 OUT PREGISTRY_HIVE
*RegistryHive
)
817 PKEY_OBJECT KeyObject
;
821 PLIST_ENTRY CurrentEntry
;
822 PKEY_OBJECT CurrentKey
;
824 DPRINT("CmiDisconnectHive() called\n");
826 *RegistryHive
= NULL
;
828 Status
= ObOpenObjectByName (KeyObjectAttributes
,
832 STANDARD_RIGHTS_REQUIRED
,
835 if (!NT_SUCCESS(Status
))
837 DPRINT1 ("ObOpenObjectByName() failed (Status %lx)\n", Status
);
841 Status
= ObReferenceObjectByHandle (KeyHandle
,
842 STANDARD_RIGHTS_REQUIRED
,
848 if (!NT_SUCCESS(Status
))
850 DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status
);
853 DPRINT ("KeyObject %p Hive %p\n", KeyObject
, KeyObject
->RegistryHive
);
855 if (!(KeyObject
->KeyCell
->Flags
& REG_KEY_ROOT_CELL
))
857 DPRINT1 ("Key is not the Hive-Root-Key\n");
858 ObDereferenceObject (KeyObject
);
859 return STATUS_INVALID_PARAMETER
;
862 /* Acquire registry lock exclusively */
863 KeEnterCriticalRegion();
864 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
866 CurrentEntry
= CmiKeyObjectListHead
.Flink
;
867 while (CurrentEntry
!= &CmiKeyObjectListHead
)
869 CurrentKey
= CONTAINING_RECORD(CurrentEntry
, KEY_OBJECT
, ListEntry
);
870 if (1 == ObGetObjectPointerCount(CurrentKey
) &&
871 !(CurrentKey
->Flags
& KO_MARKED_FOR_DELETE
))
873 ObDereferenceObject(CurrentKey
);
874 CurrentEntry
= CmiKeyObjectListHead
.Flink
;
878 CurrentEntry
= CurrentEntry
->Flink
;
882 if (ObGetObjectHandleCount (KeyObject
) != 0 ||
883 ObGetObjectPointerCount (KeyObject
) != 2)
885 DPRINT1 ("Hive is still in use (hc %d, rc %d)\n", ObGetObjectHandleCount (KeyObject
), ObGetObjectPointerCount (KeyObject
));
886 ObDereferenceObject (KeyObject
);
888 /* Release registry lock */
889 ExReleaseResourceLite (&CmiRegistryLock
);
890 KeLeaveCriticalRegion();
892 return STATUS_UNSUCCESSFUL
;
895 Hive
= KeyObject
->RegistryHive
;
897 /* Dereference KeyObject twice to delete it */
898 ObDereferenceObject (KeyObject
);
899 ObDereferenceObject (KeyObject
);
901 *RegistryHive
= Hive
;
903 /* Release registry lock */
904 ExReleaseResourceLite (&CmiRegistryLock
);
905 KeLeaveCriticalRegion();
907 DPRINT ("CmiDisconnectHive() done\n");
909 return STATUS_SUCCESS
;
914 CmiInitControlSetLink (VOID
)
916 OBJECT_ATTRIBUTES ObjectAttributes
;
917 UNICODE_STRING ControlSetKeyName
;
918 UNICODE_STRING ControlSetLinkName
;
919 UNICODE_STRING ControlSetValueName
;
923 /* Create 'ControlSet001' key */
924 RtlRosInitUnicodeStringFromLiteral (&ControlSetKeyName
,
925 L
"\\Registry\\Machine\\SYSTEM\\ControlSet001");
926 InitializeObjectAttributes (&ObjectAttributes
,
928 OBJ_CASE_INSENSITIVE
,
931 Status
= ZwCreateKey (&KeyHandle
,
936 REG_OPTION_NON_VOLATILE
,
938 if (!NT_SUCCESS(Status
))
940 DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status
);
945 /* Link 'CurrentControlSet' to 'ControlSet001' key */
946 RtlRosInitUnicodeStringFromLiteral (&ControlSetLinkName
,
947 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
948 InitializeObjectAttributes (&ObjectAttributes
,
950 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
| OBJ_OPENLINK
,
953 Status
= ZwCreateKey (&KeyHandle
,
954 KEY_ALL_ACCESS
| KEY_CREATE_LINK
,
958 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
960 if (!NT_SUCCESS(Status
))
962 DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status
);
966 RtlRosInitUnicodeStringFromLiteral (&ControlSetValueName
,
967 L
"SymbolicLinkValue");
968 Status
= ZwSetValueKey (KeyHandle
,
969 &ControlSetValueName
,
972 (PVOID
)ControlSetKeyName
.Buffer
,
973 ControlSetKeyName
.Length
);
974 if (!NT_SUCCESS(Status
))
976 DPRINT1 ("ZwSetValueKey() failed (Status %lx)\n", Status
);
980 return STATUS_SUCCESS
;
985 CmiInitHives(BOOLEAN SetupBoot
)
987 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
988 OBJECT_ATTRIBUTES ObjectAttributes
;
989 UNICODE_STRING FileName
;
990 UNICODE_STRING KeyName
;
991 UNICODE_STRING ValueName
;
996 WCHAR ConfigPath
[MAX_PATH
];
1003 DPRINT("CmiInitHives() called\n");
1005 if (SetupBoot
== TRUE
)
1007 RtlRosInitUnicodeStringFromLiteral(&KeyName
,
1008 L
"\\Registry\\Machine\\HARDWARE");
1009 InitializeObjectAttributes(&ObjectAttributes
,
1011 OBJ_CASE_INSENSITIVE
,
1014 Status
= ZwOpenKey(&KeyHandle
,
1017 if (!NT_SUCCESS(Status
))
1019 DPRINT1("ZwOpenKey() failed (Status %lx)\n", Status
);
1023 RtlRosInitUnicodeStringFromLiteral(&ValueName
,
1026 BufferSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4096;
1027 ValueInfo
= ExAllocatePool(PagedPool
,
1029 if (ValueInfo
== NULL
)
1032 return(STATUS_INSUFFICIENT_RESOURCES
);
1035 Status
= ZwQueryValueKey(KeyHandle
,
1037 KeyValuePartialInformation
,
1042 if (!NT_SUCCESS(Status
))
1044 ExFreePool(ValueInfo
);
1048 RtlCopyMemory(ConfigPath
,
1050 ValueInfo
->DataLength
);
1051 ConfigPath
[ValueInfo
->DataLength
/ sizeof(WCHAR
)] = (WCHAR
)0;
1052 ExFreePool(ValueInfo
);
1056 wcscpy(ConfigPath
, L
"\\SystemRoot");
1058 wcscat(ConfigPath
, L
"\\system32\\config");
1060 DPRINT("ConfigPath: %S\n", ConfigPath
);
1062 EndPtr
= ConfigPath
+ wcslen(ConfigPath
);
1066 /* FIXME: Save boot log */
1068 /* Connect the SYSTEM hive only if it has been created */
1069 if (SetupBoot
== TRUE
)
1071 wcscpy(EndPtr
, REG_SYSTEM_FILE_NAME
);
1072 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1074 RtlInitUnicodeString (&KeyName
,
1075 REG_SYSTEM_KEY_NAME
);
1076 InitializeObjectAttributes(&ObjectAttributes
,
1078 OBJ_CASE_INSENSITIVE
,
1082 RtlInitUnicodeString (&FileName
,
1084 Status
= CmiLoadHive (&ObjectAttributes
,
1087 if (!NT_SUCCESS(Status
))
1089 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status
);
1093 Status
= CmiInitControlSetLink ();
1094 if (!NT_SUCCESS(Status
))
1096 DPRINT1("CmiInitControlSetLink() failed (Status %lx)\n", Status
);
1101 /* Connect the SOFTWARE hive */
1102 wcscpy(EndPtr
, REG_SOFTWARE_FILE_NAME
);
1103 RtlInitUnicodeString (&FileName
,
1105 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1107 RtlInitUnicodeString (&KeyName
,
1108 REG_SOFTWARE_KEY_NAME
);
1109 InitializeObjectAttributes(&ObjectAttributes
,
1111 OBJ_CASE_INSENSITIVE
,
1115 Status
= CmiLoadHive (&ObjectAttributes
,
1118 if (!NT_SUCCESS(Status
))
1120 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1124 /* Connect the SAM hive */
1125 wcscpy(EndPtr
, REG_SAM_FILE_NAME
);
1126 RtlInitUnicodeString (&FileName
,
1128 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1130 RtlInitUnicodeString (&KeyName
,
1132 InitializeObjectAttributes(&ObjectAttributes
,
1134 OBJ_CASE_INSENSITIVE
,
1137 Status
= CmiLoadHive (&ObjectAttributes
,
1140 if (!NT_SUCCESS(Status
))
1142 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1146 /* Connect the SECURITY hive */
1147 wcscpy(EndPtr
, REG_SEC_FILE_NAME
);
1148 RtlInitUnicodeString (&FileName
,
1150 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1152 RtlInitUnicodeString (&KeyName
,
1154 InitializeObjectAttributes(&ObjectAttributes
,
1156 OBJ_CASE_INSENSITIVE
,
1159 Status
= CmiLoadHive (&ObjectAttributes
,
1162 if (!NT_SUCCESS(Status
))
1164 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1168 /* Connect the DEFAULT hive */
1169 wcscpy(EndPtr
, REG_DEFAULT_USER_FILE_NAME
);
1170 RtlInitUnicodeString (&FileName
,
1172 DPRINT ("ConfigPath: %S\n", ConfigPath
);
1174 RtlInitUnicodeString (&KeyName
,
1175 REG_DEFAULT_USER_KEY_NAME
);
1176 InitializeObjectAttributes(&ObjectAttributes
,
1178 OBJ_CASE_INSENSITIVE
,
1181 Status
= CmiLoadHive (&ObjectAttributes
,
1184 if (!NT_SUCCESS(Status
))
1186 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status
);
1190 // CmiCheckRegistry(TRUE);
1192 /* Start automatic hive synchronization */
1193 KeInitializeDpc(&CmiHiveSyncDpc
,
1194 CmiHiveSyncDpcRoutine
,
1196 KeInitializeTimer(&CmiHiveSyncTimer
);
1197 CmiHiveSyncEnabled
= TRUE
;
1199 DPRINT("CmiInitHives() done\n");
1201 return(STATUS_SUCCESS
);
1206 CmShutdownRegistry(VOID
)
1208 PREGISTRY_HIVE Hive
;
1211 DPRINT("CmShutdownRegistry() called\n");
1213 /* Stop automatic hive synchronization */
1214 CmiHiveSyncEnabled
= FALSE
;
1216 /* Cancel pending hive synchronization */
1217 if (CmiHiveSyncPending
== TRUE
)
1219 KeCancelTimer(&CmiHiveSyncTimer
);
1220 CmiHiveSyncPending
= FALSE
;
1223 /* Acquire hive list lock exclusively */
1224 KeEnterCriticalRegion();
1225 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1227 Entry
= CmiHiveListHead
.Flink
;
1228 while (Entry
!= &CmiHiveListHead
)
1230 Hive
= CONTAINING_RECORD(Entry
, REGISTRY_HIVE
, HiveList
);
1232 if (!(IsNoFileHive(Hive
) || IsNoSynchHive(Hive
)))
1234 /* Flush non-volatile hive */
1235 CmiFlushRegistryHive(Hive
);
1238 Entry
= Entry
->Flink
;
1241 /* Release hive list lock */
1242 ExReleaseResourceLite(&CmiRegistryLock
);
1243 KeLeaveCriticalRegion();
1245 DPRINT("CmShutdownRegistry() done\n");
1250 CmiHiveSyncRoutine(PVOID DeferredContext
)
1252 PREGISTRY_HIVE Hive
;
1255 DPRINT("CmiHiveSyncRoutine() called\n");
1257 CmiHiveSyncPending
= FALSE
;
1259 /* Acquire hive list lock exclusively */
1260 KeEnterCriticalRegion();
1261 ExAcquireResourceExclusiveLite(&CmiRegistryLock
, TRUE
);
1263 Entry
= CmiHiveListHead
.Flink
;
1264 while (Entry
!= &CmiHiveListHead
)
1266 Hive
= CONTAINING_RECORD(Entry
, REGISTRY_HIVE
, HiveList
);
1268 if (!(IsNoFileHive(Hive
) || IsNoSynchHive(Hive
)))
1270 /* Flush non-volatile hive */
1271 CmiFlushRegistryHive(Hive
);
1274 Entry
= Entry
->Flink
;
1277 /* Release hive list lock */
1278 ExReleaseResourceLite(&CmiRegistryLock
);
1279 KeLeaveCriticalRegion();
1281 DPRINT("DeferredContext %x\n", DeferredContext
);
1282 ExFreePool(DeferredContext
);
1284 DPRINT("CmiHiveSyncRoutine() done\n");
1289 CmiHiveSyncDpcRoutine(PKDPC Dpc
,
1290 PVOID DeferredContext
,
1291 PVOID SystemArgument1
,
1292 PVOID SystemArgument2
)
1294 PWORK_QUEUE_ITEM WorkQueueItem
;
1296 WorkQueueItem
= ExAllocatePool(NonPagedPool
,
1297 sizeof(WORK_QUEUE_ITEM
));
1298 if (WorkQueueItem
== NULL
)
1300 DbgPrint("Failed to allocate work item\n");
1304 ExInitializeWorkItem(WorkQueueItem
,
1308 DPRINT("DeferredContext %x\n", WorkQueueItem
);
1309 ExQueueWorkItem(WorkQueueItem
,
1317 LARGE_INTEGER Timeout
;
1319 DPRINT("CmiSyncHives() called\n");
1321 if (CmiHiveSyncEnabled
== FALSE
||
1322 CmiHiveSyncPending
== TRUE
)
1325 CmiHiveSyncPending
= TRUE
;
1327 Timeout
.QuadPart
= (LONGLONG
)-50000000;
1328 KeSetTimer(&CmiHiveSyncTimer
,