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