1 /* $Id: registry.c,v 1.74 2002/08/20 20:37:11 hyperion Exp $
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().