- Free or recycle the remaining path string after a call to ObFindObject.
[reactos.git] / reactos / ntoskrnl / cm / registry.c
1 /* $Id: registry.c,v 1.121 2004/02/07 17:30:14 hbirr 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 <reactos/bugcodes.h>
21 #include <rosrtl/string.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 RtlRosInitUnicodeStringFromLiteral(&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 RtlRosInitUnicodeStringFromLiteral(&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 RtlFreeUnicodeString(&RemainingPath);
536 return STATUS_OBJECT_NAME_COLLISION;
537 }
538
539 /* If RemainingPath contains \ we must return error
540 because CmiConnectHive() can not create trees */
541 SubName = RemainingPath.Buffer;
542 if (*SubName == L'\\')
543 SubName++;
544
545 if (wcschr (SubName, L'\\') != NULL)
546 {
547 ObDereferenceObject (ParentKey);
548 RtlFreeUnicodeString(&RemainingPath);
549 return STATUS_OBJECT_NAME_NOT_FOUND;
550 }
551
552 DPRINT("RemainingPath %wZ ParentKey %p\n",
553 &RemainingPath, ParentKey);
554
555 Status = ObCreateObject(KernelMode,
556 CmiKeyType,
557 NULL,
558 KernelMode,
559 NULL,
560 sizeof(KEY_OBJECT),
561 0,
562 0,
563 (PVOID*)&NewKey);
564 if (!NT_SUCCESS(Status))
565 {
566 DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status);
567 ObDereferenceObject (ParentKey);
568 RtlFreeUnicodeString(&RemainingPath);
569 return Status;
570 }
571
572 NewKey->RegistryHive = RegistryHive;
573 NewKey->KeyCellOffset = RegistryHive->HiveHeader->RootKeyOffset;
574 NewKey->KeyCell = CmiGetCell (RegistryHive, NewKey->KeyCellOffset, NULL);
575 NewKey->Flags = 0;
576 NewKey->NumberOfSubKeys = 0;
577 NewKey->SubKeys = ExAllocatePool(PagedPool,
578 NewKey->KeyCell->NumberOfSubKeys * sizeof(ULONG));
579
580 if ((NewKey->SubKeys == NULL) && (NewKey->KeyCell->NumberOfSubKeys != 0))
581 {
582 DPRINT("NumberOfSubKeys %d\n", NewKey->KeyCell->NumberOfSubKeys);
583 ObDereferenceObject (NewKey);
584 ObDereferenceObject (ParentKey);
585 RtlFreeUnicodeString(&RemainingPath);
586 return STATUS_INSUFFICIENT_RESOURCES;
587 }
588
589 if (SubName == RemainingPath.Buffer)
590 {
591 NewKey->Name = RemainingPath;
592 }
593 else
594 {
595 Status = RtlCreateUnicodeString(&NewKey->Name,
596 SubName);
597 RtlFreeUnicodeString(&RemainingPath);
598 if (!NT_SUCCESS(Status))
599 {
600 DPRINT1("RtlCreateUnicodeString() failed (Status %lx)\n", Status);
601 if (NewKey->SubKeys != NULL)
602 {
603 ExFreePool (NewKey->SubKeys);
604 }
605 ObDereferenceObject (NewKey);
606 ObDereferenceObject (ParentKey);
607 return STATUS_INSUFFICIENT_RESOURCES;
608 }
609 }
610
611 CmiAddKeyToList (ParentKey, NewKey);
612 ObDereferenceObject (ParentKey);
613
614 VERIFY_KEY_OBJECT(NewKey);
615
616 /* Note: Do not dereference NewKey here! */
617
618 return STATUS_SUCCESS;
619 }
620
621
622 NTSTATUS
623 CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
624 OUT PREGISTRY_HIVE *RegistryHive)
625 {
626 PKEY_OBJECT KeyObject;
627 PREGISTRY_HIVE Hive;
628 HANDLE KeyHandle;
629 NTSTATUS Status;
630
631 DPRINT("CmiDisconnectHive() called\n");
632
633 *RegistryHive = NULL;
634
635 Status = ObOpenObjectByName (KeyObjectAttributes,
636 CmiKeyType,
637 NULL,
638 KernelMode,
639 STANDARD_RIGHTS_REQUIRED,
640 NULL,
641 &KeyHandle);
642 if (!NT_SUCCESS(Status))
643 {
644 DPRINT1 ("ObOpenObjectByName() failed (Status %lx)\n", Status);
645 return Status;
646 }
647
648 Status = ObReferenceObjectByHandle (KeyHandle,
649 STANDARD_RIGHTS_REQUIRED,
650 CmiKeyType,
651 KernelMode,
652 (PVOID*)&KeyObject,
653 NULL);
654 NtClose (KeyHandle);
655 if (!NT_SUCCESS(Status))
656 {
657 DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status);
658 return Status;
659 }
660 DPRINT ("KeyObject %p Hive %p\n", KeyObject, KeyObject->RegistryHive);
661
662 if (!(KeyObject->KeyCell->Flags & REG_KEY_ROOT_CELL))
663 {
664 DPRINT1 ("Key is not the Hive-Root-Key\n");
665 ObDereferenceObject (KeyObject);
666 return STATUS_INVALID_PARAMETER;
667 }
668
669 if (ObGetObjectHandleCount (KeyObject) != 0 ||
670 ObGetObjectPointerCount (KeyObject) != 2)
671 {
672 DPRINT1 ("Hive is still in use\n");
673 ObDereferenceObject (KeyObject);
674 return STATUS_UNSUCCESSFUL;
675 }
676
677 Hive = KeyObject->RegistryHive;
678
679 /* Dereference KeyObject twice to delete it */
680 ObDereferenceObject (KeyObject);
681 ObDereferenceObject (KeyObject);
682
683 *RegistryHive = Hive;
684
685 DPRINT ("CmiDisconnectHive() done\n");
686
687 return STATUS_SUCCESS;
688 }
689
690
691 static NTSTATUS
692 CmiInitControlSetLink (VOID)
693 {
694 OBJECT_ATTRIBUTES ObjectAttributes;
695 UNICODE_STRING ControlSetKeyName;
696 UNICODE_STRING ControlSetLinkName;
697 UNICODE_STRING ControlSetValueName;
698 HANDLE KeyHandle;
699 NTSTATUS Status;
700
701 /* Create 'ControlSet001' key */
702 RtlRosInitUnicodeStringFromLiteral (&ControlSetKeyName,
703 L"\\Registry\\Machine\\SYSTEM\\ControlSet001");
704 InitializeObjectAttributes (&ObjectAttributes,
705 &ControlSetKeyName,
706 OBJ_CASE_INSENSITIVE,
707 NULL,
708 NULL);
709 Status = NtCreateKey (&KeyHandle,
710 KEY_ALL_ACCESS,
711 &ObjectAttributes,
712 0,
713 NULL,
714 REG_OPTION_NON_VOLATILE,
715 NULL);
716 if (!NT_SUCCESS(Status))
717 {
718 DPRINT1 ("NtCreateKey() failed (Status %lx)\n", Status);
719 return Status;
720 }
721 NtClose (KeyHandle);
722
723 /* Link 'CurrentControlSet' to 'ControlSet001' key */
724 RtlRosInitUnicodeStringFromLiteral (&ControlSetLinkName,
725 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
726 InitializeObjectAttributes (&ObjectAttributes,
727 &ControlSetLinkName,
728 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
729 NULL,
730 NULL);
731 Status = NtCreateKey (&KeyHandle,
732 KEY_ALL_ACCESS | KEY_CREATE_LINK,
733 &ObjectAttributes,
734 0,
735 NULL,
736 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
737 NULL);
738 if (!NT_SUCCESS(Status))
739 {
740 DPRINT1 ("NtCreateKey() failed (Status %lx)\n", Status);
741 return Status;
742 }
743
744 RtlRosInitUnicodeStringFromLiteral (&ControlSetValueName,
745 L"SymbolicLinkValue");
746 Status = NtSetValueKey (KeyHandle,
747 &ControlSetValueName,
748 0,
749 REG_LINK,
750 (PVOID)ControlSetKeyName.Buffer,
751 ControlSetKeyName.Length);
752 if (!NT_SUCCESS(Status))
753 {
754 DPRINT1 ("NtSetValueKey() failed (Status %lx)\n", Status);
755 }
756 NtClose (KeyHandle);
757
758 return STATUS_SUCCESS;
759 }
760
761
762 NTSTATUS
763 CmiInitHives(BOOLEAN SetupBoot)
764 {
765 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
766 OBJECT_ATTRIBUTES ObjectAttributes;
767 UNICODE_STRING FileName;
768 UNICODE_STRING KeyName;
769 UNICODE_STRING ValueName;
770 HANDLE KeyHandle;
771
772 NTSTATUS Status;
773
774 WCHAR ConfigPath[MAX_PATH];
775
776 ULONG BufferSize;
777 ULONG ResultSize;
778 PWSTR EndPtr;
779
780
781 DPRINT("CmiInitHives() called\n");
782
783 if (SetupBoot == TRUE)
784 {
785 RtlRosInitUnicodeStringFromLiteral(&KeyName,
786 L"\\Registry\\Machine\\HARDWARE");
787 InitializeObjectAttributes(&ObjectAttributes,
788 &KeyName,
789 OBJ_CASE_INSENSITIVE,
790 NULL,
791 NULL);
792 Status = NtOpenKey(&KeyHandle,
793 KEY_ALL_ACCESS,
794 &ObjectAttributes);
795 if (!NT_SUCCESS(Status))
796 {
797 DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
798 return(Status);
799 }
800
801 RtlRosInitUnicodeStringFromLiteral(&ValueName,
802 L"InstallPath");
803
804 BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
805 ValueInfo = ExAllocatePool(PagedPool,
806 BufferSize);
807 if (ValueInfo == NULL)
808 {
809 NtClose(KeyHandle);
810 return(STATUS_INSUFFICIENT_RESOURCES);
811 }
812
813 Status = NtQueryValueKey(KeyHandle,
814 &ValueName,
815 KeyValuePartialInformation,
816 ValueInfo,
817 BufferSize,
818 &ResultSize);
819 NtClose(KeyHandle);
820 if (!NT_SUCCESS(Status))
821 {
822 ExFreePool(ValueInfo);
823 return(Status);
824 }
825
826 RtlCopyMemory(ConfigPath,
827 ValueInfo->Data,
828 ValueInfo->DataLength);
829 ConfigPath[ValueInfo->DataLength / sizeof(WCHAR)] = (WCHAR)0;
830 ExFreePool(ValueInfo);
831 }
832 else
833 {
834 wcscpy(ConfigPath, L"\\SystemRoot");
835 }
836 wcscat(ConfigPath, L"\\system32\\config");
837
838 DPRINT("ConfigPath: %S\n", ConfigPath);
839
840 EndPtr = ConfigPath + wcslen(ConfigPath);
841
842 CmiDoVerify = TRUE;
843
844 /* FIXME: Save boot log */
845
846 /* Connect the SYSTEM hive only if it has been created */
847 if (SetupBoot == TRUE)
848 {
849 wcscpy(EndPtr, REG_SYSTEM_FILE_NAME);
850 DPRINT ("ConfigPath: %S\n", ConfigPath);
851
852 RtlInitUnicodeString (&KeyName,
853 REG_SYSTEM_KEY_NAME);
854 InitializeObjectAttributes(&ObjectAttributes,
855 &KeyName,
856 OBJ_CASE_INSENSITIVE,
857 NULL,
858 NULL);
859
860 RtlInitUnicodeString (&FileName,
861 ConfigPath);
862 Status = CmiLoadHive (&ObjectAttributes,
863 &FileName,
864 0);
865 if (!NT_SUCCESS(Status))
866 {
867 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status);
868 return Status;
869 }
870
871 Status = CmiInitControlSetLink ();
872 if (!NT_SUCCESS(Status))
873 {
874 DPRINT1("CmiInitControlSetLink() failed (Status %lx)\n", Status);
875 return(Status);
876 }
877 }
878
879 /* Connect the SOFTWARE hive */
880 wcscpy(EndPtr, REG_SOFTWARE_FILE_NAME);
881 RtlInitUnicodeString (&FileName,
882 ConfigPath);
883 DPRINT ("ConfigPath: %S\n", ConfigPath);
884
885 RtlInitUnicodeString (&KeyName,
886 REG_SOFTWARE_KEY_NAME);
887 InitializeObjectAttributes(&ObjectAttributes,
888 &KeyName,
889 OBJ_CASE_INSENSITIVE,
890 NULL,
891 NULL);
892
893 Status = CmiLoadHive (&ObjectAttributes,
894 &FileName,
895 0);
896 if (!NT_SUCCESS(Status))
897 {
898 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
899 return(Status);
900 }
901
902 /* Connect the SAM hive */
903 wcscpy(EndPtr, REG_SAM_FILE_NAME);
904 RtlInitUnicodeString (&FileName,
905 ConfigPath);
906 DPRINT ("ConfigPath: %S\n", ConfigPath);
907
908 RtlInitUnicodeString (&KeyName,
909 REG_SAM_KEY_NAME);
910 InitializeObjectAttributes(&ObjectAttributes,
911 &KeyName,
912 OBJ_CASE_INSENSITIVE,
913 NULL,
914 NULL);
915 Status = CmiLoadHive (&ObjectAttributes,
916 &FileName,
917 0);
918 if (!NT_SUCCESS(Status))
919 {
920 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
921 return(Status);
922 }
923
924 /* Connect the SECURITY hive */
925 wcscpy(EndPtr, REG_SEC_FILE_NAME);
926 RtlInitUnicodeString (&FileName,
927 ConfigPath);
928 DPRINT ("ConfigPath: %S\n", ConfigPath);
929
930 RtlInitUnicodeString (&KeyName,
931 REG_SEC_KEY_NAME);
932 InitializeObjectAttributes(&ObjectAttributes,
933 &KeyName,
934 OBJ_CASE_INSENSITIVE,
935 NULL,
936 NULL);
937 Status = CmiLoadHive (&ObjectAttributes,
938 &FileName,
939 0);
940 if (!NT_SUCCESS(Status))
941 {
942 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
943 return(Status);
944 }
945
946 /* Connect the DEFAULT hive */
947 wcscpy(EndPtr, REG_DEFAULT_USER_FILE_NAME);
948 RtlInitUnicodeString (&FileName,
949 ConfigPath);
950 DPRINT ("ConfigPath: %S\n", ConfigPath);
951
952 RtlInitUnicodeString (&KeyName,
953 REG_DEFAULT_USER_KEY_NAME);
954 InitializeObjectAttributes(&ObjectAttributes,
955 &KeyName,
956 OBJ_CASE_INSENSITIVE,
957 NULL,
958 NULL);
959 Status = CmiLoadHive (&ObjectAttributes,
960 &FileName,
961 0);
962 if (!NT_SUCCESS(Status))
963 {
964 DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
965 return(Status);
966 }
967
968 // CmiCheckRegistry(TRUE);
969
970 /* Start automatic hive synchronization */
971 KeInitializeDpc(&CmiHiveSyncDpc,
972 CmiHiveSyncDpcRoutine,
973 NULL);
974 KeInitializeTimer(&CmiHiveSyncTimer);
975 CmiHiveSyncEnabled = TRUE;
976
977 DPRINT("CmiInitHives() done\n");
978
979 return(STATUS_SUCCESS);
980 }
981
982
983 VOID
984 CmShutdownRegistry(VOID)
985 {
986 PREGISTRY_HIVE Hive;
987 PLIST_ENTRY Entry;
988
989 DPRINT1("CmShutdownRegistry() called\n");
990
991 /* Stop automatic hive synchronization */
992 CmiHiveSyncEnabled = FALSE;
993
994 /* Cancel pending hive synchronization */
995 if (CmiHiveSyncPending == TRUE)
996 {
997 KeCancelTimer(&CmiHiveSyncTimer);
998 CmiHiveSyncPending = FALSE;
999 }
1000
1001 /* Acquire hive list lock exclusively */
1002 KeEnterCriticalRegion();
1003 ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
1004
1005 Entry = CmiHiveListHead.Flink;
1006 while (Entry != &CmiHiveListHead)
1007 {
1008 Hive = CONTAINING_RECORD(Entry, REGISTRY_HIVE, HiveList);
1009
1010 if (!(IsNoFileHive(Hive) || IsNoSynchHive(Hive)))
1011 {
1012 /* Acquire hive resource exclusively */
1013 ExAcquireResourceExclusiveLite(&Hive->HiveResource,
1014 TRUE);
1015
1016 /* Flush non-volatile hive */
1017 CmiFlushRegistryHive(Hive);
1018
1019 /* Release hive resource */
1020 ExReleaseResourceLite(&Hive->HiveResource);
1021 }
1022
1023 Entry = Entry->Flink;
1024 }
1025
1026 /* Release hive list lock */
1027 ExReleaseResourceLite(&CmiHiveListLock);
1028 KeLeaveCriticalRegion();
1029
1030 DPRINT1("CmShutdownRegistry() done\n");
1031 }
1032
1033
1034 VOID STDCALL
1035 CmiHiveSyncRoutine(PVOID DeferredContext)
1036 {
1037 PREGISTRY_HIVE Hive;
1038 PLIST_ENTRY Entry;
1039
1040 DPRINT("CmiHiveSyncRoutine() called\n");
1041
1042 CmiHiveSyncPending = FALSE;
1043
1044 /* Acquire hive list lock exclusively */
1045 KeEnterCriticalRegion();
1046 ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
1047
1048 Entry = CmiHiveListHead.Flink;
1049 while (Entry != &CmiHiveListHead)
1050 {
1051 Hive = CONTAINING_RECORD(Entry, REGISTRY_HIVE, HiveList);
1052
1053 if (!(IsNoFileHive(Hive) || IsNoSynchHive(Hive)))
1054 {
1055 /* Acquire hive resource exclusively */
1056 ExAcquireResourceExclusiveLite(&Hive->HiveResource,
1057 TRUE);
1058
1059 /* Flush non-volatile hive */
1060 CmiFlushRegistryHive(Hive);
1061
1062 /* Release hive resource */
1063 ExReleaseResourceLite(&Hive->HiveResource);
1064 }
1065
1066 Entry = Entry->Flink;
1067 }
1068
1069 /* Release hive list lock */
1070 ExReleaseResourceLite(&CmiHiveListLock);
1071 KeLeaveCriticalRegion();
1072
1073 DPRINT("DeferredContext %x\n", DeferredContext);
1074 ExFreePool(DeferredContext);
1075
1076 DPRINT("CmiHiveSyncRoutine() done\n");
1077 }
1078
1079
1080 static VOID STDCALL
1081 CmiHiveSyncDpcRoutine(PKDPC Dpc,
1082 PVOID DeferredContext,
1083 PVOID SystemArgument1,
1084 PVOID SystemArgument2)
1085 {
1086 PWORK_QUEUE_ITEM WorkQueueItem;
1087
1088 WorkQueueItem = ExAllocatePool(NonPagedPool,
1089 sizeof(WORK_QUEUE_ITEM));
1090 if (WorkQueueItem == NULL)
1091 {
1092 DbgPrint("Failed to allocate work item\n");
1093 return;
1094 }
1095
1096 ExInitializeWorkItem(WorkQueueItem,
1097 CmiHiveSyncRoutine,
1098 WorkQueueItem);
1099
1100 DPRINT("DeferredContext %x\n", WorkQueueItem);
1101 ExQueueWorkItem(WorkQueueItem,
1102 CriticalWorkQueue);
1103 }
1104
1105
1106 VOID
1107 CmiSyncHives(VOID)
1108 {
1109 LARGE_INTEGER Timeout;
1110
1111 DPRINT("CmiSyncHives() called\n");
1112
1113 if (CmiHiveSyncEnabled == FALSE ||
1114 CmiHiveSyncPending == TRUE)
1115 return;
1116
1117 CmiHiveSyncPending = TRUE;
1118
1119
1120 #if defined(__GNUC__)
1121 Timeout.QuadPart = -50000000LL;
1122 #else
1123 Timeout.QuadPart = -50000000;
1124 #endif
1125 KeSetTimer(&CmiHiveSyncTimer,
1126 Timeout,
1127 &CmiHiveSyncDpc);
1128 }
1129
1130 /* EOF */