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