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