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