Point the root key's parent key pointer to the root key to prevent check routines...
[reactos.git] / reactos / ntoskrnl / cm / registry.c
1 /* $Id: registry.c,v 1.103 2003/06/03 07:28:01 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/ob.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 KeyName;
254 PKEY_OBJECT RootKey;
255 HANDLE RootKeyHandle;
256 HANDLE KeyHandle;
257 NTSTATUS Status;
258
259 /* Initialize the Key object type */
260 CmiKeyType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
261 assert(CmiKeyType);
262 CmiKeyType->TotalObjects = 0;
263 CmiKeyType->TotalHandles = 0;
264 CmiKeyType->MaxObjects = LONG_MAX;
265 CmiKeyType->MaxHandles = LONG_MAX;
266 CmiKeyType->PagedPoolCharge = 0;
267 CmiKeyType->NonpagedPoolCharge = sizeof(KEY_OBJECT);
268 CmiKeyType->Mapping = &CmiKeyMapping;
269 CmiKeyType->Dump = NULL;
270 CmiKeyType->Open = NULL;
271 CmiKeyType->Close = NULL;
272 CmiKeyType->Delete = CmiObjectDelete;
273 CmiKeyType->Parse = CmiObjectParse;
274 CmiKeyType->Security = CmiObjectSecurity;
275 CmiKeyType->QueryName = CmiObjectQueryName;
276 CmiKeyType->OkayToClose = NULL;
277 CmiKeyType->Create = CmiObjectCreate;
278 CmiKeyType->DuplicationNotify = NULL;
279 RtlInitUnicodeString(&CmiKeyType->TypeName, L"Key");
280
281 /* Initialize the hive list */
282 InitializeListHead(&CmiHiveListHead);
283 ExInitializeResourceLite(&CmiHiveListLock);
284
285 /* Build volatile registry store */
286 Status = CmiCreateVolatileHive (&CmiVolatileHive);
287 assert(NT_SUCCESS(Status));
288
289 /* Create '\Registry' key. */
290 RtlInitUnicodeString(&KeyName, REG_ROOT_KEY_NAME);
291 InitializeObjectAttributes(&ObjectAttributes, &KeyName, 0, NULL, NULL);
292 Status = ObCreateObject(&RootKeyHandle,
293 STANDARD_RIGHTS_REQUIRED,
294 &ObjectAttributes,
295 CmiKeyType,
296 (PVOID *) &RootKey);
297 assert(NT_SUCCESS(Status));
298 Status = ObReferenceObjectByHandle(RootKeyHandle,
299 STANDARD_RIGHTS_REQUIRED,
300 CmiKeyType,
301 KernelMode,
302 (PVOID *)&RootKey,
303 NULL);
304 assert(NT_SUCCESS(Status));
305 RootKey->RegistryHive = CmiVolatileHive;
306 RootKey->BlockOffset = CmiVolatileHive->HiveHeader->RootKeyCell;
307 RootKey->KeyCell = CmiGetBlock(CmiVolatileHive, RootKey->BlockOffset, NULL);
308 RootKey->ParentKey = RootKey;
309 RootKey->Flags = 0;
310 RootKey->NumberOfSubKeys = 0;
311 RootKey->SubKeys = NULL;
312 RootKey->SizeOfSubKeys = 0;
313 Status = RtlCreateUnicodeString(&RootKey->Name, L"Registry");
314 assert(NT_SUCCESS(Status));
315
316 KeInitializeSpinLock(&CmiKeyListLock);
317
318 /* Create '\Registry\Machine' key. */
319 RtlInitUnicodeString(&KeyName,
320 L"Machine");
321 InitializeObjectAttributes(&ObjectAttributes,
322 &KeyName,
323 0,
324 RootKeyHandle,
325 NULL);
326 Status = NtCreateKey(&KeyHandle,
327 STANDARD_RIGHTS_REQUIRED,
328 &ObjectAttributes,
329 0,
330 NULL,
331 REG_OPTION_VOLATILE,
332 NULL);
333 assert(NT_SUCCESS(Status));
334
335 /* Create '\Registry\User' key. */
336 RtlInitUnicodeString(&KeyName,
337 L"User");
338 InitializeObjectAttributes(&ObjectAttributes,
339 &KeyName,
340 0,
341 RootKeyHandle,
342 NULL);
343 Status = NtCreateKey(&KeyHandle,
344 STANDARD_RIGHTS_REQUIRED,
345 &ObjectAttributes,
346 0,
347 NULL,
348 REG_OPTION_VOLATILE,
349 NULL);
350 assert(NT_SUCCESS(Status));
351 }
352
353
354 VOID
355 CmInit2(PCHAR CommandLine)
356 {
357 PCHAR p1, p2;
358 ULONG PiceStart;
359 NTSTATUS Status;
360
361 /* FIXME: Store system start options */
362
363
364
365 /* Create the 'CurrentControlSet' link. */
366 Status = CmiCreateCurrentControlSetLink();
367 if (!NT_SUCCESS(Status))
368 {
369 KeBugCheck(CONFIG_INITIALIZATION_FAILED);
370 }
371
372 /* Set PICE 'Start' value to 1, if PICE debugging is enabled */
373 PiceStart = 4;
374 p1 = (PCHAR)CommandLine;
375 while (p1 && (p2 = strchr(p1, '/')))
376 {
377 p2++;
378 if (_strnicmp(p2, "DEBUGPORT", 9) == 0)
379 {
380 p2 += 9;
381 if (*p2 == '=')
382 {
383 p2++;
384 if (_strnicmp(p2, "PICE", 4) == 0)
385 {
386 p2 += 4;
387 PiceStart = 1;
388 }
389 }
390 }
391 p1 = p2;
392 }
393
394 Status = RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
395 L"\\Pice",
396 L"Start",
397 REG_DWORD,
398 &PiceStart,
399 sizeof(ULONG));
400 if (!NT_SUCCESS(Status))
401 {
402 KeBugCheck(CONFIG_INITIALIZATION_FAILED);
403 }
404 }
405
406
407 static NTSTATUS
408 CmiCreateCurrentControlSetLink(VOID)
409 {
410 RTL_QUERY_REGISTRY_TABLE QueryTable[5];
411 WCHAR TargetNameBuffer[80];
412 ULONG TargetNameLength;
413 UNICODE_STRING LinkName;
414 UNICODE_STRING LinkValue;
415 ULONG CurrentSet;
416 ULONG DefaultSet;
417 ULONG Failed;
418 ULONG LastKnownGood;
419 NTSTATUS Status;
420 OBJECT_ATTRIBUTES ObjectAttributes;
421 HANDLE KeyHandle;
422
423 DPRINT("CmiCreateCurrentControlSetLink() called\n");
424
425 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
426
427 QueryTable[0].Name = L"Current";
428 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
429 QueryTable[0].EntryContext = &CurrentSet;
430
431 QueryTable[1].Name = L"Default";
432 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
433 QueryTable[1].EntryContext = &DefaultSet;
434
435 QueryTable[2].Name = L"Failed";
436 QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
437 QueryTable[2].EntryContext = &Failed;
438
439 QueryTable[3].Name = L"LastKnownGood";
440 QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
441 QueryTable[3].EntryContext = &LastKnownGood;
442
443 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
444 L"\\Registry\\Machine\\SYSTEM\\Select",
445 QueryTable,
446 NULL,
447 NULL);
448 if (!NT_SUCCESS(Status))
449 {
450 return(Status);
451 }
452
453 DPRINT("Current %ld Default %ld\n", CurrentSet, DefaultSet);
454
455 swprintf(TargetNameBuffer,
456 L"\\Registry\\Machine\\SYSTEM\\ControlSet%03lu",
457 CurrentSet);
458 TargetNameLength = wcslen(TargetNameBuffer) * sizeof(WCHAR);
459
460 DPRINT("Link target '%S'\n", TargetNameBuffer);
461
462 RtlInitUnicodeStringFromLiteral(&LinkName,
463 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
464 InitializeObjectAttributes(&ObjectAttributes,
465 &LinkName,
466 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
467 NULL,
468 NULL);
469 Status = NtCreateKey(&KeyHandle,
470 KEY_ALL_ACCESS | KEY_CREATE_LINK,
471 &ObjectAttributes,
472 0,
473 NULL,
474 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
475 NULL);
476 if (!NT_SUCCESS(Status))
477 {
478 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
479 return(Status);
480 }
481
482 RtlInitUnicodeStringFromLiteral(&LinkValue,
483 L"SymbolicLinkValue");
484 Status = NtSetValueKey(KeyHandle,
485 &LinkValue,
486 0,
487 REG_LINK,
488 (PVOID)TargetNameBuffer,
489 TargetNameLength);
490 if (!NT_SUCCESS(Status))
491 {
492 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
493 }
494
495 NtClose(KeyHandle);
496
497 return(Status);
498 }
499
500
501 NTSTATUS
502 CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
503 IN PREGISTRY_HIVE RegistryHive)
504 {
505 UNICODE_STRING RemainingPath;
506 PKEY_OBJECT ParentKey;
507 PKEY_OBJECT NewKey;
508 NTSTATUS Status;
509 PWSTR SubName;
510
511 DPRINT("CmiConnectHive(%p, %wZ) called.\n",
512 RegistryHive, KeyName);
513
514 Status = ObFindObject(KeyObjectAttributes,
515 (PVOID*)&ParentKey,
516 &RemainingPath,
517 CmiKeyType);
518 if (!NT_SUCCESS(Status))
519 {
520 return(Status);
521 }
522
523 DPRINT ("RemainingPath %wZ\n", &RemainingPath);
524
525 if ((RemainingPath.Buffer == NULL) || (RemainingPath.Buffer[0] == 0))
526 {
527 ObDereferenceObject (ParentKey);
528 return STATUS_OBJECT_NAME_COLLISION;
529 }
530
531 /* If RemainingPath contains \ we must return error
532 because CmiConnectHive() can not create trees */
533 SubName = RemainingPath.Buffer;
534 if (*SubName == L'\\')
535 SubName++;
536
537 if (wcschr (SubName, L'\\') != NULL)
538 {
539 ObDereferenceObject (ParentKey);
540 return STATUS_OBJECT_NAME_NOT_FOUND;
541 }
542
543 DPRINT("RemainingPath %S ParentObject %x\n", RemainingPath.Buffer, Object);
544
545 Status = ObCreateObject(NULL,
546 STANDARD_RIGHTS_REQUIRED,
547 NULL,
548 CmiKeyType,
549 (PVOID*)&NewKey);
550 if (!NT_SUCCESS(Status))
551 {
552 return(Status);
553 }
554
555 if (!NT_SUCCESS(Status))
556 {
557 DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status);
558 ObDereferenceObject (ParentKey);
559 return Status;
560 }
561
562 NewKey->RegistryHive = RegistryHive;
563 NewKey->BlockOffset = RegistryHive->HiveHeader->RootKeyCell;
564 NewKey->KeyCell = CmiGetBlock(RegistryHive, NewKey->BlockOffset, NULL);
565 NewKey->Flags = 0;
566 NewKey->NumberOfSubKeys = 0;
567 NewKey->SubKeys = ExAllocatePool(PagedPool,
568 NewKey->KeyCell->NumberOfSubKeys * sizeof(ULONG));
569
570 if ((NewKey->SubKeys == NULL) && (NewKey->KeyCell->NumberOfSubKeys != 0))
571 {
572 DPRINT("NumberOfSubKeys %d\n", NewKey->KeyCell->NumberOfSubKeys);
573 ObDereferenceObject (NewKey);
574 ObDereferenceObject (ParentKey);
575 return(STATUS_INSUFFICIENT_RESOURCES);
576 }
577
578 Status = RtlCreateUnicodeString(&NewKey->Name,
579 SubName);
580 if (!NT_SUCCESS(Status))
581 {
582 DPRINT1("RtlCreateUnicodeString() failed (Status %lx)\n", Status);
583 if (NewKey->SubKeys != NULL)
584 {
585 ExFreePool (NewKey->SubKeys);
586 }
587 ObDereferenceObject (NewKey);
588 ObDereferenceObject (ParentKey);
589 return STATUS_INSUFFICIENT_RESOURCES;
590 }
591
592 CmiAddKeyToList (ParentKey, NewKey);
593 ObDereferenceObject (ParentKey);
594
595 VERIFY_KEY_OBJECT(NewKey);
596
597 /* Note: Do not dereference NewKey here! */
598
599 return STATUS_SUCCESS;
600 }
601
602
603 NTSTATUS
604 CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
605 OUT PREGISTRY_HIVE *RegistryHive)
606 {
607 PKEY_OBJECT KeyObject;
608 PREGISTRY_HIVE Hive;
609 HANDLE KeyHandle;
610 NTSTATUS Status;
611
612 DPRINT("CmiDisconnectHive() called\n");
613
614 *RegistryHive = NULL;
615
616 Status = ObOpenObjectByName (KeyObjectAttributes,
617 CmiKeyType,
618 NULL,
619 KernelMode,
620 STANDARD_RIGHTS_REQUIRED,
621 NULL,
622 &KeyHandle);
623 if (!NT_SUCCESS(Status))
624 {
625 DPRINT1 ("ObOpenObjectByName() failed (Status %lx)\n", Status);
626 return Status;
627 }
628
629 Status = ObReferenceObjectByHandle (KeyHandle,
630 STANDARD_RIGHTS_REQUIRED,
631 CmiKeyType,
632 KernelMode,
633 (PVOID*)&KeyObject,
634 NULL);
635 NtClose (KeyHandle);
636 if (!NT_SUCCESS(Status))
637 {
638 DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status);
639 return Status;
640 }
641 DPRINT ("KeyObject %p Hive %p\n", KeyObject, KeyObject->RegistryHive);
642
643 if (!(KeyObject->KeyCell->Flags & REG_KEY_ROOT_CELL))
644 {
645 DPRINT1 ("Key is not the Hive-Root-Key\n");
646 ObDereferenceObject (KeyObject);
647 return STATUS_INVALID_PARAMETER;
648 }
649
650 if (ObGetObjectHandleCount (KeyObject) != 0 ||
651 ObGetObjectPointerCount (KeyObject) != 2)
652 {
653 DPRINT1 ("Hive is still in use\n");
654 ObDereferenceObject (KeyObject);
655 return STATUS_UNSUCCESSFUL;
656 }
657
658 Hive = KeyObject->RegistryHive;
659 CmiRemoveKeyFromList (KeyObject);
660
661 /* Dereference KeyObject twice to delete it */
662 ObDereferenceObject (KeyObject);
663 ObDereferenceObject (KeyObject);
664
665 *RegistryHive = Hive;
666
667 DPRINT ("CmiDisconnectHive() done\n");
668
669 return STATUS_SUCCESS;
670 }
671
672
673 static NTSTATUS
674 CmiInitControlSetLink (VOID)
675 {
676 OBJECT_ATTRIBUTES ObjectAttributes;
677 UNICODE_STRING ControlSetKeyName;
678 UNICODE_STRING ControlSetLinkName;
679 UNICODE_STRING ControlSetValueName;
680 HANDLE KeyHandle;
681 NTSTATUS Status;
682
683 /* Create 'ControlSet001' key */
684 RtlInitUnicodeStringFromLiteral (&ControlSetKeyName,
685 L"\\Registry\\Machine\\SYSTEM\\ControlSet001");
686 InitializeObjectAttributes (&ObjectAttributes,
687 &ControlSetKeyName,
688 OBJ_CASE_INSENSITIVE,
689 NULL,
690 NULL);
691 Status = NtCreateKey (&KeyHandle,
692 KEY_ALL_ACCESS,
693 &ObjectAttributes,
694 0,
695 NULL,
696 REG_OPTION_NON_VOLATILE,
697 NULL);
698 if (!NT_SUCCESS(Status))
699 {
700 DPRINT1 ("NtCreateKey() failed (Status %lx)\n", Status);
701 return Status;
702 }
703 NtClose (KeyHandle);
704
705 /* Link 'CurrentControlSet' to 'ControlSet001' key */
706 RtlInitUnicodeStringFromLiteral (&ControlSetLinkName,
707 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
708 InitializeObjectAttributes (&ObjectAttributes,
709 &ControlSetLinkName,
710 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
711 NULL,
712 NULL);
713 Status = NtCreateKey (&KeyHandle,
714 KEY_ALL_ACCESS | KEY_CREATE_LINK,
715 &ObjectAttributes,
716 0,
717 NULL,
718 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
719 NULL);
720 if (!NT_SUCCESS(Status))
721 {
722 DPRINT1 ("NtCreateKey() failed (Status %lx)\n", Status);
723 return Status;
724 }
725
726 RtlInitUnicodeStringFromLiteral (&ControlSetValueName,
727 L"SymbolicLinkValue");
728 Status = NtSetValueKey (KeyHandle,
729 &ControlSetValueName,
730 0,
731 REG_LINK,
732 (PVOID)ControlSetKeyName.Buffer,
733 ControlSetKeyName.Length);
734 if (!NT_SUCCESS(Status))
735 {
736 DPRINT1 ("NtSetValueKey() failed (Status %lx)\n", Status);
737 }
738 NtClose (KeyHandle);
739
740 return STATUS_SUCCESS;
741 }
742
743
744 NTSTATUS
745 CmiInitHives(BOOLEAN SetupBoot)
746 {
747 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
748 OBJECT_ATTRIBUTES ObjectAttributes;
749 UNICODE_STRING FileName;
750 UNICODE_STRING KeyName;
751 UNICODE_STRING ValueName;
752 HANDLE KeyHandle;
753
754 NTSTATUS Status;
755
756 WCHAR ConfigPath[MAX_PATH];
757
758 ULONG BufferSize;
759 ULONG ResultSize;
760 PWSTR EndPtr;
761
762
763 DPRINT("CmiInitHives() called\n");
764
765 if (SetupBoot == TRUE)
766 {
767 RtlInitUnicodeStringFromLiteral(&KeyName,
768 L"\\Registry\\Machine\\HARDWARE");
769 InitializeObjectAttributes(&ObjectAttributes,
770 &KeyName,
771 OBJ_CASE_INSENSITIVE,
772 NULL,
773 NULL);
774 Status = NtOpenKey(&KeyHandle,
775 KEY_ALL_ACCESS,
776 &ObjectAttributes);
777 if (!NT_SUCCESS(Status))
778 {
779 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
780 return(Status);
781 }
782
783 RtlInitUnicodeStringFromLiteral(&ValueName,
784 L"InstallPath");
785
786 BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
787 ValueInfo = ExAllocatePool(PagedPool,
788 BufferSize);
789 if (ValueInfo == NULL)
790 {
791 NtClose(KeyHandle);
792 return(STATUS_INSUFFICIENT_RESOURCES);
793 }
794
795 Status = NtQueryValueKey(KeyHandle,
796 &ValueName,
797 KeyValuePartialInformation,
798 ValueInfo,
799 BufferSize,
800 &ResultSize);
801 NtClose(KeyHandle);
802 if (!NT_SUCCESS(Status))
803 {
804 ExFreePool(ValueInfo);
805 return(Status);
806 }
807
808 RtlCopyMemory(ConfigPath,
809 ValueInfo->Data,
810 ValueInfo->DataLength);
811 ConfigPath[ValueInfo->DataLength / sizeof(WCHAR)] = (WCHAR)0;
812 ExFreePool(ValueInfo);
813 }
814 else
815 {
816 wcscpy(ConfigPath, L"\\SystemRoot");
817 }
818 wcscat(ConfigPath, L"\\system32\\config");
819
820 DPRINT("ConfigPath: %S\n", ConfigPath);
821
822 EndPtr = ConfigPath + wcslen(ConfigPath);
823
824 CmiDoVerify = TRUE;
825
826 /* FIXME: Save boot log */
827
828 /* Connect the SYSTEM hive only if it has been created */
829 if (SetupBoot == TRUE)
830 {
831 wcscpy(EndPtr, REG_SYSTEM_FILE_NAME);
832 DPRINT ("ConfigPath: %S\n", ConfigPath);
833
834 RtlInitUnicodeString (&KeyName,
835 REG_SYSTEM_KEY_NAME);
836 InitializeObjectAttributes(&ObjectAttributes,
837 &KeyName,
838 OBJ_CASE_INSENSITIVE,
839 NULL,
840 NULL);
841
842 RtlInitUnicodeString (&FileName,
843 ConfigPath);
844 Status = CmiLoadHive (&ObjectAttributes,
845 &FileName,
846 0);
847 if (!NT_SUCCESS(Status))
848 {
849 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status);
850 return Status;
851 }
852
853 Status = CmiInitControlSetLink ();
854 if (!NT_SUCCESS(Status))
855 {
856 DPRINT1("CmiInitControlSetLink() failed (Status %lx)\n", Status);
857 return(Status);
858 }
859 }
860
861 /* Connect the SOFTWARE hive */
862 wcscpy(EndPtr, REG_SOFTWARE_FILE_NAME);
863 RtlInitUnicodeString (&FileName,
864 ConfigPath);
865 DPRINT ("ConfigPath: %S\n", ConfigPath);
866
867 RtlInitUnicodeString (&KeyName,
868 REG_SOFTWARE_KEY_NAME);
869 InitializeObjectAttributes(&ObjectAttributes,
870 &KeyName,
871 OBJ_CASE_INSENSITIVE,
872 NULL,
873 NULL);
874
875 Status = CmiLoadHive (&ObjectAttributes,
876 &FileName,
877 0);
878 if (!NT_SUCCESS(Status))
879 {
880 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
881 return(Status);
882 }
883
884 /* Connect the SAM hive */
885 wcscpy(EndPtr, REG_SAM_FILE_NAME);
886 RtlInitUnicodeString (&FileName,
887 ConfigPath);
888 DPRINT ("ConfigPath: %S\n", ConfigPath);
889
890 RtlInitUnicodeString (&KeyName,
891 REG_SAM_KEY_NAME);
892 InitializeObjectAttributes(&ObjectAttributes,
893 &KeyName,
894 OBJ_CASE_INSENSITIVE,
895 NULL,
896 NULL);
897 Status = CmiLoadHive (&ObjectAttributes,
898 &FileName,
899 0);
900 if (!NT_SUCCESS(Status))
901 {
902 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
903 return(Status);
904 }
905
906 /* Connect the SECURITY hive */
907 wcscpy(EndPtr, REG_SEC_FILE_NAME);
908 RtlInitUnicodeString (&FileName,
909 ConfigPath);
910 DPRINT ("ConfigPath: %S\n", ConfigPath);
911
912 RtlInitUnicodeString (&KeyName,
913 REG_SEC_KEY_NAME);
914 InitializeObjectAttributes(&ObjectAttributes,
915 &KeyName,
916 OBJ_CASE_INSENSITIVE,
917 NULL,
918 NULL);
919 Status = CmiLoadHive (&ObjectAttributes,
920 &FileName,
921 0);
922 if (!NT_SUCCESS(Status))
923 {
924 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
925 return(Status);
926 }
927
928 /* Connect the DEFAULT hive */
929 wcscpy(EndPtr, REG_DEFAULT_USER_FILE_NAME);
930 RtlInitUnicodeString (&FileName,
931 ConfigPath);
932 DPRINT ("ConfigPath: %S\n", ConfigPath);
933
934 RtlInitUnicodeString (&KeyName,
935 REG_DEFAULT_USER_KEY_NAME);
936 InitializeObjectAttributes(&ObjectAttributes,
937 &KeyName,
938 OBJ_CASE_INSENSITIVE,
939 NULL,
940 NULL);
941 Status = CmiLoadHive (&ObjectAttributes,
942 &FileName,
943 0);
944 if (!NT_SUCCESS(Status))
945 {
946 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
947 return(Status);
948 }
949
950 // CmiCheckRegistry(TRUE);
951
952 /* Start automatic hive synchronization */
953 KeInitializeDpc(&CmiHiveSyncDpc,
954 CmiHiveSyncDpcRoutine,
955 NULL);
956 KeInitializeTimer(&CmiHiveSyncTimer);
957 CmiHiveSyncEnabled = TRUE;
958
959 DPRINT("CmiInitHives() done\n");
960
961 return(STATUS_SUCCESS);
962 }
963
964
965 VOID
966 CmShutdownRegistry(VOID)
967 {
968 PREGISTRY_HIVE Hive;
969 PLIST_ENTRY Entry;
970
971 DPRINT1("CmShutdownRegistry() called\n");
972
973 /* Stop automatic hive synchronization */
974 CmiHiveSyncEnabled = FALSE;
975
976 /* Acquire hive list lock exclusively */
977 ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
978
979 Entry = CmiHiveListHead.Flink;
980 while (Entry != &CmiHiveListHead)
981 {
982 Hive = CONTAINING_RECORD(Entry, REGISTRY_HIVE, HiveList);
983
984 if (!(IsNoFileHive(Hive) || IsNoSynchHive(Hive)))
985 {
986 /* Acquire hive resource exclusively */
987 ExAcquireResourceExclusiveLite(&Hive->HiveResource,
988 TRUE);
989
990 /* Flush non-volatile hive */
991 CmiFlushRegistryHive(Hive);
992
993 /* Release hive resource */
994 ExReleaseResourceLite(&Hive->HiveResource);
995 }
996
997 Entry = Entry->Flink;
998 }
999
1000 /* Release hive list lock */
1001 ExReleaseResourceLite(&CmiHiveListLock);
1002
1003 DPRINT1("CmShutdownRegistry() done\n");
1004 }
1005
1006
1007 VOID STDCALL
1008 CmiHiveSyncRoutine(PVOID DeferredContext)
1009 {
1010 PREGISTRY_HIVE Hive;
1011 PLIST_ENTRY Entry;
1012
1013 DPRINT("CmiHiveSyncRoutine() called\n");
1014
1015 CmiHiveSyncPending = FALSE;
1016
1017 /* Acquire hive list lock exclusively */
1018 ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
1019
1020 Entry = CmiHiveListHead.Flink;
1021 while (Entry != &CmiHiveListHead)
1022 {
1023 Hive = CONTAINING_RECORD(Entry, REGISTRY_HIVE, HiveList);
1024
1025 if (!(IsNoFileHive(Hive) || IsNoSynchHive(Hive)))
1026 {
1027 /* Acquire hive resource exclusively */
1028 ExAcquireResourceExclusiveLite(&Hive->HiveResource,
1029 TRUE);
1030
1031 /* Flush non-volatile hive */
1032 CmiFlushRegistryHive(Hive);
1033
1034 /* Release hive resource */
1035 ExReleaseResourceLite(&Hive->HiveResource);
1036 }
1037
1038 Entry = Entry->Flink;
1039 }
1040
1041 /* Release hive list lock */
1042 ExReleaseResourceLite(&CmiHiveListLock);
1043
1044 DPRINT("DeferredContext %x\n", DeferredContext);
1045 ExFreePool(DeferredContext);
1046
1047 DPRINT("CmiHiveSyncRoutine() done\n");
1048 }
1049
1050
1051 static VOID STDCALL
1052 CmiHiveSyncDpcRoutine(PKDPC Dpc,
1053 PVOID DeferredContext,
1054 PVOID SystemArgument1,
1055 PVOID SystemArgument2)
1056 {
1057 PWORK_QUEUE_ITEM WorkQueueItem;
1058
1059 WorkQueueItem = ExAllocatePool(NonPagedPool,
1060 sizeof(WORK_QUEUE_ITEM));
1061 if (WorkQueueItem == NULL)
1062 {
1063 DbgPrint("Failed to allocate work item\n");
1064 return;
1065 }
1066
1067 ExInitializeWorkItem(WorkQueueItem,
1068 CmiHiveSyncRoutine,
1069 WorkQueueItem);
1070
1071 DPRINT("DeferredContext %x\n", WorkQueueItem);
1072 ExQueueWorkItem(WorkQueueItem,
1073 CriticalWorkQueue);
1074 }
1075
1076
1077 VOID
1078 CmiSyncHives(VOID)
1079 {
1080 LARGE_INTEGER Timeout;
1081
1082 DPRINT("CmiSyncHives() called\n");
1083
1084 if (CmiHiveSyncEnabled == FALSE ||
1085 CmiHiveSyncPending == TRUE)
1086 return;
1087
1088 CmiHiveSyncPending = TRUE;
1089
1090
1091 Timeout.QuadPart = -50000000LL;
1092 KeSetTimer(&CmiHiveSyncTimer,
1093 Timeout,
1094 &CmiHiveSyncDpc);
1095 }
1096
1097 /* EOF */