de5288f3a50a2925fa00715620269a3487642201
[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 = ExGetPreviousMode();
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 DPRINT1("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 DPRINT1("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 DPRINT1("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 if (!NT_SUCCESS(Status))
301 DPRINT1("ObpCreateHandle failed Status 0x%x\n", Status);
302
303 PostCreateKeyInfo.Object = NULL;
304 PostCreateKeyInfo.Status = Status;
305 CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
306
307 LocalDisposition = REG_OPENED_EXISTING_KEY;
308 goto SuccessReturn;
309 }
310
311 /* If RemainingPath contains \ we must return error
312 because NtCreateKey doesn't create trees */
313 Start = RemainingPath.Buffer;
314 if (*Start == L'\\')
315 Start++;
316
317 for (i = 1; i < RemainingPath.Length / sizeof(WCHAR); i++)
318 {
319 if (L'\\' == RemainingPath.Buffer[i])
320 {
321 DPRINT("NtCreateKey() doesn't create trees! (found \'\\\' in remaining path: \"%wZ\"!)\n", &RemainingPath);
322
323 PostCreateKeyInfo.Object = NULL;
324 PostCreateKeyInfo.Status = STATUS_OBJECT_NAME_NOT_FOUND;
325 CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
326
327 Status = STATUS_OBJECT_NAME_NOT_FOUND;
328 goto Cleanup;
329 }
330 }
331
332 DPRINT("RemainingPath %S ParentObject 0x%p\n", RemainingPath.Buffer, Object);
333
334 Status = ObCreateObject(PreviousMode,
335 CmiKeyType,
336 NULL,
337 PreviousMode,
338 NULL,
339 sizeof(KEY_OBJECT),
340 0,
341 0,
342 (PVOID*)&KeyObject);
343 if (!NT_SUCCESS(Status))
344 {
345 DPRINT1("ObCreateObject() failed!\n");
346 PostCreateKeyInfo.Object = NULL;
347 PostCreateKeyInfo.Status = Status;
348 CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
349
350 goto Cleanup;
351 }
352
353 Status = ObInsertObject((PVOID)KeyObject,
354 NULL,
355 DesiredAccess,
356 0,
357 NULL,
358 &hKey);
359 if (!NT_SUCCESS(Status))
360 {
361 ObDereferenceObject(KeyObject);
362 DPRINT1("ObInsertObject() failed!\n");
363
364 PostCreateKeyInfo.Object = NULL;
365 PostCreateKeyInfo.Status = Status;
366 CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
367
368 goto Cleanup;
369 }
370
371 KeyObject->ParentKey = Object;
372
373 if (CreateOptions & REG_OPTION_VOLATILE)
374 KeyObject->RegistryHive = CmiVolatileHive;
375 else
376 KeyObject->RegistryHive = KeyObject->ParentKey->RegistryHive;
377
378 KeyObject->Flags = 0;
379 KeyObject->NumberOfSubKeys = 0;
380 KeyObject->SizeOfSubKeys = 0;
381 KeyObject->SubKeys = NULL;
382
383 /* Acquire hive lock */
384 KeEnterCriticalRegion();
385 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
386
387 InsertTailList(&CmiKeyObjectListHead, &KeyObject->ListEntry);
388
389 /* add key to subkeys of parent if needed */
390 Status = CmiAddSubKey(KeyObject->RegistryHive,
391 KeyObject->ParentKey,
392 KeyObject,
393 &RemainingPath,
394 TitleIndex,
395 &CapturedClass,
396 CreateOptions);
397 if (!NT_SUCCESS(Status))
398 {
399 DPRINT1("CmiAddSubKey() failed (Status %lx)\n", Status);
400 /* Release hive lock */
401 ExReleaseResourceLite(&CmiRegistryLock);
402 KeLeaveCriticalRegion();
403 ObDereferenceObject(KeyObject);
404
405 PostCreateKeyInfo.Object = NULL;
406 PostCreateKeyInfo.Status = STATUS_UNSUCCESSFUL;
407 CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
408
409 Status = STATUS_UNSUCCESSFUL;
410 goto Cleanup;
411 }
412
413 if (Start == RemainingPath.Buffer)
414 {
415 KeyObject->Name = RemainingPath;
416 FreeRemainingPath = FALSE;
417 }
418 else
419 {
420 RtlpCreateUnicodeString(&KeyObject->Name, Start, NonPagedPool);
421 }
422
423 if (KeyObject->RegistryHive == KeyObject->ParentKey->RegistryHive)
424 {
425 KeyObject->KeyCell->ParentKeyOffset = KeyObject->ParentKey->KeyCellOffset;
426 KeyObject->KeyCell->SecurityKeyOffset = KeyObject->ParentKey->KeyCell->SecurityKeyOffset;
427 }
428 else
429 {
430 KeyObject->KeyCell->ParentKeyOffset = -1;
431 KeyObject->KeyCell->SecurityKeyOffset = -1;
432 /* This key must remain in memory unless it is deleted
433 or file is unloaded */
434 ObReferenceObject(KeyObject);
435 }
436
437 CmiAddKeyToList(KeyObject->ParentKey, KeyObject);
438
439 VERIFY_KEY_OBJECT(KeyObject);
440
441 /* Release hive lock */
442 ExReleaseResourceLite(&CmiRegistryLock);
443 KeLeaveCriticalRegion();
444
445 PostCreateKeyInfo.Object = KeyObject;
446 PostCreateKeyInfo.Status = Status;
447 CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
448
449 CmiSyncHives();
450
451 LocalDisposition = REG_CREATED_NEW_KEY;
452
453 SuccessReturn:
454 _SEH_TRY
455 {
456 *KeyHandle = hKey;
457 if (Disposition != NULL)
458 {
459 *Disposition = LocalDisposition;
460 }
461 }
462 _SEH_HANDLE
463 {
464 Status = _SEH_GetExceptionCode();
465 }
466 _SEH_END;
467
468 Cleanup:
469 if (Class != NULL)
470 {
471 ReleaseCapturedUnicodeString(&CapturedClass,
472 PreviousMode);
473 }
474 if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
475 if (FreeRemainingPath) RtlFreeUnicodeString(&RemainingPath);
476 if (Object != NULL) ObDereferenceObject(Object);
477
478 return Status;
479 }
480
481
482 NTSTATUS STDCALL
483 NtDeleteKey(IN HANDLE KeyHandle)
484 {
485 KPROCESSOR_MODE PreviousMode;
486 PKEY_OBJECT KeyObject;
487 NTSTATUS Status;
488 REG_DELETE_KEY_INFORMATION DeleteKeyInfo;
489 REG_POST_OPERATION_INFORMATION PostOperationInfo;
490
491 PAGED_CODE();
492
493 DPRINT("NtDeleteKey(KeyHandle 0x%p) called\n", KeyHandle);
494
495 PreviousMode = ExGetPreviousMode();
496
497 /* Verify that the handle is valid and is a registry key */
498 Status = ObReferenceObjectByHandle(KeyHandle,
499 DELETE,
500 CmiKeyType,
501 PreviousMode,
502 (PVOID *)&KeyObject,
503 NULL);
504 if (!NT_SUCCESS(Status))
505 {
506 DPRINT1("ObReferenceObjectByHandle() failed (Status %lx)\n", Status);
507 return Status;
508 }
509
510 PostOperationInfo.Object = (PVOID)KeyObject;
511 DeleteKeyInfo.Object = (PVOID)KeyObject;
512 Status = CmiCallRegisteredCallbacks(RegNtPreSetValueKey, &DeleteKeyInfo);
513 if (!NT_SUCCESS(Status))
514 {
515 PostOperationInfo.Status = Status;
516 CmiCallRegisteredCallbacks(RegNtDeleteKey, &PostOperationInfo);
517 ObDereferenceObject(KeyObject);
518 return Status;
519 }
520
521 /* Acquire hive lock */
522 KeEnterCriticalRegion();
523 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
524
525 VERIFY_KEY_OBJECT(KeyObject);
526
527 /* Check for subkeys */
528 if (KeyObject->NumberOfSubKeys != 0)
529 {
530 Status = STATUS_CANNOT_DELETE;
531 }
532 else
533 {
534 /* Set the marked for delete bit in the key object */
535 KeyObject->Flags |= KO_MARKED_FOR_DELETE;
536 Status = STATUS_SUCCESS;
537 }
538
539 /* Release hive lock */
540 ExReleaseResourceLite(&CmiRegistryLock);
541 KeLeaveCriticalRegion();
542
543 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID)KeyObject));
544
545 /* Remove the keep-alive reference */
546 ObDereferenceObject(KeyObject);
547
548 if (KeyObject->RegistryHive != KeyObject->ParentKey->RegistryHive)
549 ObDereferenceObject(KeyObject);
550
551 PostOperationInfo.Status = Status;
552 CmiCallRegisteredCallbacks(RegNtPostDeleteKey, &PostOperationInfo);
553
554 /* Dereference the object */
555 ObDereferenceObject(KeyObject);
556
557 DPRINT("PointerCount %lu\n", ObGetObjectPointerCount((PVOID)KeyObject));
558 DPRINT("HandleCount %lu\n", ObGetObjectHandleCount((PVOID)KeyObject));
559
560 /*
561 * Note:
562 * Hive-Synchronization will not be triggered here. This is done in
563 * CmiObjectDelete() (in regobj.c) after all key-related structures
564 * have been released.
565 */
566
567 return Status;
568 }
569
570
571 NTSTATUS STDCALL
572 NtEnumerateKey(IN HANDLE KeyHandle,
573 IN ULONG Index,
574 IN KEY_INFORMATION_CLASS KeyInformationClass,
575 OUT PVOID KeyInformation,
576 IN ULONG Length,
577 OUT PULONG ResultLength)
578 {
579 PKEY_OBJECT KeyObject;
580 PKEY_OBJECT SubKeyObject;
581 PREGISTRY_HIVE RegistryHive;
582 PKEY_CELL KeyCell, SubKeyCell;
583 PHASH_TABLE_CELL HashTableBlock;
584 PKEY_BASIC_INFORMATION BasicInformation;
585 PKEY_NODE_INFORMATION NodeInformation;
586 PKEY_FULL_INFORMATION FullInformation;
587 PDATA_CELL ClassCell;
588 ULONG NameSize, ClassSize;
589 KPROCESSOR_MODE PreviousMode;
590 NTSTATUS Status;
591 REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo;
592 REG_POST_OPERATION_INFORMATION PostOperationInfo;
593
594 PAGED_CODE();
595
596 PreviousMode = ExGetPreviousMode();
597
598 DPRINT("KH 0x%p I %d KIC %x KI 0x%p L %d RL 0x%p\n",
599 KeyHandle,
600 Index,
601 KeyInformationClass,
602 KeyInformation,
603 Length,
604 ResultLength);
605
606 /* Verify that the handle is valid and is a registry key */
607 Status = ObReferenceObjectByHandle(KeyHandle,
608 KEY_ENUMERATE_SUB_KEYS,
609 CmiKeyType,
610 PreviousMode,
611 (PVOID *) &KeyObject,
612 NULL);
613 if (!NT_SUCCESS(Status))
614 {
615 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
616 return(Status);
617 }
618
619 PostOperationInfo.Object = (PVOID)KeyObject;
620 EnumerateKeyInfo.Object = (PVOID)KeyObject;
621 EnumerateKeyInfo.Index = Index;
622 EnumerateKeyInfo.KeyInformationClass = KeyInformationClass;
623 EnumerateKeyInfo.Length = Length;
624 EnumerateKeyInfo.ResultLength = ResultLength;
625
626 Status = CmiCallRegisteredCallbacks(RegNtEnumerateKey, &EnumerateKeyInfo);
627 if (!NT_SUCCESS(Status))
628 {
629 ObDereferenceObject(KeyObject);
630 return Status;
631 }
632
633 /* Acquire hive lock */
634 KeEnterCriticalRegion();
635 ExAcquireResourceSharedLite(&CmiRegistryLock, TRUE);
636
637 VERIFY_KEY_OBJECT(KeyObject);
638
639 /* Get pointer to KeyCell */
640 KeyCell = KeyObject->KeyCell;
641 RegistryHive = KeyObject->RegistryHive;
642
643 SubKeyObject = NULL;
644
645 /* Check for hightest possible sub key index */
646 if (Index >= KeyCell->NumberOfSubKeys + KeyObject->NumberOfSubKeys)
647 {
648 ExReleaseResourceLite(&CmiRegistryLock);
649 KeLeaveCriticalRegion();
650 PostOperationInfo.Status = STATUS_NO_MORE_ENTRIES;
651 CmiCallRegisteredCallbacks(RegNtPostDeleteKey, &PostOperationInfo);
652 ObDereferenceObject(KeyObject);
653 DPRINT("No more volatile entries\n");
654 return STATUS_NO_MORE_ENTRIES;
655 }
656
657 /* Get pointer to SubKey */
658 if (Index >= KeyCell->NumberOfSubKeys)
659 {
660 PKEY_OBJECT CurKey = NULL;
661 ULONG i;
662 ULONG j;
663
664 /* Search for volatile or 'foreign' keys */
665 j = KeyCell->NumberOfSubKeys;
666 for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
667 {
668 CurKey = KeyObject->SubKeys[i];
669 if (CurKey->RegistryHive != RegistryHive)
670 {
671 if (j == Index)
672 break;
673 j++;
674 }
675 }
676
677 if (i >= KeyObject->NumberOfSubKeys)
678 {
679 ExReleaseResourceLite(&CmiRegistryLock);
680 KeLeaveCriticalRegion();
681 PostOperationInfo.Status = STATUS_NO_MORE_ENTRIES;
682 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey, &PostOperationInfo);
683 ObDereferenceObject(KeyObject);
684 DPRINT("No more non-volatile entries\n");
685 return STATUS_NO_MORE_ENTRIES;
686 }
687
688 SubKeyObject = CurKey;
689 SubKeyCell = CurKey->KeyCell;
690 }
691 else
692 {
693 if (KeyCell->HashTableOffset == (BLOCK_OFFSET)-1)
694 {
695 ExReleaseResourceLite(&CmiRegistryLock);
696 KeLeaveCriticalRegion();
697 PostOperationInfo.Status = STATUS_NO_MORE_ENTRIES;
698 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey, &PostOperationInfo);
699 ObDereferenceObject(KeyObject);
700 return STATUS_NO_MORE_ENTRIES;
701 }
702
703 HashTableBlock = CmiGetCell (RegistryHive, KeyCell->HashTableOffset, NULL);
704 if (HashTableBlock == NULL)
705 {
706 DPRINT("CmiGetBlock() failed\n");
707 ExReleaseResourceLite(&CmiRegistryLock);
708 KeLeaveCriticalRegion();
709 PostOperationInfo.Status = STATUS_UNSUCCESSFUL;
710 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey, &PostOperationInfo);
711 ObDereferenceObject(KeyObject);
712 return STATUS_UNSUCCESSFUL;
713 }
714
715 SubKeyCell = CmiGetKeyFromHashByIndex(RegistryHive,
716 HashTableBlock,
717 Index);
718 }
719
720 if (SubKeyCell == NULL)
721 {
722 ExReleaseResourceLite(&CmiRegistryLock);
723 KeLeaveCriticalRegion();
724 PostOperationInfo.Status = STATUS_NO_MORE_ENTRIES;
725 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey, &PostOperationInfo);
726 ObDereferenceObject(KeyObject);
727 DPRINT("No more entries\n");
728 return STATUS_NO_MORE_ENTRIES;
729 }
730
731 Status = STATUS_SUCCESS;
732 switch (KeyInformationClass)
733 {
734 case KeyBasicInformation:
735 /* Check size of buffer */
736 if (SubKeyObject != NULL)
737 {
738 NameSize = SubKeyObject->Name.Length;
739 }
740 else
741 {
742 NameSize = SubKeyCell->NameSize;
743 if (SubKeyCell->Flags & REG_KEY_NAME_PACKED)
744 {
745 NameSize *= sizeof(WCHAR);
746 }
747 }
748
749 *ResultLength = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]) + NameSize;
750
751 /*
752 * NOTE: It's perfetly valid to call NtEnumerateKey to get
753 * all the information but name. Actually the NT4 sound
754 * framework does that while querying parameters from registry.
755 * -- Filip Navara, 19/07/2004
756 */
757 if (Length < FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]))
758 {
759 Status = STATUS_BUFFER_TOO_SMALL;
760 }
761 else
762 {
763 /* Fill buffer with requested info */
764 BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
765 BasicInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.u.LowPart;
766 BasicInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.u.HighPart;
767 BasicInformation->TitleIndex = Index;
768 BasicInformation->NameLength = NameSize;
769
770 if (Length - FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]) < NameSize)
771 {
772 NameSize = Length - FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]);
773 Status = STATUS_BUFFER_OVERFLOW;
774 CHECKPOINT;
775 }
776
777 if (SubKeyObject != NULL)
778 {
779 RtlCopyMemory(BasicInformation->Name,
780 SubKeyObject->Name.Buffer,
781 NameSize);
782 }
783 else
784 {
785 if (SubKeyCell->Flags & REG_KEY_NAME_PACKED)
786 {
787 CmiCopyPackedName(BasicInformation->Name,
788 SubKeyCell->Name,
789 NameSize / sizeof(WCHAR));
790 }
791 else
792 {
793 RtlCopyMemory(BasicInformation->Name,
794 SubKeyCell->Name,
795 NameSize);
796 }
797 }
798 }
799 break;
800
801 case KeyNodeInformation:
802 /* Check size of buffer */
803 if (SubKeyObject != NULL)
804 {
805 NameSize = SubKeyObject->Name.Length;
806 }
807 else
808 {
809 NameSize = SubKeyCell->NameSize;
810 if (SubKeyCell->Flags & REG_KEY_NAME_PACKED)
811 {
812 NameSize *= sizeof(WCHAR);
813 }
814 }
815 ClassSize = SubKeyCell->ClassSize;
816
817 *ResultLength = FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) +
818 NameSize + ClassSize;
819
820 if (Length < FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]))
821 {
822 Status = STATUS_BUFFER_TOO_SMALL;
823 }
824 else
825 {
826 /* Fill buffer with requested info */
827 NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
828 NodeInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.u.LowPart;
829 NodeInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.u.HighPart;
830 NodeInformation->TitleIndex = Index;
831 NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) + NameSize;
832 NodeInformation->ClassLength = SubKeyCell->ClassSize;
833 NodeInformation->NameLength = NameSize;
834
835 if (Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) < NameSize)
836 {
837 NameSize = Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]);
838 ClassSize = 0;
839 Status = STATUS_BUFFER_OVERFLOW;
840 CHECKPOINT;
841 }
842 else if (Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) -
843 NameSize < ClassSize)
844 {
845 ClassSize = Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) -
846 NameSize;
847 Status = STATUS_BUFFER_OVERFLOW;
848 CHECKPOINT;
849 }
850
851 if (SubKeyObject != NULL)
852 {
853 RtlCopyMemory(NodeInformation->Name,
854 SubKeyObject->Name.Buffer,
855 NameSize);
856 }
857 else
858 {
859 if (SubKeyCell->Flags & REG_KEY_NAME_PACKED)
860 {
861 CmiCopyPackedName(NodeInformation->Name,
862 SubKeyCell->Name,
863 NameSize / sizeof(WCHAR));
864 }
865 else
866 {
867 RtlCopyMemory(NodeInformation->Name,
868 SubKeyCell->Name,
869 NameSize);
870 }
871 }
872
873 if (ClassSize != 0)
874 {
875 ClassCell = CmiGetCell (KeyObject->RegistryHive,
876 SubKeyCell->ClassNameOffset,
877 NULL);
878 RtlCopyMemory (NodeInformation->Name + SubKeyCell->NameSize,
879 ClassCell->Data,
880 ClassSize);
881 }
882 }
883 break;
884
885 case KeyFullInformation:
886 ClassSize = SubKeyCell->ClassSize;
887
888 *ResultLength = FIELD_OFFSET(KEY_FULL_INFORMATION, Class[0]) +
889 ClassSize;
890
891 /* Check size of buffer */
892 if (Length < FIELD_OFFSET(KEY_FULL_INFORMATION, Class[0]))
893 {
894 Status = STATUS_BUFFER_TOO_SMALL;
895 }
896 else
897 {
898 /* Fill buffer with requested info */
899 FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
900 FullInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.u.LowPart;
901 FullInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.u.HighPart;
902 FullInformation->TitleIndex = Index;
903 FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) -
904 sizeof(WCHAR);
905 FullInformation->ClassLength = SubKeyCell->ClassSize;
906 FullInformation->SubKeys = CmiGetNumberOfSubKeys(KeyObject); //SubKeyCell->NumberOfSubKeys;
907 FullInformation->MaxNameLen = CmiGetMaxNameLength(KeyObject);
908 FullInformation->MaxClassLen = CmiGetMaxClassLength(KeyObject);
909 FullInformation->Values = SubKeyCell->NumberOfValues;
910 FullInformation->MaxValueNameLen =
911 CmiGetMaxValueNameLength(RegistryHive, SubKeyCell);
912 FullInformation->MaxValueDataLen =
913 CmiGetMaxValueDataLength(RegistryHive, SubKeyCell);
914
915 if (Length - FIELD_OFFSET(KEY_FULL_INFORMATION, Class[0]) < ClassSize)
916 {
917 ClassSize = Length - FIELD_OFFSET(KEY_FULL_INFORMATION, Class[0]);
918 Status = STATUS_BUFFER_OVERFLOW;
919 CHECKPOINT;
920 }
921
922 if (ClassSize != 0)
923 {
924 ClassCell = CmiGetCell (KeyObject->RegistryHive,
925 SubKeyCell->ClassNameOffset,
926 NULL);
927 RtlCopyMemory (FullInformation->Class,
928 ClassCell->Data,
929 ClassSize);
930 }
931 }
932 break;
933
934 default:
935 DPRINT1("Not handling 0x%x\n", KeyInformationClass);
936 break;
937 }
938
939 ExReleaseResourceLite(&CmiRegistryLock);
940 KeLeaveCriticalRegion();
941
942 PostOperationInfo.Status = Status;
943 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey, &PostOperationInfo);
944
945 ObDereferenceObject(KeyObject);
946
947 DPRINT("Returning status %x\n", Status);
948
949 return(Status);
950 }
951
952
953 NTSTATUS STDCALL
954 NtEnumerateValueKey(IN HANDLE KeyHandle,
955 IN ULONG Index,
956 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
957 OUT PVOID KeyValueInformation,
958 IN ULONG Length,
959 OUT PULONG ResultLength)
960 {
961 NTSTATUS Status;
962 PKEY_OBJECT KeyObject;
963 PREGISTRY_HIVE RegistryHive;
964 PKEY_CELL KeyCell;
965 PVALUE_CELL ValueCell;
966 PDATA_CELL DataCell;
967 ULONG NameSize, DataSize;
968 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation;
969 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
970 PKEY_VALUE_FULL_INFORMATION ValueFullInformation;
971
972 PAGED_CODE();
973
974 DPRINT("KH 0x%p I %d KVIC %x KVI 0x%p L %d RL 0x%p\n",
975 KeyHandle,
976 Index,
977 KeyValueInformationClass,
978 KeyValueInformation,
979 Length,
980 ResultLength);
981
982 /* Verify that the handle is valid and is a registry key */
983 Status = ObReferenceObjectByHandle(KeyHandle,
984 KEY_QUERY_VALUE,
985 CmiKeyType,
986 ExGetPreviousMode(),
987 (PVOID *) &KeyObject,
988 NULL);
989
990 if (!NT_SUCCESS(Status))
991 {
992 return Status;
993 }
994
995 /* Acquire hive lock */
996 KeEnterCriticalRegion();
997 ExAcquireResourceSharedLite(&CmiRegistryLock, TRUE);
998
999 VERIFY_KEY_OBJECT(KeyObject);
1000
1001 /* Get pointer to KeyCell */
1002 KeyCell = KeyObject->KeyCell;
1003 RegistryHive = KeyObject->RegistryHive;
1004
1005 /* Get Value block of interest */
1006 Status = CmiGetValueFromKeyByIndex(RegistryHive,
1007 KeyCell,
1008 Index,
1009 &ValueCell);
1010
1011 if (!NT_SUCCESS(Status))
1012 {
1013 ExReleaseResourceLite(&CmiRegistryLock);
1014 KeLeaveCriticalRegion();
1015 ObDereferenceObject(KeyObject);
1016 return Status;
1017 }
1018
1019 if (ValueCell != NULL)
1020 {
1021 switch (KeyValueInformationClass)
1022 {
1023 case KeyValueBasicInformation:
1024 NameSize = ValueCell->NameSize;
1025 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1026 {
1027 NameSize *= sizeof(WCHAR);
1028 }
1029
1030 *ResultLength = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]) + NameSize;
1031
1032 if (Length < FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]))
1033 {
1034 Status = STATUS_BUFFER_TOO_SMALL;
1035 }
1036 else
1037 {
1038 ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION)
1039 KeyValueInformation;
1040 ValueBasicInformation->TitleIndex = 0;
1041 ValueBasicInformation->Type = ValueCell->DataType;
1042 ValueBasicInformation->NameLength = NameSize;
1043
1044 if (Length - FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]) <
1045 NameSize)
1046 {
1047 NameSize = Length - FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
1048 Status = STATUS_BUFFER_OVERFLOW;
1049 CHECKPOINT;
1050 }
1051
1052 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1053 {
1054 CmiCopyPackedName(ValueBasicInformation->Name,
1055 ValueCell->Name,
1056 NameSize / sizeof(WCHAR));
1057 }
1058 else
1059 {
1060 RtlCopyMemory(ValueBasicInformation->Name,
1061 ValueCell->Name,
1062 NameSize);
1063 }
1064 }
1065 break;
1066
1067 case KeyValuePartialInformation:
1068 DataSize = ValueCell->DataSize & REG_DATA_SIZE_MASK;
1069
1070 *ResultLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) +
1071 DataSize;
1072
1073 if (Length < FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]))
1074 {
1075 Status = STATUS_BUFFER_TOO_SMALL;
1076 }
1077 else
1078 {
1079 ValuePartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)
1080 KeyValueInformation;
1081 ValuePartialInformation->TitleIndex = 0;
1082 ValuePartialInformation->Type = ValueCell->DataType;
1083 ValuePartialInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK;
1084
1085 if (Length - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) <
1086 DataSize)
1087 {
1088 DataSize = Length - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
1089 Status = STATUS_BUFFER_OVERFLOW;
1090 CHECKPOINT;
1091 }
1092
1093 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
1094 {
1095 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
1096 RtlCopyMemory(ValuePartialInformation->Data,
1097 DataCell->Data,
1098 DataSize);
1099 }
1100 else
1101 {
1102 RtlCopyMemory(ValuePartialInformation->Data,
1103 &ValueCell->DataOffset,
1104 DataSize);
1105 }
1106 }
1107 break;
1108
1109 case KeyValueFullInformation:
1110 NameSize = ValueCell->NameSize;
1111 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1112 {
1113 NameSize *= sizeof(WCHAR);
1114 }
1115 DataSize = ValueCell->DataSize & REG_DATA_SIZE_MASK;
1116
1117 *ResultLength = ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION,
1118 Name[0]) + NameSize, sizeof(PVOID)) + DataSize;
1119
1120 if (Length < FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]))
1121 {
1122 Status = STATUS_BUFFER_TOO_SMALL;
1123 }
1124 else
1125 {
1126 ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)
1127 KeyValueInformation;
1128 ValueFullInformation->TitleIndex = 0;
1129 ValueFullInformation->Type = ValueCell->DataType;
1130 ValueFullInformation->NameLength = NameSize;
1131 ValueFullInformation->DataOffset =
1132 (ULONG_PTR)ValueFullInformation->Name -
1133 (ULONG_PTR)ValueFullInformation +
1134 ValueFullInformation->NameLength;
1135 ValueFullInformation->DataOffset =
1136 ROUND_UP(ValueFullInformation->DataOffset, sizeof(PVOID));
1137 ValueFullInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK;
1138
1139 if (Length < ValueFullInformation->DataOffset)
1140 {
1141 NameSize = Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
1142 DataSize = 0;
1143 Status = STATUS_BUFFER_OVERFLOW;
1144 CHECKPOINT;
1145 }
1146 else if (Length - ValueFullInformation->DataOffset < DataSize)
1147 {
1148 DataSize = Length - ValueFullInformation->DataOffset;
1149 Status = STATUS_BUFFER_OVERFLOW;
1150 CHECKPOINT;
1151 }
1152
1153 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1154 {
1155 CmiCopyPackedName(ValueFullInformation->Name,
1156 ValueCell->Name,
1157 NameSize / sizeof(WCHAR));
1158 }
1159 else
1160 {
1161 RtlCopyMemory(ValueFullInformation->Name,
1162 ValueCell->Name,
1163 NameSize);
1164 }
1165
1166 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
1167 {
1168 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
1169 RtlCopyMemory((PCHAR) ValueFullInformation
1170 + ValueFullInformation->DataOffset,
1171 DataCell->Data, DataSize);
1172 }
1173 else
1174 {
1175 RtlCopyMemory((PCHAR) ValueFullInformation
1176 + ValueFullInformation->DataOffset,
1177 &ValueCell->DataOffset, DataSize);
1178 }
1179 }
1180 break;
1181
1182 default:
1183 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass);
1184 break;
1185 }
1186 }
1187 else
1188 {
1189 Status = STATUS_UNSUCCESSFUL;
1190 }
1191
1192 ExReleaseResourceLite(&CmiRegistryLock);
1193 KeLeaveCriticalRegion();
1194 ObDereferenceObject(KeyObject);
1195
1196 return Status;
1197 }
1198
1199
1200 NTSTATUS STDCALL
1201 NtFlushKey(IN HANDLE KeyHandle)
1202 {
1203 NTSTATUS Status;
1204 PKEY_OBJECT KeyObject;
1205 PREGISTRY_HIVE RegistryHive;
1206 KPROCESSOR_MODE PreviousMode;
1207
1208 PAGED_CODE();
1209
1210 DPRINT("NtFlushKey (KeyHandle %lx) called\n", KeyHandle);
1211
1212 PreviousMode = ExGetPreviousMode();
1213
1214 /* Verify that the handle is valid and is a registry key */
1215 Status = ObReferenceObjectByHandle(KeyHandle,
1216 0,
1217 CmiKeyType,
1218 PreviousMode,
1219 (PVOID *)&KeyObject,
1220 NULL);
1221 if (!NT_SUCCESS(Status))
1222 {
1223 return(Status);
1224 }
1225
1226 VERIFY_KEY_OBJECT(KeyObject);
1227
1228 RegistryHive = KeyObject->RegistryHive;
1229
1230 /* Acquire hive lock */
1231 KeEnterCriticalRegion();
1232 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
1233
1234 if (IsNoFileHive(RegistryHive))
1235 {
1236 Status = STATUS_SUCCESS;
1237 }
1238 else
1239 {
1240 /* Flush non-volatile hive */
1241 Status = CmiFlushRegistryHive(RegistryHive);
1242 }
1243
1244 ExReleaseResourceLite(&CmiRegistryLock);
1245 KeLeaveCriticalRegion();
1246
1247 ObDereferenceObject(KeyObject);
1248
1249 return STATUS_SUCCESS;
1250 }
1251
1252
1253 NTSTATUS STDCALL
1254 NtOpenKey(OUT PHANDLE KeyHandle,
1255 IN ACCESS_MASK DesiredAccess,
1256 IN POBJECT_ATTRIBUTES ObjectAttributes)
1257 {
1258 UNICODE_STRING RemainingPath;
1259 KPROCESSOR_MODE PreviousMode;
1260 PVOID Object = NULL;
1261 HANDLE hKey;
1262 NTSTATUS Status = STATUS_SUCCESS;
1263 UNICODE_STRING ObjectName;
1264 OBJECT_CREATE_INFORMATION ObjectCreateInfo;
1265 REG_PRE_OPEN_KEY_INFORMATION PreOpenKeyInfo;
1266 REG_POST_OPEN_KEY_INFORMATION PostOpenKeyInfo;
1267
1268 PAGED_CODE();
1269
1270 DPRINT("NtOpenKey(KH 0x%p DA %x OA 0x%p OA->ON '%wZ'\n",
1271 KeyHandle,
1272 DesiredAccess,
1273 ObjectAttributes,
1274 ObjectAttributes ? ObjectAttributes->ObjectName : NULL);
1275
1276 /* Check place for result handle, if it's null - return immediately */
1277 if (KeyHandle == NULL)
1278 return(STATUS_INVALID_PARAMETER);
1279
1280 PreviousMode = ExGetPreviousMode();
1281
1282 if(PreviousMode != KernelMode)
1283 {
1284 _SEH_TRY
1285 {
1286 ProbeForWriteHandle(KeyHandle);
1287 }
1288 _SEH_HANDLE
1289 {
1290 Status = _SEH_GetExceptionCode();
1291 }
1292 _SEH_END;
1293
1294 if(!NT_SUCCESS(Status))
1295 {
1296 return Status;
1297 }
1298 }
1299
1300 /* WINE checks for the length also */
1301 /*if (ObjectAttributes->ObjectName->Length > MAX_NAME_LENGTH)
1302 return(STATUS_BUFFER_OVERFLOW);*/
1303
1304 /* Capture all the info */
1305 DPRINT("Capturing Create Info\n");
1306 Status = ObpCaptureObjectAttributes(ObjectAttributes,
1307 PreviousMode,
1308 CmiKeyType,
1309 &ObjectCreateInfo,
1310 &ObjectName);
1311 if (!NT_SUCCESS(Status))
1312 {
1313 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status);
1314 return Status;
1315 }
1316
1317 PostOpenKeyInfo.CompleteName = &ObjectName;
1318 PreOpenKeyInfo.CompleteName = &ObjectName;
1319 Status = CmiCallRegisteredCallbacks(RegNtPreOpenKey, &PreOpenKeyInfo);
1320 if (!NT_SUCCESS(Status))
1321 {
1322 ObpReleaseCapturedAttributes(&ObjectCreateInfo);
1323 if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
1324 return Status;
1325 }
1326
1327
1328 RemainingPath.Buffer = NULL;
1329
1330 Status = ObFindObject(&ObjectCreateInfo,
1331 &ObjectName,
1332 (PVOID*)&Object,
1333 &RemainingPath,
1334 CmiKeyType);
1335 ObpReleaseCapturedAttributes(&ObjectCreateInfo);
1336 if (!NT_SUCCESS(Status))
1337 {
1338 DPRINT("CmpFindObject() returned 0x%08lx\n", Status);
1339 Status = STATUS_INVALID_HANDLE; /* Because CmpFindObject returns STATUS_UNSUCCESSFUL */
1340 hKey = *KeyHandle; /* Preserve hkResult value */
1341 goto openkey_cleanup;
1342 }
1343
1344 VERIFY_KEY_OBJECT((PKEY_OBJECT) Object);
1345
1346 DPRINT("RemainingPath '%wZ'\n", &RemainingPath);
1347
1348 if ((RemainingPath.Buffer != NULL) && (RemainingPath.Buffer[0] != 0))
1349 {
1350 RtlFreeUnicodeString(&RemainingPath);
1351 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1352 hKey = NULL;
1353 goto openkey_cleanup;
1354 }
1355
1356 RtlFreeUnicodeString(&RemainingPath);
1357
1358 /* Fail if the key has been deleted */
1359 if (((PKEY_OBJECT)Object)->Flags & KO_MARKED_FOR_DELETE)
1360 {
1361 Status = STATUS_UNSUCCESSFUL;
1362 hKey = NULL;
1363 goto openkey_cleanup;
1364 }
1365
1366 Status = ObpCreateHandle(PsGetCurrentProcess(),
1367 Object,
1368 DesiredAccess,
1369 TRUE,
1370 &hKey);
1371
1372 if (!NT_SUCCESS(Status))
1373 hKey = NULL;
1374
1375 openkey_cleanup:
1376
1377 PostOpenKeyInfo.Object = NT_SUCCESS(Status) ? (PVOID)Object : NULL;
1378 PostOpenKeyInfo.Status = Status;
1379 CmiCallRegisteredCallbacks (RegNtPostOpenKey, &PostOpenKeyInfo);
1380 if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
1381
1382 if (Object)
1383 {
1384 ObDereferenceObject(Object);
1385 }
1386
1387 _SEH_TRY
1388 {
1389 *KeyHandle = hKey;
1390 }
1391 _SEH_HANDLE
1392 {
1393 Status = _SEH_GetExceptionCode();
1394 }
1395 _SEH_END;
1396
1397 return Status;
1398 }
1399
1400
1401 NTSTATUS STDCALL
1402 NtQueryKey(IN HANDLE KeyHandle,
1403 IN KEY_INFORMATION_CLASS KeyInformationClass,
1404 OUT PVOID KeyInformation,
1405 IN ULONG Length,
1406 OUT PULONG ResultLength)
1407 {
1408 PKEY_BASIC_INFORMATION BasicInformation;
1409 PKEY_NODE_INFORMATION NodeInformation;
1410 PKEY_FULL_INFORMATION FullInformation;
1411 PREGISTRY_HIVE RegistryHive;
1412 PDATA_CELL ClassCell;
1413 PKEY_OBJECT KeyObject;
1414 PKEY_CELL KeyCell;
1415 ULONG NameSize, ClassSize;
1416 NTSTATUS Status;
1417 REG_QUERY_KEY_INFORMATION QueryKeyInfo;
1418 REG_POST_OPERATION_INFORMATION PostOperationInfo;
1419
1420 PAGED_CODE();
1421
1422 DPRINT("NtQueryKey(KH 0x%p KIC %x KI 0x%p L %d RL 0x%p)\n",
1423 KeyHandle,
1424 KeyInformationClass,
1425 KeyInformation,
1426 Length,
1427 ResultLength);
1428
1429 /* Verify that the handle is valid and is a registry key */
1430 Status = ObReferenceObjectByHandle(KeyHandle,
1431 (KeyInformationClass != KeyNameInformation ? KEY_QUERY_VALUE : 0),
1432 CmiKeyType,
1433 ExGetPreviousMode(),
1434 (PVOID *) &KeyObject,
1435 NULL);
1436 if (!NT_SUCCESS(Status))
1437 {
1438 return Status;
1439 }
1440
1441 PostOperationInfo.Object = (PVOID)KeyObject;
1442 QueryKeyInfo.Object = (PVOID)KeyObject;
1443 QueryKeyInfo.KeyInformationClass = KeyInformationClass;
1444 QueryKeyInfo.KeyInformation = KeyInformation;
1445 QueryKeyInfo.Length = Length;
1446 QueryKeyInfo.ResultLength = ResultLength;
1447
1448 Status = CmiCallRegisteredCallbacks(RegNtQueryKey, &QueryKeyInfo);
1449 if (!NT_SUCCESS(Status))
1450 {
1451 ObDereferenceObject(KeyObject);
1452 return Status;
1453 }
1454
1455 /* Acquire hive lock */
1456 KeEnterCriticalRegion();
1457 ExAcquireResourceSharedLite(&CmiRegistryLock, TRUE);
1458
1459 VERIFY_KEY_OBJECT(KeyObject);
1460
1461 /* Get pointer to KeyCell */
1462 KeyCell = KeyObject->KeyCell;
1463 RegistryHive = KeyObject->RegistryHive;
1464
1465 Status = STATUS_SUCCESS;
1466 switch (KeyInformationClass)
1467 {
1468 case KeyBasicInformation:
1469 NameSize = KeyObject->Name.Length;
1470
1471 *ResultLength = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]);
1472
1473 /* Check size of buffer */
1474 if (Length < FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]))
1475 {
1476 Status = STATUS_BUFFER_TOO_SMALL;
1477 }
1478 else
1479 {
1480 /* Fill buffer with requested info */
1481 BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
1482 BasicInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.u.LowPart;
1483 BasicInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.u.HighPart;
1484 BasicInformation->TitleIndex = 0;
1485 BasicInformation->NameLength = KeyObject->Name.Length;
1486
1487 if (Length - FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]) <
1488 NameSize)
1489 {
1490 NameSize = Length - FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]);
1491 Status = STATUS_BUFFER_OVERFLOW;
1492 CHECKPOINT;
1493 }
1494
1495 RtlCopyMemory(BasicInformation->Name,
1496 KeyObject->Name.Buffer,
1497 NameSize);
1498 }
1499 break;
1500
1501 case KeyNodeInformation:
1502 NameSize = KeyObject->Name.Length;
1503 ClassSize = KeyCell->ClassSize;
1504
1505 *ResultLength = FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) +
1506 NameSize + ClassSize;
1507
1508 /* Check size of buffer */
1509 if (Length < *ResultLength)
1510 {
1511 Status = STATUS_BUFFER_TOO_SMALL;
1512 }
1513 else
1514 {
1515 /* Fill buffer with requested info */
1516 NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
1517 NodeInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.u.LowPart;
1518 NodeInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.u.HighPart;
1519 NodeInformation->TitleIndex = 0;
1520 NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) +
1521 KeyObject->Name.Length;
1522 NodeInformation->ClassLength = KeyCell->ClassSize;
1523 NodeInformation->NameLength = KeyObject->Name.Length;
1524
1525 if (Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) < NameSize)
1526 {
1527 NameSize = Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]);
1528 ClassSize = 0;
1529 Status = STATUS_BUFFER_OVERFLOW;
1530 CHECKPOINT;
1531 }
1532 else if (Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) -
1533 NameSize < ClassSize)
1534 {
1535 ClassSize = Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) -
1536 NameSize;
1537 Status = STATUS_BUFFER_OVERFLOW;
1538 CHECKPOINT;
1539 }
1540
1541 RtlCopyMemory(NodeInformation->Name,
1542 KeyObject->Name.Buffer,
1543 NameSize);
1544
1545 if (ClassSize != 0)
1546 {
1547 ClassCell = CmiGetCell (KeyObject->RegistryHive,
1548 KeyCell->ClassNameOffset,
1549 NULL);
1550 RtlCopyMemory (NodeInformation->Name + KeyObject->Name.Length,
1551 ClassCell->Data,
1552 ClassSize);
1553 }
1554 }
1555 break;
1556
1557 case KeyFullInformation:
1558 ClassSize = KeyCell->ClassSize;
1559
1560 *ResultLength = FIELD_OFFSET(KEY_FULL_INFORMATION, Class) +
1561 ClassSize;
1562
1563 /* Check size of buffer */
1564 if (Length < FIELD_OFFSET(KEY_FULL_INFORMATION, Class))
1565 {
1566 Status = STATUS_BUFFER_TOO_SMALL;
1567 }
1568 else
1569 {
1570 /* Fill buffer with requested info */
1571 FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
1572 FullInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.u.LowPart;
1573 FullInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.u.HighPart;
1574 FullInformation->TitleIndex = 0;
1575 FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) - sizeof(WCHAR);
1576 FullInformation->ClassLength = KeyCell->ClassSize;
1577 FullInformation->SubKeys = CmiGetNumberOfSubKeys(KeyObject); //KeyCell->NumberOfSubKeys;
1578 FullInformation->MaxNameLen = CmiGetMaxNameLength(KeyObject);
1579 FullInformation->MaxClassLen = CmiGetMaxClassLength(KeyObject);
1580 FullInformation->Values = KeyCell->NumberOfValues;
1581 FullInformation->MaxValueNameLen =
1582 CmiGetMaxValueNameLength(RegistryHive, KeyCell);
1583 FullInformation->MaxValueDataLen =
1584 CmiGetMaxValueDataLength(RegistryHive, KeyCell);
1585
1586 if (Length - FIELD_OFFSET(KEY_FULL_INFORMATION, Class[0]) < ClassSize)
1587 {
1588 ClassSize = Length - FIELD_OFFSET(KEY_FULL_INFORMATION, Class[0]);
1589 Status = STATUS_BUFFER_OVERFLOW;
1590 CHECKPOINT;
1591 }
1592
1593 if (ClassSize)
1594 {
1595 ClassCell = CmiGetCell (KeyObject->RegistryHive,
1596 KeyCell->ClassNameOffset,
1597 NULL);
1598 RtlCopyMemory (FullInformation->Class,
1599 ClassCell->Data, ClassSize);
1600 }
1601 }
1602 break;
1603
1604 case KeyNameInformation:
1605 case KeyCachedInformation:
1606 case KeyFlagsInformation:
1607 DPRINT1("Key information class 0x%x not yet implemented!\n", KeyInformationClass);
1608 Status = STATUS_NOT_IMPLEMENTED;
1609 break;
1610
1611 default:
1612 DPRINT1("Not handling 0x%x\n", KeyInformationClass);
1613 Status = STATUS_INVALID_INFO_CLASS;
1614 break;
1615 }
1616
1617 ExReleaseResourceLite(&CmiRegistryLock);
1618 KeLeaveCriticalRegion();
1619
1620 PostOperationInfo.Status = Status;
1621 CmiCallRegisteredCallbacks(RegNtPostQueryKey, &PostOperationInfo);
1622
1623 ObDereferenceObject(KeyObject);
1624
1625 return(Status);
1626 }
1627
1628
1629 NTSTATUS STDCALL
1630 NtQueryValueKey(IN HANDLE KeyHandle,
1631 IN PUNICODE_STRING ValueName,
1632 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
1633 OUT PVOID KeyValueInformation,
1634 IN ULONG Length,
1635 OUT PULONG ResultLength)
1636 {
1637 NTSTATUS Status;
1638 ULONG NameSize, DataSize;
1639 PKEY_OBJECT KeyObject;
1640 PREGISTRY_HIVE RegistryHive;
1641 PKEY_CELL KeyCell;
1642 PVALUE_CELL ValueCell;
1643 PDATA_CELL DataCell;
1644 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation;
1645 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
1646 PKEY_VALUE_FULL_INFORMATION ValueFullInformation;
1647 REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo;
1648 REG_POST_OPERATION_INFORMATION PostOperationInfo;
1649
1650 PAGED_CODE();
1651
1652 DPRINT("NtQueryValueKey(KeyHandle 0x%p ValueName %S Length %x)\n",
1653 KeyHandle, ValueName->Buffer, Length);
1654
1655 /* Verify that the handle is valid and is a registry key */
1656 Status = ObReferenceObjectByHandle(KeyHandle,
1657 KEY_QUERY_VALUE,
1658 CmiKeyType,
1659 ExGetPreviousMode(),
1660 (PVOID *)&KeyObject,
1661 NULL);
1662
1663 if (!NT_SUCCESS(Status))
1664 {
1665 DPRINT1("ObReferenceObjectByHandle() failed with status %x %p\n", Status, KeyHandle);
1666 return Status;
1667 }
1668
1669 PostOperationInfo.Object = (PVOID)KeyObject;
1670 QueryValueKeyInfo.Object = (PVOID)KeyObject;
1671 QueryValueKeyInfo.ValueName = ValueName;
1672 QueryValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass;
1673 QueryValueKeyInfo.Length = Length;
1674 QueryValueKeyInfo.ResultLength = ResultLength;
1675
1676 Status = CmiCallRegisteredCallbacks(RegNtPreQueryValueKey, &QueryValueKeyInfo);
1677 if (!NT_SUCCESS(Status))
1678 {
1679 ObDereferenceObject(KeyObject);
1680 return Status;
1681 }
1682
1683 /* Acquire hive lock */
1684 KeEnterCriticalRegion();
1685 ExAcquireResourceSharedLite(&CmiRegistryLock, TRUE);
1686
1687 VERIFY_KEY_OBJECT(KeyObject);
1688
1689 /* Get pointer to KeyCell */
1690 KeyCell = KeyObject->KeyCell;
1691 RegistryHive = KeyObject->RegistryHive;
1692
1693 /* Get value cell by name */
1694 Status = CmiScanKeyForValue(RegistryHive,
1695 KeyCell,
1696 ValueName,
1697 &ValueCell,
1698 NULL);
1699 if (!NT_SUCCESS(Status))
1700 {
1701 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status);
1702 goto ByeBye;
1703 }
1704
1705 Status = STATUS_SUCCESS;
1706 switch (KeyValueInformationClass)
1707 {
1708 case KeyValueBasicInformation:
1709 NameSize = ValueCell->NameSize;
1710 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1711 {
1712 NameSize *= sizeof(WCHAR);
1713 }
1714
1715 *ResultLength = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]) +
1716 NameSize;
1717
1718 if (Length < FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]))
1719 {
1720 Status = STATUS_BUFFER_TOO_SMALL;
1721 }
1722 else
1723 {
1724 ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION)
1725 KeyValueInformation;
1726 ValueBasicInformation->TitleIndex = 0;
1727 ValueBasicInformation->Type = ValueCell->DataType;
1728 ValueBasicInformation->NameLength = NameSize;
1729
1730 if (Length - FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]) <
1731 NameSize)
1732 {
1733 NameSize = Length - FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
1734 Status = STATUS_BUFFER_OVERFLOW;
1735 CHECKPOINT;
1736 }
1737
1738 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1739 {
1740 CmiCopyPackedName(ValueBasicInformation->Name,
1741 ValueCell->Name,
1742 NameSize / sizeof(WCHAR));
1743 }
1744 else
1745 {
1746 RtlCopyMemory(ValueBasicInformation->Name,
1747 ValueCell->Name,
1748 NameSize);
1749 }
1750 }
1751 break;
1752
1753 case KeyValuePartialInformation:
1754 DataSize = ValueCell->DataSize & REG_DATA_SIZE_MASK;
1755
1756 *ResultLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) +
1757 DataSize;
1758
1759 if (Length < FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]))
1760 {
1761 Status = STATUS_BUFFER_TOO_SMALL;
1762 }
1763 else
1764 {
1765 ValuePartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)
1766 KeyValueInformation;
1767 ValuePartialInformation->TitleIndex = 0;
1768 ValuePartialInformation->Type = ValueCell->DataType;
1769 ValuePartialInformation->DataLength = DataSize;
1770
1771 if (Length - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) <
1772 DataSize)
1773 {
1774 DataSize = Length - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
1775 Status = STATUS_BUFFER_OVERFLOW;
1776 CHECKPOINT;
1777 }
1778
1779 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
1780 {
1781 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
1782 RtlCopyMemory(ValuePartialInformation->Data,
1783 DataCell->Data,
1784 DataSize);
1785 }
1786 else
1787 {
1788 RtlCopyMemory(ValuePartialInformation->Data,
1789 &ValueCell->DataOffset,
1790 DataSize);
1791 }
1792 }
1793 break;
1794
1795 case KeyValueFullInformation:
1796 NameSize = ValueCell->NameSize;
1797 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1798 {
1799 NameSize *= sizeof(WCHAR);
1800 }
1801 DataSize = ValueCell->DataSize & REG_DATA_SIZE_MASK;
1802
1803 *ResultLength = ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION,
1804 Name[0]) + NameSize, sizeof(PVOID)) + DataSize;
1805
1806 if (Length < FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]))
1807 {
1808 Status = STATUS_BUFFER_TOO_SMALL;
1809 }
1810 else
1811 {
1812 ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)
1813 KeyValueInformation;
1814 ValueFullInformation->TitleIndex = 0;
1815 ValueFullInformation->Type = ValueCell->DataType;
1816 ValueFullInformation->NameLength = NameSize;
1817 ValueFullInformation->DataOffset =
1818 (ULONG_PTR)ValueFullInformation->Name -
1819 (ULONG_PTR)ValueFullInformation +
1820 ValueFullInformation->NameLength;
1821 ValueFullInformation->DataOffset =
1822 ROUND_UP(ValueFullInformation->DataOffset, sizeof(PVOID));
1823 ValueFullInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK;
1824
1825 if (Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) <
1826 NameSize)
1827 {
1828 NameSize = Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
1829 DataSize = 0;
1830 Status = STATUS_BUFFER_OVERFLOW;
1831 CHECKPOINT;
1832 }
1833 else if (ROUND_UP(Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION,
1834 Name[0]) - NameSize, sizeof(PVOID)) < DataSize)
1835 {
1836 DataSize = ROUND_UP(Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION,
1837 Name[0]) - NameSize, sizeof(PVOID));
1838 Status = STATUS_BUFFER_OVERFLOW;
1839 CHECKPOINT;
1840 }
1841
1842 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1843 {
1844 CmiCopyPackedName(ValueFullInformation->Name,
1845 ValueCell->Name,
1846 NameSize / sizeof(WCHAR));
1847 }
1848 else
1849 {
1850 RtlCopyMemory(ValueFullInformation->Name,
1851 ValueCell->Name,
1852 NameSize);
1853 }
1854 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
1855 {
1856 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
1857 RtlCopyMemory((PCHAR) ValueFullInformation
1858 + ValueFullInformation->DataOffset,
1859 DataCell->Data,
1860 DataSize);
1861 }
1862 else
1863 {
1864 RtlCopyMemory((PCHAR) ValueFullInformation
1865 + ValueFullInformation->DataOffset,
1866 &ValueCell->DataOffset,
1867 DataSize);
1868 }
1869 }
1870 break;
1871
1872 default:
1873 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass);
1874 Status = STATUS_INVALID_INFO_CLASS;
1875 break;
1876 }
1877
1878 ByeBye:;
1879 ExReleaseResourceLite(&CmiRegistryLock);
1880 KeLeaveCriticalRegion();
1881
1882 PostOperationInfo.Status = Status;
1883 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey, &PostOperationInfo);
1884 ObDereferenceObject(KeyObject);
1885
1886 return Status;
1887 }
1888
1889
1890 NTSTATUS STDCALL
1891 NtSetValueKey(IN HANDLE KeyHandle,
1892 IN PUNICODE_STRING ValueName,
1893 IN ULONG TitleIndex,
1894 IN ULONG Type,
1895 IN PVOID Data,
1896 IN ULONG DataSize)
1897 {
1898 NTSTATUS Status;
1899 PKEY_OBJECT KeyObject;
1900 PREGISTRY_HIVE RegistryHive;
1901 PKEY_CELL KeyCell;
1902 PVALUE_CELL ValueCell;
1903 BLOCK_OFFSET ValueCellOffset;
1904 PDATA_CELL DataCell;
1905 PDATA_CELL NewDataCell;
1906 ULONG DesiredAccess;
1907 REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo;
1908 REG_POST_OPERATION_INFORMATION PostOperationInfo;
1909 ULONG DataCellSize;
1910
1911 PAGED_CODE();
1912
1913 DPRINT("NtSetValueKey(KeyHandle 0x%p ValueName '%wZ' Type %d)\n",
1914 KeyHandle, ValueName, Type);
1915
1916 DesiredAccess = KEY_SET_VALUE;
1917
1918 /* Verify that the handle is valid and is a registry key */
1919 Status = ObReferenceObjectByHandle(KeyHandle,
1920 DesiredAccess,
1921 CmiKeyType,
1922 ExGetPreviousMode(),
1923 (PVOID *)&KeyObject,
1924 NULL);
1925 if (!NT_SUCCESS(Status))
1926 return(Status);
1927
1928 PostOperationInfo.Object = (PVOID)KeyObject;
1929 SetValueKeyInfo.Object = (PVOID)KeyObject;
1930 SetValueKeyInfo.ValueName = ValueName;
1931 SetValueKeyInfo.TitleIndex = TitleIndex;
1932 SetValueKeyInfo.Type = Type;
1933 SetValueKeyInfo.Data = Data;
1934 SetValueKeyInfo.DataSize = DataSize;
1935 Status = CmiCallRegisteredCallbacks(RegNtPreSetValueKey, &SetValueKeyInfo);
1936 if (!NT_SUCCESS(Status))
1937 {
1938 ObDereferenceObject(KeyObject);
1939 return Status;
1940 }
1941
1942 /* Acquire hive lock exclucively */
1943 KeEnterCriticalRegion();
1944 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
1945
1946 VERIFY_KEY_OBJECT(KeyObject);
1947
1948 /* Get pointer to key cell */
1949 KeyCell = KeyObject->KeyCell;
1950 RegistryHive = KeyObject->RegistryHive;
1951 Status = CmiScanKeyForValue(RegistryHive,
1952 KeyCell,
1953 ValueName,
1954 &ValueCell,
1955 &ValueCellOffset);
1956 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1957 {
1958 DPRINT("Allocate new value cell\n");
1959 Status = CmiAddValueToKey(RegistryHive,
1960 KeyCell,
1961 KeyObject->KeyCellOffset,
1962 ValueName,
1963 &ValueCell,
1964 &ValueCellOffset);
1965 }
1966
1967 if (!NT_SUCCESS(Status))
1968 {
1969 DPRINT("Cannot add value. Status 0x%X\n", Status);
1970
1971 ExReleaseResourceLite(&CmiRegistryLock);
1972 KeLeaveCriticalRegion();
1973 PostOperationInfo.Status = Status;
1974 CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
1975 ObDereferenceObject(KeyObject);
1976 return Status;
1977 }
1978
1979 DPRINT("DataSize %lu\n", DataSize);
1980 DPRINT("ValueCell %p\n", ValueCell);
1981 DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
1982
1983 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET) &&
1984 (ValueCell->DataSize & REG_DATA_SIZE_MASK) != 0)
1985 {
1986 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
1987 DataCellSize = (DataCell->CellSize < 0 ? -DataCell->CellSize : DataCell->CellSize) - sizeof(CELL_HEADER);
1988 }
1989 else
1990 {
1991 DataCell = NULL;
1992 DataCellSize = 0;
1993 }
1994
1995
1996 if (DataSize <= sizeof(BLOCK_OFFSET))
1997 {
1998 /* If data size <= sizeof(BLOCK_OFFSET) then store data in the data offset */
1999 DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
2000 if (DataCell)
2001 {
2002 CmiDestroyCell(RegistryHive, DataCell, ValueCell->DataOffset);
2003 }
2004
2005 RtlCopyMemory(&ValueCell->DataOffset, Data, DataSize);
2006 ValueCell->DataSize = DataSize | REG_DATA_IN_OFFSET;
2007 ValueCell->DataType = Type;
2008 CmiMarkBlockDirty(RegistryHive, ValueCellOffset);
2009 }
2010 else
2011 {
2012 if (DataSize > DataCellSize)
2013 {
2014 /*
2015 * New data size is larger than the current, destroy current
2016 * data block and allocate a new one.
2017 */
2018 BLOCK_OFFSET NewOffset;
2019
2020 DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
2021
2022 Status = CmiAllocateCell (RegistryHive,
2023 sizeof(CELL_HEADER) + DataSize,
2024 (PVOID *)&NewDataCell,
2025 &NewOffset);
2026 if (!NT_SUCCESS(Status))
2027 {
2028 DPRINT("CmiAllocateBlock() failed (Status %lx)\n", Status);
2029
2030 ExReleaseResourceLite(&CmiRegistryLock);
2031 KeLeaveCriticalRegion();
2032 PostOperationInfo.Status = Status;
2033 CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
2034 ObDereferenceObject(KeyObject);
2035
2036 return Status;
2037 }
2038
2039 if (DataCell)
2040 {
2041 CmiDestroyCell(RegistryHive, DataCell, ValueCell->DataOffset);
2042 }
2043
2044 ValueCell->DataOffset = NewOffset;
2045 DataCell = NewDataCell;
2046 }
2047
2048 RtlCopyMemory(DataCell->Data, Data, DataSize);
2049 ValueCell->DataSize = DataSize & REG_DATA_SIZE_MASK;
2050 ValueCell->DataType = Type;
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 = ExGetPreviousMode();
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, ExGetPreviousMode ()))
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 ExGetPreviousMode(),
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, ExGetPreviousMode ()))
2518 return STATUS_PRIVILEGE_NOT_HELD;
2519 #endif
2520
2521 Status = ObReferenceObjectByHandle (KeyHandle,
2522 0,
2523 CmiKeyType,
2524 ExGetPreviousMode(),
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 ExGetPreviousMode(),
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, ExGetPreviousMode ()))
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 */