eef32478e070ab15a975365736d61494f2c54df1
[reactos.git] / reactos / ntoskrnl / cm / registry.c
1 /* $Id: registry.c,v 1.126 2004/09/13 11:46:07 ekohl Exp $
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 ERESOURCE CmiHiveListLock;
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 = NtEnumerateKey(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 = NtOpenKey(&SubKey,
114 KEY_ALL_ACCESS,
115 &ObjectAttributes);
116
117 assert(NT_SUCCESS(Status));
118
119 CmiCheckKey(Verbose, SubKey);
120
121 NtClose(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 = NtEnumerateValueKey(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 = NtOpenKey(&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 NtClose(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->MaxObjects = LONG_MAX;
262 CmiKeyType->MaxHandles = LONG_MAX;
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 ExInitializeResourceLite(&CmiHiveListLock);
283
284 /* Build volatile registry store */
285 Status = CmiCreateVolatileHive (&CmiVolatileHive);
286 assert(NT_SUCCESS(Status));
287
288 /* Create '\Registry' key. */
289 RtlInitUnicodeString(&KeyName, REG_ROOT_KEY_NAME);
290 InitializeObjectAttributes(&ObjectAttributes, &KeyName, 0, NULL, NULL);
291 Status = ObCreateObject(KernelMode,
292 CmiKeyType,
293 &ObjectAttributes,
294 KernelMode,
295 NULL,
296 sizeof(KEY_OBJECT),
297 0,
298 0,
299 (PVOID *) &RootKey);
300 assert(NT_SUCCESS(Status));
301 Status = ObInsertObject(RootKey,
302 NULL,
303 STANDARD_RIGHTS_REQUIRED,
304 0,
305 NULL,
306 &RootKeyHandle);
307 assert(NT_SUCCESS(Status));
308 RootKey->RegistryHive = CmiVolatileHive;
309 RootKey->KeyCellOffset = CmiVolatileHive->HiveHeader->RootKeyOffset;
310 RootKey->KeyCell = CmiGetCell (CmiVolatileHive, RootKey->KeyCellOffset, NULL);
311 RootKey->ParentKey = RootKey;
312 RootKey->Flags = 0;
313 RootKey->NumberOfSubKeys = 0;
314 RootKey->SubKeys = NULL;
315 RootKey->SizeOfSubKeys = 0;
316 Status = RtlCreateUnicodeString(&RootKey->Name, L"Registry");
317 assert(NT_SUCCESS(Status));
318
319 #if 0
320 Status = CmiAllocateCell(CmiVolatileHive,
321 0x10, //LONG CellSize,
322 (PVOID *)&RootSecurityCell,
323 &RootKey->KeyCell->SecurityKeyOffset);
324 assert(NT_SUCCESS(Status));
325
326 /* Copy the security descriptor */
327
328 CmiVolatileHive->RootSecurityCell = RootSecurityCell;
329 #endif
330
331 KeInitializeSpinLock(&CmiKeyListLock);
332
333 /* Create '\Registry\Machine' key. */
334 RtlInitUnicodeString(&KeyName,
335 L"Machine");
336 InitializeObjectAttributes(&ObjectAttributes,
337 &KeyName,
338 0,
339 RootKeyHandle,
340 NULL);
341 Status = NtCreateKey(&KeyHandle,
342 STANDARD_RIGHTS_REQUIRED,
343 &ObjectAttributes,
344 0,
345 NULL,
346 REG_OPTION_VOLATILE,
347 NULL);
348 assert(NT_SUCCESS(Status));
349
350 /* Create '\Registry\User' key. */
351 RtlInitUnicodeString(&KeyName,
352 L"User");
353 InitializeObjectAttributes(&ObjectAttributes,
354 &KeyName,
355 0,
356 RootKeyHandle,
357 NULL);
358 Status = NtCreateKey(&KeyHandle,
359 STANDARD_RIGHTS_REQUIRED,
360 &ObjectAttributes,
361 0,
362 NULL,
363 REG_OPTION_VOLATILE,
364 NULL);
365 assert(NT_SUCCESS(Status));
366 }
367
368
369 VOID INIT_FUNCTION
370 CmInit2(PCHAR CommandLine)
371 {
372 ULONG PiceStart = 4;
373 BOOLEAN MiniNT = FALSE;
374 PWCHAR SystemBootDevice;
375 PWCHAR SystemStartOptions;
376 ULONG Position;
377 NTSTATUS Status;
378
379 /* Create the 'CurrentControlSet' link. */
380 Status = CmiCreateCurrentControlSetLink();
381 if (!NT_SUCCESS(Status))
382 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
383
384 /*
385 * Parse the system boot device.
386 */
387 Position = 0;
388 SystemBootDevice = ExAllocatePool(PagedPool,
389 (strlen(CommandLine) + 1) * sizeof(WCHAR));
390 if (SystemBootDevice == NULL)
391 {
392 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
393 }
394
395 while (*CommandLine != 0 && *CommandLine != ' ')
396 SystemBootDevice[Position++] = *(CommandLine++);
397 SystemBootDevice[Position++] = 0;
398
399 /*
400 * Write the system boot device to registry.
401 */
402 Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
403 L"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
404 L"SystemBootDevice",
405 REG_SZ,
406 SystemBootDevice,
407 Position * sizeof(WCHAR));
408 if (!NT_SUCCESS(Status))
409 {
410 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
411 }
412
413 /*
414 * Parse the system start options.
415 */
416 Position = 0;
417 SystemStartOptions = SystemBootDevice;
418 while ((CommandLine = strchr(CommandLine, '/')) != NULL)
419 {
420 /* Skip over the slash */
421 CommandLine++;
422
423 /* Special options */
424 if (!_strnicmp(CommandLine, "MININT", 6))
425 MiniNT = TRUE;
426 else if (!_strnicmp(CommandLine, "DEBUGPORT=PICE", 14))
427 PiceStart = 1;
428
429 /* Add a space between the options */
430 if (Position != 0)
431 SystemStartOptions[Position++] = L' ';
432
433 /* Copy the command */
434 while (*CommandLine != 0 && *CommandLine != ' ')
435 SystemStartOptions[Position++] = *(CommandLine++);
436 }
437 SystemStartOptions[Position++] = 0;
438
439 /*
440 * Write the system start options to registry.
441 */
442 Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
443 L"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
444 L"SystemStartOptions",
445 REG_SZ,
446 SystemStartOptions,
447 Position * sizeof(WCHAR));
448 if (!NT_SUCCESS(Status))
449 {
450 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
451 }
452
453 /*
454 * Create a CurrentControlSet\Control\MiniNT key that is used
455 * to detect WinPE/MiniNT systems.
456 */
457 if (MiniNT)
458 {
459 Status = RtlCreateRegistryKey(RTL_REGISTRY_CONTROL, L"MiniNT");
460 if (!NT_SUCCESS(Status))
461 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
462 }
463
464 /* Set PICE 'Start' value to 1, if PICE debugging is enabled */
465 Status = RtlWriteRegistryValue(
466 RTL_REGISTRY_SERVICES,
467 L"\\Pice",
468 L"Start",
469 REG_DWORD,
470 &PiceStart,
471 sizeof(ULONG));
472 if (!NT_SUCCESS(Status))
473 KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
474
475 ExFreePool(SystemBootDevice);
476 }
477
478
479 static NTSTATUS
480 CmiCreateCurrentControlSetLink(VOID)
481 {
482 RTL_QUERY_REGISTRY_TABLE QueryTable[5];
483 WCHAR TargetNameBuffer[80];
484 ULONG TargetNameLength;
485 UNICODE_STRING LinkName;
486 UNICODE_STRING LinkValue;
487 ULONG CurrentSet;
488 ULONG DefaultSet;
489 ULONG Failed;
490 ULONG LastKnownGood;
491 NTSTATUS Status;
492 OBJECT_ATTRIBUTES ObjectAttributes;
493 HANDLE KeyHandle;
494
495 DPRINT("CmiCreateCurrentControlSetLink() called\n");
496
497 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
498
499 QueryTable[0].Name = L"Current";
500 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
501 QueryTable[0].EntryContext = &CurrentSet;
502
503 QueryTable[1].Name = L"Default";
504 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
505 QueryTable[1].EntryContext = &DefaultSet;
506
507 QueryTable[2].Name = L"Failed";
508 QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
509 QueryTable[2].EntryContext = &Failed;
510
511 QueryTable[3].Name = L"LastKnownGood";
512 QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
513 QueryTable[3].EntryContext = &LastKnownGood;
514
515 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
516 L"\\Registry\\Machine\\SYSTEM\\Select",
517 QueryTable,
518 NULL,
519 NULL);
520 if (!NT_SUCCESS(Status))
521 {
522 return(Status);
523 }
524
525 DPRINT("Current %ld Default %ld\n", CurrentSet, DefaultSet);
526
527 swprintf(TargetNameBuffer,
528 L"\\Registry\\Machine\\SYSTEM\\ControlSet%03lu",
529 CurrentSet);
530 TargetNameLength = wcslen(TargetNameBuffer) * sizeof(WCHAR);
531
532 DPRINT("Link target '%S'\n", TargetNameBuffer);
533
534 RtlRosInitUnicodeStringFromLiteral(&LinkName,
535 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
536 InitializeObjectAttributes(&ObjectAttributes,
537 &LinkName,
538 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
539 NULL,
540 NULL);
541 Status = NtCreateKey(&KeyHandle,
542 KEY_ALL_ACCESS | KEY_CREATE_LINK,
543 &ObjectAttributes,
544 0,
545 NULL,
546 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
547 NULL);
548 if (!NT_SUCCESS(Status))
549 {
550 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
551 return(Status);
552 }
553
554 RtlRosInitUnicodeStringFromLiteral(&LinkValue,
555 L"SymbolicLinkValue");
556 Status = NtSetValueKey(KeyHandle,
557 &LinkValue,
558 0,
559 REG_LINK,
560 (PVOID)TargetNameBuffer,
561 TargetNameLength);
562 if (!NT_SUCCESS(Status))
563 {
564 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
565 }
566
567 NtClose(KeyHandle);
568
569 return Status;
570 }
571
572
573 NTSTATUS
574 CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
575 IN PREGISTRY_HIVE RegistryHive)
576 {
577 UNICODE_STRING RemainingPath;
578 PKEY_OBJECT ParentKey;
579 PKEY_OBJECT NewKey;
580 NTSTATUS Status;
581 PWSTR SubName;
582
583 DPRINT("CmiConnectHive(%p, %p) called.\n",
584 KeyObjectAttributes, RegistryHive);
585
586 Status = ObFindObject(KeyObjectAttributes,
587 (PVOID*)&ParentKey,
588 &RemainingPath,
589 CmiKeyType);
590 if (!NT_SUCCESS(Status))
591 {
592 return Status;
593 }
594
595 DPRINT ("RemainingPath %wZ\n", &RemainingPath);
596
597 if ((RemainingPath.Buffer == NULL) || (RemainingPath.Buffer[0] == 0))
598 {
599 ObDereferenceObject (ParentKey);
600 RtlFreeUnicodeString(&RemainingPath);
601 return STATUS_OBJECT_NAME_COLLISION;
602 }
603
604 /* Ignore leading backslash */
605 SubName = RemainingPath.Buffer;
606 if (*SubName == L'\\')
607 SubName++;
608
609 /* If RemainingPath contains \ we must return error
610 because CmiConnectHive() can not create trees */
611 if (wcschr (SubName, L'\\') != NULL)
612 {
613 ObDereferenceObject (ParentKey);
614 RtlFreeUnicodeString(&RemainingPath);
615 return STATUS_OBJECT_NAME_NOT_FOUND;
616 }
617
618 DPRINT("RemainingPath %wZ ParentKey %p\n",
619 &RemainingPath, ParentKey);
620
621 Status = ObCreateObject(KernelMode,
622 CmiKeyType,
623 NULL,
624 KernelMode,
625 NULL,
626 sizeof(KEY_OBJECT),
627 0,
628 0,
629 (PVOID*)&NewKey);
630 if (!NT_SUCCESS(Status))
631 {
632 DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status);
633 ObDereferenceObject (ParentKey);
634 RtlFreeUnicodeString(&RemainingPath);
635 return Status;
636 }
637
638 NewKey->RegistryHive = RegistryHive;
639 NewKey->KeyCellOffset = RegistryHive->HiveHeader->RootKeyOffset;
640 NewKey->KeyCell = CmiGetCell (RegistryHive, NewKey->KeyCellOffset, NULL);
641 NewKey->Flags = 0;
642 NewKey->NumberOfSubKeys = 0;
643 if (NewKey->KeyCell->NumberOfSubKeys != 0)
644 {
645 NewKey->SubKeys = ExAllocatePool(PagedPool,
646 NewKey->KeyCell->NumberOfSubKeys * sizeof(ULONG));
647 if (NewKey->SubKeys == NULL)
648 {
649 DPRINT("ExAllocatePool() failed\n");
650 ObDereferenceObject (NewKey);
651 ObDereferenceObject (ParentKey);
652 RtlFreeUnicodeString(&RemainingPath);
653 return STATUS_INSUFFICIENT_RESOURCES;
654 }
655 }
656 else
657 {
658 NewKey->SubKeys = NULL;
659 }
660
661 DPRINT ("SubName %S\n", SubName);
662
663 Status = RtlCreateUnicodeString(&NewKey->Name,
664 SubName);
665 RtlFreeUnicodeString(&RemainingPath);
666 if (!NT_SUCCESS(Status))
667 {
668 DPRINT1("RtlCreateUnicodeString() failed (Status %lx)\n", Status);
669 if (NewKey->SubKeys != NULL)
670 {
671 ExFreePool (NewKey->SubKeys);
672 }
673 ObDereferenceObject (NewKey);
674 ObDereferenceObject (ParentKey);
675 return STATUS_INSUFFICIENT_RESOURCES;
676 }
677
678 CmiAddKeyToList (ParentKey, NewKey);
679 ObDereferenceObject (ParentKey);
680
681 VERIFY_KEY_OBJECT(NewKey);
682
683 /* Note: Do not dereference NewKey here! */
684
685 return STATUS_SUCCESS;
686 }
687
688
689 NTSTATUS
690 CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
691 OUT PREGISTRY_HIVE *RegistryHive)
692 {
693 PKEY_OBJECT KeyObject;
694 PREGISTRY_HIVE Hive;
695 HANDLE KeyHandle;
696 NTSTATUS Status;
697
698 DPRINT("CmiDisconnectHive() called\n");
699
700 *RegistryHive = NULL;
701
702 Status = ObOpenObjectByName (KeyObjectAttributes,
703 CmiKeyType,
704 NULL,
705 KernelMode,
706 STANDARD_RIGHTS_REQUIRED,
707 NULL,
708 &KeyHandle);
709 if (!NT_SUCCESS(Status))
710 {
711 DPRINT1 ("ObOpenObjectByName() failed (Status %lx)\n", Status);
712 return Status;
713 }
714
715 Status = ObReferenceObjectByHandle (KeyHandle,
716 STANDARD_RIGHTS_REQUIRED,
717 CmiKeyType,
718 KernelMode,
719 (PVOID*)&KeyObject,
720 NULL);
721 NtClose (KeyHandle);
722 if (!NT_SUCCESS(Status))
723 {
724 DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status);
725 return Status;
726 }
727 DPRINT ("KeyObject %p Hive %p\n", KeyObject, KeyObject->RegistryHive);
728
729 if (!(KeyObject->KeyCell->Flags & REG_KEY_ROOT_CELL))
730 {
731 DPRINT1 ("Key is not the Hive-Root-Key\n");
732 ObDereferenceObject (KeyObject);
733 return STATUS_INVALID_PARAMETER;
734 }
735
736 if (ObGetObjectHandleCount (KeyObject) != 0 ||
737 ObGetObjectPointerCount (KeyObject) != 2)
738 {
739 DPRINT1 ("Hive is still in use\n");
740 ObDereferenceObject (KeyObject);
741 return STATUS_UNSUCCESSFUL;
742 }
743
744 Hive = KeyObject->RegistryHive;
745
746 /* Dereference KeyObject twice to delete it */
747 ObDereferenceObject (KeyObject);
748 ObDereferenceObject (KeyObject);
749
750 *RegistryHive = Hive;
751
752 DPRINT ("CmiDisconnectHive() done\n");
753
754 return STATUS_SUCCESS;
755 }
756
757
758 static NTSTATUS
759 CmiInitControlSetLink (VOID)
760 {
761 OBJECT_ATTRIBUTES ObjectAttributes;
762 UNICODE_STRING ControlSetKeyName;
763 UNICODE_STRING ControlSetLinkName;
764 UNICODE_STRING ControlSetValueName;
765 HANDLE KeyHandle;
766 NTSTATUS Status;
767
768 /* Create 'ControlSet001' key */
769 RtlRosInitUnicodeStringFromLiteral (&ControlSetKeyName,
770 L"\\Registry\\Machine\\SYSTEM\\ControlSet001");
771 InitializeObjectAttributes (&ObjectAttributes,
772 &ControlSetKeyName,
773 OBJ_CASE_INSENSITIVE,
774 NULL,
775 NULL);
776 Status = NtCreateKey (&KeyHandle,
777 KEY_ALL_ACCESS,
778 &ObjectAttributes,
779 0,
780 NULL,
781 REG_OPTION_NON_VOLATILE,
782 NULL);
783 if (!NT_SUCCESS(Status))
784 {
785 DPRINT1 ("NtCreateKey() failed (Status %lx)\n", Status);
786 return Status;
787 }
788 NtClose (KeyHandle);
789
790 /* Link 'CurrentControlSet' to 'ControlSet001' key */
791 RtlRosInitUnicodeStringFromLiteral (&ControlSetLinkName,
792 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
793 InitializeObjectAttributes (&ObjectAttributes,
794 &ControlSetLinkName,
795 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
796 NULL,
797 NULL);
798 Status = NtCreateKey (&KeyHandle,
799 KEY_ALL_ACCESS | KEY_CREATE_LINK,
800 &ObjectAttributes,
801 0,
802 NULL,
803 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
804 NULL);
805 if (!NT_SUCCESS(Status))
806 {
807 DPRINT1 ("NtCreateKey() failed (Status %lx)\n", Status);
808 return Status;
809 }
810
811 RtlRosInitUnicodeStringFromLiteral (&ControlSetValueName,
812 L"SymbolicLinkValue");
813 Status = NtSetValueKey (KeyHandle,
814 &ControlSetValueName,
815 0,
816 REG_LINK,
817 (PVOID)ControlSetKeyName.Buffer,
818 ControlSetKeyName.Length);
819 if (!NT_SUCCESS(Status))
820 {
821 DPRINT1 ("NtSetValueKey() failed (Status %lx)\n", Status);
822 }
823 NtClose (KeyHandle);
824
825 return STATUS_SUCCESS;
826 }
827
828
829 NTSTATUS
830 CmiInitHives(BOOLEAN SetupBoot)
831 {
832 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
833 OBJECT_ATTRIBUTES ObjectAttributes;
834 UNICODE_STRING FileName;
835 UNICODE_STRING KeyName;
836 UNICODE_STRING ValueName;
837 HANDLE KeyHandle;
838
839 NTSTATUS Status;
840
841 WCHAR ConfigPath[MAX_PATH];
842
843 ULONG BufferSize;
844 ULONG ResultSize;
845 PWSTR EndPtr;
846
847
848 DPRINT("CmiInitHives() called\n");
849
850 if (SetupBoot == TRUE)
851 {
852 RtlRosInitUnicodeStringFromLiteral(&KeyName,
853 L"\\Registry\\Machine\\HARDWARE");
854 InitializeObjectAttributes(&ObjectAttributes,
855 &KeyName,
856 OBJ_CASE_INSENSITIVE,
857 NULL,
858 NULL);
859 Status = NtOpenKey(&KeyHandle,
860 KEY_ALL_ACCESS,
861 &ObjectAttributes);
862 if (!NT_SUCCESS(Status))
863 {
864 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
865 return(Status);
866 }
867
868 RtlRosInitUnicodeStringFromLiteral(&ValueName,
869 L"InstallPath");
870
871 BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
872 ValueInfo = ExAllocatePool(PagedPool,
873 BufferSize);
874 if (ValueInfo == NULL)
875 {
876 NtClose(KeyHandle);
877 return(STATUS_INSUFFICIENT_RESOURCES);
878 }
879
880 Status = NtQueryValueKey(KeyHandle,
881 &ValueName,
882 KeyValuePartialInformation,
883 ValueInfo,
884 BufferSize,
885 &ResultSize);
886 NtClose(KeyHandle);
887 if (!NT_SUCCESS(Status))
888 {
889 ExFreePool(ValueInfo);
890 return(Status);
891 }
892
893 RtlCopyMemory(ConfigPath,
894 ValueInfo->Data,
895 ValueInfo->DataLength);
896 ConfigPath[ValueInfo->DataLength / sizeof(WCHAR)] = (WCHAR)0;
897 ExFreePool(ValueInfo);
898 }
899 else
900 {
901 wcscpy(ConfigPath, L"\\SystemRoot");
902 }
903 wcscat(ConfigPath, L"\\system32\\config");
904
905 DPRINT("ConfigPath: %S\n", ConfigPath);
906
907 EndPtr = ConfigPath + wcslen(ConfigPath);
908
909 CmiDoVerify = TRUE;
910
911 /* FIXME: Save boot log */
912
913 /* Connect the SYSTEM hive only if it has been created */
914 if (SetupBoot == TRUE)
915 {
916 wcscpy(EndPtr, REG_SYSTEM_FILE_NAME);
917 DPRINT ("ConfigPath: %S\n", ConfigPath);
918
919 RtlInitUnicodeString (&KeyName,
920 REG_SYSTEM_KEY_NAME);
921 InitializeObjectAttributes(&ObjectAttributes,
922 &KeyName,
923 OBJ_CASE_INSENSITIVE,
924 NULL,
925 NULL);
926
927 RtlInitUnicodeString (&FileName,
928 ConfigPath);
929 Status = CmiLoadHive (&ObjectAttributes,
930 &FileName,
931 0);
932 if (!NT_SUCCESS(Status))
933 {
934 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status);
935 return Status;
936 }
937
938 Status = CmiInitControlSetLink ();
939 if (!NT_SUCCESS(Status))
940 {
941 DPRINT1("CmiInitControlSetLink() failed (Status %lx)\n", Status);
942 return(Status);
943 }
944 }
945
946 /* Connect the SOFTWARE hive */
947 wcscpy(EndPtr, REG_SOFTWARE_FILE_NAME);
948 RtlInitUnicodeString (&FileName,
949 ConfigPath);
950 DPRINT ("ConfigPath: %S\n", ConfigPath);
951
952 RtlInitUnicodeString (&KeyName,
953 REG_SOFTWARE_KEY_NAME);
954 InitializeObjectAttributes(&ObjectAttributes,
955 &KeyName,
956 OBJ_CASE_INSENSITIVE,
957 NULL,
958 NULL);
959
960 Status = CmiLoadHive (&ObjectAttributes,
961 &FileName,
962 0);
963 if (!NT_SUCCESS(Status))
964 {
965 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
966 return(Status);
967 }
968
969 /* Connect the SAM hive */
970 wcscpy(EndPtr, REG_SAM_FILE_NAME);
971 RtlInitUnicodeString (&FileName,
972 ConfigPath);
973 DPRINT ("ConfigPath: %S\n", ConfigPath);
974
975 RtlInitUnicodeString (&KeyName,
976 REG_SAM_KEY_NAME);
977 InitializeObjectAttributes(&ObjectAttributes,
978 &KeyName,
979 OBJ_CASE_INSENSITIVE,
980 NULL,
981 NULL);
982 Status = CmiLoadHive (&ObjectAttributes,
983 &FileName,
984 0);
985 if (!NT_SUCCESS(Status))
986 {
987 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
988 return(Status);
989 }
990
991 /* Connect the SECURITY hive */
992 wcscpy(EndPtr, REG_SEC_FILE_NAME);
993 RtlInitUnicodeString (&FileName,
994 ConfigPath);
995 DPRINT ("ConfigPath: %S\n", ConfigPath);
996
997 RtlInitUnicodeString (&KeyName,
998 REG_SEC_KEY_NAME);
999 InitializeObjectAttributes(&ObjectAttributes,
1000 &KeyName,
1001 OBJ_CASE_INSENSITIVE,
1002 NULL,
1003 NULL);
1004 Status = CmiLoadHive (&ObjectAttributes,
1005 &FileName,
1006 0);
1007 if (!NT_SUCCESS(Status))
1008 {
1009 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
1010 return(Status);
1011 }
1012
1013 /* Connect the DEFAULT hive */
1014 wcscpy(EndPtr, REG_DEFAULT_USER_FILE_NAME);
1015 RtlInitUnicodeString (&FileName,
1016 ConfigPath);
1017 DPRINT ("ConfigPath: %S\n", ConfigPath);
1018
1019 RtlInitUnicodeString (&KeyName,
1020 REG_DEFAULT_USER_KEY_NAME);
1021 InitializeObjectAttributes(&ObjectAttributes,
1022 &KeyName,
1023 OBJ_CASE_INSENSITIVE,
1024 NULL,
1025 NULL);
1026 Status = CmiLoadHive (&ObjectAttributes,
1027 &FileName,
1028 0);
1029 if (!NT_SUCCESS(Status))
1030 {
1031 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
1032 return(Status);
1033 }
1034
1035 // CmiCheckRegistry(TRUE);
1036
1037 /* Start automatic hive synchronization */
1038 KeInitializeDpc(&CmiHiveSyncDpc,
1039 CmiHiveSyncDpcRoutine,
1040 NULL);
1041 KeInitializeTimer(&CmiHiveSyncTimer);
1042 CmiHiveSyncEnabled = TRUE;
1043
1044 DPRINT("CmiInitHives() done\n");
1045
1046 return(STATUS_SUCCESS);
1047 }
1048
1049
1050 VOID
1051 CmShutdownRegistry(VOID)
1052 {
1053 PREGISTRY_HIVE Hive;
1054 PLIST_ENTRY Entry;
1055
1056 DPRINT("CmShutdownRegistry() called\n");
1057
1058 /* Stop automatic hive synchronization */
1059 CmiHiveSyncEnabled = FALSE;
1060
1061 /* Cancel pending hive synchronization */
1062 if (CmiHiveSyncPending == TRUE)
1063 {
1064 KeCancelTimer(&CmiHiveSyncTimer);
1065 CmiHiveSyncPending = FALSE;
1066 }
1067
1068 /* Acquire hive list lock exclusively */
1069 KeEnterCriticalRegion();
1070 ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
1071
1072 Entry = CmiHiveListHead.Flink;
1073 while (Entry != &CmiHiveListHead)
1074 {
1075 Hive = CONTAINING_RECORD(Entry, REGISTRY_HIVE, HiveList);
1076
1077 if (!(IsNoFileHive(Hive) || IsNoSynchHive(Hive)))
1078 {
1079 /* Acquire hive resource exclusively */
1080 ExAcquireResourceExclusiveLite(&Hive->HiveResource,
1081 TRUE);
1082
1083 /* Flush non-volatile hive */
1084 CmiFlushRegistryHive(Hive);
1085
1086 /* Release hive resource */
1087 ExReleaseResourceLite(&Hive->HiveResource);
1088 }
1089
1090 Entry = Entry->Flink;
1091 }
1092
1093 /* Release hive list lock */
1094 ExReleaseResourceLite(&CmiHiveListLock);
1095 KeLeaveCriticalRegion();
1096
1097 DPRINT("CmShutdownRegistry() done\n");
1098 }
1099
1100
1101 VOID STDCALL
1102 CmiHiveSyncRoutine(PVOID DeferredContext)
1103 {
1104 PREGISTRY_HIVE Hive;
1105 PLIST_ENTRY Entry;
1106
1107 DPRINT("CmiHiveSyncRoutine() called\n");
1108
1109 CmiHiveSyncPending = FALSE;
1110
1111 /* Acquire hive list lock exclusively */
1112 KeEnterCriticalRegion();
1113 ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
1114
1115 Entry = CmiHiveListHead.Flink;
1116 while (Entry != &CmiHiveListHead)
1117 {
1118 Hive = CONTAINING_RECORD(Entry, REGISTRY_HIVE, HiveList);
1119
1120 if (!(IsNoFileHive(Hive) || IsNoSynchHive(Hive)))
1121 {
1122 /* Acquire hive resource exclusively */
1123 ExAcquireResourceExclusiveLite(&Hive->HiveResource,
1124 TRUE);
1125
1126 /* Flush non-volatile hive */
1127 CmiFlushRegistryHive(Hive);
1128
1129 /* Release hive resource */
1130 ExReleaseResourceLite(&Hive->HiveResource);
1131 }
1132
1133 Entry = Entry->Flink;
1134 }
1135
1136 /* Release hive list lock */
1137 ExReleaseResourceLite(&CmiHiveListLock);
1138 KeLeaveCriticalRegion();
1139
1140 DPRINT("DeferredContext %x\n", DeferredContext);
1141 ExFreePool(DeferredContext);
1142
1143 DPRINT("CmiHiveSyncRoutine() done\n");
1144 }
1145
1146
1147 static VOID STDCALL
1148 CmiHiveSyncDpcRoutine(PKDPC Dpc,
1149 PVOID DeferredContext,
1150 PVOID SystemArgument1,
1151 PVOID SystemArgument2)
1152 {
1153 PWORK_QUEUE_ITEM WorkQueueItem;
1154
1155 WorkQueueItem = ExAllocatePool(NonPagedPool,
1156 sizeof(WORK_QUEUE_ITEM));
1157 if (WorkQueueItem == NULL)
1158 {
1159 DbgPrint("Failed to allocate work item\n");
1160 return;
1161 }
1162
1163 ExInitializeWorkItem(WorkQueueItem,
1164 CmiHiveSyncRoutine,
1165 WorkQueueItem);
1166
1167 DPRINT("DeferredContext %x\n", WorkQueueItem);
1168 ExQueueWorkItem(WorkQueueItem,
1169 CriticalWorkQueue);
1170 }
1171
1172
1173 VOID
1174 CmiSyncHives(VOID)
1175 {
1176 LARGE_INTEGER Timeout;
1177
1178 DPRINT("CmiSyncHives() called\n");
1179
1180 if (CmiHiveSyncEnabled == FALSE ||
1181 CmiHiveSyncPending == TRUE)
1182 return;
1183
1184 CmiHiveSyncPending = TRUE;
1185
1186
1187 #if defined(__GNUC__)
1188 Timeout.QuadPart = -50000000LL;
1189 #else
1190 Timeout.QuadPart = -50000000;
1191 #endif
1192 KeSetTimer(&CmiHiveSyncTimer,
1193 Timeout,
1194 &CmiHiveSyncDpc);
1195 }
1196
1197 /* EOF */