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