- KdDebuggerNotPresent should be FALSE by default.
[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) ObpFreeObjectNameBuffer(&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 #if 0
601 DPRINT("Inserting Key into Object Tree\n");
602 Status = ObInsertObject((PVOID)NewKey,
603 NULL,
604 KEY_ALL_ACCESS,
605 0,
606 NULL,
607 NULL);
608 DPRINT("Status %x\n", Status);
609 #else
610 /* Free the create information */
611 ObpFreeAndReleaseCapturedAttributes(OBJECT_TO_OBJECT_HEADER(NewKey)->ObjectCreateInfo);
612 OBJECT_TO_OBJECT_HEADER(NewKey)->ObjectCreateInfo = NULL;
613 #endif
614 NewKey->Flags = 0;
615 NewKey->SubKeyCounts = 0;
616 NewKey->SubKeys = NULL;
617 NewKey->SizeOfSubKeys = 0;
618 InsertTailList(&CmiKeyObjectListHead, &NewKey->ListEntry);
619
620 DPRINT ("SubName %S\n", SubName);
621
622 Status = CmiAddSubKey(ParentKey->RegistryHive,
623 ParentKey,
624 NewKey,
625 &RemainingPath,
626 0,
627 NULL,
628 REG_OPTION_VOLATILE);
629 if (!NT_SUCCESS(Status))
630 {
631 DPRINT1("CmiAddSubKey() failed (Status %lx)\n", Status);
632 ObDereferenceObject (NewKey);
633 ObDereferenceObject (ParentKey);
634 return STATUS_INSUFFICIENT_RESOURCES;
635 }
636
637 NewKey->KeyCellOffset = RegistryHive->Hive.HiveHeader->RootCell;
638 NewKey->KeyCell = HvGetCell (&RegistryHive->Hive, NewKey->KeyCellOffset);
639 NewKey->RegistryHive = RegistryHive;
640
641 Status = RtlpCreateUnicodeString(&NewKey->Name,
642 SubName, NonPagedPool);
643 RtlFreeUnicodeString(&RemainingPath);
644 if (!NT_SUCCESS(Status))
645 {
646 DPRINT1("RtlpCreateUnicodeString() failed (Status %lx)\n", Status);
647 ObDereferenceObject (NewKey);
648 ObDereferenceObject (ParentKey);
649 return STATUS_INSUFFICIENT_RESOURCES;
650 }
651
652 /* FN1 */
653 ObReferenceObject (NewKey);
654
655 CmiAddKeyToList (ParentKey, NewKey);
656 ObDereferenceObject (ParentKey);
657
658 VERIFY_KEY_OBJECT(NewKey);
659
660 /* We're holding a pointer to the parent key .. We must keep it
661 * referenced */
662 /* Note: Do not dereference NewKey here! */
663
664 return STATUS_SUCCESS;
665 }
666
667
668 NTSTATUS
669 CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
670 OUT PEREGISTRY_HIVE *RegistryHive)
671 {
672 PKEY_OBJECT KeyObject;
673 PEREGISTRY_HIVE Hive;
674 HANDLE KeyHandle;
675 NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
676 PLIST_ENTRY CurrentEntry;
677 PKEY_OBJECT CurrentKey;
678
679 DPRINT("CmiDisconnectHive() called\n");
680
681 *RegistryHive = NULL;
682
683 Status = ObOpenObjectByName (KeyObjectAttributes,
684 CmiKeyType,
685 KernelMode,
686 NULL,
687 STANDARD_RIGHTS_REQUIRED,
688 NULL,
689 &KeyHandle);
690 if (!NT_SUCCESS(Status))
691 {
692 DPRINT1 ("ObOpenObjectByName() failed (Status %lx)\n", Status);
693 return Status;
694 }
695
696 Status = ObReferenceObjectByHandle (KeyHandle,
697 STANDARD_RIGHTS_REQUIRED,
698 CmiKeyType,
699 KernelMode,
700 (PVOID*)&KeyObject,
701 NULL);
702 ZwClose (KeyHandle);
703
704 if (!NT_SUCCESS(Status))
705 {
706 DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status);
707 return Status;
708 }
709 DPRINT ("KeyObject %p Hive %p\n", KeyObject, KeyObject->RegistryHive);
710
711 /* Acquire registry lock exclusively */
712 KeEnterCriticalRegion();
713 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
714
715 Hive = KeyObject->RegistryHive;
716
717 CurrentEntry = CmiKeyObjectListHead.Flink;
718 while (CurrentEntry != &CmiKeyObjectListHead)
719 {
720 CurrentKey = CONTAINING_RECORD(CurrentEntry, KEY_OBJECT, ListEntry);
721 if (CurrentKey->RegistryHive == Hive &&
722 1 == ObGetObjectPointerCount(CurrentKey) &&
723 !(CurrentKey->Flags & KO_MARKED_FOR_DELETE))
724 {
725 ObDereferenceObject(CurrentKey);
726 CurrentEntry = CmiKeyObjectListHead.Flink;
727 }
728 else
729 {
730 CurrentEntry = CurrentEntry->Flink;
731 }
732 }
733
734 /* FN1 */
735 ObDereferenceObject (KeyObject);
736
737 if (ObGetObjectHandleCount (KeyObject) != 0 ||
738 ObGetObjectPointerCount (KeyObject) != 2)
739 {
740 DPRINT1 ("Hive is still in use (hc %d, rc %d)\n", ObGetObjectHandleCount (KeyObject), ObGetObjectPointerCount (KeyObject));
741 ObDereferenceObject (KeyObject);
742
743 /* Release registry lock */
744 ExReleaseResourceLite (&CmiRegistryLock);
745 KeLeaveCriticalRegion();
746
747 return STATUS_UNSUCCESSFUL;
748 }
749
750 /* Dereference KeyObject twice to delete it */
751 ObDereferenceObject (KeyObject);
752 ObDereferenceObject (KeyObject);
753
754 *RegistryHive = Hive;
755
756 /* Release registry lock */
757 ExReleaseResourceLite (&CmiRegistryLock);
758 KeLeaveCriticalRegion();
759
760 /* Release reference above */
761 ObDereferenceObject (KeyObject);
762
763 DPRINT ("CmiDisconnectHive() done\n");
764
765 return Status;
766 }
767
768
769 static NTSTATUS
770 CmiInitControlSetLink (VOID)
771 {
772 OBJECT_ATTRIBUTES ObjectAttributes;
773 UNICODE_STRING ControlSetKeyName = RTL_CONSTANT_STRING(
774 L"\\Registry\\Machine\\SYSTEM\\ControlSet001");
775 UNICODE_STRING ControlSetLinkName = RTL_CONSTANT_STRING(
776 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
777 UNICODE_STRING ControlSetValueName = RTL_CONSTANT_STRING(L"SymbolicLinkValue");
778 HANDLE KeyHandle;
779 NTSTATUS Status;
780
781 /* Create 'ControlSet001' key */
782 InitializeObjectAttributes (&ObjectAttributes,
783 &ControlSetKeyName,
784 OBJ_CASE_INSENSITIVE,
785 NULL,
786 NULL);
787 Status = ZwCreateKey (&KeyHandle,
788 KEY_ALL_ACCESS,
789 &ObjectAttributes,
790 0,
791 NULL,
792 REG_OPTION_NON_VOLATILE,
793 NULL);
794 if (!NT_SUCCESS(Status))
795 {
796 DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status);
797 return Status;
798 }
799 ZwClose (KeyHandle);
800
801 /* Link 'CurrentControlSet' to 'ControlSet001' key */
802 InitializeObjectAttributes (&ObjectAttributes,
803 &ControlSetLinkName,
804 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
805 NULL,
806 NULL);
807 Status = ZwCreateKey (&KeyHandle,
808 KEY_ALL_ACCESS | KEY_CREATE_LINK,
809 &ObjectAttributes,
810 0,
811 NULL,
812 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
813 NULL);
814 if (!NT_SUCCESS(Status))
815 {
816 DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status);
817 return Status;
818 }
819
820 Status = ZwSetValueKey (KeyHandle,
821 &ControlSetValueName,
822 0,
823 REG_LINK,
824 (PVOID)ControlSetKeyName.Buffer,
825 ControlSetKeyName.Length);
826 if (!NT_SUCCESS(Status))
827 {
828 DPRINT1 ("ZwSetValueKey() failed (Status %lx)\n", Status);
829 }
830 ZwClose (KeyHandle);
831
832 return STATUS_SUCCESS;
833 }
834
835
836 NTSTATUS
837 CmiInitHives(BOOLEAN SetupBoot)
838 {
839 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
840 OBJECT_ATTRIBUTES ObjectAttributes;
841 UNICODE_STRING FileName;
842 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE");
843 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"InstallPath");
844 HANDLE KeyHandle;
845
846 NTSTATUS Status;
847
848 WCHAR ConfigPath[MAX_PATH];
849
850 ULONG BufferSize;
851 ULONG ResultSize;
852 PWSTR EndPtr;
853
854
855 DPRINT("CmiInitHives() called\n");
856
857 if (SetupBoot == TRUE)
858 {
859 InitializeObjectAttributes(&ObjectAttributes,
860 &KeyName,
861 OBJ_CASE_INSENSITIVE,
862 NULL,
863 NULL);
864 Status = ZwOpenKey(&KeyHandle,
865 KEY_ALL_ACCESS,
866 &ObjectAttributes);
867 if (!NT_SUCCESS(Status))
868 {
869 DPRINT1("ZwOpenKey() failed (Status %lx)\n", Status);
870 return(Status);
871 }
872
873 BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
874 ValueInfo = ExAllocatePool(PagedPool,
875 BufferSize);
876 if (ValueInfo == NULL)
877 {
878 ZwClose(KeyHandle);
879 return(STATUS_INSUFFICIENT_RESOURCES);
880 }
881
882 Status = ZwQueryValueKey(KeyHandle,
883 &ValueName,
884 KeyValuePartialInformation,
885 ValueInfo,
886 BufferSize,
887 &ResultSize);
888 ZwClose(KeyHandle);
889 if (!NT_SUCCESS(Status))
890 {
891 ExFreePool(ValueInfo);
892 return(Status);
893 }
894
895 RtlCopyMemory(ConfigPath,
896 ValueInfo->Data,
897 ValueInfo->DataLength);
898 ConfigPath[ValueInfo->DataLength / sizeof(WCHAR)] = (WCHAR)0;
899 ExFreePool(ValueInfo);
900 }
901 else
902 {
903 wcscpy(ConfigPath, L"\\SystemRoot");
904 }
905 wcscat(ConfigPath, L"\\system32\\config");
906
907 DPRINT("ConfigPath: %S\n", ConfigPath);
908
909 EndPtr = ConfigPath + wcslen(ConfigPath);
910
911 /* FIXME: Save boot log */
912
913 /* Connect the SYSTEM hive only if it has been created */
914 if (SetupBoot == TRUE)
915 {
916 wcscpy(EndPtr, REG_SYSTEM_FILE_NAME);
917 DPRINT ("ConfigPath: %S\n", ConfigPath);
918
919 RtlInitUnicodeString (&KeyName,
920 REG_SYSTEM_KEY_NAME);
921 InitializeObjectAttributes(&ObjectAttributes,
922 &KeyName,
923 OBJ_CASE_INSENSITIVE,
924 NULL,
925 NULL);
926
927 RtlInitUnicodeString (&FileName,
928 ConfigPath);
929 Status = CmiLoadHive (&ObjectAttributes,
930 &FileName,
931 0);
932 if (!NT_SUCCESS(Status))
933 {
934 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status);
935 return Status;
936 }
937
938 Status = CmiInitControlSetLink ();
939 if (!NT_SUCCESS(Status))
940 {
941 DPRINT1("CmiInitControlSetLink() failed (Status %lx)\n", Status);
942 return(Status);
943 }
944 }
945
946 /* Connect the SOFTWARE hive */
947 wcscpy(EndPtr, REG_SOFTWARE_FILE_NAME);
948 RtlInitUnicodeString (&FileName,
949 ConfigPath);
950 DPRINT ("ConfigPath: %S\n", ConfigPath);
951
952 RtlInitUnicodeString (&KeyName,
953 REG_SOFTWARE_KEY_NAME);
954 InitializeObjectAttributes(&ObjectAttributes,
955 &KeyName,
956 OBJ_CASE_INSENSITIVE,
957 NULL,
958 NULL);
959
960 Status = CmiLoadHive (&ObjectAttributes,
961 &FileName,
962 0);
963 if (!NT_SUCCESS(Status))
964 {
965 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
966 return(Status);
967 }
968
969 /* Connect the SAM hive */
970 wcscpy(EndPtr, REG_SAM_FILE_NAME);
971 RtlInitUnicodeString (&FileName,
972 ConfigPath);
973 DPRINT ("ConfigPath: %S\n", ConfigPath);
974
975 RtlInitUnicodeString (&KeyName,
976 REG_SAM_KEY_NAME);
977 InitializeObjectAttributes(&ObjectAttributes,
978 &KeyName,
979 OBJ_CASE_INSENSITIVE,
980 NULL,
981 NULL);
982 Status = CmiLoadHive (&ObjectAttributes,
983 &FileName,
984 0);
985 if (!NT_SUCCESS(Status))
986 {
987 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
988 return(Status);
989 }
990
991 /* Connect the SECURITY hive */
992 wcscpy(EndPtr, REG_SEC_FILE_NAME);
993 RtlInitUnicodeString (&FileName,
994 ConfigPath);
995 DPRINT ("ConfigPath: %S\n", ConfigPath);
996
997 RtlInitUnicodeString (&KeyName,
998 REG_SEC_KEY_NAME);
999 InitializeObjectAttributes(&ObjectAttributes,
1000 &KeyName,
1001 OBJ_CASE_INSENSITIVE,
1002 NULL,
1003 NULL);
1004 Status = CmiLoadHive (&ObjectAttributes,
1005 &FileName,
1006 0);
1007 if (!NT_SUCCESS(Status))
1008 {
1009 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
1010 return(Status);
1011 }
1012
1013 /* Connect the DEFAULT hive */
1014 wcscpy(EndPtr, REG_DEFAULT_USER_FILE_NAME);
1015 RtlInitUnicodeString (&FileName,
1016 ConfigPath);
1017 DPRINT ("ConfigPath: %S\n", ConfigPath);
1018
1019 RtlInitUnicodeString (&KeyName,
1020 REG_DEFAULT_USER_KEY_NAME);
1021 InitializeObjectAttributes(&ObjectAttributes,
1022 &KeyName,
1023 OBJ_CASE_INSENSITIVE,
1024 NULL,
1025 NULL);
1026 Status = CmiLoadHive (&ObjectAttributes,
1027 &FileName,
1028 0);
1029 if (!NT_SUCCESS(Status))
1030 {
1031 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
1032 return(Status);
1033 }
1034
1035 // CmiCheckRegistry(TRUE);
1036
1037 /* Start automatic hive synchronization */
1038 KeInitializeDpc(&CmiHiveSyncDpc,
1039 CmiHiveSyncDpcRoutine,
1040 NULL);
1041 KeInitializeTimer(&CmiHiveSyncTimer);
1042 CmiHiveSyncEnabled = TRUE;
1043
1044 DPRINT("CmiInitHives() done\n");
1045
1046 return(STATUS_SUCCESS);
1047 }
1048
1049
1050 VOID
1051 CmShutdownRegistry(VOID)
1052 {
1053 PEREGISTRY_HIVE Hive;
1054 PLIST_ENTRY Entry;
1055
1056 DPRINT("CmShutdownRegistry() called\n");
1057
1058 /* Stop automatic hive synchronization */
1059 CmiHiveSyncEnabled = FALSE;
1060
1061 /* Cancel pending hive synchronization */
1062 if (CmiHiveSyncPending == TRUE)
1063 {
1064 KeCancelTimer(&CmiHiveSyncTimer);
1065 CmiHiveSyncPending = FALSE;
1066 }
1067
1068 /* Acquire hive list lock exclusively */
1069 KeEnterCriticalRegion();
1070 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
1071
1072 Entry = CmiHiveListHead.Flink;
1073 while (Entry != &CmiHiveListHead)
1074 {
1075 Hive = CONTAINING_RECORD(Entry, EREGISTRY_HIVE, HiveList);
1076
1077 if (!(IsNoFileHive(Hive) || IsNoSynchHive(Hive)))
1078 {
1079 /* Flush non-volatile hive */
1080 CmiFlushRegistryHive(Hive);
1081 }
1082
1083 Entry = Entry->Flink;
1084 }
1085
1086 /* Release hive list lock */
1087 ExReleaseResourceLite(&CmiRegistryLock);
1088 KeLeaveCriticalRegion();
1089
1090 DPRINT("CmShutdownRegistry() done\n");
1091 }
1092
1093
1094 VOID STDCALL
1095 CmiHiveSyncRoutine(PVOID DeferredContext)
1096 {
1097 PEREGISTRY_HIVE Hive;
1098 PLIST_ENTRY Entry;
1099
1100 DPRINT("CmiHiveSyncRoutine() called\n");
1101
1102 CmiHiveSyncPending = FALSE;
1103
1104 /* Acquire hive list lock exclusively */
1105 KeEnterCriticalRegion();
1106 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
1107
1108 Entry = CmiHiveListHead.Flink;
1109 while (Entry != &CmiHiveListHead)
1110 {
1111 Hive = CONTAINING_RECORD(Entry, EREGISTRY_HIVE, HiveList);
1112
1113 if (!(IsNoFileHive(Hive) || IsNoSynchHive(Hive)))
1114 {
1115 /* Flush non-volatile hive */
1116 CmiFlushRegistryHive(Hive);
1117 }
1118
1119 Entry = Entry->Flink;
1120 }
1121
1122 /* Release hive list lock */
1123 ExReleaseResourceLite(&CmiRegistryLock);
1124 KeLeaveCriticalRegion();
1125
1126 DPRINT("DeferredContext 0x%p\n", DeferredContext);
1127 ExFreePool(DeferredContext);
1128
1129 DPRINT("CmiHiveSyncRoutine() done\n");
1130 }
1131
1132
1133 static VOID STDCALL
1134 CmiHiveSyncDpcRoutine(PKDPC Dpc,
1135 PVOID DeferredContext,
1136 PVOID SystemArgument1,
1137 PVOID SystemArgument2)
1138 {
1139 PWORK_QUEUE_ITEM WorkQueueItem;
1140
1141 WorkQueueItem = ExAllocatePool(NonPagedPool,
1142 sizeof(WORK_QUEUE_ITEM));
1143 if (WorkQueueItem == NULL)
1144 {
1145 DbgPrint("Failed to allocate work item\n");
1146 return;
1147 }
1148
1149 ExInitializeWorkItem(WorkQueueItem,
1150 CmiHiveSyncRoutine,
1151 WorkQueueItem);
1152
1153 DPRINT("DeferredContext 0x%p\n", WorkQueueItem);
1154 ExQueueWorkItem(WorkQueueItem,
1155 CriticalWorkQueue);
1156 }
1157
1158
1159 VOID
1160 CmiSyncHives(VOID)
1161 {
1162 LARGE_INTEGER Timeout;
1163
1164 DPRINT("CmiSyncHives() called\n");
1165
1166 if (CmiHiveSyncEnabled == FALSE ||
1167 CmiHiveSyncPending == TRUE)
1168 return;
1169
1170 CmiHiveSyncPending = TRUE;
1171
1172 Timeout.QuadPart = (LONGLONG)-50000000;
1173 KeSetTimer(&CmiHiveSyncTimer,
1174 Timeout,
1175 &CmiHiveSyncDpc);
1176 }
1177
1178 /* EOF */