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