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