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