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