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