- reverted ObpCaptureObjectAttributes back to my old implementation (slightly modifie...
[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 = RTL_CONSTANT_STRING(
605 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
606 UNICODE_STRING LinkValue = RTL_CONSTANT_STRING(L"SymbolicLinkValue");
607 ULONG CurrentSet;
608 ULONG DefaultSet;
609 ULONG Failed;
610 ULONG LastKnownGood;
611 NTSTATUS Status;
612 OBJECT_ATTRIBUTES ObjectAttributes;
613 HANDLE KeyHandle;
614
615 DPRINT("CmiCreateCurrentControlSetLink() called\n");
616
617 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
618
619 QueryTable[0].Name = L"Current";
620 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
621 QueryTable[0].EntryContext = &CurrentSet;
622
623 QueryTable[1].Name = L"Default";
624 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
625 QueryTable[1].EntryContext = &DefaultSet;
626
627 QueryTable[2].Name = L"Failed";
628 QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
629 QueryTable[2].EntryContext = &Failed;
630
631 QueryTable[3].Name = L"LastKnownGood";
632 QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
633 QueryTable[3].EntryContext = &LastKnownGood;
634
635 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
636 L"\\Registry\\Machine\\SYSTEM\\Select",
637 QueryTable,
638 NULL,
639 NULL);
640 if (!NT_SUCCESS(Status))
641 {
642 return(Status);
643 }
644
645 DPRINT("Current %ld Default %ld\n", CurrentSet, DefaultSet);
646
647 swprintf(TargetNameBuffer,
648 L"\\Registry\\Machine\\SYSTEM\\ControlSet%03lu",
649 CurrentSet);
650 TargetNameLength = wcslen(TargetNameBuffer) * sizeof(WCHAR);
651
652 DPRINT("Link target '%S'\n", TargetNameBuffer);
653
654 InitializeObjectAttributes(&ObjectAttributes,
655 &LinkName,
656 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
657 NULL,
658 NULL);
659 Status = ZwCreateKey(&KeyHandle,
660 KEY_ALL_ACCESS | KEY_CREATE_LINK,
661 &ObjectAttributes,
662 0,
663 NULL,
664 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
665 NULL);
666 if (!NT_SUCCESS(Status))
667 {
668 DPRINT1("ZwCreateKey() failed (Status %lx)\n", Status);
669 return(Status);
670 }
671
672 Status = ZwSetValueKey(KeyHandle,
673 &LinkValue,
674 0,
675 REG_LINK,
676 (PVOID)TargetNameBuffer,
677 TargetNameLength);
678 if (!NT_SUCCESS(Status))
679 {
680 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
681 }
682
683 ZwClose(KeyHandle);
684
685 return Status;
686 }
687
688
689 NTSTATUS
690 CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
691 IN PREGISTRY_HIVE RegistryHive)
692 {
693 UNICODE_STRING RemainingPath;
694 PKEY_OBJECT ParentKey;
695 PKEY_OBJECT NewKey;
696 NTSTATUS Status;
697 PWSTR SubName;
698 UNICODE_STRING ObjectName;
699 OBJECT_CREATE_INFORMATION ObjectCreateInfo;
700
701 DPRINT("CmiConnectHive(%p, %p) called.\n",
702 KeyObjectAttributes, RegistryHive);
703
704 /* Capture all the info */
705 DPRINT("Capturing Create Info\n");
706 Status = ObpCaptureObjectAttributes(KeyObjectAttributes,
707 KernelMode,
708 PagedPool,
709 FALSE,
710 &ObjectCreateInfo,
711 &ObjectName);
712 if (!NT_SUCCESS(Status))
713 {
714 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status);
715 return Status;
716 }
717
718 Status = ObFindObject(&ObjectCreateInfo,
719 &ObjectName,
720 (PVOID*)&ParentKey,
721 &RemainingPath,
722 CmiKeyType);
723 ObpReleaseCapturedAttributes(&ObjectCreateInfo,
724 &ObjectName,
725 KernelMode,
726 FALSE);
727 if (!NT_SUCCESS(Status))
728 {
729 return Status;
730 }
731
732 DPRINT ("RemainingPath %wZ\n", &RemainingPath);
733
734 if ((RemainingPath.Buffer == NULL) || (RemainingPath.Buffer[0] == 0))
735 {
736 ObDereferenceObject (ParentKey);
737 RtlFreeUnicodeString(&RemainingPath);
738 return STATUS_OBJECT_NAME_COLLISION;
739 }
740
741 /* Ignore leading backslash */
742 SubName = RemainingPath.Buffer;
743 if (*SubName == L'\\')
744 SubName++;
745
746 /* If RemainingPath contains \ we must return error
747 because CmiConnectHive() can not create trees */
748 if (wcschr (SubName, L'\\') != NULL)
749 {
750 ObDereferenceObject (ParentKey);
751 RtlFreeUnicodeString(&RemainingPath);
752 return STATUS_OBJECT_NAME_NOT_FOUND;
753 }
754
755 DPRINT("RemainingPath %wZ ParentKey %p\n",
756 &RemainingPath, ParentKey);
757
758 Status = ObCreateObject(KernelMode,
759 CmiKeyType,
760 NULL,
761 KernelMode,
762 NULL,
763 sizeof(KEY_OBJECT),
764 0,
765 0,
766 (PVOID*)&NewKey);
767
768 if (!NT_SUCCESS(Status))
769 {
770 DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status);
771 ObDereferenceObject (ParentKey);
772 RtlFreeUnicodeString(&RemainingPath);
773 return Status;
774 }
775 DPRINT("Inserting Key into Object Tree\n");
776 Status = ObInsertObject((PVOID)NewKey,
777 NULL,
778 KEY_ALL_ACCESS,
779 0,
780 NULL,
781 NULL);
782 DPRINT("Status %x\n", Status);
783 NewKey->RegistryHive = RegistryHive;
784 NewKey->KeyCellOffset = RegistryHive->HiveHeader->RootKeyOffset;
785 NewKey->KeyCell = CmiGetCell (RegistryHive, NewKey->KeyCellOffset, NULL);
786 NewKey->Flags = 0;
787 NewKey->NumberOfSubKeys = 0;
788 InsertTailList(&CmiKeyObjectListHead, &NewKey->ListEntry);
789 if (NewKey->KeyCell->NumberOfSubKeys != 0)
790 {
791 NewKey->SubKeys = ExAllocatePool(NonPagedPool,
792 NewKey->KeyCell->NumberOfSubKeys * sizeof(ULONG));
793 if (NewKey->SubKeys == NULL)
794 {
795 DPRINT("ExAllocatePool() failed\n");
796 ObDereferenceObject (NewKey);
797 ObDereferenceObject (ParentKey);
798 RtlFreeUnicodeString(&RemainingPath);
799 return STATUS_INSUFFICIENT_RESOURCES;
800 }
801 }
802 else
803 {
804 NewKey->SubKeys = NULL;
805 }
806
807 DPRINT ("SubName %S\n", SubName);
808
809 Status = RtlpCreateUnicodeString(&NewKey->Name,
810 SubName, NonPagedPool);
811 RtlFreeUnicodeString(&RemainingPath);
812 if (!NT_SUCCESS(Status))
813 {
814 DPRINT1("RtlpCreateUnicodeString() failed (Status %lx)\n", Status);
815 if (NewKey->SubKeys != NULL)
816 {
817 ExFreePool (NewKey->SubKeys);
818 }
819 ObDereferenceObject (NewKey);
820 ObDereferenceObject (ParentKey);
821 return STATUS_INSUFFICIENT_RESOURCES;
822 }
823
824 CmiAddKeyToList (ParentKey, NewKey);
825 ObDereferenceObject (ParentKey);
826
827 VERIFY_KEY_OBJECT(NewKey);
828
829 /* Note: Do not dereference NewKey here! */
830
831 return STATUS_SUCCESS;
832 }
833
834
835 NTSTATUS
836 CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
837 OUT PREGISTRY_HIVE *RegistryHive)
838 {
839 PKEY_OBJECT KeyObject;
840 PREGISTRY_HIVE Hive;
841 HANDLE KeyHandle;
842 NTSTATUS Status;
843 PLIST_ENTRY CurrentEntry;
844 PKEY_OBJECT CurrentKey;
845
846 DPRINT("CmiDisconnectHive() called\n");
847
848 *RegistryHive = NULL;
849
850 Status = ObOpenObjectByName (KeyObjectAttributes,
851 CmiKeyType,
852 NULL,
853 KernelMode,
854 STANDARD_RIGHTS_REQUIRED,
855 NULL,
856 &KeyHandle);
857 if (!NT_SUCCESS(Status))
858 {
859 DPRINT1 ("ObOpenObjectByName() failed (Status %lx)\n", Status);
860 return Status;
861 }
862
863 Status = ObReferenceObjectByHandle (KeyHandle,
864 STANDARD_RIGHTS_REQUIRED,
865 CmiKeyType,
866 KernelMode,
867 (PVOID*)&KeyObject,
868 NULL);
869 ZwClose (KeyHandle);
870 if (!NT_SUCCESS(Status))
871 {
872 DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status);
873 return Status;
874 }
875 DPRINT ("KeyObject %p Hive %p\n", KeyObject, KeyObject->RegistryHive);
876
877 if (!(KeyObject->KeyCell->Flags & REG_KEY_ROOT_CELL))
878 {
879 DPRINT1 ("Key is not the Hive-Root-Key\n");
880 ObDereferenceObject (KeyObject);
881 return STATUS_INVALID_PARAMETER;
882 }
883
884 /* Acquire registry lock exclusively */
885 KeEnterCriticalRegion();
886 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
887
888 CurrentEntry = CmiKeyObjectListHead.Flink;
889 while (CurrentEntry != &CmiKeyObjectListHead)
890 {
891 CurrentKey = CONTAINING_RECORD(CurrentEntry, KEY_OBJECT, ListEntry);
892 if (1 == ObGetObjectPointerCount(CurrentKey) &&
893 !(CurrentKey->Flags & KO_MARKED_FOR_DELETE))
894 {
895 ObDereferenceObject(CurrentKey);
896 CurrentEntry = CmiKeyObjectListHead.Flink;
897 }
898 else
899 {
900 CurrentEntry = CurrentEntry->Flink;
901 }
902 }
903
904 if (ObGetObjectHandleCount (KeyObject) != 0 ||
905 ObGetObjectPointerCount (KeyObject) != 2)
906 {
907 DPRINT1 ("Hive is still in use (hc %d, rc %d)\n", ObGetObjectHandleCount (KeyObject), ObGetObjectPointerCount (KeyObject));
908 ObDereferenceObject (KeyObject);
909
910 /* Release registry lock */
911 ExReleaseResourceLite (&CmiRegistryLock);
912 KeLeaveCriticalRegion();
913
914 return STATUS_UNSUCCESSFUL;
915 }
916
917 Hive = KeyObject->RegistryHive;
918
919 /* Dereference KeyObject twice to delete it */
920 ObDereferenceObject (KeyObject);
921 ObDereferenceObject (KeyObject);
922
923 *RegistryHive = Hive;
924
925 /* Release registry lock */
926 ExReleaseResourceLite (&CmiRegistryLock);
927 KeLeaveCriticalRegion();
928
929 DPRINT ("CmiDisconnectHive() done\n");
930
931 return STATUS_SUCCESS;
932 }
933
934
935 static NTSTATUS
936 CmiInitControlSetLink (VOID)
937 {
938 OBJECT_ATTRIBUTES ObjectAttributes;
939 UNICODE_STRING ControlSetKeyName = RTL_CONSTANT_STRING(
940 L"\\Registry\\Machine\\SYSTEM\\ControlSet001");
941 UNICODE_STRING ControlSetLinkName = RTL_CONSTANT_STRING(
942 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
943 UNICODE_STRING ControlSetValueName = RTL_CONSTANT_STRING(L"SymbolicLinkValue");
944 HANDLE KeyHandle;
945 NTSTATUS Status;
946
947 /* Create 'ControlSet001' key */
948 InitializeObjectAttributes (&ObjectAttributes,
949 &ControlSetKeyName,
950 OBJ_CASE_INSENSITIVE,
951 NULL,
952 NULL);
953 Status = ZwCreateKey (&KeyHandle,
954 KEY_ALL_ACCESS,
955 &ObjectAttributes,
956 0,
957 NULL,
958 REG_OPTION_NON_VOLATILE,
959 NULL);
960 if (!NT_SUCCESS(Status))
961 {
962 DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status);
963 return Status;
964 }
965 ZwClose (KeyHandle);
966
967 /* Link 'CurrentControlSet' to 'ControlSet001' key */
968 InitializeObjectAttributes (&ObjectAttributes,
969 &ControlSetLinkName,
970 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
971 NULL,
972 NULL);
973 Status = ZwCreateKey (&KeyHandle,
974 KEY_ALL_ACCESS | KEY_CREATE_LINK,
975 &ObjectAttributes,
976 0,
977 NULL,
978 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
979 NULL);
980 if (!NT_SUCCESS(Status))
981 {
982 DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status);
983 return Status;
984 }
985
986 Status = ZwSetValueKey (KeyHandle,
987 &ControlSetValueName,
988 0,
989 REG_LINK,
990 (PVOID)ControlSetKeyName.Buffer,
991 ControlSetKeyName.Length);
992 if (!NT_SUCCESS(Status))
993 {
994 DPRINT1 ("ZwSetValueKey() failed (Status %lx)\n", Status);
995 }
996 ZwClose (KeyHandle);
997
998 return STATUS_SUCCESS;
999 }
1000
1001
1002 NTSTATUS
1003 CmiInitHives(BOOLEAN SetupBoot)
1004 {
1005 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
1006 OBJECT_ATTRIBUTES ObjectAttributes;
1007 UNICODE_STRING FileName;
1008 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE");
1009 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"InstallPath");
1010 HANDLE KeyHandle;
1011
1012 NTSTATUS Status;
1013
1014 WCHAR ConfigPath[MAX_PATH];
1015
1016 ULONG BufferSize;
1017 ULONG ResultSize;
1018 PWSTR EndPtr;
1019
1020
1021 DPRINT("CmiInitHives() called\n");
1022
1023 if (SetupBoot == TRUE)
1024 {
1025 InitializeObjectAttributes(&ObjectAttributes,
1026 &KeyName,
1027 OBJ_CASE_INSENSITIVE,
1028 NULL,
1029 NULL);
1030 Status = ZwOpenKey(&KeyHandle,
1031 KEY_ALL_ACCESS,
1032 &ObjectAttributes);
1033 if (!NT_SUCCESS(Status))
1034 {
1035 DPRINT1("ZwOpenKey() failed (Status %lx)\n", Status);
1036 return(Status);
1037 }
1038
1039 BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
1040 ValueInfo = ExAllocatePool(PagedPool,
1041 BufferSize);
1042 if (ValueInfo == NULL)
1043 {
1044 ZwClose(KeyHandle);
1045 return(STATUS_INSUFFICIENT_RESOURCES);
1046 }
1047
1048 Status = ZwQueryValueKey(KeyHandle,
1049 &ValueName,
1050 KeyValuePartialInformation,
1051 ValueInfo,
1052 BufferSize,
1053 &ResultSize);
1054 ZwClose(KeyHandle);
1055 if (!NT_SUCCESS(Status))
1056 {
1057 ExFreePool(ValueInfo);
1058 return(Status);
1059 }
1060
1061 RtlCopyMemory(ConfigPath,
1062 ValueInfo->Data,
1063 ValueInfo->DataLength);
1064 ConfigPath[ValueInfo->DataLength / sizeof(WCHAR)] = (WCHAR)0;
1065 ExFreePool(ValueInfo);
1066 }
1067 else
1068 {
1069 wcscpy(ConfigPath, L"\\SystemRoot");
1070 }
1071 wcscat(ConfigPath, L"\\system32\\config");
1072
1073 DPRINT("ConfigPath: %S\n", ConfigPath);
1074
1075 EndPtr = ConfigPath + wcslen(ConfigPath);
1076
1077 CmiDoVerify = TRUE;
1078
1079 /* FIXME: Save boot log */
1080
1081 /* Connect the SYSTEM hive only if it has been created */
1082 if (SetupBoot == TRUE)
1083 {
1084 wcscpy(EndPtr, REG_SYSTEM_FILE_NAME);
1085 DPRINT ("ConfigPath: %S\n", ConfigPath);
1086
1087 RtlInitUnicodeString (&KeyName,
1088 REG_SYSTEM_KEY_NAME);
1089 InitializeObjectAttributes(&ObjectAttributes,
1090 &KeyName,
1091 OBJ_CASE_INSENSITIVE,
1092 NULL,
1093 NULL);
1094
1095 RtlInitUnicodeString (&FileName,
1096 ConfigPath);
1097 Status = CmiLoadHive (&ObjectAttributes,
1098 &FileName,
1099 0);
1100 if (!NT_SUCCESS(Status))
1101 {
1102 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status);
1103 return Status;
1104 }
1105
1106 Status = CmiInitControlSetLink ();
1107 if (!NT_SUCCESS(Status))
1108 {
1109 DPRINT1("CmiInitControlSetLink() failed (Status %lx)\n", Status);
1110 return(Status);
1111 }
1112 }
1113
1114 /* Connect the SOFTWARE hive */
1115 wcscpy(EndPtr, REG_SOFTWARE_FILE_NAME);
1116 RtlInitUnicodeString (&FileName,
1117 ConfigPath);
1118 DPRINT ("ConfigPath: %S\n", ConfigPath);
1119
1120 RtlInitUnicodeString (&KeyName,
1121 REG_SOFTWARE_KEY_NAME);
1122 InitializeObjectAttributes(&ObjectAttributes,
1123 &KeyName,
1124 OBJ_CASE_INSENSITIVE,
1125 NULL,
1126 NULL);
1127
1128 Status = CmiLoadHive (&ObjectAttributes,
1129 &FileName,
1130 0);
1131 if (!NT_SUCCESS(Status))
1132 {
1133 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
1134 return(Status);
1135 }
1136
1137 /* Connect the SAM hive */
1138 wcscpy(EndPtr, REG_SAM_FILE_NAME);
1139 RtlInitUnicodeString (&FileName,
1140 ConfigPath);
1141 DPRINT ("ConfigPath: %S\n", ConfigPath);
1142
1143 RtlInitUnicodeString (&KeyName,
1144 REG_SAM_KEY_NAME);
1145 InitializeObjectAttributes(&ObjectAttributes,
1146 &KeyName,
1147 OBJ_CASE_INSENSITIVE,
1148 NULL,
1149 NULL);
1150 Status = CmiLoadHive (&ObjectAttributes,
1151 &FileName,
1152 0);
1153 if (!NT_SUCCESS(Status))
1154 {
1155 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
1156 return(Status);
1157 }
1158
1159 /* Connect the SECURITY hive */
1160 wcscpy(EndPtr, REG_SEC_FILE_NAME);
1161 RtlInitUnicodeString (&FileName,
1162 ConfigPath);
1163 DPRINT ("ConfigPath: %S\n", ConfigPath);
1164
1165 RtlInitUnicodeString (&KeyName,
1166 REG_SEC_KEY_NAME);
1167 InitializeObjectAttributes(&ObjectAttributes,
1168 &KeyName,
1169 OBJ_CASE_INSENSITIVE,
1170 NULL,
1171 NULL);
1172 Status = CmiLoadHive (&ObjectAttributes,
1173 &FileName,
1174 0);
1175 if (!NT_SUCCESS(Status))
1176 {
1177 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
1178 return(Status);
1179 }
1180
1181 /* Connect the DEFAULT hive */
1182 wcscpy(EndPtr, REG_DEFAULT_USER_FILE_NAME);
1183 RtlInitUnicodeString (&FileName,
1184 ConfigPath);
1185 DPRINT ("ConfigPath: %S\n", ConfigPath);
1186
1187 RtlInitUnicodeString (&KeyName,
1188 REG_DEFAULT_USER_KEY_NAME);
1189 InitializeObjectAttributes(&ObjectAttributes,
1190 &KeyName,
1191 OBJ_CASE_INSENSITIVE,
1192 NULL,
1193 NULL);
1194 Status = CmiLoadHive (&ObjectAttributes,
1195 &FileName,
1196 0);
1197 if (!NT_SUCCESS(Status))
1198 {
1199 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
1200 return(Status);
1201 }
1202
1203 // CmiCheckRegistry(TRUE);
1204
1205 /* Start automatic hive synchronization */
1206 KeInitializeDpc(&CmiHiveSyncDpc,
1207 CmiHiveSyncDpcRoutine,
1208 NULL);
1209 KeInitializeTimer(&CmiHiveSyncTimer);
1210 CmiHiveSyncEnabled = TRUE;
1211
1212 DPRINT("CmiInitHives() done\n");
1213
1214 return(STATUS_SUCCESS);
1215 }
1216
1217
1218 VOID
1219 CmShutdownRegistry(VOID)
1220 {
1221 PREGISTRY_HIVE Hive;
1222 PLIST_ENTRY Entry;
1223
1224 DPRINT("CmShutdownRegistry() called\n");
1225
1226 /* Stop automatic hive synchronization */
1227 CmiHiveSyncEnabled = FALSE;
1228
1229 /* Cancel pending hive synchronization */
1230 if (CmiHiveSyncPending == TRUE)
1231 {
1232 KeCancelTimer(&CmiHiveSyncTimer);
1233 CmiHiveSyncPending = FALSE;
1234 }
1235
1236 /* Acquire hive list lock exclusively */
1237 KeEnterCriticalRegion();
1238 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
1239
1240 Entry = CmiHiveListHead.Flink;
1241 while (Entry != &CmiHiveListHead)
1242 {
1243 Hive = CONTAINING_RECORD(Entry, REGISTRY_HIVE, HiveList);
1244
1245 if (!(IsNoFileHive(Hive) || IsNoSynchHive(Hive)))
1246 {
1247 /* Flush non-volatile hive */
1248 CmiFlushRegistryHive(Hive);
1249 }
1250
1251 Entry = Entry->Flink;
1252 }
1253
1254 /* Release hive list lock */
1255 ExReleaseResourceLite(&CmiRegistryLock);
1256 KeLeaveCriticalRegion();
1257
1258 DPRINT("CmShutdownRegistry() done\n");
1259 }
1260
1261
1262 VOID STDCALL
1263 CmiHiveSyncRoutine(PVOID DeferredContext)
1264 {
1265 PREGISTRY_HIVE Hive;
1266 PLIST_ENTRY Entry;
1267
1268 DPRINT("CmiHiveSyncRoutine() called\n");
1269
1270 CmiHiveSyncPending = FALSE;
1271
1272 /* Acquire hive list lock exclusively */
1273 KeEnterCriticalRegion();
1274 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
1275
1276 Entry = CmiHiveListHead.Flink;
1277 while (Entry != &CmiHiveListHead)
1278 {
1279 Hive = CONTAINING_RECORD(Entry, REGISTRY_HIVE, HiveList);
1280
1281 if (!(IsNoFileHive(Hive) || IsNoSynchHive(Hive)))
1282 {
1283 /* Flush non-volatile hive */
1284 CmiFlushRegistryHive(Hive);
1285 }
1286
1287 Entry = Entry->Flink;
1288 }
1289
1290 /* Release hive list lock */
1291 ExReleaseResourceLite(&CmiRegistryLock);
1292 KeLeaveCriticalRegion();
1293
1294 DPRINT("DeferredContext 0x%p\n", DeferredContext);
1295 ExFreePool(DeferredContext);
1296
1297 DPRINT("CmiHiveSyncRoutine() done\n");
1298 }
1299
1300
1301 static VOID STDCALL
1302 CmiHiveSyncDpcRoutine(PKDPC Dpc,
1303 PVOID DeferredContext,
1304 PVOID SystemArgument1,
1305 PVOID SystemArgument2)
1306 {
1307 PWORK_QUEUE_ITEM WorkQueueItem;
1308
1309 WorkQueueItem = ExAllocatePool(NonPagedPool,
1310 sizeof(WORK_QUEUE_ITEM));
1311 if (WorkQueueItem == NULL)
1312 {
1313 DbgPrint("Failed to allocate work item\n");
1314 return;
1315 }
1316
1317 ExInitializeWorkItem(WorkQueueItem,
1318 CmiHiveSyncRoutine,
1319 WorkQueueItem);
1320
1321 DPRINT("DeferredContext 0x%p\n", WorkQueueItem);
1322 ExQueueWorkItem(WorkQueueItem,
1323 CriticalWorkQueue);
1324 }
1325
1326
1327 VOID
1328 CmiSyncHives(VOID)
1329 {
1330 LARGE_INTEGER Timeout;
1331
1332 DPRINT("CmiSyncHives() called\n");
1333
1334 if (CmiHiveSyncEnabled == FALSE ||
1335 CmiHiveSyncPending == TRUE)
1336 return;
1337
1338 CmiHiveSyncPending = TRUE;
1339
1340 Timeout.QuadPart = (LONGLONG)-50000000;
1341 KeSetTimer(&CmiHiveSyncTimer,
1342 Timeout,
1343 &CmiHiveSyncDpc);
1344 }
1345
1346 /* EOF */