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