merge ROS Shell without integrated explorer part into 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 INIT_FUNCTION
335 CmInitializeRegistry(VOID)
336 {
337 OBJECT_ATTRIBUTES ObjectAttributes;
338 UNICODE_STRING KeyName;
339 PKEY_OBJECT RootKey;
340 #if 0
341 PSECURITY_CELL RootSecurityCell;
342 #endif
343 HANDLE RootKeyHandle;
344 HANDLE KeyHandle;
345 NTSTATUS Status;
346 LARGE_INTEGER DueTime;
347 HANDLE ThreadHandle;
348 CLIENT_ID ThreadId;
349
350 /* Initialize the Key object type */
351 CmiKeyType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
352 ASSERT(CmiKeyType);
353 CmiKeyType->Tag = TAG('R', 'e', 'g', 'K');
354 CmiKeyType->TotalObjects = 0;
355 CmiKeyType->TotalHandles = 0;
356 CmiKeyType->PeakObjects = 0;
357 CmiKeyType->PeakHandles = 0;
358 CmiKeyType->PagedPoolCharge = 0;
359 CmiKeyType->NonpagedPoolCharge = sizeof(KEY_OBJECT);
360 CmiKeyType->Mapping = &CmiKeyMapping;
361 CmiKeyType->Dump = NULL;
362 CmiKeyType->Open = NULL;
363 CmiKeyType->Close = NULL;
364 CmiKeyType->Delete = CmiObjectDelete;
365 CmiKeyType->Parse = CmiObjectParse;
366 CmiKeyType->Security = CmiObjectSecurity;
367 CmiKeyType->QueryName = CmiObjectQueryName;
368 CmiKeyType->OkayToClose = NULL;
369 CmiKeyType->Create = CmiObjectCreate;
370 CmiKeyType->DuplicationNotify = NULL;
371 RtlInitUnicodeString(&CmiKeyType->TypeName, L"Key");
372
373 ObpCreateTypeObject (CmiKeyType);
374
375 /* Initialize the hive list */
376 InitializeListHead(&CmiHiveListHead);
377
378 /* Initialize registry lock */
379 ExInitializeResourceLite(&CmiRegistryLock);
380
381 /* Initialize the key object list */
382 InitializeListHead(&CmiKeyObjectListHead);
383
384 /* Initialize the worker timer */
385 KeInitializeTimerEx(&CmiWorkerTimer, SynchronizationTimer);
386
387 /* Initialize the worker thread */
388 Status = PsCreateSystemThread(&ThreadHandle,
389 THREAD_ALL_ACCESS,
390 NULL,
391 NULL,
392 &ThreadId,
393 CmiWorkerThread,
394 NULL);
395 if (!NT_SUCCESS(Status))
396 {
397 KEBUGCHECK(0);
398 }
399
400 /* Start the timer */
401 DueTime.QuadPart = -1;
402 KeSetTimerEx(&CmiWorkerTimer, DueTime, 5000, NULL); /* 5sec */
403
404 /* Build volatile registry store */
405 Status = CmiCreateVolatileHive (&CmiVolatileHive);
406 ASSERT(NT_SUCCESS(Status));
407
408 InitializeListHead(&CmiCallbackHead);
409 ExInitializeFastMutex(&CmiCallbackLock);
410
411 /* Create '\Registry' key. */
412 RtlInitUnicodeString(&KeyName, REG_ROOT_KEY_NAME);
413 InitializeObjectAttributes(&ObjectAttributes, &KeyName, 0, NULL, NULL);
414 Status = ObCreateObject(KernelMode,
415 CmiKeyType,
416 &ObjectAttributes,
417 KernelMode,
418 NULL,
419 sizeof(KEY_OBJECT),
420 0,
421 0,
422 (PVOID *) &RootKey);
423 ASSERT(NT_SUCCESS(Status));
424 Status = ObInsertObject(RootKey,
425 NULL,
426 KEY_ALL_ACCESS,
427 0,
428 NULL,
429 &RootKeyHandle);
430 ASSERT(NT_SUCCESS(Status));
431 RootKey->RegistryHive = CmiVolatileHive;
432 RootKey->KeyCellOffset = CmiVolatileHive->HiveHeader->RootKeyOffset;
433 RootKey->KeyCell = CmiGetCell (CmiVolatileHive, RootKey->KeyCellOffset, NULL);
434 RootKey->ParentKey = RootKey;
435 RootKey->Flags = 0;
436 RootKey->NumberOfSubKeys = 0;
437 RootKey->SubKeys = NULL;
438 RootKey->SizeOfSubKeys = 0;
439 InsertTailList(&CmiKeyObjectListHead, &RootKey->ListEntry);
440 Status = RtlpCreateUnicodeString(&RootKey->Name, L"Registry", NonPagedPool);
441 ASSERT(NT_SUCCESS(Status));
442
443 #if 0
444 Status = CmiAllocateCell(CmiVolatileHive,
445 0x10, //LONG CellSize,
446 (PVOID *)&RootSecurityCell,
447 &RootKey->KeyCell->SecurityKeyOffset);
448 ASSERT(NT_SUCCESS(Status));
449
450 /* Copy the security descriptor */
451
452 CmiVolatileHive->RootSecurityCell = RootSecurityCell;
453 #endif
454
455
456 /* Create '\Registry\Machine' key. */
457 RtlInitUnicodeString(&KeyName,
458 L"Machine");
459 InitializeObjectAttributes(&ObjectAttributes,
460 &KeyName,
461 0,
462 RootKeyHandle,
463 NULL);
464 Status = ZwCreateKey(&KeyHandle,
465 KEY_ALL_ACCESS,
466 &ObjectAttributes,
467 0,
468 NULL,
469 REG_OPTION_VOLATILE,
470 NULL);
471 ASSERT(NT_SUCCESS(Status));
472
473 /* Create '\Registry\User' key. */
474 RtlInitUnicodeString(&KeyName,
475 L"User");
476 InitializeObjectAttributes(&ObjectAttributes,
477 &KeyName,
478 0,
479 RootKeyHandle,
480 NULL);
481 Status = ZwCreateKey(&KeyHandle,
482 KEY_ALL_ACCESS,
483 &ObjectAttributes,
484 0,
485 NULL,
486 REG_OPTION_VOLATILE,
487 NULL);
488 ASSERT(NT_SUCCESS(Status));
489 }
490
491
492 VOID INIT_FUNCTION
493 CmInit2(PCHAR CommandLine)
494 {
495 ULONG PiceStart = 4;
496 BOOLEAN MiniNT = FALSE;
497 PWCHAR SystemBootDevice;
498 PWCHAR SystemStartOptions;
499 ULONG Position;
500 NTSTATUS Status;
501
502 /* Create the 'CurrentControlSet' link. */
503 Status = CmiCreateCurrentControlSetLink();
504 if (!NT_SUCCESS(Status))
505 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
506
507 /*
508 * Parse the system boot device.
509 */
510 Position = 0;
511 SystemBootDevice = ExAllocatePool(PagedPool,
512 (strlen(CommandLine) + 1) * sizeof(WCHAR));
513 if (SystemBootDevice == NULL)
514 {
515 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
516 }
517
518 while (*CommandLine != 0 && *CommandLine != ' ')
519 SystemBootDevice[Position++] = *(CommandLine++);
520 SystemBootDevice[Position++] = 0;
521
522 /*
523 * Write the system boot device to registry.
524 */
525 Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
526 L"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
527 L"SystemBootDevice",
528 REG_SZ,
529 SystemBootDevice,
530 Position * sizeof(WCHAR));
531 if (!NT_SUCCESS(Status))
532 {
533 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
534 }
535
536 /*
537 * Parse the system start options.
538 */
539 Position = 0;
540 SystemStartOptions = SystemBootDevice;
541 while ((CommandLine = strchr(CommandLine, '/')) != NULL)
542 {
543 /* Skip over the slash */
544 CommandLine++;
545
546 /* Special options */
547 if (!_strnicmp(CommandLine, "MININT", 6))
548 MiniNT = TRUE;
549 else if (!_strnicmp(CommandLine, "DEBUGPORT=PICE", 14))
550 PiceStart = 1;
551
552 /* Add a space between the options */
553 if (Position != 0)
554 SystemStartOptions[Position++] = L' ';
555
556 /* Copy the command */
557 while (*CommandLine != 0 && *CommandLine != ' ')
558 SystemStartOptions[Position++] = *(CommandLine++);
559 }
560 SystemStartOptions[Position++] = 0;
561
562 /*
563 * Write the system start options to registry.
564 */
565 Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
566 L"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
567 L"SystemStartOptions",
568 REG_SZ,
569 SystemStartOptions,
570 Position * sizeof(WCHAR));
571 if (!NT_SUCCESS(Status))
572 {
573 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
574 }
575
576 /*
577 * Create a CurrentControlSet\Control\MiniNT key that is used
578 * to detect WinPE/MiniNT systems.
579 */
580 if (MiniNT)
581 {
582 Status = RtlCreateRegistryKey(RTL_REGISTRY_CONTROL, L"MiniNT");
583 if (!NT_SUCCESS(Status))
584 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
585 }
586
587 /* Set PICE 'Start' value to 1, if PICE debugging is enabled */
588 Status = RtlWriteRegistryValue(
589 RTL_REGISTRY_SERVICES,
590 L"\\Pice",
591 L"Start",
592 REG_DWORD,
593 &PiceStart,
594 sizeof(ULONG));
595 if (!NT_SUCCESS(Status))
596 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
597
598 ExFreePool(SystemBootDevice);
599 }
600
601
602 static NTSTATUS
603 CmiCreateCurrentControlSetLink(VOID)
604 {
605 RTL_QUERY_REGISTRY_TABLE QueryTable[5];
606 WCHAR TargetNameBuffer[80];
607 ULONG TargetNameLength;
608 UNICODE_STRING LinkName;
609 UNICODE_STRING LinkValue;
610 ULONG CurrentSet;
611 ULONG DefaultSet;
612 ULONG Failed;
613 ULONG LastKnownGood;
614 NTSTATUS Status;
615 OBJECT_ATTRIBUTES ObjectAttributes;
616 HANDLE KeyHandle;
617
618 DPRINT("CmiCreateCurrentControlSetLink() called\n");
619
620 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
621
622 QueryTable[0].Name = L"Current";
623 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
624 QueryTable[0].EntryContext = &CurrentSet;
625
626 QueryTable[1].Name = L"Default";
627 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
628 QueryTable[1].EntryContext = &DefaultSet;
629
630 QueryTable[2].Name = L"Failed";
631 QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
632 QueryTable[2].EntryContext = &Failed;
633
634 QueryTable[3].Name = L"LastKnownGood";
635 QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
636 QueryTable[3].EntryContext = &LastKnownGood;
637
638 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
639 L"\\Registry\\Machine\\SYSTEM\\Select",
640 QueryTable,
641 NULL,
642 NULL);
643 if (!NT_SUCCESS(Status))
644 {
645 return(Status);
646 }
647
648 DPRINT("Current %ld Default %ld\n", CurrentSet, DefaultSet);
649
650 swprintf(TargetNameBuffer,
651 L"\\Registry\\Machine\\SYSTEM\\ControlSet%03lu",
652 CurrentSet);
653 TargetNameLength = wcslen(TargetNameBuffer) * sizeof(WCHAR);
654
655 DPRINT("Link target '%S'\n", TargetNameBuffer);
656
657 RtlRosInitUnicodeStringFromLiteral(&LinkName,
658 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
659 InitializeObjectAttributes(&ObjectAttributes,
660 &LinkName,
661 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
662 NULL,
663 NULL);
664 Status = ZwCreateKey(&KeyHandle,
665 KEY_ALL_ACCESS | KEY_CREATE_LINK,
666 &ObjectAttributes,
667 0,
668 NULL,
669 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
670 NULL);
671 if (!NT_SUCCESS(Status))
672 {
673 DPRINT1("ZwCreateKey() failed (Status %lx)\n", Status);
674 return(Status);
675 }
676
677 RtlRosInitUnicodeStringFromLiteral(&LinkValue,
678 L"SymbolicLinkValue");
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
706 DPRINT("CmiConnectHive(%p, %p) called.\n",
707 KeyObjectAttributes, RegistryHive);
708
709 Status = ObFindObject(KeyObjectAttributes,
710 (PVOID*)&ParentKey,
711 &RemainingPath,
712 CmiKeyType);
713 if (!NT_SUCCESS(Status))
714 {
715 return Status;
716 }
717
718 DPRINT ("RemainingPath %wZ\n", &RemainingPath);
719
720 if ((RemainingPath.Buffer == NULL) || (RemainingPath.Buffer[0] == 0))
721 {
722 ObDereferenceObject (ParentKey);
723 RtlFreeUnicodeString(&RemainingPath);
724 return STATUS_OBJECT_NAME_COLLISION;
725 }
726
727 /* Ignore leading backslash */
728 SubName = RemainingPath.Buffer;
729 if (*SubName == L'\\')
730 SubName++;
731
732 /* If RemainingPath contains \ we must return error
733 because CmiConnectHive() can not create trees */
734 if (wcschr (SubName, L'\\') != NULL)
735 {
736 ObDereferenceObject (ParentKey);
737 RtlFreeUnicodeString(&RemainingPath);
738 return STATUS_OBJECT_NAME_NOT_FOUND;
739 }
740
741 DPRINT("RemainingPath %wZ ParentKey %p\n",
742 &RemainingPath, ParentKey);
743
744 Status = ObCreateObject(KernelMode,
745 CmiKeyType,
746 NULL,
747 KernelMode,
748 NULL,
749 sizeof(KEY_OBJECT),
750 0,
751 0,
752 (PVOID*)&NewKey);
753 if (!NT_SUCCESS(Status))
754 {
755 DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status);
756 ObDereferenceObject (ParentKey);
757 RtlFreeUnicodeString(&RemainingPath);
758 return Status;
759 }
760
761 NewKey->RegistryHive = RegistryHive;
762 NewKey->KeyCellOffset = RegistryHive->HiveHeader->RootKeyOffset;
763 NewKey->KeyCell = CmiGetCell (RegistryHive, NewKey->KeyCellOffset, NULL);
764 NewKey->Flags = 0;
765 NewKey->NumberOfSubKeys = 0;
766 InsertTailList(&CmiKeyObjectListHead, &NewKey->ListEntry);
767 if (NewKey->KeyCell->NumberOfSubKeys != 0)
768 {
769 NewKey->SubKeys = ExAllocatePool(NonPagedPool,
770 NewKey->KeyCell->NumberOfSubKeys * sizeof(ULONG));
771 if (NewKey->SubKeys == NULL)
772 {
773 DPRINT("ExAllocatePool() failed\n");
774 ObDereferenceObject (NewKey);
775 ObDereferenceObject (ParentKey);
776 RtlFreeUnicodeString(&RemainingPath);
777 return STATUS_INSUFFICIENT_RESOURCES;
778 }
779 }
780 else
781 {
782 NewKey->SubKeys = NULL;
783 }
784
785 DPRINT ("SubName %S\n", SubName);
786
787 Status = RtlpCreateUnicodeString(&NewKey->Name,
788 SubName, NonPagedPool);
789 RtlFreeUnicodeString(&RemainingPath);
790 if (!NT_SUCCESS(Status))
791 {
792 DPRINT1("RtlpCreateUnicodeString() failed (Status %lx)\n", Status);
793 if (NewKey->SubKeys != NULL)
794 {
795 ExFreePool (NewKey->SubKeys);
796 }
797 ObDereferenceObject (NewKey);
798 ObDereferenceObject (ParentKey);
799 return STATUS_INSUFFICIENT_RESOURCES;
800 }
801
802 CmiAddKeyToList (ParentKey, NewKey);
803 ObDereferenceObject (ParentKey);
804
805 VERIFY_KEY_OBJECT(NewKey);
806
807 /* Note: Do not dereference NewKey here! */
808
809 return STATUS_SUCCESS;
810 }
811
812
813 NTSTATUS
814 CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
815 OUT PREGISTRY_HIVE *RegistryHive)
816 {
817 PKEY_OBJECT KeyObject;
818 PREGISTRY_HIVE Hive;
819 HANDLE KeyHandle;
820 NTSTATUS Status;
821 PLIST_ENTRY CurrentEntry;
822 PKEY_OBJECT CurrentKey;
823
824 DPRINT("CmiDisconnectHive() called\n");
825
826 *RegistryHive = NULL;
827
828 Status = ObOpenObjectByName (KeyObjectAttributes,
829 CmiKeyType,
830 NULL,
831 KernelMode,
832 STANDARD_RIGHTS_REQUIRED,
833 NULL,
834 &KeyHandle);
835 if (!NT_SUCCESS(Status))
836 {
837 DPRINT1 ("ObOpenObjectByName() failed (Status %lx)\n", Status);
838 return Status;
839 }
840
841 Status = ObReferenceObjectByHandle (KeyHandle,
842 STANDARD_RIGHTS_REQUIRED,
843 CmiKeyType,
844 KernelMode,
845 (PVOID*)&KeyObject,
846 NULL);
847 ZwClose (KeyHandle);
848 if (!NT_SUCCESS(Status))
849 {
850 DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status);
851 return Status;
852 }
853 DPRINT ("KeyObject %p Hive %p\n", KeyObject, KeyObject->RegistryHive);
854
855 if (!(KeyObject->KeyCell->Flags & REG_KEY_ROOT_CELL))
856 {
857 DPRINT1 ("Key is not the Hive-Root-Key\n");
858 ObDereferenceObject (KeyObject);
859 return STATUS_INVALID_PARAMETER;
860 }
861
862 /* Acquire registry lock exclusively */
863 KeEnterCriticalRegion();
864 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
865
866 CurrentEntry = CmiKeyObjectListHead.Flink;
867 while (CurrentEntry != &CmiKeyObjectListHead)
868 {
869 CurrentKey = CONTAINING_RECORD(CurrentEntry, KEY_OBJECT, ListEntry);
870 if (1 == ObGetObjectPointerCount(CurrentKey) &&
871 !(CurrentKey->Flags & KO_MARKED_FOR_DELETE))
872 {
873 ObDereferenceObject(CurrentKey);
874 CurrentEntry = CmiKeyObjectListHead.Flink;
875 }
876 else
877 {
878 CurrentEntry = CurrentEntry->Flink;
879 }
880 }
881
882 if (ObGetObjectHandleCount (KeyObject) != 0 ||
883 ObGetObjectPointerCount (KeyObject) != 2)
884 {
885 DPRINT1 ("Hive is still in use (hc %d, rc %d)\n", ObGetObjectHandleCount (KeyObject), ObGetObjectPointerCount (KeyObject));
886 ObDereferenceObject (KeyObject);
887
888 /* Release registry lock */
889 ExReleaseResourceLite (&CmiRegistryLock);
890 KeLeaveCriticalRegion();
891
892 return STATUS_UNSUCCESSFUL;
893 }
894
895 Hive = KeyObject->RegistryHive;
896
897 /* Dereference KeyObject twice to delete it */
898 ObDereferenceObject (KeyObject);
899 ObDereferenceObject (KeyObject);
900
901 *RegistryHive = Hive;
902
903 /* Release registry lock */
904 ExReleaseResourceLite (&CmiRegistryLock);
905 KeLeaveCriticalRegion();
906
907 DPRINT ("CmiDisconnectHive() done\n");
908
909 return STATUS_SUCCESS;
910 }
911
912
913 static NTSTATUS
914 CmiInitControlSetLink (VOID)
915 {
916 OBJECT_ATTRIBUTES ObjectAttributes;
917 UNICODE_STRING ControlSetKeyName;
918 UNICODE_STRING ControlSetLinkName;
919 UNICODE_STRING ControlSetValueName;
920 HANDLE KeyHandle;
921 NTSTATUS Status;
922
923 /* Create 'ControlSet001' key */
924 RtlRosInitUnicodeStringFromLiteral (&ControlSetKeyName,
925 L"\\Registry\\Machine\\SYSTEM\\ControlSet001");
926 InitializeObjectAttributes (&ObjectAttributes,
927 &ControlSetKeyName,
928 OBJ_CASE_INSENSITIVE,
929 NULL,
930 NULL);
931 Status = ZwCreateKey (&KeyHandle,
932 KEY_ALL_ACCESS,
933 &ObjectAttributes,
934 0,
935 NULL,
936 REG_OPTION_NON_VOLATILE,
937 NULL);
938 if (!NT_SUCCESS(Status))
939 {
940 DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status);
941 return Status;
942 }
943 ZwClose (KeyHandle);
944
945 /* Link 'CurrentControlSet' to 'ControlSet001' key */
946 RtlRosInitUnicodeStringFromLiteral (&ControlSetLinkName,
947 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
948 InitializeObjectAttributes (&ObjectAttributes,
949 &ControlSetLinkName,
950 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
951 NULL,
952 NULL);
953 Status = ZwCreateKey (&KeyHandle,
954 KEY_ALL_ACCESS | KEY_CREATE_LINK,
955 &ObjectAttributes,
956 0,
957 NULL,
958 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
959 NULL);
960 if (!NT_SUCCESS(Status))
961 {
962 DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status);
963 return Status;
964 }
965
966 RtlRosInitUnicodeStringFromLiteral (&ControlSetValueName,
967 L"SymbolicLinkValue");
968 Status = ZwSetValueKey (KeyHandle,
969 &ControlSetValueName,
970 0,
971 REG_LINK,
972 (PVOID)ControlSetKeyName.Buffer,
973 ControlSetKeyName.Length);
974 if (!NT_SUCCESS(Status))
975 {
976 DPRINT1 ("ZwSetValueKey() failed (Status %lx)\n", Status);
977 }
978 ZwClose (KeyHandle);
979
980 return STATUS_SUCCESS;
981 }
982
983
984 NTSTATUS
985 CmiInitHives(BOOLEAN SetupBoot)
986 {
987 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
988 OBJECT_ATTRIBUTES ObjectAttributes;
989 UNICODE_STRING FileName;
990 UNICODE_STRING KeyName;
991 UNICODE_STRING ValueName;
992 HANDLE KeyHandle;
993
994 NTSTATUS Status;
995
996 WCHAR ConfigPath[MAX_PATH];
997
998 ULONG BufferSize;
999 ULONG ResultSize;
1000 PWSTR EndPtr;
1001
1002
1003 DPRINT("CmiInitHives() called\n");
1004
1005 if (SetupBoot == TRUE)
1006 {
1007 RtlRosInitUnicodeStringFromLiteral(&KeyName,
1008 L"\\Registry\\Machine\\HARDWARE");
1009 InitializeObjectAttributes(&ObjectAttributes,
1010 &KeyName,
1011 OBJ_CASE_INSENSITIVE,
1012 NULL,
1013 NULL);
1014 Status = ZwOpenKey(&KeyHandle,
1015 KEY_ALL_ACCESS,
1016 &ObjectAttributes);
1017 if (!NT_SUCCESS(Status))
1018 {
1019 DPRINT1("ZwOpenKey() failed (Status %lx)\n", Status);
1020 return(Status);
1021 }
1022
1023 RtlRosInitUnicodeStringFromLiteral(&ValueName,
1024 L"InstallPath");
1025
1026 BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
1027 ValueInfo = ExAllocatePool(PagedPool,
1028 BufferSize);
1029 if (ValueInfo == NULL)
1030 {
1031 ZwClose(KeyHandle);
1032 return(STATUS_INSUFFICIENT_RESOURCES);
1033 }
1034
1035 Status = ZwQueryValueKey(KeyHandle,
1036 &ValueName,
1037 KeyValuePartialInformation,
1038 ValueInfo,
1039 BufferSize,
1040 &ResultSize);
1041 ZwClose(KeyHandle);
1042 if (!NT_SUCCESS(Status))
1043 {
1044 ExFreePool(ValueInfo);
1045 return(Status);
1046 }
1047
1048 RtlCopyMemory(ConfigPath,
1049 ValueInfo->Data,
1050 ValueInfo->DataLength);
1051 ConfigPath[ValueInfo->DataLength / sizeof(WCHAR)] = (WCHAR)0;
1052 ExFreePool(ValueInfo);
1053 }
1054 else
1055 {
1056 wcscpy(ConfigPath, L"\\SystemRoot");
1057 }
1058 wcscat(ConfigPath, L"\\system32\\config");
1059
1060 DPRINT("ConfigPath: %S\n", ConfigPath);
1061
1062 EndPtr = ConfigPath + wcslen(ConfigPath);
1063
1064 CmiDoVerify = TRUE;
1065
1066 /* FIXME: Save boot log */
1067
1068 /* Connect the SYSTEM hive only if it has been created */
1069 if (SetupBoot == TRUE)
1070 {
1071 wcscpy(EndPtr, REG_SYSTEM_FILE_NAME);
1072 DPRINT ("ConfigPath: %S\n", ConfigPath);
1073
1074 RtlInitUnicodeString (&KeyName,
1075 REG_SYSTEM_KEY_NAME);
1076 InitializeObjectAttributes(&ObjectAttributes,
1077 &KeyName,
1078 OBJ_CASE_INSENSITIVE,
1079 NULL,
1080 NULL);
1081
1082 RtlInitUnicodeString (&FileName,
1083 ConfigPath);
1084 Status = CmiLoadHive (&ObjectAttributes,
1085 &FileName,
1086 0);
1087 if (!NT_SUCCESS(Status))
1088 {
1089 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status);
1090 return Status;
1091 }
1092
1093 Status = CmiInitControlSetLink ();
1094 if (!NT_SUCCESS(Status))
1095 {
1096 DPRINT1("CmiInitControlSetLink() failed (Status %lx)\n", Status);
1097 return(Status);
1098 }
1099 }
1100
1101 /* Connect the SOFTWARE hive */
1102 wcscpy(EndPtr, REG_SOFTWARE_FILE_NAME);
1103 RtlInitUnicodeString (&FileName,
1104 ConfigPath);
1105 DPRINT ("ConfigPath: %S\n", ConfigPath);
1106
1107 RtlInitUnicodeString (&KeyName,
1108 REG_SOFTWARE_KEY_NAME);
1109 InitializeObjectAttributes(&ObjectAttributes,
1110 &KeyName,
1111 OBJ_CASE_INSENSITIVE,
1112 NULL,
1113 NULL);
1114
1115 Status = CmiLoadHive (&ObjectAttributes,
1116 &FileName,
1117 0);
1118 if (!NT_SUCCESS(Status))
1119 {
1120 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
1121 return(Status);
1122 }
1123
1124 /* Connect the SAM hive */
1125 wcscpy(EndPtr, REG_SAM_FILE_NAME);
1126 RtlInitUnicodeString (&FileName,
1127 ConfigPath);
1128 DPRINT ("ConfigPath: %S\n", ConfigPath);
1129
1130 RtlInitUnicodeString (&KeyName,
1131 REG_SAM_KEY_NAME);
1132 InitializeObjectAttributes(&ObjectAttributes,
1133 &KeyName,
1134 OBJ_CASE_INSENSITIVE,
1135 NULL,
1136 NULL);
1137 Status = CmiLoadHive (&ObjectAttributes,
1138 &FileName,
1139 0);
1140 if (!NT_SUCCESS(Status))
1141 {
1142 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
1143 return(Status);
1144 }
1145
1146 /* Connect the SECURITY hive */
1147 wcscpy(EndPtr, REG_SEC_FILE_NAME);
1148 RtlInitUnicodeString (&FileName,
1149 ConfigPath);
1150 DPRINT ("ConfigPath: %S\n", ConfigPath);
1151
1152 RtlInitUnicodeString (&KeyName,
1153 REG_SEC_KEY_NAME);
1154 InitializeObjectAttributes(&ObjectAttributes,
1155 &KeyName,
1156 OBJ_CASE_INSENSITIVE,
1157 NULL,
1158 NULL);
1159 Status = CmiLoadHive (&ObjectAttributes,
1160 &FileName,
1161 0);
1162 if (!NT_SUCCESS(Status))
1163 {
1164 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
1165 return(Status);
1166 }
1167
1168 /* Connect the DEFAULT hive */
1169 wcscpy(EndPtr, REG_DEFAULT_USER_FILE_NAME);
1170 RtlInitUnicodeString (&FileName,
1171 ConfigPath);
1172 DPRINT ("ConfigPath: %S\n", ConfigPath);
1173
1174 RtlInitUnicodeString (&KeyName,
1175 REG_DEFAULT_USER_KEY_NAME);
1176 InitializeObjectAttributes(&ObjectAttributes,
1177 &KeyName,
1178 OBJ_CASE_INSENSITIVE,
1179 NULL,
1180 NULL);
1181 Status = CmiLoadHive (&ObjectAttributes,
1182 &FileName,
1183 0);
1184 if (!NT_SUCCESS(Status))
1185 {
1186 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
1187 return(Status);
1188 }
1189
1190 // CmiCheckRegistry(TRUE);
1191
1192 /* Start automatic hive synchronization */
1193 KeInitializeDpc(&CmiHiveSyncDpc,
1194 CmiHiveSyncDpcRoutine,
1195 NULL);
1196 KeInitializeTimer(&CmiHiveSyncTimer);
1197 CmiHiveSyncEnabled = TRUE;
1198
1199 DPRINT("CmiInitHives() done\n");
1200
1201 return(STATUS_SUCCESS);
1202 }
1203
1204
1205 VOID
1206 CmShutdownRegistry(VOID)
1207 {
1208 PREGISTRY_HIVE Hive;
1209 PLIST_ENTRY Entry;
1210
1211 DPRINT("CmShutdownRegistry() called\n");
1212
1213 /* Stop automatic hive synchronization */
1214 CmiHiveSyncEnabled = FALSE;
1215
1216 /* Cancel pending hive synchronization */
1217 if (CmiHiveSyncPending == TRUE)
1218 {
1219 KeCancelTimer(&CmiHiveSyncTimer);
1220 CmiHiveSyncPending = FALSE;
1221 }
1222
1223 /* Acquire hive list lock exclusively */
1224 KeEnterCriticalRegion();
1225 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
1226
1227 Entry = CmiHiveListHead.Flink;
1228 while (Entry != &CmiHiveListHead)
1229 {
1230 Hive = CONTAINING_RECORD(Entry, REGISTRY_HIVE, HiveList);
1231
1232 if (!(IsNoFileHive(Hive) || IsNoSynchHive(Hive)))
1233 {
1234 /* Flush non-volatile hive */
1235 CmiFlushRegistryHive(Hive);
1236 }
1237
1238 Entry = Entry->Flink;
1239 }
1240
1241 /* Release hive list lock */
1242 ExReleaseResourceLite(&CmiRegistryLock);
1243 KeLeaveCriticalRegion();
1244
1245 DPRINT("CmShutdownRegistry() done\n");
1246 }
1247
1248
1249 VOID STDCALL
1250 CmiHiveSyncRoutine(PVOID DeferredContext)
1251 {
1252 PREGISTRY_HIVE Hive;
1253 PLIST_ENTRY Entry;
1254
1255 DPRINT("CmiHiveSyncRoutine() called\n");
1256
1257 CmiHiveSyncPending = FALSE;
1258
1259 /* Acquire hive list lock exclusively */
1260 KeEnterCriticalRegion();
1261 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
1262
1263 Entry = CmiHiveListHead.Flink;
1264 while (Entry != &CmiHiveListHead)
1265 {
1266 Hive = CONTAINING_RECORD(Entry, REGISTRY_HIVE, HiveList);
1267
1268 if (!(IsNoFileHive(Hive) || IsNoSynchHive(Hive)))
1269 {
1270 /* Flush non-volatile hive */
1271 CmiFlushRegistryHive(Hive);
1272 }
1273
1274 Entry = Entry->Flink;
1275 }
1276
1277 /* Release hive list lock */
1278 ExReleaseResourceLite(&CmiRegistryLock);
1279 KeLeaveCriticalRegion();
1280
1281 DPRINT("DeferredContext %x\n", DeferredContext);
1282 ExFreePool(DeferredContext);
1283
1284 DPRINT("CmiHiveSyncRoutine() done\n");
1285 }
1286
1287
1288 static VOID STDCALL
1289 CmiHiveSyncDpcRoutine(PKDPC Dpc,
1290 PVOID DeferredContext,
1291 PVOID SystemArgument1,
1292 PVOID SystemArgument2)
1293 {
1294 PWORK_QUEUE_ITEM WorkQueueItem;
1295
1296 WorkQueueItem = ExAllocatePool(NonPagedPool,
1297 sizeof(WORK_QUEUE_ITEM));
1298 if (WorkQueueItem == NULL)
1299 {
1300 DbgPrint("Failed to allocate work item\n");
1301 return;
1302 }
1303
1304 ExInitializeWorkItem(WorkQueueItem,
1305 CmiHiveSyncRoutine,
1306 WorkQueueItem);
1307
1308 DPRINT("DeferredContext %x\n", WorkQueueItem);
1309 ExQueueWorkItem(WorkQueueItem,
1310 CriticalWorkQueue);
1311 }
1312
1313
1314 VOID
1315 CmiSyncHives(VOID)
1316 {
1317 LARGE_INTEGER Timeout;
1318
1319 DPRINT("CmiSyncHives() called\n");
1320
1321 if (CmiHiveSyncEnabled == FALSE ||
1322 CmiHiveSyncPending == TRUE)
1323 return;
1324
1325 CmiHiveSyncPending = TRUE;
1326
1327 Timeout.QuadPart = (LONGLONG)-50000000;
1328 KeSetTimer(&CmiHiveSyncTimer,
1329 Timeout,
1330 &CmiHiveSyncDpc);
1331 }
1332
1333 /* EOF */