disable regular kmode apc's around Resource locks
[reactos.git] / reactos / ntoskrnl / cm / ntfunc.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cm/ntfunc.c
5 * PURPOSE: Ntxxx function for registry access
6 * UPDATE HISTORY:
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #define NTOS_MODE_KERNEL
12 #include <ntos.h>
13 #include <string.h>
14 #include <roscfg.h>
15 #include <internal/ob.h>
16 #include <internal/se.h>
17
18 #define NDEBUG
19 #include <internal/debug.h>
20
21 #include "cm.h"
22
23
24 /* GLOBALS ******************************************************************/
25
26 extern POBJECT_TYPE CmiKeyType;
27 extern PREGISTRY_HIVE CmiVolatileHive;
28
29 static BOOLEAN CmiRegistryInitialized = FALSE;
30
31
32 /* FUNCTIONS ****************************************************************/
33
34 NTSTATUS STDCALL
35 NtCreateKey(OUT PHANDLE KeyHandle,
36 IN ACCESS_MASK DesiredAccess,
37 IN POBJECT_ATTRIBUTES ObjectAttributes,
38 IN ULONG TitleIndex,
39 IN PUNICODE_STRING Class,
40 IN ULONG CreateOptions,
41 OUT PULONG Disposition)
42 {
43 UNICODE_STRING RemainingPath;
44 PKEY_OBJECT KeyObject;
45 NTSTATUS Status;
46 PVOID Object;
47 PWSTR End;
48 PWSTR Start;
49
50 DPRINT("NtCreateKey (Name %wZ KeyHandle %x Root %x)\n",
51 ObjectAttributes->ObjectName,
52 KeyHandle,
53 ObjectAttributes->RootDirectory);
54
55 Status = ObFindObject(ObjectAttributes,
56 &Object,
57 &RemainingPath,
58 CmiKeyType);
59 if (!NT_SUCCESS(Status))
60 {
61 return(Status);
62 }
63
64 DPRINT("RemainingPath %wZ\n", &RemainingPath);
65
66 if ((RemainingPath.Buffer == NULL) || (RemainingPath.Buffer[0] == 0))
67 {
68 /* Fail if the key has been deleted */
69 if (((PKEY_OBJECT) Object)->Flags & KO_MARKED_FOR_DELETE)
70 {
71 ObDereferenceObject(Object);
72 return(STATUS_UNSUCCESSFUL);
73 }
74
75 if (Disposition)
76 *Disposition = REG_OPENED_EXISTING_KEY;
77
78 Status = ObCreateHandle(PsGetCurrentProcess(),
79 Object,
80 DesiredAccess,
81 TRUE,
82 KeyHandle);
83
84 DPRINT("Status %x\n", Status);
85 ObDereferenceObject(Object);
86 return Status;
87 }
88
89 /* If RemainingPath contains \ we must return error
90 because NtCreateKey don't create trees */
91 Start = RemainingPath.Buffer;
92 if (*Start == L'\\')
93 Start++;
94
95 End = wcschr(Start, L'\\');
96 if (End != NULL)
97 {
98 ObDereferenceObject(Object);
99 return STATUS_OBJECT_NAME_NOT_FOUND;
100 }
101
102 DPRINT("RemainingPath %S ParentObject %x\n", RemainingPath.Buffer, Object);
103
104 Status = ObCreateObject(ExGetPreviousMode(),
105 CmiKeyType,
106 NULL,
107 ExGetPreviousMode(),
108 NULL,
109 sizeof(KEY_OBJECT),
110 0,
111 0,
112 (PVOID*)&KeyObject);
113 if (!NT_SUCCESS(Status))
114 {
115 return(Status);
116 }
117
118 Status = ObInsertObject((PVOID)KeyObject,
119 NULL,
120 DesiredAccess,
121 0,
122 NULL,
123 KeyHandle);
124 if (!NT_SUCCESS(Status))
125 {
126 ObDereferenceObject(KeyObject);
127 return(Status);
128 }
129
130 KeyObject->ParentKey = Object;
131
132 if (CreateOptions & REG_OPTION_VOLATILE)
133 KeyObject->RegistryHive = CmiVolatileHive;
134 else
135 KeyObject->RegistryHive = KeyObject->ParentKey->RegistryHive;
136
137 KeyObject->Flags = 0;
138 KeyObject->NumberOfSubKeys = 0;
139 KeyObject->SizeOfSubKeys = 0;
140 KeyObject->SubKeys = NULL;
141
142 /* Acquire hive lock */
143 KeEnterCriticalRegion();
144 ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
145
146 /* add key to subkeys of parent if needed */
147 Status = CmiAddSubKey(KeyObject->RegistryHive,
148 KeyObject->ParentKey,
149 KeyObject,
150 &RemainingPath,
151 TitleIndex,
152 Class,
153 CreateOptions);
154 if (!NT_SUCCESS(Status))
155 {
156 DPRINT("CmiAddSubKey() failed (Status %lx)\n", Status);
157 /* Release hive lock */
158 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
159 KeLeaveCriticalRegion();
160 ObDereferenceObject(KeyObject);
161 ObDereferenceObject(Object);
162 return STATUS_UNSUCCESSFUL;
163 }
164
165 RtlCreateUnicodeString(&KeyObject->Name,
166 Start);
167
168 if (KeyObject->RegistryHive == KeyObject->ParentKey->RegistryHive)
169 {
170 KeyObject->KeyCell->ParentKeyOffset = KeyObject->ParentKey->KeyCellOffset;
171 KeyObject->KeyCell->SecurityKeyOffset = KeyObject->ParentKey->KeyCell->SecurityKeyOffset;
172 }
173 else
174 {
175 KeyObject->KeyCell->ParentKeyOffset = -1;
176 KeyObject->KeyCell->SecurityKeyOffset = -1;
177 /* This key must remain in memory unless it is deleted
178 or file is unloaded */
179 ObReferenceObjectByPointer(KeyObject,
180 STANDARD_RIGHTS_REQUIRED,
181 NULL,
182 UserMode);
183 }
184
185 CmiAddKeyToList(KeyObject->ParentKey, KeyObject);
186
187 VERIFY_KEY_OBJECT(KeyObject);
188
189 /* Release hive lock */
190 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
191 KeLeaveCriticalRegion();
192
193 ObDereferenceObject(KeyObject);
194 ObDereferenceObject(Object);
195
196 if (Disposition)
197 *Disposition = REG_CREATED_NEW_KEY;
198
199 CmiSyncHives();
200
201 return Status;
202 }
203
204
205 NTSTATUS STDCALL
206 NtDeleteKey(IN HANDLE KeyHandle)
207 {
208 PKEY_OBJECT KeyObject;
209 NTSTATUS Status;
210
211 DPRINT("KeyHandle %x\n", KeyHandle);
212
213 /* Verify that the handle is valid and is a registry key */
214 Status = ObReferenceObjectByHandle(KeyHandle,
215 KEY_WRITE,
216 CmiKeyType,
217 UserMode,
218 (PVOID *)&KeyObject,
219 NULL);
220 if (!NT_SUCCESS(Status))
221 {
222 return(Status);
223 }
224
225 /* Acquire hive lock */
226 KeEnterCriticalRegion();
227 ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
228
229 VERIFY_KEY_OBJECT(KeyObject);
230
231 /* Check for subkeys */
232 if (KeyObject->NumberOfSubKeys != 0)
233 {
234 Status = STATUS_CANNOT_DELETE;
235 }
236 else
237 {
238 /* Set the marked for delete bit in the key object */
239 KeyObject->Flags |= KO_MARKED_FOR_DELETE;
240 Status = STATUS_SUCCESS;
241 }
242
243 /* Release hive lock */
244 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
245 KeLeaveCriticalRegion();
246
247 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID)KeyObject));
248
249 /* Dereference the object */
250 ObDereferenceObject(KeyObject);
251 if(KeyObject->RegistryHive != KeyObject->ParentKey->RegistryHive)
252 ObDereferenceObject(KeyObject);
253
254 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID)KeyObject));
255
256 /*
257 * Note:
258 * Hive-Synchronization will not be triggered here. This is done in
259 * CmiObjectDelete() (in regobj.c) after all key-related structures
260 * have been released.
261 */
262
263 return(Status);
264 }
265
266
267 NTSTATUS STDCALL
268 NtEnumerateKey(IN HANDLE KeyHandle,
269 IN ULONG Index,
270 IN KEY_INFORMATION_CLASS KeyInformationClass,
271 OUT PVOID KeyInformation,
272 IN ULONG Length,
273 OUT PULONG ResultLength)
274 {
275 PKEY_OBJECT KeyObject;
276 PREGISTRY_HIVE RegistryHive;
277 PKEY_CELL KeyCell, SubKeyCell;
278 PHASH_TABLE_CELL HashTableBlock;
279 PKEY_BASIC_INFORMATION BasicInformation;
280 PKEY_NODE_INFORMATION NodeInformation;
281 PKEY_FULL_INFORMATION FullInformation;
282 PDATA_CELL ClassCell;
283 ULONG NameSize;
284 NTSTATUS Status;
285
286 DPRINT("KH %x I %d KIC %x KI %x L %d RL %x\n",
287 KeyHandle,
288 Index,
289 KeyInformationClass,
290 KeyInformation,
291 Length,
292 ResultLength);
293
294 /* Verify that the handle is valid and is a registry key */
295 Status = ObReferenceObjectByHandle(KeyHandle,
296 KEY_ENUMERATE_SUB_KEYS,
297 CmiKeyType,
298 UserMode,
299 (PVOID *) &KeyObject,
300 NULL);
301 if (!NT_SUCCESS(Status))
302 {
303 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
304 return(Status);
305 }
306
307 /* Acquire hive lock */
308 KeEnterCriticalRegion();
309 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
310
311 VERIFY_KEY_OBJECT(KeyObject);
312
313 /* Get pointer to KeyCell */
314 KeyCell = KeyObject->KeyCell;
315 RegistryHive = KeyObject->RegistryHive;
316
317 /* Get pointer to SubKey */
318 if (Index >= KeyCell->NumberOfSubKeys)
319 {
320 if (RegistryHive == CmiVolatileHive)
321 {
322 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
323 KeLeaveCriticalRegion();
324 ObDereferenceObject(KeyObject);
325 DPRINT("No more volatile entries\n");
326 return(STATUS_NO_MORE_ENTRIES);
327 }
328 else
329 {
330 ULONG i;
331 PKEY_OBJECT CurKey = NULL;
332
333 /* Search volatile keys */
334 for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
335 {
336 CurKey = KeyObject->SubKeys[i];
337 if (CurKey->RegistryHive == CmiVolatileHive)
338 {
339 if (Index-- == KeyCell->NumberOfSubKeys)
340 break;
341 }
342 }
343 if (Index >= KeyCell->NumberOfSubKeys)
344 {
345 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
346 KeLeaveCriticalRegion();
347 ObDereferenceObject(KeyObject);
348 DPRINT("No more non-volatile entries\n");
349 return(STATUS_NO_MORE_ENTRIES);
350 }
351 SubKeyCell = CurKey->KeyCell;
352 }
353 }
354 else
355 {
356 if (KeyCell->HashTableOffset == (BLOCK_OFFSET)-1)
357 {
358 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
359 KeLeaveCriticalRegion();
360 ObDereferenceObject(KeyObject);
361 return(STATUS_NO_MORE_ENTRIES);
362 }
363
364 HashTableBlock = CmiGetCell (RegistryHive, KeyCell->HashTableOffset, NULL);
365 if (HashTableBlock == NULL)
366 {
367 DPRINT("CmiGetBlock() failed\n");
368 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
369 KeLeaveCriticalRegion();
370 ObDereferenceObject(KeyObject);
371 return STATUS_UNSUCCESSFUL;
372 }
373 SubKeyCell = CmiGetKeyFromHashByIndex(RegistryHive,
374 HashTableBlock,
375 Index);
376 }
377
378 if (SubKeyCell == NULL)
379 {
380 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
381 KeLeaveCriticalRegion();
382 ObDereferenceObject(KeyObject);
383 DPRINT("No more entries\n");
384 return(STATUS_NO_MORE_ENTRIES);
385 }
386
387 Status = STATUS_SUCCESS;
388 switch (KeyInformationClass)
389 {
390 case KeyBasicInformation:
391 /* Check size of buffer */
392 NameSize = SubKeyCell->NameSize;
393 if (SubKeyCell->Flags & REG_KEY_NAME_PACKED)
394 {
395 NameSize *= sizeof(WCHAR);
396 }
397 *ResultLength = sizeof(KEY_BASIC_INFORMATION) + NameSize;
398
399 if (Length < *ResultLength)
400 {
401 Status = STATUS_BUFFER_OVERFLOW;
402 }
403 else
404 {
405 /* Fill buffer with requested info */
406 BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
407 BasicInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.u.LowPart;
408 BasicInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.u.HighPart;
409 BasicInformation->TitleIndex = Index;
410 BasicInformation->NameLength = NameSize;
411
412 if (SubKeyCell->Flags & REG_KEY_NAME_PACKED)
413 {
414 CmiCopyPackedName(BasicInformation->Name,
415 SubKeyCell->Name,
416 SubKeyCell->NameSize);
417 }
418 else
419 {
420 RtlCopyMemory(BasicInformation->Name,
421 SubKeyCell->Name,
422 SubKeyCell->NameSize);
423 }
424 }
425 break;
426
427 case KeyNodeInformation:
428 /* Check size of buffer */
429 if (SubKeyCell->Flags & REG_KEY_NAME_PACKED)
430 {
431 NameSize = SubKeyCell->NameSize * sizeof(WCHAR);
432 }
433 else
434 {
435 NameSize = SubKeyCell->NameSize;
436 }
437 *ResultLength = sizeof(KEY_NODE_INFORMATION) +
438 NameSize + SubKeyCell->ClassSize;
439
440 if (Length < *ResultLength)
441 {
442 Status = STATUS_BUFFER_OVERFLOW;
443 }
444 else
445 {
446 /* Fill buffer with requested info */
447 NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
448 NodeInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.u.LowPart;
449 NodeInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.u.HighPart;
450 NodeInformation->TitleIndex = Index;
451 NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) + NameSize;
452 NodeInformation->ClassLength = SubKeyCell->ClassSize;
453 NodeInformation->NameLength = NameSize;
454
455 if (SubKeyCell->Flags & REG_KEY_NAME_PACKED)
456 {
457 CmiCopyPackedName(NodeInformation->Name,
458 SubKeyCell->Name,
459 SubKeyCell->NameSize);
460 }
461 else
462 {
463 RtlCopyMemory(NodeInformation->Name,
464 SubKeyCell->Name,
465 SubKeyCell->NameSize);
466 }
467
468 if (SubKeyCell->ClassSize != 0)
469 {
470 ClassCell = CmiGetCell (KeyObject->RegistryHive,
471 SubKeyCell->ClassNameOffset,
472 NULL);
473 RtlCopyMemory (NodeInformation->Name + SubKeyCell->NameSize,
474 ClassCell->Data,
475 SubKeyCell->ClassSize);
476 }
477 }
478 break;
479
480 case KeyFullInformation:
481 /* Check size of buffer */
482 *ResultLength = sizeof(KEY_FULL_INFORMATION) +
483 SubKeyCell->ClassSize;
484
485 if (Length < *ResultLength)
486 {
487 Status = STATUS_BUFFER_OVERFLOW;
488 }
489 else
490 {
491 /* Fill buffer with requested info */
492 FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
493 FullInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.u.LowPart;
494 FullInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.u.HighPart;
495 FullInformation->TitleIndex = Index;
496 FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) -
497 sizeof(WCHAR);
498 FullInformation->ClassLength = SubKeyCell->ClassSize;
499 FullInformation->SubKeys = SubKeyCell->NumberOfSubKeys;
500 FullInformation->MaxNameLen = CmiGetMaxNameLength(KeyObject);
501 FullInformation->MaxClassLen = CmiGetMaxClassLength(KeyObject);
502 FullInformation->Values = SubKeyCell->NumberOfValues;
503 FullInformation->MaxValueNameLen =
504 CmiGetMaxValueNameLength(RegistryHive, SubKeyCell);
505 FullInformation->MaxValueDataLen =
506 CmiGetMaxValueDataLength(RegistryHive, SubKeyCell);
507 if (SubKeyCell->ClassSize != 0)
508 {
509 ClassCell = CmiGetCell (KeyObject->RegistryHive,
510 SubKeyCell->ClassNameOffset,
511 NULL);
512 RtlCopyMemory (FullInformation->Class,
513 ClassCell->Data,
514 SubKeyCell->ClassSize);
515 }
516 }
517 break;
518
519 default:
520 DPRINT1("Not handling 0x%x\n", KeyInformationClass);
521 break;
522 }
523
524 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
525 KeLeaveCriticalRegion();
526 ObDereferenceObject(KeyObject);
527
528 DPRINT("Returning status %x\n", Status);
529
530 return(Status);
531 }
532
533
534 NTSTATUS STDCALL
535 NtEnumerateValueKey(IN HANDLE KeyHandle,
536 IN ULONG Index,
537 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
538 OUT PVOID KeyValueInformation,
539 IN ULONG Length,
540 OUT PULONG ResultLength)
541 {
542 NTSTATUS Status;
543 PKEY_OBJECT KeyObject;
544 PREGISTRY_HIVE RegistryHive;
545 PKEY_CELL KeyCell;
546 PVALUE_CELL ValueCell;
547 PDATA_CELL DataCell;
548 ULONG NameSize;
549 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation;
550 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
551 PKEY_VALUE_FULL_INFORMATION ValueFullInformation;
552
553 DPRINT("KH %x I %d KVIC %x KVI %x L %d RL %x\n",
554 KeyHandle,
555 Index,
556 KeyValueInformationClass,
557 KeyValueInformation,
558 Length,
559 ResultLength);
560
561 /* Verify that the handle is valid and is a registry key */
562 Status = ObReferenceObjectByHandle(KeyHandle,
563 KEY_QUERY_VALUE,
564 CmiKeyType,
565 UserMode,
566 (PVOID *) &KeyObject,
567 NULL);
568
569 if (!NT_SUCCESS(Status))
570 {
571 return Status;
572 }
573
574 /* Acquire hive lock */
575 KeEnterCriticalRegion();
576 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
577
578 VERIFY_KEY_OBJECT(KeyObject);
579
580 /* Get pointer to KeyCell */
581 KeyCell = KeyObject->KeyCell;
582 RegistryHive = KeyObject->RegistryHive;
583
584 /* Get Value block of interest */
585 Status = CmiGetValueFromKeyByIndex(RegistryHive,
586 KeyCell,
587 Index,
588 &ValueCell);
589
590 if (!NT_SUCCESS(Status))
591 {
592 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
593 KeLeaveCriticalRegion();
594 ObDereferenceObject(KeyObject);
595 return Status;
596 }
597
598 if (ValueCell != NULL)
599 {
600 switch (KeyValueInformationClass)
601 {
602 case KeyValueBasicInformation:
603 NameSize = ValueCell->NameSize;
604 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
605 {
606 NameSize *= sizeof(WCHAR);
607 }
608 *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameSize;
609 if (Length < *ResultLength)
610 {
611 Status = STATUS_BUFFER_OVERFLOW;
612 }
613 else
614 {
615 ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION)
616 KeyValueInformation;
617 ValueBasicInformation->TitleIndex = 0;
618 ValueBasicInformation->Type = ValueCell->DataType;
619 ValueBasicInformation->NameLength = NameSize;
620 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
621 {
622 CmiCopyPackedName(ValueBasicInformation->Name,
623 ValueCell->Name,
624 ValueCell->NameSize);
625 }
626 else
627 {
628 RtlCopyMemory(ValueBasicInformation->Name,
629 ValueCell->Name,
630 NameSize);
631 }
632 }
633 break;
634
635 case KeyValuePartialInformation:
636 *ResultLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
637 (ValueCell->DataSize & REG_DATA_SIZE_MASK);
638 if (Length < *ResultLength)
639 {
640 Status = STATUS_BUFFER_OVERFLOW;
641 }
642 else
643 {
644 ValuePartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)
645 KeyValueInformation;
646 ValuePartialInformation->TitleIndex = 0;
647 ValuePartialInformation->Type = ValueCell->DataType;
648 ValuePartialInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK;
649 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
650 {
651 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
652 RtlCopyMemory(ValuePartialInformation->Data,
653 DataCell->Data,
654 ValueCell->DataSize & REG_DATA_SIZE_MASK);
655 }
656 else
657 {
658 RtlCopyMemory(ValuePartialInformation->Data,
659 &ValueCell->DataOffset,
660 ValueCell->DataSize & REG_DATA_SIZE_MASK);
661 }
662 }
663 break;
664
665 case KeyValueFullInformation:
666 NameSize = ValueCell->NameSize;
667 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
668 {
669 NameSize *= sizeof(WCHAR);
670 }
671 *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) +
672 NameSize + (ValueCell->DataSize & REG_DATA_SIZE_MASK);
673 if (Length < *ResultLength)
674 {
675 Status = STATUS_BUFFER_OVERFLOW;
676 }
677 else
678 {
679 ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)
680 KeyValueInformation;
681 ValueFullInformation->TitleIndex = 0;
682 ValueFullInformation->Type = ValueCell->DataType;
683 ValueFullInformation->NameLength = NameSize;
684 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
685 {
686 CmiCopyPackedName(ValueFullInformation->Name,
687 ValueCell->Name,
688 ValueCell->NameSize);
689 }
690 else
691 {
692 RtlCopyMemory(ValueFullInformation->Name,
693 ValueCell->Name,
694 ValueCell->NameSize);
695 }
696 ValueFullInformation->DataOffset =
697 (ULONG)ValueFullInformation->Name - (ULONG)ValueFullInformation +
698 ValueFullInformation->NameLength;
699 ValueFullInformation->DataOffset =
700 ROUND_UP(ValueFullInformation->DataOffset, sizeof(PVOID));
701 ValueFullInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK;
702 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
703 {
704 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
705 RtlCopyMemory((PCHAR) ValueFullInformation
706 + ValueFullInformation->DataOffset,
707 DataCell->Data,
708 ValueCell->DataSize & REG_DATA_SIZE_MASK);
709 }
710 else
711 {
712 RtlCopyMemory((PCHAR) ValueFullInformation
713 + ValueFullInformation->DataOffset,
714 &ValueCell->DataOffset,
715 ValueCell->DataSize & REG_DATA_SIZE_MASK);
716 }
717 }
718 break;
719
720 default:
721 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass);
722 break;
723 }
724 }
725 else
726 {
727 Status = STATUS_UNSUCCESSFUL;
728 }
729
730 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
731 KeLeaveCriticalRegion();
732 ObDereferenceObject(KeyObject);
733
734 return Status;
735 }
736
737
738 NTSTATUS STDCALL
739 NtFlushKey(IN HANDLE KeyHandle)
740 {
741 NTSTATUS Status;
742 PKEY_OBJECT KeyObject;
743 PREGISTRY_HIVE RegistryHive;
744
745 DPRINT("NtFlushKey (KeyHandle %lx) called\n", KeyHandle);
746
747 /* Verify that the handle is valid and is a registry key */
748 Status = ObReferenceObjectByHandle(KeyHandle,
749 KEY_QUERY_VALUE,
750 CmiKeyType,
751 UserMode,
752 (PVOID *)&KeyObject,
753 NULL);
754 if (!NT_SUCCESS(Status))
755 {
756 return(Status);
757 }
758
759 VERIFY_KEY_OBJECT(KeyObject);
760
761 RegistryHive = KeyObject->RegistryHive;
762
763 /* Acquire hive lock */
764 KeEnterCriticalRegion();
765 ExAcquireResourceExclusiveLite(&RegistryHive->HiveResource,
766 TRUE);
767
768 if (IsNoFileHive(RegistryHive))
769 {
770 Status = STATUS_SUCCESS;
771 }
772 else
773 {
774 /* Flush non-volatile hive */
775 Status = CmiFlushRegistryHive(RegistryHive);
776 }
777
778 ExReleaseResourceLite(&RegistryHive->HiveResource);
779 KeLeaveCriticalRegion();
780
781 ObDereferenceObject(KeyObject);
782
783 return STATUS_SUCCESS;
784 }
785
786
787 NTSTATUS STDCALL
788 NtOpenKey(OUT PHANDLE KeyHandle,
789 IN ACCESS_MASK DesiredAccess,
790 IN POBJECT_ATTRIBUTES ObjectAttributes)
791 {
792 UNICODE_STRING RemainingPath;
793 NTSTATUS Status;
794 PVOID Object;
795
796 DPRINT("NtOpenKey(KH %x DA %x OA %x OA->ON '%wZ'\n",
797 KeyHandle,
798 DesiredAccess,
799 ObjectAttributes,
800 ObjectAttributes ? ObjectAttributes->ObjectName : NULL);
801
802 RemainingPath.Buffer = NULL;
803 Status = ObFindObject(ObjectAttributes,
804 &Object,
805 &RemainingPath,
806 CmiKeyType);
807 if (!NT_SUCCESS(Status))
808 {
809 return(Status);
810 }
811
812 VERIFY_KEY_OBJECT((PKEY_OBJECT) Object);
813
814 DPRINT("RemainingPath '%wZ'\n", &RemainingPath);
815
816 if ((RemainingPath.Buffer != NULL) && (RemainingPath.Buffer[0] != 0))
817 {
818 ObDereferenceObject(Object);
819 return(STATUS_UNSUCCESSFUL);
820 }
821
822 /* Fail if the key has been deleted */
823 if (((PKEY_OBJECT)Object)->Flags & KO_MARKED_FOR_DELETE)
824 {
825 ObDereferenceObject(Object);
826 return(STATUS_UNSUCCESSFUL);
827 }
828
829 Status = ObCreateHandle(PsGetCurrentProcess(),
830 Object,
831 DesiredAccess,
832 TRUE,
833 KeyHandle);
834 ObDereferenceObject(Object);
835
836 if (!NT_SUCCESS(Status))
837 {
838 return(Status);
839 }
840
841 return(STATUS_SUCCESS);
842 }
843
844
845 NTSTATUS STDCALL
846 NtQueryKey(IN HANDLE KeyHandle,
847 IN KEY_INFORMATION_CLASS KeyInformationClass,
848 OUT PVOID KeyInformation,
849 IN ULONG Length,
850 OUT PULONG ResultLength)
851 {
852 PKEY_BASIC_INFORMATION BasicInformation;
853 PKEY_NODE_INFORMATION NodeInformation;
854 PKEY_FULL_INFORMATION FullInformation;
855 PREGISTRY_HIVE RegistryHive;
856 PDATA_CELL ClassCell;
857 PKEY_OBJECT KeyObject;
858 PKEY_CELL KeyCell;
859 NTSTATUS Status;
860
861 DPRINT("NtQueryKey(KH %x KIC %x KI %x L %d RL %x)\n",
862 KeyHandle,
863 KeyInformationClass,
864 KeyInformation,
865 Length,
866 ResultLength);
867
868 /* Verify that the handle is valid and is a registry key */
869 Status = ObReferenceObjectByHandle(KeyHandle,
870 KEY_READ,
871 CmiKeyType,
872 UserMode,
873 (PVOID *) &KeyObject,
874 NULL);
875 if (!NT_SUCCESS(Status))
876 {
877 return Status;
878 }
879
880 /* Acquire hive lock */
881 KeEnterCriticalRegion();
882 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
883
884 VERIFY_KEY_OBJECT(KeyObject);
885
886 /* Get pointer to KeyCell */
887 KeyCell = KeyObject->KeyCell;
888 RegistryHive = KeyObject->RegistryHive;
889
890 Status = STATUS_SUCCESS;
891 switch (KeyInformationClass)
892 {
893 case KeyBasicInformation:
894 /* Check size of buffer */
895 *ResultLength = sizeof(KEY_BASIC_INFORMATION) +
896 KeyObject->Name.Length;
897
898 if (Length < *ResultLength)
899 {
900 Status = STATUS_BUFFER_OVERFLOW;
901 }
902 else
903 {
904 /* Fill buffer with requested info */
905 BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
906 BasicInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.u.LowPart;
907 BasicInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.u.HighPart;
908 BasicInformation->TitleIndex = 0;
909 BasicInformation->NameLength = KeyObject->Name.Length;
910
911 if (KeyCell->Flags & REG_KEY_NAME_PACKED)
912 {
913 CmiCopyPackedName(BasicInformation->Name,
914 KeyCell->Name,
915 KeyCell->NameSize);
916 }
917 else
918 {
919 RtlCopyMemory(BasicInformation->Name,
920 KeyCell->Name,
921 KeyCell->NameSize);
922 }
923 }
924 break;
925
926 case KeyNodeInformation:
927 /* Check size of buffer */
928 *ResultLength = sizeof(KEY_NODE_INFORMATION) +
929 KeyObject->Name.Length + KeyCell->ClassSize;
930
931 if (Length < *ResultLength)
932 {
933 Status = STATUS_BUFFER_OVERFLOW;
934 }
935 else
936 {
937 /* Fill buffer with requested info */
938 NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
939 NodeInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.u.LowPart;
940 NodeInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.u.HighPart;
941 NodeInformation->TitleIndex = 0;
942 NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) +
943 KeyObject->Name.Length;
944 NodeInformation->ClassLength = KeyCell->ClassSize;
945 NodeInformation->NameLength = KeyObject->Name.Length;
946
947 if (KeyCell->Flags & REG_KEY_NAME_PACKED)
948 {
949 CmiCopyPackedName(NodeInformation->Name,
950 KeyCell->Name,
951 KeyCell->NameSize);
952 }
953 else
954 {
955 RtlCopyMemory(NodeInformation->Name,
956 KeyCell->Name,
957 KeyCell->NameSize);
958 }
959
960 if (KeyCell->ClassSize != 0)
961 {
962 ClassCell = CmiGetCell (KeyObject->RegistryHive,
963 KeyCell->ClassNameOffset,
964 NULL);
965 RtlCopyMemory (NodeInformation->Name + KeyObject->Name.Length,
966 ClassCell->Data,
967 KeyCell->ClassSize);
968 }
969 }
970 break;
971
972 case KeyFullInformation:
973 /* Check size of buffer */
974 *ResultLength = sizeof(KEY_FULL_INFORMATION) +
975 KeyCell->ClassSize;
976
977 if (Length < *ResultLength)
978 {
979 Status = STATUS_BUFFER_OVERFLOW;
980 }
981 else
982 {
983 /* Fill buffer with requested info */
984 FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
985 FullInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.u.LowPart;
986 FullInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.u.HighPart;
987 FullInformation->TitleIndex = 0;
988 FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) - sizeof(WCHAR);
989 FullInformation->ClassLength = KeyCell->ClassSize;
990 FullInformation->SubKeys = KeyCell->NumberOfSubKeys;
991 FullInformation->MaxNameLen = CmiGetMaxNameLength(KeyObject);
992 FullInformation->MaxClassLen = CmiGetMaxClassLength(KeyObject);
993 FullInformation->Values = KeyCell->NumberOfValues;
994 FullInformation->MaxValueNameLen =
995 CmiGetMaxValueNameLength(RegistryHive, KeyCell);
996 FullInformation->MaxValueDataLen =
997 CmiGetMaxValueDataLength(RegistryHive, KeyCell);
998 if (KeyCell->ClassSize != 0)
999 {
1000 ClassCell = CmiGetCell (KeyObject->RegistryHive,
1001 KeyCell->ClassNameOffset,
1002 NULL);
1003 RtlCopyMemory (FullInformation->Class,
1004 ClassCell->Data,
1005 KeyCell->ClassSize);
1006 }
1007 }
1008 break;
1009 default:
1010 DPRINT1("Not handling 0x%x\n", KeyInformationClass);
1011 break;
1012 }
1013
1014 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1015 KeLeaveCriticalRegion();
1016 ObDereferenceObject(KeyObject);
1017
1018 return(Status);
1019 }
1020
1021
1022 NTSTATUS STDCALL
1023 NtQueryValueKey(IN HANDLE KeyHandle,
1024 IN PUNICODE_STRING ValueName,
1025 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
1026 OUT PVOID KeyValueInformation,
1027 IN ULONG Length,
1028 OUT PULONG ResultLength)
1029 {
1030 NTSTATUS Status;
1031 ULONG NameSize;
1032 PKEY_OBJECT KeyObject;
1033 PREGISTRY_HIVE RegistryHive;
1034 PKEY_CELL KeyCell;
1035 PVALUE_CELL ValueCell;
1036 PDATA_CELL DataCell;
1037 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation;
1038 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
1039 PKEY_VALUE_FULL_INFORMATION ValueFullInformation;
1040
1041 DPRINT("NtQueryValueKey(KeyHandle %x ValueName %S Length %x)\n",
1042 KeyHandle, ValueName->Buffer, Length);
1043
1044 /* Verify that the handle is valid and is a registry key */
1045 Status = ObReferenceObjectByHandle(KeyHandle,
1046 KEY_QUERY_VALUE,
1047 CmiKeyType,
1048 UserMode,
1049 (PVOID *)&KeyObject,
1050 NULL);
1051
1052 if (!NT_SUCCESS(Status))
1053 {
1054 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
1055 return Status;
1056 }
1057
1058 /* Acquire hive lock */
1059 KeEnterCriticalRegion();
1060 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1061
1062 VERIFY_KEY_OBJECT(KeyObject);
1063
1064 /* Get pointer to KeyCell */
1065 KeyCell = KeyObject->KeyCell;
1066 RegistryHive = KeyObject->RegistryHive;
1067
1068 /* Get Value block of interest */
1069 Status = CmiScanKeyForValue(RegistryHive,
1070 KeyCell,
1071 ValueName,
1072 &ValueCell,
1073 NULL);
1074 if (!NT_SUCCESS(Status))
1075 {
1076 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status);
1077 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1078 KeLeaveCriticalRegion();
1079 ObDereferenceObject(KeyObject);
1080 return(Status);
1081 }
1082 else if (ValueCell != NULL)
1083 {
1084 switch (KeyValueInformationClass)
1085 {
1086 case KeyValueBasicInformation:
1087 NameSize = ValueCell->NameSize;
1088 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1089 {
1090 NameSize *= sizeof(WCHAR);
1091 }
1092 *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameSize;
1093 if (Length < *ResultLength)
1094 {
1095 Status = STATUS_BUFFER_TOO_SMALL;
1096 }
1097 else
1098 {
1099 ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION)
1100 KeyValueInformation;
1101 ValueBasicInformation->TitleIndex = 0;
1102 ValueBasicInformation->Type = ValueCell->DataType;
1103 ValueBasicInformation->NameLength = NameSize;
1104 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1105 {
1106 CmiCopyPackedName(ValueBasicInformation->Name,
1107 ValueCell->Name,
1108 ValueCell->NameSize);
1109 }
1110 else
1111 {
1112 RtlCopyMemory(ValueBasicInformation->Name,
1113 ValueCell->Name,
1114 ValueCell->NameSize * sizeof(WCHAR));
1115 }
1116 }
1117 break;
1118
1119 case KeyValuePartialInformation:
1120 *ResultLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION)
1121 + (ValueCell->DataSize & REG_DATA_SIZE_MASK);
1122 if (Length < *ResultLength)
1123 {
1124 Status = STATUS_BUFFER_TOO_SMALL;
1125 }
1126 else
1127 {
1128 ValuePartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)
1129 KeyValueInformation;
1130 ValuePartialInformation->TitleIndex = 0;
1131 ValuePartialInformation->Type = ValueCell->DataType;
1132 ValuePartialInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK;
1133 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
1134 {
1135 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
1136 RtlCopyMemory(ValuePartialInformation->Data,
1137 DataCell->Data,
1138 ValueCell->DataSize & REG_DATA_SIZE_MASK);
1139 }
1140 else
1141 {
1142 RtlCopyMemory(ValuePartialInformation->Data,
1143 &ValueCell->DataOffset,
1144 ValueCell->DataSize & REG_DATA_SIZE_MASK);
1145 }
1146 }
1147 break;
1148
1149 case KeyValueFullInformation:
1150 NameSize = ValueCell->NameSize;
1151 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1152 {
1153 NameSize *= sizeof(WCHAR);
1154 }
1155 *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) +
1156 NameSize + (ValueCell->DataSize & REG_DATA_SIZE_MASK);
1157 if (Length < *ResultLength)
1158 {
1159 Status = STATUS_BUFFER_TOO_SMALL;
1160 }
1161 else
1162 {
1163 ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)
1164 KeyValueInformation;
1165 ValueFullInformation->TitleIndex = 0;
1166 ValueFullInformation->Type = ValueCell->DataType;
1167 ValueFullInformation->NameLength = NameSize;
1168 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1169 {
1170 CmiCopyPackedName(ValueFullInformation->Name,
1171 ValueCell->Name,
1172 ValueCell->NameSize);
1173 }
1174 else
1175 {
1176 RtlCopyMemory(ValueFullInformation->Name,
1177 ValueCell->Name,
1178 ValueCell->NameSize);
1179 }
1180 ValueFullInformation->DataOffset =
1181 (ULONG)ValueFullInformation->Name - (ULONG)ValueFullInformation +
1182 ValueFullInformation->NameLength;
1183 ValueFullInformation->DataOffset =
1184 ROUND_UP(ValueFullInformation->DataOffset, sizeof(PVOID));
1185 ValueFullInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK;
1186 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
1187 {
1188 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
1189 RtlCopyMemory((PCHAR) ValueFullInformation
1190 + ValueFullInformation->DataOffset,
1191 DataCell->Data,
1192 ValueCell->DataSize & REG_DATA_SIZE_MASK);
1193 }
1194 else
1195 {
1196 RtlCopyMemory((PCHAR) ValueFullInformation
1197 + ValueFullInformation->DataOffset,
1198 &ValueCell->DataOffset,
1199 ValueCell->DataSize & REG_DATA_SIZE_MASK);
1200 }
1201 }
1202 break;
1203 default:
1204 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass);
1205 break;
1206 }
1207 }
1208 else
1209 {
1210 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1211 }
1212
1213 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1214 KeLeaveCriticalRegion();
1215 ObDereferenceObject(KeyObject);
1216
1217 return Status;
1218 }
1219
1220
1221 NTSTATUS STDCALL
1222 NtSetValueKey(IN HANDLE KeyHandle,
1223 IN PUNICODE_STRING ValueName,
1224 IN ULONG TitleIndex,
1225 IN ULONG Type,
1226 IN PVOID Data,
1227 IN ULONG DataSize)
1228 {
1229 NTSTATUS Status;
1230 PKEY_OBJECT KeyObject;
1231 PREGISTRY_HIVE RegistryHive;
1232 PKEY_CELL KeyCell;
1233 PVALUE_CELL ValueCell;
1234 BLOCK_OFFSET ValueCellOffset;
1235 PDATA_CELL DataCell;
1236 PDATA_CELL NewDataCell;
1237 PHBIN pBin;
1238 ULONG DesiredAccess;
1239
1240 DPRINT("NtSetValueKey(KeyHandle %x ValueName '%wZ' Type %d)\n",
1241 KeyHandle, ValueName, Type);
1242
1243 DesiredAccess = KEY_SET_VALUE;
1244 if (Type == REG_LINK)
1245 DesiredAccess |= KEY_CREATE_LINK;
1246
1247 /* Verify that the handle is valid and is a registry key */
1248 Status = ObReferenceObjectByHandle(KeyHandle,
1249 DesiredAccess,
1250 CmiKeyType,
1251 UserMode,
1252 (PVOID *)&KeyObject,
1253 NULL);
1254 if (!NT_SUCCESS(Status))
1255 return(Status);
1256
1257 /* Acquire hive lock exclucively */
1258 KeEnterCriticalRegion();
1259 ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1260
1261 VERIFY_KEY_OBJECT(KeyObject);
1262
1263 /* Get pointer to key cell */
1264 KeyCell = KeyObject->KeyCell;
1265 RegistryHive = KeyObject->RegistryHive;
1266 Status = CmiScanKeyForValue(RegistryHive,
1267 KeyCell,
1268 ValueName,
1269 &ValueCell,
1270 &ValueCellOffset);
1271 if (!NT_SUCCESS(Status))
1272 {
1273 DPRINT("Value not found. Status 0x%X\n", Status);
1274
1275 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1276 KeLeaveCriticalRegion();
1277 ObDereferenceObject(KeyObject);
1278 return(Status);
1279 }
1280
1281 if (ValueCell == NULL)
1282 {
1283 DPRINT("Allocate new value cell\n");
1284 Status = CmiAddValueToKey(RegistryHive,
1285 KeyCell,
1286 ValueName,
1287 &ValueCell,
1288 &ValueCellOffset);
1289 if (NT_SUCCESS(Status))
1290 {
1291 CmiMarkBlockDirty(RegistryHive, ValueCellOffset);
1292 }
1293 }
1294
1295 if (!NT_SUCCESS(Status))
1296 {
1297 DPRINT("Cannot add value. Status 0x%X\n", Status);
1298
1299 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1300 KeLeaveCriticalRegion();
1301 ObDereferenceObject(KeyObject);
1302 return(Status);
1303 }
1304
1305 DPRINT("DataSize %lu\n", DataSize);
1306 DPRINT("ValueCell %p\n", ValueCell);
1307 DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
1308
1309 if (DataSize <= sizeof(BLOCK_OFFSET))
1310 {
1311 /* If data size <= sizeof(BLOCK_OFFSET) then store data in the data offset */
1312 DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
1313 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET) &&
1314 (ValueCell->DataSize & REG_DATA_SIZE_MASK) != 0)
1315 {
1316 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
1317 CmiDestroyCell(RegistryHive, DataCell, ValueCell->DataOffset);
1318 }
1319
1320 RtlCopyMemory(&ValueCell->DataOffset, Data, DataSize);
1321 ValueCell->DataSize = DataSize | REG_DATA_IN_OFFSET;
1322 ValueCell->DataType = Type;
1323 RtlMoveMemory(&ValueCell->DataOffset, Data, DataSize);
1324 CmiMarkBlockDirty(RegistryHive, ValueCellOffset);
1325 }
1326 else if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET) &&
1327 (DataSize <= (ValueCell->DataSize & REG_DATA_SIZE_MASK)))
1328 {
1329 /* If new data size is <= current then overwrite current data */
1330 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset,&pBin);
1331 RtlZeroMemory(DataCell->Data, ValueCell->DataSize);
1332 RtlCopyMemory(DataCell->Data, Data, DataSize);
1333 ValueCell->DataSize = DataSize;
1334 ValueCell->DataType = Type;
1335 }
1336 else
1337 {
1338 /*
1339 * New data size is larger than the current, destroy current
1340 * data block and allocate a new one.
1341 */
1342 BLOCK_OFFSET NewOffset;
1343
1344 DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
1345
1346 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET) &&
1347 (ValueCell->DataSize & REG_DATA_SIZE_MASK) != 0)
1348 {
1349 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
1350 CmiDestroyCell(RegistryHive, DataCell, ValueCell->DataOffset);
1351 ValueCell->DataSize = 0;
1352 ValueCell->DataType = 0;
1353 ValueCell->DataOffset = (BLOCK_OFFSET)-1;
1354 }
1355
1356 Status = CmiAllocateCell (RegistryHive,
1357 sizeof(CELL_HEADER) + DataSize,
1358 (PVOID *)&NewDataCell,
1359 &NewOffset);
1360 if (!NT_SUCCESS(Status))
1361 {
1362 DPRINT("CmiAllocateBlock() failed (Status %lx)\n", Status);
1363
1364 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1365 KeLeaveCriticalRegion();
1366 ObDereferenceObject(KeyObject);
1367
1368 return(Status);
1369 }
1370
1371 RtlCopyMemory(&NewDataCell->Data[0], Data, DataSize);
1372 ValueCell->DataSize = DataSize & REG_DATA_SIZE_MASK;
1373 ValueCell->DataType = Type;
1374 ValueCell->DataOffset = NewOffset;
1375 CmiMarkBlockDirty(RegistryHive, ValueCell->DataOffset);
1376 CmiMarkBlockDirty(RegistryHive, ValueCellOffset);
1377 }
1378
1379 /* Mark link key */
1380 if ((Type == REG_LINK) &&
1381 (_wcsicmp(ValueName->Buffer, L"SymbolicLinkValue") == 0))
1382 {
1383 KeyCell->Flags |= REG_KEY_LINK_CELL;
1384 }
1385
1386 NtQuerySystemTime (&KeyCell->LastWriteTime);
1387 CmiMarkBlockDirty (RegistryHive, KeyObject->KeyCellOffset);
1388
1389 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1390 KeLeaveCriticalRegion();
1391 ObDereferenceObject(KeyObject);
1392
1393 CmiSyncHives();
1394
1395 DPRINT("Return Status 0x%X\n", Status);
1396
1397 return(Status);
1398 }
1399
1400
1401 NTSTATUS STDCALL
1402 NtDeleteValueKey (IN HANDLE KeyHandle,
1403 IN PUNICODE_STRING ValueName)
1404 {
1405 PKEY_OBJECT KeyObject;
1406 NTSTATUS Status;
1407
1408 /* Verify that the handle is valid and is a registry key */
1409 Status = ObReferenceObjectByHandle(KeyHandle,
1410 KEY_QUERY_VALUE,
1411 CmiKeyType,
1412 UserMode,
1413 (PVOID *)&KeyObject,
1414 NULL);
1415 if (!NT_SUCCESS(Status))
1416 {
1417 return Status;
1418 }
1419
1420 /* Acquire hive lock */
1421 KeEnterCriticalRegion();
1422 ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1423
1424 VERIFY_KEY_OBJECT(KeyObject);
1425
1426 Status = CmiDeleteValueFromKey(KeyObject->RegistryHive,
1427 KeyObject->KeyCell,
1428 KeyObject->KeyCellOffset,
1429 ValueName);
1430
1431 NtQuerySystemTime (&KeyObject->KeyCell->LastWriteTime);
1432 CmiMarkBlockDirty (KeyObject->RegistryHive, KeyObject->KeyCellOffset);
1433
1434 /* Release hive lock */
1435 ExReleaseResourceLite (&KeyObject->RegistryHive->HiveResource);
1436 KeLeaveCriticalRegion();
1437
1438 ObDereferenceObject (KeyObject);
1439
1440 CmiSyncHives ();
1441
1442 return Status;
1443 }
1444
1445
1446 /*
1447 * NOTE:
1448 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
1449 * KeyObjectAttributes->Name specifies the name of the key to load.
1450 */
1451 NTSTATUS STDCALL
1452 NtLoadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
1453 IN POBJECT_ATTRIBUTES FileObjectAttributes)
1454 {
1455 return NtLoadKey2 (KeyObjectAttributes,
1456 FileObjectAttributes,
1457 0);
1458 }
1459
1460
1461 /*
1462 * NOTE:
1463 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
1464 * KeyObjectAttributes->Name specifies the name of the key to load.
1465 * Flags can be 0 or REG_NO_LAZY_FLUSH.
1466 */
1467 NTSTATUS STDCALL
1468 NtLoadKey2 (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
1469 IN POBJECT_ATTRIBUTES FileObjectAttributes,
1470 IN ULONG Flags)
1471 {
1472 POBJECT_NAME_INFORMATION NameInfo;
1473 PUNICODE_STRING NamePointer;
1474 PUCHAR Buffer;
1475 ULONG BufferSize;
1476 ULONG Length;
1477 NTSTATUS Status;
1478
1479 DPRINT ("NtLoadKey2() called\n");
1480
1481 #if 0
1482 if (!SeSinglePrivilegeCheck (SeRestorePrivilege, KeGetPreviousMode ()))
1483 return STATUS_PRIVILEGE_NOT_HELD;
1484 #endif
1485
1486 if (FileObjectAttributes->RootDirectory != NULL)
1487 {
1488 BufferSize =
1489 sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
1490 Buffer = ExAllocatePool (NonPagedPool,
1491 BufferSize);
1492 if (Buffer == NULL)
1493 return STATUS_INSUFFICIENT_RESOURCES;
1494
1495 Status = NtQueryObject (FileObjectAttributes->RootDirectory,
1496 ObjectNameInformation,
1497 Buffer,
1498 BufferSize,
1499 &Length);
1500 if (!NT_SUCCESS(Status))
1501 {
1502 DPRINT1 ("NtQueryObject() failed (Status %lx)\n", Status);
1503 ExFreePool (Buffer);
1504 return Status;
1505 }
1506
1507 NameInfo = (POBJECT_NAME_INFORMATION)Buffer;
1508 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
1509 &NameInfo->Name, NameInfo->Name.Length);
1510
1511 NameInfo->Name.MaximumLength = MAX_PATH * sizeof(WCHAR);
1512 if (FileObjectAttributes->ObjectName->Buffer[0] != L'\\')
1513 {
1514 RtlAppendUnicodeToString (&NameInfo->Name,
1515 L"\\");
1516 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
1517 &NameInfo->Name, NameInfo->Name.Length);
1518 }
1519 RtlAppendUnicodeStringToString (&NameInfo->Name,
1520 FileObjectAttributes->ObjectName);
1521
1522 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
1523 &NameInfo->Name, NameInfo->Name.Length);
1524 NamePointer = &NameInfo->Name;
1525 }
1526 else
1527 {
1528 if (FileObjectAttributes->ObjectName->Buffer[0] == L'\\')
1529 {
1530 Buffer = NULL;
1531 NamePointer = FileObjectAttributes->ObjectName;
1532 }
1533 else
1534 {
1535 BufferSize =
1536 sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
1537 Buffer = ExAllocatePool (NonPagedPool,
1538 BufferSize);
1539 if (Buffer == NULL)
1540 return STATUS_INSUFFICIENT_RESOURCES;
1541
1542 NameInfo = (POBJECT_NAME_INFORMATION)Buffer;
1543 NameInfo->Name.MaximumLength = MAX_PATH * sizeof(WCHAR);
1544 NameInfo->Name.Length = 0;
1545 NameInfo->Name.Buffer = (PWSTR)((ULONG_PTR)Buffer + sizeof(OBJECT_NAME_INFORMATION));
1546 NameInfo->Name.Buffer[0] = 0;
1547
1548 RtlAppendUnicodeToString (&NameInfo->Name,
1549 L"\\");
1550 RtlAppendUnicodeStringToString (&NameInfo->Name,
1551 FileObjectAttributes->ObjectName);
1552
1553 NamePointer = &NameInfo->Name;
1554 }
1555 }
1556
1557 DPRINT ("Full name: '%wZ'\n", NamePointer);
1558
1559 Status = CmiLoadHive (KeyObjectAttributes,
1560 NamePointer,
1561 Flags);
1562 if (!NT_SUCCESS (Status))
1563 {
1564 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status);
1565 }
1566
1567 if (Buffer != NULL)
1568 ExFreePool (Buffer);
1569
1570 return Status;
1571 }
1572
1573
1574 NTSTATUS STDCALL
1575 NtNotifyChangeKey (IN HANDLE KeyHandle,
1576 IN HANDLE Event,
1577 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1578 IN PVOID ApcContext OPTIONAL,
1579 OUT PIO_STATUS_BLOCK IoStatusBlock,
1580 IN ULONG CompletionFilter,
1581 IN BOOLEAN Asynchroneous,
1582 OUT PVOID ChangeBuffer,
1583 IN ULONG Length,
1584 IN BOOLEAN WatchSubtree)
1585 {
1586 UNIMPLEMENTED;
1587 return(STATUS_NOT_IMPLEMENTED);
1588 }
1589
1590
1591 NTSTATUS STDCALL
1592 NtQueryMultipleValueKey (IN HANDLE KeyHandle,
1593 IN OUT PKEY_VALUE_ENTRY ValueList,
1594 IN ULONG NumberOfValues,
1595 OUT PVOID Buffer,
1596 IN OUT PULONG Length,
1597 OUT PULONG ReturnLength)
1598 {
1599 PREGISTRY_HIVE RegistryHive;
1600 PVALUE_CELL ValueCell;
1601 PKEY_OBJECT KeyObject;
1602 PDATA_CELL DataCell;
1603 ULONG BufferLength = 0;
1604 PKEY_CELL KeyCell;
1605 NTSTATUS Status;
1606 PUCHAR DataPtr;
1607 ULONG i;
1608
1609 /* Verify that the handle is valid and is a registry key */
1610 Status = ObReferenceObjectByHandle(KeyHandle,
1611 KEY_QUERY_VALUE,
1612 CmiKeyType,
1613 UserMode,
1614 (PVOID *) &KeyObject,
1615 NULL);
1616 if (!NT_SUCCESS(Status))
1617 {
1618 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
1619 return(Status);
1620 }
1621
1622 /* Acquire hive lock */
1623 KeEnterCriticalRegion();
1624 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1625
1626 VERIFY_KEY_OBJECT(KeyObject);
1627
1628 /* Get pointer to KeyCell */
1629 KeyCell = KeyObject->KeyCell;
1630 RegistryHive = KeyObject->RegistryHive;
1631
1632 DataPtr = (PUCHAR) Buffer;
1633
1634 for (i = 0; i < NumberOfValues; i++)
1635 {
1636 DPRINT("ValueName: '%wZ'\n", ValueList[i].ValueName);
1637
1638 /* Get Value block of interest */
1639 Status = CmiScanKeyForValue(RegistryHive,
1640 KeyCell,
1641 ValueList[i].ValueName,
1642 &ValueCell,
1643 NULL);
1644
1645 if (!NT_SUCCESS(Status))
1646 {
1647 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status);
1648 break;
1649 }
1650 else if (ValueCell == NULL)
1651 {
1652 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1653 break;
1654 }
1655
1656 BufferLength = ROUND_UP(BufferLength, sizeof(PVOID));
1657
1658 if (BufferLength + (ValueCell->DataSize & REG_DATA_SIZE_MASK) <= *Length)
1659 {
1660 DataPtr = (PUCHAR)ROUND_UP((ULONG)DataPtr, sizeof(PVOID));
1661
1662 ValueList[i].Type = ValueCell->DataType;
1663 ValueList[i].DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK;
1664 ValueList[i].DataOffset = (ULONG) DataPtr - (ULONG) Buffer;
1665
1666 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
1667 {
1668 DataCell = CmiGetCell (RegistryHive,
1669 ValueCell->DataOffset,
1670 NULL);
1671 RtlCopyMemory(DataPtr,
1672 DataCell->Data,
1673 ValueCell->DataSize & REG_DATA_SIZE_MASK);
1674 }
1675 else
1676 {
1677 RtlCopyMemory(DataPtr,
1678 &ValueCell->DataOffset,
1679 ValueCell->DataSize & REG_DATA_SIZE_MASK);
1680 }
1681
1682 DataPtr += ValueCell->DataSize & REG_DATA_SIZE_MASK;
1683 }
1684 else
1685 {
1686 Status = STATUS_BUFFER_TOO_SMALL;
1687 }
1688
1689 BufferLength += ValueCell->DataSize & REG_DATA_SIZE_MASK;
1690 }
1691
1692 if (NT_SUCCESS(Status))
1693 *Length = BufferLength;
1694
1695 *ReturnLength = BufferLength;
1696
1697 /* Release hive lock */
1698 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1699 KeLeaveCriticalRegion();
1700
1701 ObDereferenceObject(KeyObject);
1702
1703 DPRINT("Return Status 0x%X\n", Status);
1704
1705 return Status;
1706 }
1707
1708
1709 NTSTATUS STDCALL
1710 NtReplaceKey (IN POBJECT_ATTRIBUTES ObjectAttributes,
1711 IN HANDLE Key,
1712 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
1713 {
1714 UNIMPLEMENTED;
1715 return(STATUS_NOT_IMPLEMENTED);
1716 }
1717
1718
1719 NTSTATUS STDCALL
1720 NtRestoreKey (IN HANDLE KeyHandle,
1721 IN HANDLE FileHandle,
1722 IN ULONG RestoreFlags)
1723 {
1724 UNIMPLEMENTED;
1725 return(STATUS_NOT_IMPLEMENTED);
1726 }
1727
1728
1729 NTSTATUS STDCALL
1730 NtSaveKey (IN HANDLE KeyHandle,
1731 IN HANDLE FileHandle)
1732 {
1733 PREGISTRY_HIVE TempHive;
1734 PKEY_OBJECT KeyObject;
1735 NTSTATUS Status;
1736
1737 DPRINT ("NtSaveKey() called\n");
1738
1739 #if 0
1740 if (!SeSinglePrivilegeCheck (SeBackupPrivilege, KeGetPreviousMode ()))
1741 return STATUS_PRIVILEGE_NOT_HELD;
1742 #endif
1743
1744 Status = ObReferenceObjectByHandle (KeyHandle,
1745 0,
1746 CmiKeyType,
1747 KeGetPreviousMode(),
1748 (PVOID *)&KeyObject,
1749 NULL);
1750 if (!NT_SUCCESS(Status))
1751 {
1752 DPRINT1 ("ObReferenceObjectByHandle() failed (Status %lx)\n", Status);
1753 return Status;
1754 }
1755
1756 /* Acquire hive lock exclucively */
1757 KeEnterCriticalRegion();
1758 ExAcquireResourceExclusiveLite (&KeyObject->RegistryHive->HiveResource,
1759 TRUE);
1760
1761 /* Refuse to save a volatile key */
1762 if (KeyObject->RegistryHive == CmiVolatileHive)
1763 {
1764 DPRINT1 ("Cannot save a volatile key\n");
1765 ExReleaseResourceLite (&KeyObject->RegistryHive->HiveResource);
1766 KeLeaveCriticalRegion();
1767 ObDereferenceObject (KeyObject);
1768 return STATUS_ACCESS_DENIED;
1769 }
1770
1771 Status = CmiCreateTempHive(&TempHive);
1772 if (!NT_SUCCESS(Status))
1773 {
1774 DPRINT1 ("CmiCreateTempHive() failed (Status %lx)\n", Status);
1775 ExReleaseResourceLite (&KeyObject->RegistryHive->HiveResource);
1776 KeLeaveCriticalRegion();
1777 ObDereferenceObject (KeyObject);
1778 return(Status);
1779 }
1780
1781 Status = CmiCopyKey (TempHive,
1782 NULL,
1783 KeyObject->RegistryHive,
1784 KeyObject->KeyCell);
1785 if (!NT_SUCCESS(Status))
1786 {
1787 DPRINT1 ("CmiCopyKey() failed (Status %lx)\n", Status);
1788 CmiRemoveRegistryHive (TempHive);
1789 ExReleaseResourceLite (&KeyObject->RegistryHive->HiveResource);
1790 KeLeaveCriticalRegion();
1791 ObDereferenceObject (KeyObject);
1792 return(Status);
1793 }
1794
1795 Status = CmiSaveTempHive (TempHive,
1796 FileHandle);
1797 if (!NT_SUCCESS(Status))
1798 {
1799 DPRINT1 ("CmiSaveTempHive() failed (Status %lx)\n", Status);
1800 }
1801
1802 CmiRemoveRegistryHive (TempHive);
1803
1804 /* Release hive lock */
1805 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1806 KeLeaveCriticalRegion();
1807
1808 ObDereferenceObject (KeyObject);
1809
1810 DPRINT ("NtSaveKey() done\n");
1811
1812 return STATUS_SUCCESS;
1813 }
1814
1815
1816 NTSTATUS STDCALL
1817 NtSetInformationKey (IN HANDLE KeyHandle,
1818 IN KEY_SET_INFORMATION_CLASS KeyInformationClass,
1819 IN PVOID KeyInformation,
1820 IN ULONG KeyInformationLength)
1821 {
1822 PKEY_OBJECT KeyObject;
1823 NTSTATUS Status;
1824
1825 if (KeyInformationClass != KeyLastWriteTimeInformation)
1826 return STATUS_INVALID_INFO_CLASS;
1827
1828 if (KeyInformationLength != sizeof (KEY_LAST_WRITE_TIME_INFORMATION))
1829 return STATUS_INFO_LENGTH_MISMATCH;
1830
1831 /* Verify that the handle is valid and is a registry key */
1832 Status = ObReferenceObjectByHandle (KeyHandle,
1833 KEY_SET_VALUE,
1834 CmiKeyType,
1835 UserMode,
1836 (PVOID *)&KeyObject,
1837 NULL);
1838 if (!NT_SUCCESS (Status))
1839 {
1840 DPRINT ("ObReferenceObjectByHandle() failed with status %x\n", Status);
1841 return Status;
1842 }
1843
1844 /* Acquire hive lock */
1845 KeEnterCriticalRegion();
1846 ExAcquireResourceExclusiveLite (&KeyObject->RegistryHive->HiveResource, TRUE);
1847
1848 VERIFY_KEY_OBJECT(KeyObject);
1849
1850 KeyObject->KeyCell->LastWriteTime.QuadPart =
1851 ((PKEY_LAST_WRITE_TIME_INFORMATION)KeyInformation)->LastWriteTime.QuadPart;
1852
1853 CmiMarkBlockDirty (KeyObject->RegistryHive,
1854 KeyObject->KeyCellOffset);
1855
1856 /* Release hive lock */
1857 ExReleaseResourceLite (&KeyObject->RegistryHive->HiveResource);
1858 KeLeaveCriticalRegion();
1859
1860 ObDereferenceObject (KeyObject);
1861
1862 CmiSyncHives ();
1863
1864 DPRINT ("NtSaveKey() done\n");
1865
1866 return STATUS_SUCCESS;
1867 }
1868
1869
1870 /*
1871 * NOTE:
1872 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
1873 * KeyObjectAttributes->Name specifies the name of the key to unload.
1874 */
1875 NTSTATUS STDCALL
1876 NtUnloadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes)
1877 {
1878 PREGISTRY_HIVE RegistryHive;
1879 NTSTATUS Status;
1880
1881 DPRINT ("NtUnloadKey() called\n");
1882
1883 #if 0
1884 if (!SeSinglePrivilegeCheck (SeRestorePrivilege, KeGetPreviousMode ()))
1885 return STATUS_PRIVILEGE_NOT_HELD;
1886 #endif
1887
1888 Status = CmiDisconnectHive (KeyObjectAttributes,
1889 &RegistryHive);
1890 if (!NT_SUCCESS (Status))
1891 {
1892 DPRINT1 ("CmiDisconnectHive() failed (Status %lx)\n", Status);
1893 return Status;
1894 }
1895
1896 DPRINT ("RegistryHive %p\n", RegistryHive);
1897
1898 /* Acquire hive list lock exclusively */
1899 KeEnterCriticalRegion();
1900 ExAcquireResourceExclusiveLite (&CmiHiveListLock,
1901 TRUE);
1902
1903 #if 0
1904 /* Flush hive */
1905 if (!IsNoFileHive (RegistryHive))
1906 CmiFlushRegistryHive (RegistryHive);
1907 #endif
1908
1909 /* Release hive list lock */
1910 ExReleaseResourceLite (&CmiHiveListLock);
1911 KeLeaveCriticalRegion();
1912
1913 CmiRemoveRegistryHive (RegistryHive);
1914
1915 DPRINT ("NtUnloadKey() done\n");
1916
1917 return STATUS_SUCCESS;
1918 }
1919
1920
1921 NTSTATUS STDCALL
1922 NtInitializeRegistry (IN BOOLEAN SetUpBoot)
1923 {
1924 NTSTATUS Status;
1925
1926 if (CmiRegistryInitialized == TRUE)
1927 return STATUS_ACCESS_DENIED;
1928
1929 /* FIXME: save boot log file */
1930
1931 Status = CmiInitHives (SetUpBoot);
1932
1933 CmiRegistryInitialized = TRUE;
1934
1935 return Status;
1936 }
1937
1938 /* EOF */