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