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