3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/cm/registry.c
6 * PURPOSE: Registry functions
7 * PROGRAMMERS: Rex Jolliff
14 #include <ddk/ntddk.h>
18 #include <internal/pool.h>
19 #include <internal/registry.h>
22 #include <internal/debug.h>
26 /* ------------------------------------------------- File Statics */
28 POBJECT_TYPE CmiKeyType = NULL;
29 PREGISTRY_HIVE CmiVolatileHive = NULL;
30 KSPIN_LOCK CmiKeyListLock;
32 static PKEY_OBJECT CmiRootKey = NULL;
33 static PKEY_OBJECT CmiMachineKey = NULL;
34 static PKEY_OBJECT CmiUserKey = NULL;
35 static PKEY_OBJECT CmiHardwareKey = NULL;
37 static GENERIC_MAPPING CmiKeyMapping =
38 {KEY_READ, KEY_WRITE, KEY_EXECUTE, KEY_ALL_ACCESS};
42 CmiCheckKey(BOOLEAN Verbose,
46 CmiCreateCurrentControlSetLink(VOID);
48 /* FUNCTIONS ****************************************************************/
51 CmiCheckSubKeys(BOOLEAN Verbose,
54 OBJECT_ATTRIBUTES ObjectAttributes;
55 PKEY_NODE_INFORMATION KeyInfo;
56 WCHAR KeyBuffer[MAX_PATH];
57 UNICODE_STRING KeyPath;
68 BufferSize = sizeof(KEY_NODE_INFORMATION) + 4096;
69 KeyInfo = ExAllocatePool(PagedPool, BufferSize);
71 Status = NtEnumerateKey(Key,
77 if (!NT_SUCCESS(Status))
80 if (Status == STATUS_NO_MORE_ENTRIES)
81 Status = STATUS_SUCCESS;
87 KeyInfo->NameLength / sizeof(WCHAR));
91 DbgPrint("Key: %S\n", Name);
94 /* FIXME: Check info. */
98 wcscpy(KeyBuffer, L"\\Registry\\");
99 wcscat(KeyBuffer, Name);
101 RtlInitUnicodeString(&KeyPath, KeyBuffer);
103 InitializeObjectAttributes(&ObjectAttributes,
105 OBJ_CASE_INSENSITIVE,
109 Status = NtOpenKey(&SubKey,
113 assert(NT_SUCCESS(Status));
115 CmiCheckKey(Verbose, SubKey);
122 assert(NT_SUCCESS(Status));
127 CmiCheckValues(BOOLEAN Verbose,
130 PKEY_NODE_INFORMATION ValueInfo;
131 WCHAR Name[MAX_PATH];
140 BufferSize = sizeof(KEY_NODE_INFORMATION) + 4096;
141 ValueInfo = ExAllocatePool(PagedPool, BufferSize);
143 Status = NtEnumerateValueKey(Key,
149 if (!NT_SUCCESS(Status))
151 ExFreePool(ValueInfo);
152 if (Status == STATUS_NO_MORE_ENTRIES)
153 Status = STATUS_SUCCESS;
159 ValueInfo->NameLength / sizeof(WCHAR));
163 DbgPrint("Value: %S\n", Name);
166 /* FIXME: Check info. */
168 ExFreePool(ValueInfo);
173 assert(NT_SUCCESS(Status));
178 CmiCheckKey(BOOLEAN Verbose,
181 CmiCheckValues(Verbose, Key);
182 CmiCheckSubKeys(Verbose, Key);
187 CmiCheckByName(BOOLEAN Verbose,
190 OBJECT_ATTRIBUTES ObjectAttributes;
191 WCHAR KeyPathBuffer[MAX_PATH];
192 UNICODE_STRING KeyPath;
196 wcscpy(KeyPathBuffer, L"\\Registry\\");
197 wcscat(KeyPathBuffer, KeyName);
199 RtlInitUnicodeString(&KeyPath, KeyPathBuffer);
201 InitializeObjectAttributes(&ObjectAttributes,
203 OBJ_CASE_INSENSITIVE,
207 Status = NtOpenKey(&Key,
213 if (!NT_SUCCESS(Status))
215 DbgPrint("KeyPath %wZ Status: %.08x", KeyPath, Status);
216 DbgPrint("KeyPath %S Status: %.08x", KeyPath.Buffer, Status);
217 assert(NT_SUCCESS(Status));
221 CmiCheckKey(Verbose, Key);
228 CmiCheckRegistry(BOOLEAN Verbose)
231 DbgPrint("Checking registry internals\n");
233 CmiCheckByName(Verbose, L"Machine");
234 CmiCheckByName(Verbose, L"User");
239 CmInitializeRegistry(VOID)
241 OBJECT_ATTRIBUTES ObjectAttributes;
242 UNICODE_STRING RootKeyName;
243 HANDLE RootKeyHandle;
248 /* Initialize the Key object type */
249 CmiKeyType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
251 CmiKeyType->TotalObjects = 0;
252 CmiKeyType->TotalHandles = 0;
253 CmiKeyType->MaxObjects = LONG_MAX;
254 CmiKeyType->MaxHandles = LONG_MAX;
255 CmiKeyType->PagedPoolCharge = 0;
256 CmiKeyType->NonpagedPoolCharge = sizeof(KEY_OBJECT);
257 CmiKeyType->Mapping = &CmiKeyMapping;
258 CmiKeyType->Dump = NULL;
259 CmiKeyType->Open = NULL;
260 CmiKeyType->Close = NULL;
261 CmiKeyType->Delete = CmiObjectDelete;
262 CmiKeyType->Parse = CmiObjectParse;
263 CmiKeyType->Security = NULL;
264 CmiKeyType->QueryName = NULL;
265 CmiKeyType->OkayToClose = NULL;
266 CmiKeyType->Create = CmiObjectCreate;
267 CmiKeyType->DuplicationNotify = NULL;
268 RtlInitUnicodeString(&CmiKeyType->TypeName, L"Key");
270 /* Build volatile registry store */
271 Status = CmiCreateRegistryHive(NULL, &CmiVolatileHive, FALSE);
272 assert(NT_SUCCESS(Status));
274 /* Build the Root Key Object */
275 RtlInitUnicodeString(&RootKeyName, REG_ROOT_KEY_NAME);
276 InitializeObjectAttributes(&ObjectAttributes, &RootKeyName, 0, NULL, NULL);
277 Status = ObCreateObject(&RootKeyHandle,
278 STANDARD_RIGHTS_REQUIRED,
282 assert(NT_SUCCESS(Status));
284 Status = ObReferenceObjectByHandle(RootKeyHandle,
285 STANDARD_RIGHTS_REQUIRED,
288 (PVOID *) &CmiRootKey,
290 assert(NT_SUCCESS(Status));
291 CmiRootKey->RegistryHive = CmiVolatileHive;
292 NewKey->BlockOffset = CmiVolatileHive->HiveHeader->RootKeyCell;
293 NewKey->KeyCell = CmiGetBlock(CmiVolatileHive, NewKey->BlockOffset, NULL);
294 CmiRootKey->Flags = 0;
295 CmiRootKey->NumberOfSubKeys = 0;
296 CmiRootKey->SubKeys = NULL;
297 CmiRootKey->SizeOfSubKeys = 0;
298 CmiRootKey->Name = ExAllocatePool(PagedPool, strlen("Registry"));
299 CmiRootKey->NameSize = strlen("Registry");
300 memcpy(CmiRootKey->Name, "Registry", strlen("Registry"));
302 KeInitializeSpinLock(&CmiKeyListLock);
304 /* Create initial predefined symbolic links */
306 /* HKEY_LOCAL_MACHINE */
307 Status = ObCreateObject(&KeyHandle,
308 STANDARD_RIGHTS_REQUIRED,
312 assert(NT_SUCCESS(Status));
313 Status = CmiAddSubKey(CmiVolatileHive,
317 wcslen(L"Machine") * sizeof(WCHAR),
321 assert(NT_SUCCESS(Status));
322 NewKey->RegistryHive = CmiVolatileHive;
324 NewKey->NumberOfSubKeys = 0;
325 NewKey->SubKeys = NULL;
326 NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
327 NewKey->Name = ExAllocatePool(PagedPool, strlen("Machine"));
328 NewKey->NameSize = strlen("Machine");
329 memcpy(NewKey->Name, "Machine", strlen("Machine"));
330 CmiAddKeyToList(CmiRootKey, NewKey);
331 CmiMachineKey = NewKey;
334 Status = ObCreateObject(&KeyHandle,
335 STANDARD_RIGHTS_REQUIRED,
339 assert(NT_SUCCESS(Status));
340 Status = CmiAddSubKey(CmiVolatileHive,
344 wcslen(L"User") * sizeof(WCHAR),
348 assert(NT_SUCCESS(Status));
349 NewKey->RegistryHive = CmiVolatileHive;
351 NewKey->NumberOfSubKeys = 0;
352 NewKey->SubKeys = NULL;
353 NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
354 NewKey->Name = ExAllocatePool(PagedPool, strlen("User"));
355 NewKey->NameSize = strlen("User");
356 memcpy(NewKey->Name, "User", strlen("User"));
357 CmiAddKeyToList(CmiRootKey, NewKey);
360 /* Create '\\Registry\\Machine\\HARDWARE' key. */
361 Status = ObCreateObject(&KeyHandle,
362 STANDARD_RIGHTS_REQUIRED,
366 assert(NT_SUCCESS(Status));
367 Status = CmiAddSubKey(CmiVolatileHive,
371 wcslen(L"HARDWARE") * sizeof(WCHAR),
375 assert(NT_SUCCESS(Status));
376 NewKey->RegistryHive = CmiVolatileHive;
378 NewKey->NumberOfSubKeys = 0;
379 NewKey->SubKeys = NULL;
380 NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
381 NewKey->Name = ExAllocatePool(PagedPool, strlen("HARDWARE"));
382 NewKey->NameSize = strlen("HARDWARE");
383 memcpy(NewKey->Name, "HARDWARE", strlen("HARDWARE"));
384 CmiAddKeyToList(CmiMachineKey, NewKey);
385 CmiHardwareKey = NewKey;
387 /* Create '\\Registry\\Machine\\HARDWARE\\DESCRIPTION' key. */
388 Status = ObCreateObject(&KeyHandle,
389 STANDARD_RIGHTS_REQUIRED,
393 assert(NT_SUCCESS(Status));
394 Status = CmiAddSubKey(CmiVolatileHive,
398 wcslen(L"DESCRIPTION") * sizeof(WCHAR),
402 assert(NT_SUCCESS(Status));
403 NewKey->RegistryHive = CmiVolatileHive;
405 NewKey->NumberOfSubKeys = 0;
406 NewKey->SubKeys = NULL;
407 NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
408 NewKey->Name = ExAllocatePool(PagedPool, strlen("DESCRIPTION"));
409 NewKey->NameSize = strlen("DESCRIPTION");
410 memcpy(NewKey->Name, "DESCRIPTION", strlen("DESCRIPTION"));
411 CmiAddKeyToList(CmiHardwareKey, NewKey);
413 /* Create '\\Registry\\Machine\\HARDWARE\\DEVICEMAP' key. */
414 Status = ObCreateObject(&KeyHandle,
415 STANDARD_RIGHTS_REQUIRED,
419 assert(NT_SUCCESS(Status));
420 Status = CmiAddSubKey(CmiVolatileHive,
424 wcslen(L"DEVICEMAP") * sizeof(WCHAR),
428 assert(NT_SUCCESS(Status));
429 NewKey->RegistryHive = CmiVolatileHive;
431 NewKey->NumberOfSubKeys = 0;
432 NewKey->SubKeys = NULL;
433 NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
434 NewKey->Name = ExAllocatePool(PagedPool, strlen("DEVICEMAP"));
435 NewKey->NameSize = strlen("DEVICEMAP");
436 memcpy(NewKey->Name, "DEVICEMAP", strlen("DEVICEMAP"));
437 CmiAddKeyToList(CmiHardwareKey,NewKey);
439 /* Create '\\Registry\\Machine\\HARDWARE\\RESOURCEMAP' key. */
440 Status = ObCreateObject(&KeyHandle,
441 STANDARD_RIGHTS_REQUIRED,
445 assert(NT_SUCCESS(Status));
446 Status = CmiAddSubKey(CmiVolatileHive,
450 wcslen(L"RESOURCEMAP") * sizeof(WCHAR),
454 assert(NT_SUCCESS(Status));
455 NewKey->RegistryHive = CmiVolatileHive;
457 NewKey->NumberOfSubKeys = 0;
458 NewKey->SubKeys = NULL;
459 NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
460 NewKey->Name = ExAllocatePool(PagedPool, strlen("RESOURCEMAP"));
461 NewKey->NameSize = strlen("RESOURCEMAP");
462 memcpy(NewKey->Name, "RESOURCEMAP", strlen("RESOURCEMAP"));
463 CmiAddKeyToList(CmiHardwareKey, NewKey);
465 /* FIXME: create remaining structure needed for default handles */
466 /* FIXME: load volatile registry data from ROSDTECT */
471 CmInit2(PCHAR CommandLine)
476 /* FIXME: Store current command line */
478 /* Create the 'CurrentControlSet' link. */
479 CmiCreateCurrentControlSetLink();
482 /* Set PICE 'Start' value to 1, if PICE debugging is enabled */
484 p1 = (PCHAR)CommandLine;
485 while (p1 && (p2 = strchr(p1, '/')))
488 if (_strnicmp(p2, "DEBUGPORT", 9) == 0)
494 if (_strnicmp(p2, "PICE", 4) == 0)
504 RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
515 CmiCreateCurrentControlSetLink(VOID)
517 RTL_QUERY_REGISTRY_TABLE QueryTable[5];
518 WCHAR TargetNameBuffer[80];
519 ULONG TargetNameLength;
520 UNICODE_STRING LinkName;
521 UNICODE_STRING LinkValue;
527 OBJECT_ATTRIBUTES ObjectAttributes;
530 DPRINT("CmiCreateCurrentControlSetLink() called\n");
532 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
534 QueryTable[0].Name = L"Current";
535 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
536 QueryTable[0].EntryContext = &CurrentSet;
538 QueryTable[1].Name = L"Default";
539 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
540 QueryTable[1].EntryContext = &DefaultSet;
542 QueryTable[2].Name = L"Failed";
543 QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
544 QueryTable[2].EntryContext = &Failed;
546 QueryTable[3].Name = L"LastKnownGood";
547 QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
548 QueryTable[3].EntryContext = &LastKnownGood;
550 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
551 L"\\Registry\\Machine\\SYSTEM\\Select",
555 if (!NT_SUCCESS(Status))
560 DPRINT("Current %ld Default %ld\n", CurrentSet, DefaultSet);
562 swprintf(TargetNameBuffer,
563 L"\\Registry\\Machine\\SYSTEM\\ControlSet%03lu",
565 TargetNameLength = wcslen(TargetNameBuffer) * sizeof(WCHAR);
567 DPRINT("Link target '%S'\n", TargetNameBuffer);
569 RtlInitUnicodeStringFromLiteral(&LinkName,
570 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
571 InitializeObjectAttributes(&ObjectAttributes,
573 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
576 Status = NtCreateKey(&KeyHandle,
577 KEY_ALL_ACCESS | KEY_CREATE_LINK,
581 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
583 if (!NT_SUCCESS(Status))
585 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
589 RtlInitUnicodeStringFromLiteral(&LinkValue,
590 L"SymbolicLinkValue");
591 Status=NtSetValueKey(KeyHandle,
595 (PVOID)TargetNameBuffer,
597 if (!NT_SUCCESS(Status))
599 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
609 CmiConnectHive(PWSTR FileName,
615 OBJECT_ATTRIBUTES ObjectAttributes;
616 PREGISTRY_HIVE RegistryHive = NULL;
617 UNICODE_STRING uKeyName;
622 DPRINT("Called. FileName %S\n", FullName);
624 Status = CmiCreateRegistryHive(FileName, &RegistryHive, CreateNew);
625 if (!NT_SUCCESS(Status))
628 RtlInitUnicodeString(&uKeyName, FullName);
630 InitializeObjectAttributes(&ObjectAttributes,
636 Status = ObCreateObject(&KeyHandle,
637 STANDARD_RIGHTS_REQUIRED,
641 if (!NT_SUCCESS(Status))
644 NewKey->RegistryHive = RegistryHive;
645 NewKey->BlockOffset = RegistryHive->HiveHeader->RootKeyCell;
646 NewKey->KeyCell = CmiGetBlock(RegistryHive, NewKey->BlockOffset, NULL);
648 NewKey->NumberOfSubKeys = 0;
649 NewKey->SubKeys = ExAllocatePool(PagedPool,
650 NewKey->KeyCell->NumberOfSubKeys * sizeof(DWORD));
652 if ((NewKey->SubKeys == NULL) && (NewKey->KeyCell->NumberOfSubKeys != 0))
654 /* FIXME: Cleanup from CmiCreateRegistryHive() */
655 DPRINT("NumberOfSubKeys %d\n", NewKey->KeyCell->NumberOfSubKeys);
657 return(STATUS_INSUFFICIENT_RESOURCES);
660 NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
661 NewKey->Name = ExAllocatePool(PagedPool, strlen(KeyName));
663 if ((NewKey->Name == NULL) && (strlen(KeyName) != 0))
665 /* FIXME: Cleanup from CmiCreateRegistryHive() */
666 DPRINT("strlen(KeyName) %d\n", strlen(KeyName));
667 if (NewKey->SubKeys != NULL)
668 ExFreePool(NewKey->SubKeys);
670 return(STATUS_INSUFFICIENT_RESOURCES);
673 NewKey->NameSize = strlen(KeyName);
674 memcpy(NewKey->Name, KeyName, strlen(KeyName));
675 CmiAddKeyToList(Parent, NewKey);
677 VERIFY_KEY_OBJECT(NewKey);
679 return(STATUS_SUCCESS);
684 CmiInitializeHive(PWSTR FileName,
692 DPRINT("CmiInitializeHive(%s) called\n", KeyName);
694 /* Try to connect the hive */
695 //Status = CmiConnectHive(FileName, FullName, KeyName, Parent, FALSE);
696 Status = CmiConnectHive(FileName, FullName, KeyName, Parent, CreateNew);
698 if (!NT_SUCCESS(Status))
700 DPRINT("Status %.08x\n", Status);
702 WCHAR AltFileName[MAX_PATH];
704 CPRINT("WARNING! Registry file %S not found\n", FileName);
706 wcscpy(AltFileName, FileName);
707 wcscat(AltFileName, L".alt");
709 /* Try to connect the alternative hive */
710 Status = CmiConnectHive(AltFileName, FullName, KeyName, Parent, TRUE);
712 if (!NT_SUCCESS(Status))
714 CPRINT("WARNING! Alternative registry file %S not found\n", AltFileName);
715 DPRINT("Status %.08x\n", Status);
720 DPRINT("CmiInitializeHive() done\n");
727 CmiInitHives(BOOLEAN SetUpBoot)
731 DPRINT("CmiInitHives() called\n");
735 /* FIXME: Delete temporary \Registry\Machine\System */
737 /* Connect the SYSTEM hive */
738 /* FIXME: Don't overwrite the existing 'System' hive yet */
739 // Status = CmiInitializeHive(SYSTEM_REG_FILE, REG_SYSTEM_KEY_NAME, "System", CmiMachineKey);
740 // assert(NT_SUCCESS(Status));
742 /* Connect the SOFTWARE hive */
743 Status = CmiInitializeHive(SOFTWARE_REG_FILE, REG_SOFTWARE_KEY_NAME, "Software", CmiMachineKey, SetUpBoot);
744 //assert(NT_SUCCESS(Status));
746 /* Connect the SAM hive */
747 Status = CmiInitializeHive(SAM_REG_FILE,REG_SAM_KEY_NAME, "Sam", CmiMachineKey, SetUpBoot);
748 //assert(NT_SUCCESS(Status));
750 /* Connect the SECURITY hive */
751 Status = CmiInitializeHive(SEC_REG_FILE, REG_SEC_KEY_NAME, "Security", CmiMachineKey, SetUpBoot);
752 //assert(NT_SUCCESS(Status));
754 /* Connect the DEFAULT hive */
755 Status = CmiInitializeHive(USER_REG_FILE, REG_USER_KEY_NAME, ".Default", CmiUserKey, SetUpBoot);
756 //assert(NT_SUCCESS(Status));
758 /* FIXME : initialize standards symbolic links */
760 // CmiCheckRegistry(TRUE);
762 DPRINT("CmiInitHives() done\n");
764 return(STATUS_SUCCESS);
769 CmShutdownRegistry(VOID)
771 DPRINT("CmShutdownRegistry() called\n");
774 * Don't call UNIMPLEMENTED() here since this function is
775 * called by NtShutdownSystem().