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