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