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