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