Use Unicode strings in key objects.
[reactos.git] / reactos / ntoskrnl / cm / registry.c
1 /* $Id: registry.c,v 1.96 2003/05/28 12:04:17 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 <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 Status = RtlCreateUnicodeString(&RootKey->Name, L"Registry");
315 assert(NT_SUCCESS(Status));
316
317 KeInitializeSpinLock(&CmiKeyListLock);
318
319 /* Create '\Registry\Machine' key. */
320 Status = ObCreateObject(&KeyHandle,
321 STANDARD_RIGHTS_REQUIRED,
322 NULL,
323 CmiKeyType,
324 (PVOID*)&MachineKey);
325 assert(NT_SUCCESS(Status));
326 Status = CmiAddSubKey(CmiVolatileHive,
327 RootKey,
328 MachineKey,
329 L"Machine",
330 wcslen(L"Machine") * sizeof(WCHAR),
331 0,
332 NULL,
333 0);
334 assert(NT_SUCCESS(Status));
335 MachineKey->RegistryHive = CmiVolatileHive;
336 MachineKey->Flags = 0;
337 MachineKey->NumberOfSubKeys = 0;
338 MachineKey->SubKeys = NULL;
339 MachineKey->SizeOfSubKeys = MachineKey->KeyCell->NumberOfSubKeys;
340 Status = RtlCreateUnicodeString(&MachineKey->Name, L"Machine");
341 assert(NT_SUCCESS(Status));
342 CmiAddKeyToList(RootKey, MachineKey);
343
344 /* Create '\Registry\User' key. */
345 Status = ObCreateObject(&KeyHandle,
346 STANDARD_RIGHTS_REQUIRED,
347 NULL,
348 CmiKeyType,
349 (PVOID*)&UserKey);
350 assert(NT_SUCCESS(Status));
351 Status = CmiAddSubKey(CmiVolatileHive,
352 RootKey,
353 UserKey,
354 L"User",
355 wcslen(L"User") * sizeof(WCHAR),
356 0,
357 NULL,
358 0);
359 assert(NT_SUCCESS(Status));
360 UserKey->RegistryHive = CmiVolatileHive;
361 UserKey->Flags = 0;
362 UserKey->NumberOfSubKeys = 0;
363 UserKey->SubKeys = NULL;
364 UserKey->SizeOfSubKeys = UserKey->KeyCell->NumberOfSubKeys;
365 Status = RtlCreateUnicodeString(&UserKey->Name, L"User");
366 assert(NT_SUCCESS(Status));
367 CmiAddKeyToList(RootKey, UserKey);
368 }
369
370
371 VOID
372 CmInit2(PCHAR CommandLine)
373 {
374 PCHAR p1, p2;
375 ULONG PiceStart;
376 NTSTATUS Status;
377
378 /* FIXME: Store system start options */
379
380
381
382 /* Create the 'CurrentControlSet' link. */
383 Status = CmiCreateCurrentControlSetLink();
384 if (!NT_SUCCESS(Status))
385 {
386 KeBugCheck(CONFIG_INITIALIZATION_FAILED);
387 }
388
389 /* Set PICE 'Start' value to 1, if PICE debugging is enabled */
390 PiceStart = 4;
391 p1 = (PCHAR)CommandLine;
392 while (p1 && (p2 = strchr(p1, '/')))
393 {
394 p2++;
395 if (_strnicmp(p2, "DEBUGPORT", 9) == 0)
396 {
397 p2 += 9;
398 if (*p2 == '=')
399 {
400 p2++;
401 if (_strnicmp(p2, "PICE", 4) == 0)
402 {
403 p2 += 4;
404 PiceStart = 1;
405 }
406 }
407 }
408 p1 = p2;
409 }
410
411 Status = RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
412 L"\\Pice",
413 L"Start",
414 REG_DWORD,
415 &PiceStart,
416 sizeof(ULONG));
417 if (!NT_SUCCESS(Status))
418 {
419 KeBugCheck(CONFIG_INITIALIZATION_FAILED);
420 }
421 }
422
423
424 static NTSTATUS
425 CmiCreateCurrentControlSetLink(VOID)
426 {
427 RTL_QUERY_REGISTRY_TABLE QueryTable[5];
428 WCHAR TargetNameBuffer[80];
429 ULONG TargetNameLength;
430 UNICODE_STRING LinkName;
431 UNICODE_STRING LinkValue;
432 ULONG CurrentSet;
433 ULONG DefaultSet;
434 ULONG Failed;
435 ULONG LastKnownGood;
436 NTSTATUS Status;
437 OBJECT_ATTRIBUTES ObjectAttributes;
438 HANDLE KeyHandle;
439
440 DPRINT("CmiCreateCurrentControlSetLink() called\n");
441
442 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
443
444 QueryTable[0].Name = L"Current";
445 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
446 QueryTable[0].EntryContext = &CurrentSet;
447
448 QueryTable[1].Name = L"Default";
449 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
450 QueryTable[1].EntryContext = &DefaultSet;
451
452 QueryTable[2].Name = L"Failed";
453 QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
454 QueryTable[2].EntryContext = &Failed;
455
456 QueryTable[3].Name = L"LastKnownGood";
457 QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
458 QueryTable[3].EntryContext = &LastKnownGood;
459
460 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
461 L"\\Registry\\Machine\\SYSTEM\\Select",
462 QueryTable,
463 NULL,
464 NULL);
465 if (!NT_SUCCESS(Status))
466 {
467 return(Status);
468 }
469
470 DPRINT("Current %ld Default %ld\n", CurrentSet, DefaultSet);
471
472 swprintf(TargetNameBuffer,
473 L"\\Registry\\Machine\\SYSTEM\\ControlSet%03lu",
474 CurrentSet);
475 TargetNameLength = wcslen(TargetNameBuffer) * sizeof(WCHAR);
476
477 DPRINT("Link target '%S'\n", TargetNameBuffer);
478
479 RtlInitUnicodeStringFromLiteral(&LinkName,
480 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
481 InitializeObjectAttributes(&ObjectAttributes,
482 &LinkName,
483 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
484 NULL,
485 NULL);
486 Status = NtCreateKey(&KeyHandle,
487 KEY_ALL_ACCESS | KEY_CREATE_LINK,
488 &ObjectAttributes,
489 0,
490 NULL,
491 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
492 NULL);
493 if (!NT_SUCCESS(Status))
494 {
495 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
496 return(Status);
497 }
498
499 RtlInitUnicodeStringFromLiteral(&LinkValue,
500 L"SymbolicLinkValue");
501 Status = NtSetValueKey(KeyHandle,
502 &LinkValue,
503 0,
504 REG_LINK,
505 (PVOID)TargetNameBuffer,
506 TargetNameLength);
507 if (!NT_SUCCESS(Status))
508 {
509 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
510 }
511
512 NtClose(KeyHandle);
513
514 return(Status);
515 }
516
517
518 NTSTATUS
519 CmiConnectHive(PREGISTRY_HIVE RegistryHive,
520 PUNICODE_STRING KeyName)
521 {
522 OBJECT_ATTRIBUTES ObjectAttributes;
523 UNICODE_STRING ParentKeyName;
524 PKEY_OBJECT ParentKey;
525 PKEY_OBJECT NewKey;
526 HANDLE KeyHandle;
527 NTSTATUS Status;
528 PWSTR SubName;
529
530 DPRINT("CmiConnectHive(%p, %wZ) called.\n",
531 RegistryHive, KeyName);
532
533 SubName = wcsrchr (KeyName->Buffer, L'\\');
534 if (SubName == NULL)
535 {
536 return STATUS_UNSUCCESSFUL;
537 }
538
539 ParentKeyName.Length = (USHORT)(SubName - KeyName->Buffer) * sizeof(WCHAR);
540 ParentKeyName.MaximumLength = ParentKeyName.Length + sizeof(WCHAR);
541 ParentKeyName.Buffer = ExAllocatePool (NonPagedPool,
542 ParentKeyName.MaximumLength);
543 RtlCopyMemory (ParentKeyName.Buffer,
544 KeyName->Buffer,
545 ParentKeyName.Length);
546 ParentKeyName.Buffer[ParentKeyName.Length / sizeof(WCHAR)] = 0;
547 SubName++;
548
549 Status = ObReferenceObjectByName (&ParentKeyName,
550 OBJ_CASE_INSENSITIVE,
551 NULL,
552 STANDARD_RIGHTS_REQUIRED,
553 CmiKeyType,
554 KernelMode,
555 NULL,
556 (PVOID*)&ParentKey);
557 RtlFreeUnicodeString (&ParentKeyName);
558 if (!NT_SUCCESS(Status))
559 {
560 DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status);
561 return Status;
562 }
563
564 InitializeObjectAttributes(&ObjectAttributes,
565 KeyName,
566 0,
567 NULL,
568 NULL);
569
570 Status = ObCreateObject(&KeyHandle,
571 STANDARD_RIGHTS_REQUIRED,
572 &ObjectAttributes,
573 CmiKeyType,
574 (PVOID*)&NewKey);
575 if (!NT_SUCCESS(Status))
576 {
577 DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status);
578 ObDereferenceObject (ParentKey);
579 return Status;
580 }
581
582 NewKey->RegistryHive = RegistryHive;
583 NewKey->BlockOffset = RegistryHive->HiveHeader->RootKeyCell;
584 NewKey->KeyCell = CmiGetBlock(RegistryHive, NewKey->BlockOffset, NULL);
585 NewKey->Flags = 0;
586 NewKey->NumberOfSubKeys = 0;
587 NewKey->SubKeys = ExAllocatePool(PagedPool,
588 NewKey->KeyCell->NumberOfSubKeys * sizeof(ULONG));
589
590 if ((NewKey->SubKeys == NULL) && (NewKey->KeyCell->NumberOfSubKeys != 0))
591 {
592 DPRINT("NumberOfSubKeys %d\n", NewKey->KeyCell->NumberOfSubKeys);
593 NtClose(NewKey);
594 ObDereferenceObject (ParentKey);
595 return(STATUS_INSUFFICIENT_RESOURCES);
596 }
597
598 Status = RtlCreateUnicodeString(&NewKey->Name,
599 SubName);
600 if (!NT_SUCCESS(Status))
601 {
602 DPRINT1("RtlCreateUnicodeString() failed (Status %lx)\n", Status);
603 if (NewKey->SubKeys != NULL)
604 ExFreePool(NewKey->SubKeys);
605 NtClose(KeyHandle);
606 ObDereferenceObject (ParentKey);
607 return STATUS_INSUFFICIENT_RESOURCES;
608 }
609
610 CmiAddKeyToList (ParentKey, NewKey);
611 ObDereferenceObject (ParentKey);
612
613 VERIFY_KEY_OBJECT(NewKey);
614
615 return(STATUS_SUCCESS);
616 }
617
618
619 static NTSTATUS
620 CmiInitializeSystemHive (PWSTR FileName,
621 PUNICODE_STRING KeyName)
622 {
623 OBJECT_ATTRIBUTES ObjectAttributes;
624 UNICODE_STRING ControlSetKeyName;
625 UNICODE_STRING ControlSetLinkName;
626 UNICODE_STRING ControlSetValueName;
627 HANDLE KeyHandle;
628 NTSTATUS Status;
629 PREGISTRY_HIVE RegistryHive;
630
631 Status = CmiCreateRegistryHive (FileName,
632 &RegistryHive,
633 TRUE);
634 if (!NT_SUCCESS(Status))
635 {
636 DPRINT1 ("CmiCreateRegistryHive() failed (Status %lx)\n", Status);
637 return Status;
638 }
639
640 Status = CmiConnectHive (RegistryHive,
641 KeyName);
642 if (!NT_SUCCESS(Status))
643 {
644 DPRINT1 ("CmiConnectHive() failed (Status %lx)\n", Status);
645 CmiRemoveRegistryHive (RegistryHive);
646 return Status;
647 }
648
649 /* Create 'ControlSet001' key */
650 RtlInitUnicodeStringFromLiteral (&ControlSetKeyName,
651 L"\\Registry\\Machine\\SYSTEM\\ControlSet001");
652 InitializeObjectAttributes (&ObjectAttributes,
653 &ControlSetKeyName,
654 OBJ_CASE_INSENSITIVE,
655 NULL,
656 NULL);
657 Status = NtCreateKey (&KeyHandle,
658 KEY_ALL_ACCESS,
659 &ObjectAttributes,
660 0,
661 NULL,
662 REG_OPTION_NON_VOLATILE,
663 NULL);
664 if (!NT_SUCCESS(Status))
665 {
666 DPRINT1 ("NtCreateKey() failed (Status %lx)\n", Status);
667 return Status;
668 }
669 NtClose (KeyHandle);
670
671 /* Link 'CurrentControlSet' to 'ControlSet001' key */
672 RtlInitUnicodeStringFromLiteral (&ControlSetLinkName,
673 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
674 InitializeObjectAttributes (&ObjectAttributes,
675 &ControlSetLinkName,
676 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
677 NULL,
678 NULL);
679 Status = NtCreateKey (&KeyHandle,
680 KEY_ALL_ACCESS | KEY_CREATE_LINK,
681 &ObjectAttributes,
682 0,
683 NULL,
684 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
685 NULL);
686 if (!NT_SUCCESS(Status))
687 {
688 DPRINT1 ("NtCreateKey() failed (Status %lx)\n", Status);
689 return Status;
690 }
691
692 RtlInitUnicodeStringFromLiteral (&ControlSetValueName,
693 L"SymbolicLinkValue");
694 Status = NtSetValueKey (KeyHandle,
695 &ControlSetValueName,
696 0,
697 REG_LINK,
698 (PVOID)ControlSetKeyName.Buffer,
699 ControlSetKeyName.Length);
700 if (!NT_SUCCESS(Status))
701 {
702 DPRINT1 ("NtSetValueKey() failed (Status %lx)\n", Status);
703 }
704 NtClose (KeyHandle);
705
706 return STATUS_SUCCESS;
707 }
708
709
710 NTSTATUS
711 CmiInitializeHive(PWSTR FileName,
712 PUNICODE_STRING KeyName,
713 BOOLEAN CreateNew)
714 {
715 PREGISTRY_HIVE RegistryHive;
716 NTSTATUS Status;
717
718 DPRINT("CmiInitializeHive(%s) called\n", KeyName);
719
720 Status = CmiCreateRegistryHive(FileName,
721 &RegistryHive,
722 CreateNew);
723 if (!NT_SUCCESS(Status))
724 {
725 DPRINT1("CmiCreateRegistryHive() failed (Status %lx)\n", Status);
726
727 /* FIXME: Try to load the backup hive */
728
729 KeBugCheck(0);
730 return(Status);
731 }
732
733 /* Connect the hive */
734 Status = CmiConnectHive(RegistryHive,
735 KeyName);
736 if (!NT_SUCCESS(Status))
737 {
738 DPRINT1("CmiConnectHive() failed (Status %lx)\n", Status);
739 CmiRemoveRegistryHive(RegistryHive);
740 return(Status);
741 }
742
743 DPRINT("CmiInitializeHive() done\n");
744
745 return(STATUS_SUCCESS);
746 }
747
748
749 NTSTATUS
750 CmiInitHives(BOOLEAN SetupBoot)
751 {
752 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
753 OBJECT_ATTRIBUTES ObjectAttributes;
754 UNICODE_STRING KeyName;
755 UNICODE_STRING ValueName;
756 HANDLE KeyHandle;
757
758 NTSTATUS Status;
759
760 WCHAR ConfigPath[MAX_PATH];
761
762 ULONG BufferSize;
763 ULONG ResultSize;
764 PWSTR EndPtr;
765
766
767 DPRINT("CmiInitHives() called\n");
768
769 if (SetupBoot == TRUE)
770 {
771 RtlInitUnicodeStringFromLiteral(&KeyName,
772 L"\\Registry\\Machine\\HARDWARE");
773 InitializeObjectAttributes(&ObjectAttributes,
774 &KeyName,
775 OBJ_CASE_INSENSITIVE,
776 NULL,
777 NULL);
778 Status = NtOpenKey(&KeyHandle,
779 KEY_ALL_ACCESS,
780 &ObjectAttributes);
781 if (!NT_SUCCESS(Status))
782 {
783 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
784 return(Status);
785 }
786
787 RtlInitUnicodeStringFromLiteral(&ValueName,
788 L"InstallPath");
789
790 BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
791 ValueInfo = ExAllocatePool(PagedPool,
792 BufferSize);
793 if (ValueInfo == NULL)
794 {
795 NtClose(KeyHandle);
796 return(STATUS_INSUFFICIENT_RESOURCES);
797 }
798
799 Status = NtQueryValueKey(KeyHandle,
800 &ValueName,
801 KeyValuePartialInformation,
802 ValueInfo,
803 BufferSize,
804 &ResultSize);
805 NtClose(KeyHandle);
806 if (!NT_SUCCESS(Status))
807 {
808 ExFreePool(ValueInfo);
809 return(Status);
810 }
811
812 RtlCopyMemory(ConfigPath,
813 ValueInfo->Data,
814 ValueInfo->DataLength);
815 ConfigPath[ValueInfo->DataLength / sizeof(WCHAR)] = (WCHAR)0;
816 ExFreePool(ValueInfo);
817 }
818 else
819 {
820 wcscpy(ConfigPath, L"\\SystemRoot");
821 }
822 wcscat(ConfigPath, L"\\system32\\config");
823
824 DPRINT("ConfigPath: %S\n", ConfigPath);
825
826 EndPtr = ConfigPath + wcslen(ConfigPath);
827
828 CmiDoVerify = TRUE;
829
830 /* FIXME: Save boot log */
831
832 /* Connect the SYSTEM hive only if it has been created */
833 if (SetupBoot == TRUE)
834 {
835 wcscpy(EndPtr, REG_SYSTEM_FILE_NAME);
836 DPRINT ("ConfigPath: %S\n", ConfigPath);
837
838 RtlInitUnicodeString (&KeyName,
839 REG_SYSTEM_KEY_NAME);
840 Status = CmiInitializeSystemHive (ConfigPath,
841 &KeyName);
842 if (!NT_SUCCESS(Status))
843 {
844 DPRINT1("CmiInitializeSystemHive() failed (Status %lx)\n", Status);
845 return(Status);
846 }
847 }
848
849 /* Connect the SOFTWARE hive */
850 wcscpy(EndPtr, REG_SOFTWARE_FILE_NAME);
851 DPRINT ("ConfigPath: %S\n", ConfigPath);
852
853 RtlInitUnicodeString (&KeyName,
854 REG_SOFTWARE_KEY_NAME);
855 Status = CmiInitializeHive(ConfigPath,
856 &KeyName,
857 SetupBoot);
858 if (!NT_SUCCESS(Status))
859 {
860 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
861 return(Status);
862 }
863
864 /* Connect the SAM hive */
865 wcscpy(EndPtr, REG_SAM_FILE_NAME);
866 DPRINT ("ConfigPath: %S\n", ConfigPath);
867
868 RtlInitUnicodeString (&KeyName,
869 REG_SAM_KEY_NAME);
870 Status = CmiInitializeHive(ConfigPath,
871 &KeyName,
872 SetupBoot);
873 if (!NT_SUCCESS(Status))
874 {
875 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
876 return(Status);
877 }
878
879 /* Connect the SECURITY hive */
880 wcscpy(EndPtr, REG_SEC_FILE_NAME);
881 DPRINT ("ConfigPath: %S\n", ConfigPath);
882
883 RtlInitUnicodeString (&KeyName,
884 REG_SEC_KEY_NAME);
885 Status = CmiInitializeHive(ConfigPath,
886 &KeyName,
887 SetupBoot);
888 if (!NT_SUCCESS(Status))
889 {
890 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
891 return(Status);
892 }
893
894 /* Connect the DEFAULT hive */
895 wcscpy(EndPtr, REG_USER_FILE_NAME);
896 DPRINT ("ConfigPath: %S\n", ConfigPath);
897
898 RtlInitUnicodeString (&KeyName,
899 REG_USER_KEY_NAME);
900 Status = CmiInitializeHive(ConfigPath,
901 &KeyName,
902 SetupBoot);
903 if (!NT_SUCCESS(Status))
904 {
905 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
906 return(Status);
907 }
908
909 // CmiCheckRegistry(TRUE);
910
911 /* Start automatic hive synchronization */
912 KeInitializeDpc(&CmiHiveSyncDpc,
913 CmiHiveSyncDpcRoutine,
914 NULL);
915 KeInitializeTimer(&CmiHiveSyncTimer);
916 CmiHiveSyncEnabled = TRUE;
917
918 DPRINT("CmiInitHives() done\n");
919
920 return(STATUS_SUCCESS);
921 }
922
923
924 VOID
925 CmShutdownRegistry(VOID)
926 {
927 PREGISTRY_HIVE Hive;
928 PLIST_ENTRY Entry;
929
930 DPRINT1("CmShutdownRegistry() called\n");
931
932 /* Stop automatic hive synchronization */
933 CmiHiveSyncEnabled = FALSE;
934
935 /* Acquire hive list lock exclusively */
936 ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
937
938 Entry = CmiHiveListHead.Flink;
939 while (Entry != &CmiHiveListHead)
940 {
941 Hive = CONTAINING_RECORD(Entry, REGISTRY_HIVE, HiveList);
942
943 if (!IsVolatileHive(Hive))
944 {
945 /* Acquire hive resource exclusively */
946 ExAcquireResourceExclusiveLite(&Hive->HiveResource,
947 TRUE);
948
949 /* Flush non-volatile hive */
950 CmiFlushRegistryHive(Hive);
951
952 /* Release hive resource */
953 ExReleaseResourceLite(&Hive->HiveResource);
954 }
955
956 Entry = Entry->Flink;
957 }
958
959 /* Release hive list lock */
960 ExReleaseResourceLite(&CmiHiveListLock);
961
962 DPRINT1("CmShutdownRegistry() done\n");
963 }
964
965
966 VOID STDCALL
967 CmiHiveSyncRoutine(PVOID DeferredContext)
968 {
969 PREGISTRY_HIVE Hive;
970 PLIST_ENTRY Entry;
971
972 DPRINT("CmiHiveSyncRoutine() called\n");
973
974 CmiHiveSyncPending = FALSE;
975
976 /* Acquire hive list lock exclusively */
977 ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
978
979 Entry = CmiHiveListHead.Flink;
980 while (Entry != &CmiHiveListHead)
981 {
982 Hive = CONTAINING_RECORD(Entry, REGISTRY_HIVE, HiveList);
983
984 if (!IsVolatileHive(Hive))
985 {
986 /* Acquire hive resource exclusively */
987 ExAcquireResourceExclusiveLite(&Hive->HiveResource,
988 TRUE);
989
990 /* Flush non-volatile hive */
991 CmiFlushRegistryHive(Hive);
992
993 /* Release hive resource */
994 ExReleaseResourceLite(&Hive->HiveResource);
995 }
996
997 Entry = Entry->Flink;
998 }
999
1000 /* Release hive list lock */
1001 ExReleaseResourceLite(&CmiHiveListLock);
1002
1003 DPRINT("DeferredContext %x\n", DeferredContext);
1004 ExFreePool(DeferredContext);
1005
1006 DPRINT("CmiHiveSyncRoutine() done\n");
1007 }
1008
1009
1010 static VOID STDCALL
1011 CmiHiveSyncDpcRoutine(PKDPC Dpc,
1012 PVOID DeferredContext,
1013 PVOID SystemArgument1,
1014 PVOID SystemArgument2)
1015 {
1016 PWORK_QUEUE_ITEM WorkQueueItem;
1017
1018 WorkQueueItem = ExAllocatePool(NonPagedPool,
1019 sizeof(WORK_QUEUE_ITEM));
1020 if (WorkQueueItem == NULL)
1021 {
1022 DbgPrint("Failed to allocate work item\n");
1023 return;
1024 }
1025
1026 ExInitializeWorkItem(WorkQueueItem,
1027 CmiHiveSyncRoutine,
1028 WorkQueueItem);
1029
1030 DPRINT("DeferredContext %x\n", WorkQueueItem);
1031 ExQueueWorkItem(WorkQueueItem,
1032 CriticalWorkQueue);
1033 }
1034
1035
1036 VOID
1037 CmiSyncHives(VOID)
1038 {
1039 LARGE_INTEGER Timeout;
1040
1041 DPRINT("CmiSyncHives() called\n");
1042
1043 if (CmiHiveSyncEnabled == FALSE ||
1044 CmiHiveSyncPending == TRUE)
1045 return;
1046
1047 CmiHiveSyncPending = TRUE;
1048
1049
1050 Timeout.QuadPart = -50000000LL;
1051 KeSetTimer(&CmiHiveSyncTimer,
1052 Timeout,
1053 &CmiHiveSyncDpc);
1054 }
1055
1056 /* EOF */