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