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