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