* Removed CmiLockBlock() and CmiReleaseBlock().
[reactos.git] / reactos / ntoskrnl / cm / registry.c
1 /* $Id: registry.c,v 1.92 2003/04/12 15:09:57 ekohl Exp $
2 *
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
8 * Matt Pyne
9 * Jean Michault
10 * UPDATE HISTORY:
11 * Created 22/05/98
12 */
13
14 #include <ddk/ntddk.h>
15 #include <roscfg.h>
16 #include <limits.h>
17 #include <string.h>
18 #include <internal/pool.h>
19 #include <internal/registry.h>
20 #include <reactos/bugcodes.h>
21
22 #define NDEBUG
23 #include <internal/debug.h>
24
25 #include "cm.h"
26
27 /* GLOBALS ******************************************************************/
28
29 POBJECT_TYPE CmiKeyType = NULL;
30 PREGISTRY_HIVE CmiVolatileHive = NULL;
31 KSPIN_LOCK CmiKeyListLock;
32
33 LIST_ENTRY CmiHiveListHead;
34 ERESOURCE CmiHiveListLock;
35
36 volatile BOOLEAN CmiHiveSyncEnabled = FALSE;
37 volatile BOOLEAN CmiHiveSyncPending = FALSE;
38 KDPC CmiHiveSyncDpc;
39 KTIMER CmiHiveSyncTimer;
40
41 static GENERIC_MAPPING CmiKeyMapping =
42 {KEY_READ, KEY_WRITE, KEY_EXECUTE, KEY_ALL_ACCESS};
43
44
45
46 VOID
47 CmiCheckKey(BOOLEAN Verbose,
48 HANDLE Key);
49
50 static NTSTATUS
51 CmiCreateCurrentControlSetLink(VOID);
52
53 static VOID STDCALL
54 CmiHiveSyncDpcRoutine(PKDPC Dpc,
55 PVOID DeferredContext,
56 PVOID SystemArgument1,
57 PVOID SystemArgument2);
58
59 /* FUNCTIONS ****************************************************************/
60
61 VOID
62 CmiCheckSubKeys(BOOLEAN Verbose,
63 HANDLE Key)
64 {
65 OBJECT_ATTRIBUTES ObjectAttributes;
66 PKEY_NODE_INFORMATION KeyInfo;
67 WCHAR KeyBuffer[MAX_PATH];
68 UNICODE_STRING KeyPath;
69 WCHAR Name[MAX_PATH];
70 ULONG BufferSize;
71 ULONG ResultSize;
72 NTSTATUS Status;
73 HANDLE SubKey;
74 ULONG Index;
75
76 Index = 0;
77 while (TRUE)
78 {
79 BufferSize = sizeof(KEY_NODE_INFORMATION) + 4096;
80 KeyInfo = ExAllocatePool(PagedPool, BufferSize);
81
82 Status = NtEnumerateKey(Key,
83 Index,
84 KeyNodeInformation,
85 KeyInfo,
86 BufferSize,
87 &ResultSize);
88 if (!NT_SUCCESS(Status))
89 {
90 ExFreePool(KeyInfo);
91 if (Status == STATUS_NO_MORE_ENTRIES)
92 Status = STATUS_SUCCESS;
93 break;
94 }
95
96 wcsncpy(Name,
97 KeyInfo->Name,
98 KeyInfo->NameLength / sizeof(WCHAR));
99
100 if (Verbose)
101 {
102 DbgPrint("Key: %S\n", Name);
103 }
104
105 /* FIXME: Check info. */
106
107 ExFreePool(KeyInfo);
108
109 wcscpy(KeyBuffer, L"\\Registry\\");
110 wcscat(KeyBuffer, Name);
111
112 RtlInitUnicodeString(&KeyPath, KeyBuffer);
113
114 InitializeObjectAttributes(&ObjectAttributes,
115 &KeyPath,
116 OBJ_CASE_INSENSITIVE,
117 NULL,
118 NULL);
119
120 Status = NtOpenKey(&SubKey,
121 KEY_ALL_ACCESS,
122 &ObjectAttributes);
123
124 assert(NT_SUCCESS(Status));
125
126 CmiCheckKey(Verbose, SubKey);
127
128 NtClose(SubKey);
129
130 Index++;
131 }
132
133 assert(NT_SUCCESS(Status));
134 }
135
136
137 VOID
138 CmiCheckValues(BOOLEAN Verbose,
139 HANDLE Key)
140 {
141 PKEY_NODE_INFORMATION ValueInfo;
142 WCHAR Name[MAX_PATH];
143 ULONG BufferSize;
144 ULONG ResultSize;
145 NTSTATUS Status;
146 ULONG Index;
147
148 Index = 0;
149 while (TRUE)
150 {
151 BufferSize = sizeof(KEY_NODE_INFORMATION) + 4096;
152 ValueInfo = ExAllocatePool(PagedPool, BufferSize);
153
154 Status = NtEnumerateValueKey(Key,
155 Index,
156 KeyNodeInformation,
157 ValueInfo,
158 BufferSize,
159 &ResultSize);
160 if (!NT_SUCCESS(Status))
161 {
162 ExFreePool(ValueInfo);
163 if (Status == STATUS_NO_MORE_ENTRIES)
164 Status = STATUS_SUCCESS;
165 break;
166 }
167
168 wcsncpy(Name,
169 ValueInfo->Name,
170 ValueInfo->NameLength / sizeof(WCHAR));
171
172 if (Verbose)
173 {
174 DbgPrint("Value: %S\n", Name);
175 }
176
177 /* FIXME: Check info. */
178
179 ExFreePool(ValueInfo);
180
181 Index++;
182 }
183
184 assert(NT_SUCCESS(Status));
185 }
186
187
188 VOID
189 CmiCheckKey(BOOLEAN Verbose,
190 HANDLE Key)
191 {
192 CmiCheckValues(Verbose, Key);
193 CmiCheckSubKeys(Verbose, Key);
194 }
195
196
197 VOID
198 CmiCheckByName(BOOLEAN Verbose,
199 PWSTR KeyName)
200 {
201 OBJECT_ATTRIBUTES ObjectAttributes;
202 WCHAR KeyPathBuffer[MAX_PATH];
203 UNICODE_STRING KeyPath;
204 NTSTATUS Status;
205 HANDLE Key;
206
207 wcscpy(KeyPathBuffer, L"\\Registry\\");
208 wcscat(KeyPathBuffer, KeyName);
209
210 RtlInitUnicodeString(&KeyPath, KeyPathBuffer);
211
212 InitializeObjectAttributes(&ObjectAttributes,
213 &KeyPath,
214 OBJ_CASE_INSENSITIVE,
215 NULL,
216 NULL);
217
218 Status = NtOpenKey(&Key,
219 KEY_ALL_ACCESS,
220 &ObjectAttributes);
221
222 if (CHECKED)
223 {
224 if (!NT_SUCCESS(Status))
225 {
226 DbgPrint("KeyPath %wZ Status: %.08x", KeyPath, Status);
227 DbgPrint("KeyPath %S Status: %.08x", KeyPath.Buffer, Status);
228 assert(NT_SUCCESS(Status));
229 }
230 }
231
232 CmiCheckKey(Verbose, Key);
233
234 NtClose(Key);
235 }
236
237
238 VOID
239 CmiCheckRegistry(BOOLEAN Verbose)
240 {
241 if (Verbose)
242 DbgPrint("Checking registry internals\n");
243
244 CmiCheckByName(Verbose, L"Machine");
245 CmiCheckByName(Verbose, L"User");
246 }
247
248
249 VOID
250 CmInitializeRegistry(VOID)
251 {
252 OBJECT_ATTRIBUTES ObjectAttributes;
253 UNICODE_STRING RootKeyName;
254 PKEY_OBJECT RootKey;
255 PKEY_OBJECT MachineKey;
256 PKEY_OBJECT UserKey;
257 HANDLE RootKeyHandle;
258 HANDLE KeyHandle;
259 NTSTATUS Status;
260
261 /* FIXME: remove the hardware keys before the hardware hive is imported */
262 PKEY_OBJECT HardwareKey;
263 PKEY_OBJECT NewKey;
264
265
266 /* Initialize the Key object type */
267 CmiKeyType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
268 assert(CmiKeyType);
269 CmiKeyType->TotalObjects = 0;
270 CmiKeyType->TotalHandles = 0;
271 CmiKeyType->MaxObjects = LONG_MAX;
272 CmiKeyType->MaxHandles = LONG_MAX;
273 CmiKeyType->PagedPoolCharge = 0;
274 CmiKeyType->NonpagedPoolCharge = sizeof(KEY_OBJECT);
275 CmiKeyType->Mapping = &CmiKeyMapping;
276 CmiKeyType->Dump = NULL;
277 CmiKeyType->Open = NULL;
278 CmiKeyType->Close = NULL;
279 CmiKeyType->Delete = CmiObjectDelete;
280 CmiKeyType->Parse = CmiObjectParse;
281 CmiKeyType->Security = CmiObjectSecurity;
282 CmiKeyType->QueryName = NULL;
283 CmiKeyType->OkayToClose = NULL;
284 CmiKeyType->Create = CmiObjectCreate;
285 CmiKeyType->DuplicationNotify = NULL;
286 RtlInitUnicodeString(&CmiKeyType->TypeName, L"Key");
287
288 /* Initialize the hive list */
289 InitializeListHead(&CmiHiveListHead);
290 ExInitializeResourceLite(&CmiHiveListLock);
291
292 /* Build volatile registry store */
293 Status = CmiCreateRegistryHive(NULL, &CmiVolatileHive, FALSE);
294 assert(NT_SUCCESS(Status));
295
296 /* Create '\Registry' key. */
297 RtlInitUnicodeString(&RootKeyName, REG_ROOT_KEY_NAME);
298 InitializeObjectAttributes(&ObjectAttributes, &RootKeyName, 0, NULL, NULL);
299 Status = ObCreateObject(&RootKeyHandle,
300 STANDARD_RIGHTS_REQUIRED,
301 &ObjectAttributes,
302 CmiKeyType,
303 (PVOID *) &RootKey);
304 assert(NT_SUCCESS(Status));
305 Status = ObReferenceObjectByHandle(RootKeyHandle,
306 STANDARD_RIGHTS_REQUIRED,
307 CmiKeyType,
308 KernelMode,
309 (PVOID *)&RootKey,
310 NULL);
311 assert(NT_SUCCESS(Status));
312 RootKey->RegistryHive = CmiVolatileHive;
313 RootKey->BlockOffset = CmiVolatileHive->HiveHeader->RootKeyCell;
314 RootKey->KeyCell = CmiGetBlock(CmiVolatileHive, RootKey->BlockOffset, NULL);
315 RootKey->Flags = 0;
316 RootKey->NumberOfSubKeys = 0;
317 RootKey->SubKeys = NULL;
318 RootKey->SizeOfSubKeys = 0;
319 RootKey->NameSize = strlen("Registry");
320 RootKey->Name = ExAllocatePool(PagedPool, RootKey->NameSize);
321 RtlCopyMemory(RootKey->Name, "Registry", RootKey->NameSize);
322
323 KeInitializeSpinLock(&CmiKeyListLock);
324
325 /* Create '\Registry\Machine' key. */
326 Status = ObCreateObject(&KeyHandle,
327 STANDARD_RIGHTS_REQUIRED,
328 NULL,
329 CmiKeyType,
330 (PVOID*)&MachineKey);
331 assert(NT_SUCCESS(Status));
332 Status = CmiAddSubKey(CmiVolatileHive,
333 RootKey,
334 MachineKey,
335 L"Machine",
336 wcslen(L"Machine") * sizeof(WCHAR),
337 0,
338 NULL,
339 0);
340 assert(NT_SUCCESS(Status));
341 MachineKey->RegistryHive = CmiVolatileHive;
342 MachineKey->Flags = 0;
343 MachineKey->NumberOfSubKeys = 0;
344 MachineKey->SubKeys = NULL;
345 MachineKey->SizeOfSubKeys = MachineKey->KeyCell->NumberOfSubKeys;
346 MachineKey->NameSize = strlen("Machine");
347 MachineKey->Name = ExAllocatePool(PagedPool, MachineKey->NameSize);
348 RtlCopyMemory(MachineKey->Name, "Machine", MachineKey->NameSize);
349 CmiAddKeyToList(RootKey, MachineKey);
350
351 /* Create '\Registry\User' key. */
352 Status = ObCreateObject(&KeyHandle,
353 STANDARD_RIGHTS_REQUIRED,
354 NULL,
355 CmiKeyType,
356 (PVOID*)&UserKey);
357 assert(NT_SUCCESS(Status));
358 Status = CmiAddSubKey(CmiVolatileHive,
359 RootKey,
360 UserKey,
361 L"User",
362 wcslen(L"User") * sizeof(WCHAR),
363 0,
364 NULL,
365 0);
366 assert(NT_SUCCESS(Status));
367 UserKey->RegistryHive = CmiVolatileHive;
368 UserKey->Flags = 0;
369 UserKey->NumberOfSubKeys = 0;
370 UserKey->SubKeys = NULL;
371 UserKey->SizeOfSubKeys = UserKey->KeyCell->NumberOfSubKeys;
372 UserKey->NameSize = strlen("User");
373 UserKey->Name = ExAllocatePool(PagedPool, UserKey->NameSize);
374 RtlCopyMemory(UserKey->Name, "User", UserKey->NameSize);
375 CmiAddKeyToList(RootKey, UserKey);
376
377
378 /* FIXME: remove the hardware keys before the hardware hive is imported */
379
380 /* Create '\Registry\Machine\HARDWARE' key. */
381 Status = ObCreateObject(&KeyHandle,
382 STANDARD_RIGHTS_REQUIRED,
383 NULL,
384 CmiKeyType,
385 (PVOID*)&HardwareKey);
386 assert(NT_SUCCESS(Status));
387 Status = CmiAddSubKey(CmiVolatileHive,
388 MachineKey,
389 HardwareKey,
390 L"HARDWARE",
391 wcslen(L"HARDWARE") * sizeof(WCHAR),
392 0,
393 NULL,
394 0);
395 assert(NT_SUCCESS(Status));
396 HardwareKey->RegistryHive = CmiVolatileHive;
397 HardwareKey->Flags = 0;
398 HardwareKey->NumberOfSubKeys = 0;
399 HardwareKey->SubKeys = NULL;
400 HardwareKey->SizeOfSubKeys = HardwareKey->KeyCell->NumberOfSubKeys;
401 HardwareKey->NameSize = strlen("HARDWARE");
402 HardwareKey->Name = ExAllocatePool(PagedPool, strlen("HARDWARE"));
403 RtlCopyMemory(HardwareKey->Name, "HARDWARE", HardwareKey->NameSize);
404 CmiAddKeyToList(MachineKey, HardwareKey);
405
406 /* Create '\Registry\Machine\HARDWARE\DESCRIPTION' key. */
407 Status = ObCreateObject(&KeyHandle,
408 STANDARD_RIGHTS_REQUIRED,
409 NULL,
410 CmiKeyType,
411 (PVOID*)&NewKey);
412 assert(NT_SUCCESS(Status));
413 Status = CmiAddSubKey(CmiVolatileHive,
414 HardwareKey,
415 NewKey,
416 L"DESCRIPTION",
417 wcslen(L"DESCRIPTION") * sizeof(WCHAR),
418 0,
419 NULL,
420 0);
421 assert(NT_SUCCESS(Status));
422 NewKey->RegistryHive = CmiVolatileHive;
423 NewKey->Flags = 0;
424 NewKey->NumberOfSubKeys = 0;
425 NewKey->SubKeys = NULL;
426 NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
427 NewKey->NameSize = strlen("DESCRIPTION");
428 NewKey->Name = ExAllocatePool(PagedPool, NewKey->NameSize);
429 RtlCopyMemory(NewKey->Name, "DESCRIPTION", NewKey->NameSize);
430 CmiAddKeyToList(HardwareKey, NewKey);
431
432 /* Create '\Registry\Machine\HARDWARE\DEVICEMAP' key. */
433 Status = ObCreateObject(&KeyHandle,
434 STANDARD_RIGHTS_REQUIRED,
435 NULL,
436 CmiKeyType,
437 (PVOID*)&NewKey);
438 assert(NT_SUCCESS(Status));
439 Status = CmiAddSubKey(CmiVolatileHive,
440 HardwareKey,
441 NewKey,
442 L"DEVICEMAP",
443 wcslen(L"DEVICEMAP") * sizeof(WCHAR),
444 0,
445 NULL,
446 0);
447 assert(NT_SUCCESS(Status));
448 NewKey->RegistryHive = CmiVolatileHive;
449 NewKey->Flags = 0;
450 NewKey->NumberOfSubKeys = 0;
451 NewKey->SubKeys = NULL;
452 NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
453 NewKey->NameSize = strlen("DEVICEMAP");
454 NewKey->Name = ExAllocatePool(PagedPool, NewKey->NameSize);
455 RtlCopyMemory(NewKey->Name, "DEVICEMAP", NewKey->NameSize);
456 CmiAddKeyToList(HardwareKey,NewKey);
457
458 /* Create '\Registry\Machine\HARDWARE\RESOURCEMAP' key. */
459 Status = ObCreateObject(&KeyHandle,
460 STANDARD_RIGHTS_REQUIRED,
461 NULL,
462 CmiKeyType,
463 (PVOID*)&NewKey);
464 assert(NT_SUCCESS(Status));
465 Status = CmiAddSubKey(CmiVolatileHive,
466 HardwareKey,
467 NewKey,
468 L"RESOURCEMAP",
469 wcslen(L"RESOURCEMAP") * sizeof(WCHAR),
470 0,
471 NULL,
472 0);
473 assert(NT_SUCCESS(Status));
474 NewKey->RegistryHive = CmiVolatileHive;
475 NewKey->Flags = 0;
476 NewKey->NumberOfSubKeys = 0;
477 NewKey->SubKeys = NULL;
478 NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
479 NewKey->NameSize = strlen("RESOURCEMAP");
480 NewKey->Name = ExAllocatePool(PagedPool, NewKey->NameSize);
481 RtlCopyMemory(NewKey->Name, "RESOURCEMAP", NewKey->NameSize);
482 CmiAddKeyToList(HardwareKey, NewKey);
483 }
484
485
486 VOID
487 CmInit2(PCHAR CommandLine)
488 {
489 PCHAR p1, p2;
490 ULONG PiceStart;
491 NTSTATUS Status;
492
493 /* FIXME: Store system start options */
494
495
496
497 /* Create the 'CurrentControlSet' link. */
498 Status = CmiCreateCurrentControlSetLink();
499 if (!NT_SUCCESS(Status))
500 {
501 KeBugCheck(CONFIG_INITIALIZATION_FAILED);
502 }
503
504 /* Set PICE 'Start' value to 1, if PICE debugging is enabled */
505 PiceStart = 4;
506 p1 = (PCHAR)CommandLine;
507 while (p1 && (p2 = strchr(p1, '/')))
508 {
509 p2++;
510 if (_strnicmp(p2, "DEBUGPORT", 9) == 0)
511 {
512 p2 += 9;
513 if (*p2 == '=')
514 {
515 p2++;
516 if (_strnicmp(p2, "PICE", 4) == 0)
517 {
518 p2 += 4;
519 PiceStart = 1;
520 }
521 }
522 }
523 p1 = p2;
524 }
525
526 Status = RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
527 L"\\Pice",
528 L"Start",
529 REG_DWORD,
530 &PiceStart,
531 sizeof(ULONG));
532 if (!NT_SUCCESS(Status))
533 {
534 KeBugCheck(CONFIG_INITIALIZATION_FAILED);
535 }
536 }
537
538
539 static NTSTATUS
540 CmiCreateCurrentControlSetLink(VOID)
541 {
542 RTL_QUERY_REGISTRY_TABLE QueryTable[5];
543 WCHAR TargetNameBuffer[80];
544 ULONG TargetNameLength;
545 UNICODE_STRING LinkName;
546 UNICODE_STRING LinkValue;
547 ULONG CurrentSet;
548 ULONG DefaultSet;
549 ULONG Failed;
550 ULONG LastKnownGood;
551 NTSTATUS Status;
552 OBJECT_ATTRIBUTES ObjectAttributes;
553 HANDLE KeyHandle;
554
555 DPRINT("CmiCreateCurrentControlSetLink() called\n");
556
557 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
558
559 QueryTable[0].Name = L"Current";
560 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
561 QueryTable[0].EntryContext = &CurrentSet;
562
563 QueryTable[1].Name = L"Default";
564 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
565 QueryTable[1].EntryContext = &DefaultSet;
566
567 QueryTable[2].Name = L"Failed";
568 QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
569 QueryTable[2].EntryContext = &Failed;
570
571 QueryTable[3].Name = L"LastKnownGood";
572 QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
573 QueryTable[3].EntryContext = &LastKnownGood;
574
575 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
576 L"\\Registry\\Machine\\SYSTEM\\Select",
577 QueryTable,
578 NULL,
579 NULL);
580 if (!NT_SUCCESS(Status))
581 {
582 return(Status);
583 }
584
585 DPRINT("Current %ld Default %ld\n", CurrentSet, DefaultSet);
586
587 swprintf(TargetNameBuffer,
588 L"\\Registry\\Machine\\SYSTEM\\ControlSet%03lu",
589 CurrentSet);
590 TargetNameLength = wcslen(TargetNameBuffer) * sizeof(WCHAR);
591
592 DPRINT("Link target '%S'\n", TargetNameBuffer);
593
594 RtlInitUnicodeStringFromLiteral(&LinkName,
595 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
596 InitializeObjectAttributes(&ObjectAttributes,
597 &LinkName,
598 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
599 NULL,
600 NULL);
601 Status = NtCreateKey(&KeyHandle,
602 KEY_ALL_ACCESS | KEY_CREATE_LINK,
603 &ObjectAttributes,
604 0,
605 NULL,
606 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
607 NULL);
608 if (!NT_SUCCESS(Status))
609 {
610 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
611 return(Status);
612 }
613
614 RtlInitUnicodeStringFromLiteral(&LinkValue,
615 L"SymbolicLinkValue");
616 Status = NtSetValueKey(KeyHandle,
617 &LinkValue,
618 0,
619 REG_LINK,
620 (PVOID)TargetNameBuffer,
621 TargetNameLength);
622 if (!NT_SUCCESS(Status))
623 {
624 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
625 }
626
627 NtClose(KeyHandle);
628
629 return(Status);
630 }
631
632
633 NTSTATUS
634 CmiConnectHive(PREGISTRY_HIVE RegistryHive,
635 PUNICODE_STRING KeyName)
636 {
637 OBJECT_ATTRIBUTES ObjectAttributes;
638 UNICODE_STRING ParentKeyName;
639 PKEY_OBJECT ParentKey;
640 PKEY_OBJECT NewKey;
641 HANDLE KeyHandle;
642 NTSTATUS Status;
643 PWSTR SubName;
644
645 DPRINT("CmiConnectHive(%p, %wZ) called.\n",
646 RegistryHive, KeyName);
647
648 SubName = wcsrchr (KeyName->Buffer, L'\\');
649 if (SubName == NULL)
650 {
651 return STATUS_UNSUCCESSFUL;
652 }
653
654 ParentKeyName.Length = (USHORT)(SubName - KeyName->Buffer) * sizeof(WCHAR);
655 ParentKeyName.MaximumLength = ParentKeyName.Length + sizeof(WCHAR);
656 ParentKeyName.Buffer = ExAllocatePool (NonPagedPool,
657 ParentKeyName.MaximumLength);
658 RtlCopyMemory (ParentKeyName.Buffer,
659 KeyName->Buffer,
660 ParentKeyName.Length);
661 ParentKeyName.Buffer[ParentKeyName.Length / sizeof(WCHAR)] = 0;
662 SubName++;
663
664 Status = ObReferenceObjectByName (&ParentKeyName,
665 OBJ_CASE_INSENSITIVE,
666 NULL,
667 STANDARD_RIGHTS_REQUIRED,
668 CmiKeyType,
669 KernelMode,
670 NULL,
671 (PVOID*)&ParentKey);
672 RtlFreeUnicodeString (&ParentKeyName);
673 if (!NT_SUCCESS(Status))
674 {
675 DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status);
676 return Status;
677 }
678
679 InitializeObjectAttributes(&ObjectAttributes,
680 KeyName,
681 0,
682 NULL,
683 NULL);
684
685 Status = ObCreateObject(&KeyHandle,
686 STANDARD_RIGHTS_REQUIRED,
687 &ObjectAttributes,
688 CmiKeyType,
689 (PVOID*)&NewKey);
690 if (!NT_SUCCESS(Status))
691 {
692 DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status);
693 ObDereferenceObject (ParentKey);
694 return Status;
695 }
696
697 NewKey->RegistryHive = RegistryHive;
698 NewKey->BlockOffset = RegistryHive->HiveHeader->RootKeyCell;
699 NewKey->KeyCell = CmiGetBlock(RegistryHive, NewKey->BlockOffset, NULL);
700 NewKey->Flags = 0;
701 NewKey->NumberOfSubKeys = 0;
702 NewKey->SubKeys = ExAllocatePool(PagedPool,
703 NewKey->KeyCell->NumberOfSubKeys * sizeof(ULONG));
704
705 if ((NewKey->SubKeys == NULL) && (NewKey->KeyCell->NumberOfSubKeys != 0))
706 {
707 DPRINT("NumberOfSubKeys %d\n", NewKey->KeyCell->NumberOfSubKeys);
708 NtClose(NewKey);
709 ObDereferenceObject (ParentKey);
710 return(STATUS_INSUFFICIENT_RESOURCES);
711 }
712
713 NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
714 NewKey->NameSize = wcslen (SubName);
715 NewKey->Name = ExAllocatePool(PagedPool, NewKey->NameSize);
716
717 if ((NewKey->Name == NULL) && (NewKey->NameSize != 0))
718 {
719 DPRINT("NewKey->NameSize %d\n", NewKey->NameSize);
720 if (NewKey->SubKeys != NULL)
721 ExFreePool(NewKey->SubKeys);
722 NtClose(KeyHandle);
723 ObDereferenceObject (ParentKey);
724 return(STATUS_INSUFFICIENT_RESOURCES);
725 }
726
727 wcstombs (NewKey->Name,
728 SubName,
729 NewKey->NameSize);
730
731 CmiAddKeyToList (ParentKey, NewKey);
732 ObDereferenceObject (ParentKey);
733
734 VERIFY_KEY_OBJECT(NewKey);
735
736 return(STATUS_SUCCESS);
737 }
738
739
740 static NTSTATUS
741 CmiInitializeSystemHive (PWSTR FileName,
742 PUNICODE_STRING KeyName)
743 {
744 OBJECT_ATTRIBUTES ObjectAttributes;
745 UNICODE_STRING ControlSetKeyName;
746 UNICODE_STRING ControlSetLinkName;
747 UNICODE_STRING ControlSetValueName;
748 HANDLE KeyHandle;
749 NTSTATUS Status;
750 PREGISTRY_HIVE RegistryHive;
751
752 Status = CmiCreateRegistryHive (FileName,
753 &RegistryHive,
754 TRUE);
755 if (!NT_SUCCESS(Status))
756 {
757 DPRINT1 ("CmiCreateRegistryHive() failed (Status %lx)\n", Status);
758 return Status;
759 }
760
761 Status = CmiConnectHive (RegistryHive,
762 KeyName);
763 if (!NT_SUCCESS(Status))
764 {
765 DPRINT1 ("CmiConnectHive() failed (Status %lx)\n", Status);
766 CmiRemoveRegistryHive (RegistryHive);
767 return Status;
768 }
769
770 /* Create 'ControlSet001' key */
771 RtlInitUnicodeStringFromLiteral (&ControlSetKeyName,
772 L"\\Registry\\Machine\\SYSTEM\\ControlSet001");
773 InitializeObjectAttributes (&ObjectAttributes,
774 &ControlSetKeyName,
775 OBJ_CASE_INSENSITIVE,
776 NULL,
777 NULL);
778 Status = NtCreateKey (&KeyHandle,
779 KEY_ALL_ACCESS,
780 &ObjectAttributes,
781 0,
782 NULL,
783 REG_OPTION_NON_VOLATILE,
784 NULL);
785 if (!NT_SUCCESS(Status))
786 {
787 DPRINT1 ("NtCreateKey() failed (Status %lx)\n", Status);
788 return Status;
789 }
790 NtClose (KeyHandle);
791
792 /* Link 'CurrentControlSet' to 'ControlSet001' key */
793 RtlInitUnicodeStringFromLiteral (&ControlSetLinkName,
794 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
795 InitializeObjectAttributes (&ObjectAttributes,
796 &ControlSetLinkName,
797 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
798 NULL,
799 NULL);
800 Status = NtCreateKey (&KeyHandle,
801 KEY_ALL_ACCESS | KEY_CREATE_LINK,
802 &ObjectAttributes,
803 0,
804 NULL,
805 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
806 NULL);
807 if (!NT_SUCCESS(Status))
808 {
809 DPRINT1 ("NtCreateKey() failed (Status %lx)\n", Status);
810 return Status;
811 }
812
813 RtlInitUnicodeStringFromLiteral (&ControlSetValueName,
814 L"SymbolicLinkValue");
815 Status = NtSetValueKey (KeyHandle,
816 &ControlSetValueName,
817 0,
818 REG_LINK,
819 (PVOID)ControlSetKeyName.Buffer,
820 ControlSetKeyName.Length);
821 if (!NT_SUCCESS(Status))
822 {
823 DPRINT1 ("NtSetValueKey() failed (Status %lx)\n", Status);
824 }
825 NtClose (KeyHandle);
826
827 return STATUS_SUCCESS;
828 }
829
830
831 NTSTATUS
832 CmiInitializeHive(PWSTR FileName,
833 PUNICODE_STRING KeyName,
834 BOOLEAN CreateNew)
835 {
836 PREGISTRY_HIVE RegistryHive;
837 NTSTATUS Status;
838
839 DPRINT("CmiInitializeHive(%s) called\n", KeyName);
840
841 Status = CmiCreateRegistryHive(FileName,
842 &RegistryHive,
843 CreateNew);
844 if (!NT_SUCCESS(Status))
845 {
846 DPRINT1("CmiCreateRegistryHive() failed (Status %lx)\n", Status);
847
848 /* FIXME: Try to load the backup hive */
849
850 KeBugCheck(0);
851 return(Status);
852 }
853
854 /* Connect the hive */
855 Status = CmiConnectHive(RegistryHive,
856 KeyName);
857 if (!NT_SUCCESS(Status))
858 {
859 DPRINT1("CmiConnectHive() failed (Status %lx)\n", Status);
860 CmiRemoveRegistryHive(RegistryHive);
861 return(Status);
862 }
863
864 DPRINT("CmiInitializeHive() done\n");
865
866 return(STATUS_SUCCESS);
867 }
868
869
870 NTSTATUS
871 CmiInitHives(BOOLEAN SetupBoot)
872 {
873 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
874 OBJECT_ATTRIBUTES ObjectAttributes;
875 UNICODE_STRING KeyName;
876 UNICODE_STRING ValueName;
877 HANDLE KeyHandle;
878
879 NTSTATUS Status;
880
881 WCHAR ConfigPath[MAX_PATH];
882
883 ULONG BufferSize;
884 ULONG ResultSize;
885 PWSTR EndPtr;
886
887
888 DPRINT("CmiInitHives() called\n");
889
890 if (SetupBoot == TRUE)
891 {
892 RtlInitUnicodeStringFromLiteral(&KeyName,
893 L"\\Registry\\Machine\\HARDWARE");
894 InitializeObjectAttributes(&ObjectAttributes,
895 &KeyName,
896 OBJ_CASE_INSENSITIVE,
897 NULL,
898 NULL);
899 Status = NtOpenKey(&KeyHandle,
900 KEY_ALL_ACCESS,
901 &ObjectAttributes);
902 if (!NT_SUCCESS(Status))
903 {
904 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
905 return(Status);
906 }
907
908 RtlInitUnicodeStringFromLiteral(&ValueName,
909 L"InstallPath");
910
911 BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
912 ValueInfo = ExAllocatePool(PagedPool,
913 BufferSize);
914 if (ValueInfo == NULL)
915 {
916 NtClose(KeyHandle);
917 return(STATUS_INSUFFICIENT_RESOURCES);
918 }
919
920 Status = NtQueryValueKey(KeyHandle,
921 &ValueName,
922 KeyValuePartialInformation,
923 ValueInfo,
924 BufferSize,
925 &ResultSize);
926 NtClose(KeyHandle);
927 if (ValueInfo == NULL)
928 {
929 ExFreePool(ValueInfo);
930 return(Status);
931 }
932
933 RtlCopyMemory(ConfigPath,
934 ValueInfo->Data,
935 ValueInfo->DataLength);
936 ConfigPath[ValueInfo->DataLength / sizeof(WCHAR)] = (WCHAR)0;
937 ExFreePool(ValueInfo);
938 }
939 else
940 {
941 wcscpy(ConfigPath, L"\\SystemRoot");
942 }
943 wcscat(ConfigPath, L"\\system32\\config");
944
945 DPRINT("ConfigPath: %S\n", ConfigPath);
946
947 EndPtr = ConfigPath + wcslen(ConfigPath);
948
949 CmiDoVerify = TRUE;
950
951 /* FIXME: Save boot log */
952
953 /* Connect the SYSTEM hive only if it has been created */
954 if (SetupBoot == TRUE)
955 {
956 wcscpy(EndPtr, REG_SYSTEM_FILE_NAME);
957 DPRINT ("ConfigPath: %S\n", ConfigPath);
958
959 RtlInitUnicodeString (&KeyName,
960 REG_SYSTEM_KEY_NAME);
961 Status = CmiInitializeSystemHive (ConfigPath,
962 &KeyName);
963 if (!NT_SUCCESS(Status))
964 {
965 DPRINT1("CmiInitializeSystemHive() failed (Status %lx)\n", Status);
966 return(Status);
967 }
968 }
969
970 /* Connect the SOFTWARE hive */
971 wcscpy(EndPtr, REG_SOFTWARE_FILE_NAME);
972 DPRINT ("ConfigPath: %S\n", ConfigPath);
973
974 RtlInitUnicodeString (&KeyName,
975 REG_SOFTWARE_KEY_NAME);
976 Status = CmiInitializeHive(ConfigPath,
977 &KeyName,
978 SetupBoot);
979 if (!NT_SUCCESS(Status))
980 {
981 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
982 return(Status);
983 }
984
985 /* Connect the SAM hive */
986 wcscpy(EndPtr, REG_SAM_FILE_NAME);
987 DPRINT ("ConfigPath: %S\n", ConfigPath);
988
989 RtlInitUnicodeString (&KeyName,
990 REG_SAM_KEY_NAME);
991 Status = CmiInitializeHive(ConfigPath,
992 &KeyName,
993 SetupBoot);
994 if (!NT_SUCCESS(Status))
995 {
996 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
997 return(Status);
998 }
999
1000 /* Connect the SECURITY hive */
1001 wcscpy(EndPtr, REG_SEC_FILE_NAME);
1002 DPRINT ("ConfigPath: %S\n", ConfigPath);
1003
1004 RtlInitUnicodeString (&KeyName,
1005 REG_SEC_KEY_NAME);
1006 Status = CmiInitializeHive(ConfigPath,
1007 &KeyName,
1008 SetupBoot);
1009 if (!NT_SUCCESS(Status))
1010 {
1011 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
1012 return(Status);
1013 }
1014
1015 /* Connect the DEFAULT hive */
1016 wcscpy(EndPtr, REG_USER_FILE_NAME);
1017 DPRINT ("ConfigPath: %S\n", ConfigPath);
1018
1019 RtlInitUnicodeString (&KeyName,
1020 REG_USER_KEY_NAME);
1021 Status = CmiInitializeHive(ConfigPath,
1022 &KeyName,
1023 SetupBoot);
1024 if (!NT_SUCCESS(Status))
1025 {
1026 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
1027 return(Status);
1028 }
1029
1030 // CmiCheckRegistry(TRUE);
1031
1032 /* Start automatic hive synchronization */
1033 KeInitializeDpc(&CmiHiveSyncDpc,
1034 CmiHiveSyncDpcRoutine,
1035 NULL);
1036 KeInitializeTimer(&CmiHiveSyncTimer);
1037 CmiHiveSyncEnabled = TRUE;
1038
1039 DPRINT("CmiInitHives() done\n");
1040
1041 return(STATUS_SUCCESS);
1042 }
1043
1044
1045 VOID
1046 CmShutdownRegistry(VOID)
1047 {
1048 PREGISTRY_HIVE Hive;
1049 PLIST_ENTRY Entry;
1050
1051 DPRINT1("CmShutdownRegistry() called\n");
1052
1053 /* Stop automatic hive synchronization */
1054 CmiHiveSyncEnabled = FALSE;
1055
1056 /* Acquire hive list lock exclusively */
1057 ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
1058
1059 Entry = CmiHiveListHead.Flink;
1060 while (Entry != &CmiHiveListHead)
1061 {
1062 Hive = CONTAINING_RECORD(Entry, REGISTRY_HIVE, HiveList);
1063
1064 if (!IsVolatileHive(Hive))
1065 {
1066 /* Acquire hive resource exclusively */
1067 ExAcquireResourceExclusiveLite(&Hive->HiveResource,
1068 TRUE);
1069
1070 /* Flush non-volatile hive */
1071 CmiFlushRegistryHive(Hive);
1072
1073 /* Release hive resource */
1074 ExReleaseResourceLite(&Hive->HiveResource);
1075 }
1076
1077 Entry = Entry->Flink;
1078 }
1079
1080 /* Release hive list lock */
1081 ExReleaseResourceLite(&CmiHiveListLock);
1082
1083 DPRINT1("CmShutdownRegistry() done\n");
1084 }
1085
1086
1087 VOID STDCALL
1088 CmiHiveSyncRoutine(PVOID DeferredContext)
1089 {
1090 PREGISTRY_HIVE Hive;
1091 PLIST_ENTRY Entry;
1092
1093 DPRINT1("CmiHiveSyncRoutine() called\n");
1094
1095 CmiHiveSyncPending = FALSE;
1096
1097 /* Acquire hive list lock exclusively */
1098 ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
1099
1100 Entry = CmiHiveListHead.Flink;
1101 while (Entry != &CmiHiveListHead)
1102 {
1103 Hive = CONTAINING_RECORD(Entry, REGISTRY_HIVE, HiveList);
1104
1105 if (!IsVolatileHive(Hive))
1106 {
1107 /* Acquire hive resource exclusively */
1108 ExAcquireResourceExclusiveLite(&Hive->HiveResource,
1109 TRUE);
1110
1111 /* Flush non-volatile hive */
1112 CmiFlushRegistryHive(Hive);
1113
1114 /* Release hive resource */
1115 ExReleaseResourceLite(&Hive->HiveResource);
1116 }
1117
1118 Entry = Entry->Flink;
1119 }
1120
1121 /* Release hive list lock */
1122 ExReleaseResourceLite(&CmiHiveListLock);
1123
1124 DPRINT("DeferredContext %x\n", DeferredContext);
1125 ExFreePool(DeferredContext);
1126
1127 DPRINT1("CmiHiveSyncRoutine() done\n");
1128 }
1129
1130
1131 static VOID STDCALL
1132 CmiHiveSyncDpcRoutine(PKDPC Dpc,
1133 PVOID DeferredContext,
1134 PVOID SystemArgument1,
1135 PVOID SystemArgument2)
1136 {
1137 PWORK_QUEUE_ITEM WorkQueueItem;
1138
1139 WorkQueueItem = ExAllocatePool(NonPagedPool,
1140 sizeof(WORK_QUEUE_ITEM));
1141 if (WorkQueueItem == NULL)
1142 {
1143 DbgPrint("Failed to allocate work item\n");
1144 return;
1145 }
1146
1147 ExInitializeWorkItem(WorkQueueItem,
1148 CmiHiveSyncRoutine,
1149 WorkQueueItem);
1150
1151 DPRINT("DeferredContext %x\n", WorkQueueItem);
1152 ExQueueWorkItem(WorkQueueItem,
1153 CriticalWorkQueue);
1154 }
1155
1156
1157 VOID
1158 CmiSyncHives(VOID)
1159 {
1160 LARGE_INTEGER Timeout;
1161
1162 DPRINT("CmiSyncHives() called\n");
1163
1164 if (CmiHiveSyncEnabled == FALSE ||
1165 CmiHiveSyncPending == TRUE)
1166 return;
1167
1168 CmiHiveSyncPending = TRUE;
1169
1170
1171 Timeout.QuadPart = -50000000LL;
1172 KeSetTimer(&CmiHiveSyncTimer,
1173 Timeout,
1174 &CmiHiveSyncDpc);
1175 }
1176
1177 /* EOF */