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