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