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