612d7163f073997a0c4002612aa276083f92af03
[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 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 ExGetPreviousMode(),
986 (PVOID *) &KeyObject,
987 NULL);
988
989 if (!NT_SUCCESS(Status))
990 {
991 return Status;
992 }
993
994 /* Acquire hive lock */
995 KeEnterCriticalRegion();
996 ExAcquireResourceSharedLite(&CmiRegistryLock, TRUE);
997
998 VERIFY_KEY_OBJECT(KeyObject);
999
1000 /* Get pointer to KeyCell */
1001 KeyCell = KeyObject->KeyCell;
1002 RegistryHive = KeyObject->RegistryHive;
1003
1004 /* Get Value block of interest */
1005 Status = CmiGetValueFromKeyByIndex(RegistryHive,
1006 KeyCell,
1007 Index,
1008 &ValueCell);
1009
1010 if (!NT_SUCCESS(Status))
1011 {
1012 ExReleaseResourceLite(&CmiRegistryLock);
1013 KeLeaveCriticalRegion();
1014 ObDereferenceObject(KeyObject);
1015 return Status;
1016 }
1017
1018 if (ValueCell != NULL)
1019 {
1020 switch (KeyValueInformationClass)
1021 {
1022 case KeyValueBasicInformation:
1023 NameSize = ValueCell->NameSize;
1024 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1025 {
1026 NameSize *= sizeof(WCHAR);
1027 }
1028
1029 *ResultLength = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]) + NameSize;
1030
1031 if (Length < FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]))
1032 {
1033 Status = STATUS_BUFFER_TOO_SMALL;
1034 }
1035 else
1036 {
1037 ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION)
1038 KeyValueInformation;
1039 ValueBasicInformation->TitleIndex = 0;
1040 ValueBasicInformation->Type = ValueCell->DataType;
1041 ValueBasicInformation->NameLength = NameSize;
1042
1043 if (Length - FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]) <
1044 NameSize)
1045 {
1046 NameSize = Length - FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
1047 Status = STATUS_BUFFER_OVERFLOW;
1048 CHECKPOINT;
1049 }
1050
1051 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1052 {
1053 CmiCopyPackedName(ValueBasicInformation->Name,
1054 ValueCell->Name,
1055 NameSize / sizeof(WCHAR));
1056 }
1057 else
1058 {
1059 RtlCopyMemory(ValueBasicInformation->Name,
1060 ValueCell->Name,
1061 NameSize);
1062 }
1063 }
1064 break;
1065
1066 case KeyValuePartialInformation:
1067 DataSize = ValueCell->DataSize & REG_DATA_SIZE_MASK;
1068
1069 *ResultLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) +
1070 DataSize;
1071
1072 if (Length < FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]))
1073 {
1074 Status = STATUS_BUFFER_TOO_SMALL;
1075 }
1076 else
1077 {
1078 ValuePartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)
1079 KeyValueInformation;
1080 ValuePartialInformation->TitleIndex = 0;
1081 ValuePartialInformation->Type = ValueCell->DataType;
1082 ValuePartialInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK;
1083
1084 if (Length - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) <
1085 DataSize)
1086 {
1087 DataSize = Length - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
1088 Status = STATUS_BUFFER_OVERFLOW;
1089 CHECKPOINT;
1090 }
1091
1092 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
1093 {
1094 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
1095 RtlCopyMemory(ValuePartialInformation->Data,
1096 DataCell->Data,
1097 DataSize);
1098 }
1099 else
1100 {
1101 RtlCopyMemory(ValuePartialInformation->Data,
1102 &ValueCell->DataOffset,
1103 DataSize);
1104 }
1105 }
1106 break;
1107
1108 case KeyValueFullInformation:
1109 NameSize = ValueCell->NameSize;
1110 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1111 {
1112 NameSize *= sizeof(WCHAR);
1113 }
1114 DataSize = ValueCell->DataSize & REG_DATA_SIZE_MASK;
1115
1116 *ResultLength = ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION,
1117 Name[0]) + NameSize, sizeof(PVOID)) + DataSize;
1118
1119 if (Length < FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]))
1120 {
1121 Status = STATUS_BUFFER_TOO_SMALL;
1122 }
1123 else
1124 {
1125 ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)
1126 KeyValueInformation;
1127 ValueFullInformation->TitleIndex = 0;
1128 ValueFullInformation->Type = ValueCell->DataType;
1129 ValueFullInformation->NameLength = NameSize;
1130 ValueFullInformation->DataOffset =
1131 (ULONG_PTR)ValueFullInformation->Name -
1132 (ULONG_PTR)ValueFullInformation +
1133 ValueFullInformation->NameLength;
1134 ValueFullInformation->DataOffset =
1135 ROUND_UP(ValueFullInformation->DataOffset, sizeof(PVOID));
1136 ValueFullInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK;
1137
1138 if (Length < ValueFullInformation->DataOffset)
1139 {
1140 NameSize = Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
1141 DataSize = 0;
1142 Status = STATUS_BUFFER_OVERFLOW;
1143 CHECKPOINT;
1144 }
1145 else if (Length - ValueFullInformation->DataOffset < DataSize)
1146 {
1147 DataSize = Length - ValueFullInformation->DataOffset;
1148 Status = STATUS_BUFFER_OVERFLOW;
1149 CHECKPOINT;
1150 }
1151
1152 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1153 {
1154 CmiCopyPackedName(ValueFullInformation->Name,
1155 ValueCell->Name,
1156 NameSize / sizeof(WCHAR));
1157 }
1158 else
1159 {
1160 RtlCopyMemory(ValueFullInformation->Name,
1161 ValueCell->Name,
1162 NameSize);
1163 }
1164
1165 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
1166 {
1167 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
1168 RtlCopyMemory((PCHAR) ValueFullInformation
1169 + ValueFullInformation->DataOffset,
1170 DataCell->Data, DataSize);
1171 }
1172 else
1173 {
1174 RtlCopyMemory((PCHAR) ValueFullInformation
1175 + ValueFullInformation->DataOffset,
1176 &ValueCell->DataOffset, DataSize);
1177 }
1178 }
1179 break;
1180
1181 default:
1182 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass);
1183 break;
1184 }
1185 }
1186 else
1187 {
1188 Status = STATUS_UNSUCCESSFUL;
1189 }
1190
1191 ExReleaseResourceLite(&CmiRegistryLock);
1192 KeLeaveCriticalRegion();
1193 ObDereferenceObject(KeyObject);
1194
1195 return Status;
1196 }
1197
1198
1199 NTSTATUS STDCALL
1200 NtFlushKey(IN HANDLE KeyHandle)
1201 {
1202 NTSTATUS Status;
1203 PKEY_OBJECT KeyObject;
1204 PREGISTRY_HIVE RegistryHive;
1205 KPROCESSOR_MODE PreviousMode;
1206
1207 PAGED_CODE();
1208
1209 DPRINT("NtFlushKey (KeyHandle %lx) called\n", KeyHandle);
1210
1211 PreviousMode = ExGetPreviousMode();
1212
1213 /* Verify that the handle is valid and is a registry key */
1214 Status = ObReferenceObjectByHandle(KeyHandle,
1215 0,
1216 CmiKeyType,
1217 PreviousMode,
1218 (PVOID *)&KeyObject,
1219 NULL);
1220 if (!NT_SUCCESS(Status))
1221 {
1222 return(Status);
1223 }
1224
1225 VERIFY_KEY_OBJECT(KeyObject);
1226
1227 RegistryHive = KeyObject->RegistryHive;
1228
1229 /* Acquire hive lock */
1230 KeEnterCriticalRegion();
1231 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
1232
1233 if (IsNoFileHive(RegistryHive))
1234 {
1235 Status = STATUS_SUCCESS;
1236 }
1237 else
1238 {
1239 /* Flush non-volatile hive */
1240 Status = CmiFlushRegistryHive(RegistryHive);
1241 }
1242
1243 ExReleaseResourceLite(&CmiRegistryLock);
1244 KeLeaveCriticalRegion();
1245
1246 ObDereferenceObject(KeyObject);
1247
1248 return STATUS_SUCCESS;
1249 }
1250
1251
1252 NTSTATUS STDCALL
1253 NtOpenKey(OUT PHANDLE KeyHandle,
1254 IN ACCESS_MASK DesiredAccess,
1255 IN POBJECT_ATTRIBUTES ObjectAttributes)
1256 {
1257 UNICODE_STRING RemainingPath;
1258 KPROCESSOR_MODE PreviousMode;
1259 PVOID Object = NULL;
1260 HANDLE hKey;
1261 NTSTATUS Status = STATUS_SUCCESS;
1262 UNICODE_STRING ObjectName;
1263 OBJECT_CREATE_INFORMATION ObjectCreateInfo;
1264 REG_PRE_OPEN_KEY_INFORMATION PreOpenKeyInfo;
1265 REG_POST_OPEN_KEY_INFORMATION PostOpenKeyInfo;
1266
1267 PAGED_CODE();
1268
1269 DPRINT("NtOpenKey(KH 0x%p DA %x OA 0x%p OA->ON '%wZ'\n",
1270 KeyHandle,
1271 DesiredAccess,
1272 ObjectAttributes,
1273 ObjectAttributes ? ObjectAttributes->ObjectName : NULL);
1274
1275 /* Check place for result handle, if it's null - return immediately */
1276 if (KeyHandle == NULL)
1277 return(STATUS_INVALID_PARAMETER);
1278
1279 PreviousMode = ExGetPreviousMode();
1280
1281 if(PreviousMode != KernelMode)
1282 {
1283 _SEH_TRY
1284 {
1285 ProbeForWriteHandle(KeyHandle);
1286 }
1287 _SEH_HANDLE
1288 {
1289 Status = _SEH_GetExceptionCode();
1290 }
1291 _SEH_END;
1292
1293 if(!NT_SUCCESS(Status))
1294 {
1295 return Status;
1296 }
1297 }
1298
1299 /* WINE checks for the length also */
1300 /*if (ObjectAttributes->ObjectName->Length > MAX_NAME_LENGTH)
1301 return(STATUS_BUFFER_OVERFLOW);*/
1302
1303 /* Capture all the info */
1304 DPRINT("Capturing Create Info\n");
1305 Status = ObpCaptureObjectAttributes(ObjectAttributes,
1306 PreviousMode,
1307 CmiKeyType,
1308 &ObjectCreateInfo,
1309 &ObjectName);
1310 if (!NT_SUCCESS(Status))
1311 {
1312 DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status);
1313 return Status;
1314 }
1315
1316 PostOpenKeyInfo.CompleteName = &ObjectName;
1317 PreOpenKeyInfo.CompleteName = &ObjectName;
1318 Status = CmiCallRegisteredCallbacks(RegNtPreOpenKey, &PreOpenKeyInfo);
1319 if (!NT_SUCCESS(Status))
1320 {
1321 ObpReleaseCapturedAttributes(&ObjectCreateInfo);
1322 if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
1323 return Status;
1324 }
1325
1326
1327 RemainingPath.Buffer = NULL;
1328
1329 Status = ObFindObject(&ObjectCreateInfo,
1330 &ObjectName,
1331 (PVOID*)&Object,
1332 &RemainingPath,
1333 CmiKeyType);
1334 ObpReleaseCapturedAttributes(&ObjectCreateInfo);
1335 if (!NT_SUCCESS(Status))
1336 {
1337 DPRINT("CmpFindObject() returned 0x%08lx\n", Status);
1338 Status = STATUS_INVALID_HANDLE; /* Because CmpFindObject returns STATUS_UNSUCCESSFUL */
1339 hKey = *KeyHandle; /* Preserve hkResult value */
1340 goto openkey_cleanup;
1341 }
1342
1343 VERIFY_KEY_OBJECT((PKEY_OBJECT) Object);
1344
1345 DPRINT("RemainingPath '%wZ'\n", &RemainingPath);
1346
1347 if ((RemainingPath.Buffer != NULL) && (RemainingPath.Buffer[0] != 0))
1348 {
1349 RtlFreeUnicodeString(&RemainingPath);
1350 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1351 hKey = NULL;
1352 goto openkey_cleanup;
1353 }
1354
1355 RtlFreeUnicodeString(&RemainingPath);
1356
1357 /* Fail if the key has been deleted */
1358 if (((PKEY_OBJECT)Object)->Flags & KO_MARKED_FOR_DELETE)
1359 {
1360 Status = STATUS_UNSUCCESSFUL;
1361 hKey = NULL;
1362 goto openkey_cleanup;
1363 }
1364
1365 Status = ObpCreateHandle(PsGetCurrentProcess(),
1366 Object,
1367 DesiredAccess,
1368 TRUE,
1369 &hKey);
1370
1371 if (!NT_SUCCESS(Status))
1372 hKey = NULL;
1373
1374 openkey_cleanup:
1375
1376 PostOpenKeyInfo.Object = NT_SUCCESS(Status) ? (PVOID)Object : NULL;
1377 PostOpenKeyInfo.Status = Status;
1378 CmiCallRegisteredCallbacks (RegNtPostOpenKey, &PostOpenKeyInfo);
1379 if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
1380
1381 if (Object)
1382 {
1383 ObDereferenceObject(Object);
1384 }
1385
1386 _SEH_TRY
1387 {
1388 *KeyHandle = hKey;
1389 }
1390 _SEH_HANDLE
1391 {
1392 Status = _SEH_GetExceptionCode();
1393 }
1394 _SEH_END;
1395
1396 return Status;
1397 }
1398
1399
1400 NTSTATUS STDCALL
1401 NtQueryKey(IN HANDLE KeyHandle,
1402 IN KEY_INFORMATION_CLASS KeyInformationClass,
1403 OUT PVOID KeyInformation,
1404 IN ULONG Length,
1405 OUT PULONG ResultLength)
1406 {
1407 PKEY_BASIC_INFORMATION BasicInformation;
1408 PKEY_NODE_INFORMATION NodeInformation;
1409 PKEY_FULL_INFORMATION FullInformation;
1410 PREGISTRY_HIVE RegistryHive;
1411 PDATA_CELL ClassCell;
1412 PKEY_OBJECT KeyObject;
1413 PKEY_CELL KeyCell;
1414 ULONG NameSize, ClassSize;
1415 NTSTATUS Status;
1416 REG_QUERY_KEY_INFORMATION QueryKeyInfo;
1417 REG_POST_OPERATION_INFORMATION PostOperationInfo;
1418
1419 PAGED_CODE();
1420
1421 DPRINT("NtQueryKey(KH 0x%p KIC %x KI 0x%p L %d RL 0x%p)\n",
1422 KeyHandle,
1423 KeyInformationClass,
1424 KeyInformation,
1425 Length,
1426 ResultLength);
1427
1428 /* Verify that the handle is valid and is a registry key */
1429 Status = ObReferenceObjectByHandle(KeyHandle,
1430 (KeyInformationClass != KeyNameInformation ? KEY_QUERY_VALUE : 0),
1431 CmiKeyType,
1432 ExGetPreviousMode(),
1433 (PVOID *) &KeyObject,
1434 NULL);
1435 if (!NT_SUCCESS(Status))
1436 {
1437 return Status;
1438 }
1439
1440 PostOperationInfo.Object = (PVOID)KeyObject;
1441 QueryKeyInfo.Object = (PVOID)KeyObject;
1442 QueryKeyInfo.KeyInformationClass = KeyInformationClass;
1443 QueryKeyInfo.KeyInformation = KeyInformation;
1444 QueryKeyInfo.Length = Length;
1445 QueryKeyInfo.ResultLength = ResultLength;
1446
1447 Status = CmiCallRegisteredCallbacks(RegNtQueryKey, &QueryKeyInfo);
1448 if (!NT_SUCCESS(Status))
1449 {
1450 ObDereferenceObject(KeyObject);
1451 return Status;
1452 }
1453
1454 /* Acquire hive lock */
1455 KeEnterCriticalRegion();
1456 ExAcquireResourceSharedLite(&CmiRegistryLock, TRUE);
1457
1458 VERIFY_KEY_OBJECT(KeyObject);
1459
1460 /* Get pointer to KeyCell */
1461 KeyCell = KeyObject->KeyCell;
1462 RegistryHive = KeyObject->RegistryHive;
1463
1464 Status = STATUS_SUCCESS;
1465 switch (KeyInformationClass)
1466 {
1467 case KeyBasicInformation:
1468 NameSize = KeyObject->Name.Length;
1469
1470 *ResultLength = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]);
1471
1472 /* Check size of buffer */
1473 if (Length < FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]))
1474 {
1475 Status = STATUS_BUFFER_TOO_SMALL;
1476 }
1477 else
1478 {
1479 /* Fill buffer with requested info */
1480 BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
1481 BasicInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.u.LowPart;
1482 BasicInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.u.HighPart;
1483 BasicInformation->TitleIndex = 0;
1484 BasicInformation->NameLength = KeyObject->Name.Length;
1485
1486 if (Length - FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]) <
1487 NameSize)
1488 {
1489 NameSize = Length - FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]);
1490 Status = STATUS_BUFFER_OVERFLOW;
1491 CHECKPOINT;
1492 }
1493
1494 RtlCopyMemory(BasicInformation->Name,
1495 KeyObject->Name.Buffer,
1496 NameSize);
1497 }
1498 break;
1499
1500 case KeyNodeInformation:
1501 NameSize = KeyObject->Name.Length;
1502 ClassSize = KeyCell->ClassSize;
1503
1504 *ResultLength = FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) +
1505 NameSize + ClassSize;
1506
1507 /* Check size of buffer */
1508 if (Length < *ResultLength)
1509 {
1510 Status = STATUS_BUFFER_TOO_SMALL;
1511 }
1512 else
1513 {
1514 /* Fill buffer with requested info */
1515 NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
1516 NodeInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.u.LowPart;
1517 NodeInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.u.HighPart;
1518 NodeInformation->TitleIndex = 0;
1519 NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) +
1520 KeyObject->Name.Length;
1521 NodeInformation->ClassLength = KeyCell->ClassSize;
1522 NodeInformation->NameLength = KeyObject->Name.Length;
1523
1524 if (Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) < NameSize)
1525 {
1526 NameSize = Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]);
1527 ClassSize = 0;
1528 Status = STATUS_BUFFER_OVERFLOW;
1529 CHECKPOINT;
1530 }
1531 else if (Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) -
1532 NameSize < ClassSize)
1533 {
1534 ClassSize = Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) -
1535 NameSize;
1536 Status = STATUS_BUFFER_OVERFLOW;
1537 CHECKPOINT;
1538 }
1539
1540 RtlCopyMemory(NodeInformation->Name,
1541 KeyObject->Name.Buffer,
1542 NameSize);
1543
1544 if (ClassSize != 0)
1545 {
1546 ClassCell = CmiGetCell (KeyObject->RegistryHive,
1547 KeyCell->ClassNameOffset,
1548 NULL);
1549 RtlCopyMemory (NodeInformation->Name + KeyObject->Name.Length,
1550 ClassCell->Data,
1551 ClassSize);
1552 }
1553 }
1554 break;
1555
1556 case KeyFullInformation:
1557 ClassSize = KeyCell->ClassSize;
1558
1559 *ResultLength = FIELD_OFFSET(KEY_FULL_INFORMATION, Class) +
1560 ClassSize;
1561
1562 /* Check size of buffer */
1563 if (Length < FIELD_OFFSET(KEY_FULL_INFORMATION, Class))
1564 {
1565 Status = STATUS_BUFFER_TOO_SMALL;
1566 }
1567 else
1568 {
1569 /* Fill buffer with requested info */
1570 FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
1571 FullInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.u.LowPart;
1572 FullInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.u.HighPart;
1573 FullInformation->TitleIndex = 0;
1574 FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) - sizeof(WCHAR);
1575 FullInformation->ClassLength = KeyCell->ClassSize;
1576 FullInformation->SubKeys = CmiGetNumberOfSubKeys(KeyObject); //KeyCell->NumberOfSubKeys;
1577 FullInformation->MaxNameLen = CmiGetMaxNameLength(KeyObject);
1578 FullInformation->MaxClassLen = CmiGetMaxClassLength(KeyObject);
1579 FullInformation->Values = KeyCell->NumberOfValues;
1580 FullInformation->MaxValueNameLen =
1581 CmiGetMaxValueNameLength(RegistryHive, KeyCell);
1582 FullInformation->MaxValueDataLen =
1583 CmiGetMaxValueDataLength(RegistryHive, KeyCell);
1584
1585 if (Length - FIELD_OFFSET(KEY_FULL_INFORMATION, Class[0]) < ClassSize)
1586 {
1587 ClassSize = Length - FIELD_OFFSET(KEY_FULL_INFORMATION, Class[0]);
1588 Status = STATUS_BUFFER_OVERFLOW;
1589 CHECKPOINT;
1590 }
1591
1592 if (ClassSize)
1593 {
1594 ClassCell = CmiGetCell (KeyObject->RegistryHive,
1595 KeyCell->ClassNameOffset,
1596 NULL);
1597 RtlCopyMemory (FullInformation->Class,
1598 ClassCell->Data, ClassSize);
1599 }
1600 }
1601 break;
1602
1603 case KeyNameInformation:
1604 case KeyCachedInformation:
1605 case KeyFlagsInformation:
1606 DPRINT1("Key information class 0x%x not yet implemented!\n", KeyInformationClass);
1607 Status = STATUS_NOT_IMPLEMENTED;
1608 break;
1609
1610 default:
1611 DPRINT1("Not handling 0x%x\n", KeyInformationClass);
1612 Status = STATUS_INVALID_INFO_CLASS;
1613 break;
1614 }
1615
1616 ExReleaseResourceLite(&CmiRegistryLock);
1617 KeLeaveCriticalRegion();
1618
1619 PostOperationInfo.Status = Status;
1620 CmiCallRegisteredCallbacks(RegNtPostQueryKey, &PostOperationInfo);
1621
1622 ObDereferenceObject(KeyObject);
1623
1624 return(Status);
1625 }
1626
1627
1628 NTSTATUS STDCALL
1629 NtQueryValueKey(IN HANDLE KeyHandle,
1630 IN PUNICODE_STRING ValueName,
1631 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
1632 OUT PVOID KeyValueInformation,
1633 IN ULONG Length,
1634 OUT PULONG ResultLength)
1635 {
1636 NTSTATUS Status;
1637 ULONG NameSize, DataSize;
1638 PKEY_OBJECT KeyObject;
1639 PREGISTRY_HIVE RegistryHive;
1640 PKEY_CELL KeyCell;
1641 PVALUE_CELL ValueCell;
1642 PDATA_CELL DataCell;
1643 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation;
1644 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
1645 PKEY_VALUE_FULL_INFORMATION ValueFullInformation;
1646 REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo;
1647 REG_POST_OPERATION_INFORMATION PostOperationInfo;
1648
1649 PAGED_CODE();
1650
1651 DPRINT("NtQueryValueKey(KeyHandle 0x%p ValueName %S Length %x)\n",
1652 KeyHandle, ValueName->Buffer, Length);
1653
1654 /* Verify that the handle is valid and is a registry key */
1655 Status = ObReferenceObjectByHandle(KeyHandle,
1656 KEY_QUERY_VALUE,
1657 CmiKeyType,
1658 ExGetPreviousMode(),
1659 (PVOID *)&KeyObject,
1660 NULL);
1661
1662 if (!NT_SUCCESS(Status))
1663 {
1664 DPRINT1("ObReferenceObjectByHandle() failed with status %x %p\n", Status, KeyHandle);
1665 return Status;
1666 }
1667
1668 PostOperationInfo.Object = (PVOID)KeyObject;
1669 QueryValueKeyInfo.Object = (PVOID)KeyObject;
1670 QueryValueKeyInfo.ValueName = ValueName;
1671 QueryValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass;
1672 QueryValueKeyInfo.Length = Length;
1673 QueryValueKeyInfo.ResultLength = ResultLength;
1674
1675 Status = CmiCallRegisteredCallbacks(RegNtPreQueryValueKey, &QueryValueKeyInfo);
1676 if (!NT_SUCCESS(Status))
1677 {
1678 ObDereferenceObject(KeyObject);
1679 return Status;
1680 }
1681
1682 /* Acquire hive lock */
1683 KeEnterCriticalRegion();
1684 ExAcquireResourceSharedLite(&CmiRegistryLock, TRUE);
1685
1686 VERIFY_KEY_OBJECT(KeyObject);
1687
1688 /* Get pointer to KeyCell */
1689 KeyCell = KeyObject->KeyCell;
1690 RegistryHive = KeyObject->RegistryHive;
1691
1692 /* Get value cell by name */
1693 Status = CmiScanKeyForValue(RegistryHive,
1694 KeyCell,
1695 ValueName,
1696 &ValueCell,
1697 NULL);
1698 if (!NT_SUCCESS(Status))
1699 {
1700 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status);
1701 goto ByeBye;
1702 }
1703
1704 Status = STATUS_SUCCESS;
1705 switch (KeyValueInformationClass)
1706 {
1707 case KeyValueBasicInformation:
1708 NameSize = ValueCell->NameSize;
1709 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1710 {
1711 NameSize *= sizeof(WCHAR);
1712 }
1713
1714 *ResultLength = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]) +
1715 NameSize;
1716
1717 if (Length < FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]))
1718 {
1719 Status = STATUS_BUFFER_TOO_SMALL;
1720 }
1721 else
1722 {
1723 ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION)
1724 KeyValueInformation;
1725 ValueBasicInformation->TitleIndex = 0;
1726 ValueBasicInformation->Type = ValueCell->DataType;
1727 ValueBasicInformation->NameLength = NameSize;
1728
1729 if (Length - FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]) <
1730 NameSize)
1731 {
1732 NameSize = Length - FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
1733 Status = STATUS_BUFFER_OVERFLOW;
1734 CHECKPOINT;
1735 }
1736
1737 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1738 {
1739 CmiCopyPackedName(ValueBasicInformation->Name,
1740 ValueCell->Name,
1741 NameSize / sizeof(WCHAR));
1742 }
1743 else
1744 {
1745 RtlCopyMemory(ValueBasicInformation->Name,
1746 ValueCell->Name,
1747 NameSize);
1748 }
1749 }
1750 break;
1751
1752 case KeyValuePartialInformation:
1753 DataSize = ValueCell->DataSize & REG_DATA_SIZE_MASK;
1754
1755 *ResultLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) +
1756 DataSize;
1757
1758 if (Length < FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]))
1759 {
1760 Status = STATUS_BUFFER_TOO_SMALL;
1761 }
1762 else
1763 {
1764 ValuePartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)
1765 KeyValueInformation;
1766 ValuePartialInformation->TitleIndex = 0;
1767 ValuePartialInformation->Type = ValueCell->DataType;
1768 ValuePartialInformation->DataLength = DataSize;
1769
1770 if (Length - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) <
1771 DataSize)
1772 {
1773 DataSize = Length - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
1774 Status = STATUS_BUFFER_OVERFLOW;
1775 CHECKPOINT;
1776 }
1777
1778 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
1779 {
1780 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
1781 RtlCopyMemory(ValuePartialInformation->Data,
1782 DataCell->Data,
1783 DataSize);
1784 }
1785 else
1786 {
1787 RtlCopyMemory(ValuePartialInformation->Data,
1788 &ValueCell->DataOffset,
1789 DataSize);
1790 }
1791 }
1792 break;
1793
1794 case KeyValueFullInformation:
1795 NameSize = ValueCell->NameSize;
1796 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1797 {
1798 NameSize *= sizeof(WCHAR);
1799 }
1800 DataSize = ValueCell->DataSize & REG_DATA_SIZE_MASK;
1801
1802 *ResultLength = ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION,
1803 Name[0]) + NameSize, sizeof(PVOID)) + DataSize;
1804
1805 if (Length < FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]))
1806 {
1807 Status = STATUS_BUFFER_TOO_SMALL;
1808 }
1809 else
1810 {
1811 ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)
1812 KeyValueInformation;
1813 ValueFullInformation->TitleIndex = 0;
1814 ValueFullInformation->Type = ValueCell->DataType;
1815 ValueFullInformation->NameLength = NameSize;
1816 ValueFullInformation->DataOffset =
1817 (ULONG_PTR)ValueFullInformation->Name -
1818 (ULONG_PTR)ValueFullInformation +
1819 ValueFullInformation->NameLength;
1820 ValueFullInformation->DataOffset =
1821 ROUND_UP(ValueFullInformation->DataOffset, sizeof(PVOID));
1822 ValueFullInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK;
1823
1824 if (Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) <
1825 NameSize)
1826 {
1827 NameSize = Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
1828 DataSize = 0;
1829 Status = STATUS_BUFFER_OVERFLOW;
1830 CHECKPOINT;
1831 }
1832 else if (ROUND_UP(Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION,
1833 Name[0]) - NameSize, sizeof(PVOID)) < DataSize)
1834 {
1835 DataSize = ROUND_UP(Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION,
1836 Name[0]) - NameSize, sizeof(PVOID));
1837 Status = STATUS_BUFFER_OVERFLOW;
1838 CHECKPOINT;
1839 }
1840
1841 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1842 {
1843 CmiCopyPackedName(ValueFullInformation->Name,
1844 ValueCell->Name,
1845 NameSize / sizeof(WCHAR));
1846 }
1847 else
1848 {
1849 RtlCopyMemory(ValueFullInformation->Name,
1850 ValueCell->Name,
1851 NameSize);
1852 }
1853 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
1854 {
1855 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
1856 RtlCopyMemory((PCHAR) ValueFullInformation
1857 + ValueFullInformation->DataOffset,
1858 DataCell->Data,
1859 DataSize);
1860 }
1861 else
1862 {
1863 RtlCopyMemory((PCHAR) ValueFullInformation
1864 + ValueFullInformation->DataOffset,
1865 &ValueCell->DataOffset,
1866 DataSize);
1867 }
1868 }
1869 break;
1870
1871 default:
1872 DPRINT1("Not handling 0x%x\n", KeyValueInformationClass);
1873 Status = STATUS_INVALID_INFO_CLASS;
1874 break;
1875 }
1876
1877 ByeBye:;
1878 ExReleaseResourceLite(&CmiRegistryLock);
1879 KeLeaveCriticalRegion();
1880
1881 PostOperationInfo.Status = Status;
1882 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey, &PostOperationInfo);
1883 ObDereferenceObject(KeyObject);
1884
1885 return Status;
1886 }
1887
1888
1889 NTSTATUS STDCALL
1890 NtSetValueKey(IN HANDLE KeyHandle,
1891 IN PUNICODE_STRING ValueName,
1892 IN ULONG TitleIndex,
1893 IN ULONG Type,
1894 IN PVOID Data,
1895 IN ULONG DataSize)
1896 {
1897 NTSTATUS Status;
1898 PKEY_OBJECT KeyObject;
1899 PREGISTRY_HIVE RegistryHive;
1900 PKEY_CELL KeyCell;
1901 PVALUE_CELL ValueCell;
1902 BLOCK_OFFSET ValueCellOffset;
1903 PDATA_CELL DataCell;
1904 PDATA_CELL NewDataCell;
1905 ULONG DesiredAccess;
1906 REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo;
1907 REG_POST_OPERATION_INFORMATION PostOperationInfo;
1908 ULONG DataCellSize;
1909
1910 PAGED_CODE();
1911
1912 DPRINT("NtSetValueKey(KeyHandle 0x%p ValueName '%wZ' Type %d)\n",
1913 KeyHandle, ValueName, Type);
1914
1915 DesiredAccess = KEY_SET_VALUE;
1916
1917 /* Verify that the handle is valid and is a registry key */
1918 Status = ObReferenceObjectByHandle(KeyHandle,
1919 DesiredAccess,
1920 CmiKeyType,
1921 ExGetPreviousMode(),
1922 (PVOID *)&KeyObject,
1923 NULL);
1924 if (!NT_SUCCESS(Status))
1925 return(Status);
1926
1927 PostOperationInfo.Object = (PVOID)KeyObject;
1928 SetValueKeyInfo.Object = (PVOID)KeyObject;
1929 SetValueKeyInfo.ValueName = ValueName;
1930 SetValueKeyInfo.TitleIndex = TitleIndex;
1931 SetValueKeyInfo.Type = Type;
1932 SetValueKeyInfo.Data = Data;
1933 SetValueKeyInfo.DataSize = DataSize;
1934 Status = CmiCallRegisteredCallbacks(RegNtPreSetValueKey, &SetValueKeyInfo);
1935 if (!NT_SUCCESS(Status))
1936 {
1937 ObDereferenceObject(KeyObject);
1938 return Status;
1939 }
1940
1941 /* Acquire hive lock exclucively */
1942 KeEnterCriticalRegion();
1943 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
1944
1945 VERIFY_KEY_OBJECT(KeyObject);
1946
1947 /* Get pointer to key cell */
1948 KeyCell = KeyObject->KeyCell;
1949 RegistryHive = KeyObject->RegistryHive;
1950 Status = CmiScanKeyForValue(RegistryHive,
1951 KeyCell,
1952 ValueName,
1953 &ValueCell,
1954 &ValueCellOffset);
1955 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1956 {
1957 DPRINT("Allocate new value cell\n");
1958 Status = CmiAddValueToKey(RegistryHive,
1959 KeyCell,
1960 KeyObject->KeyCellOffset,
1961 ValueName,
1962 &ValueCell,
1963 &ValueCellOffset);
1964 }
1965
1966 if (!NT_SUCCESS(Status))
1967 {
1968 DPRINT("Cannot add value. Status 0x%X\n", Status);
1969
1970 ExReleaseResourceLite(&CmiRegistryLock);
1971 KeLeaveCriticalRegion();
1972 PostOperationInfo.Status = Status;
1973 CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
1974 ObDereferenceObject(KeyObject);
1975 return Status;
1976 }
1977
1978 DPRINT("DataSize %lu\n", DataSize);
1979 DPRINT("ValueCell %p\n", ValueCell);
1980 DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
1981
1982 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET) &&
1983 (ValueCell->DataSize & REG_DATA_SIZE_MASK) != 0)
1984 {
1985 DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
1986 DataCellSize = (DataCell->CellSize < 0 ? -DataCell->CellSize : DataCell->CellSize) - sizeof(CELL_HEADER);
1987 }
1988 else
1989 {
1990 DataCell = NULL;
1991 DataCellSize = 0;
1992 }
1993
1994
1995 if (DataSize <= sizeof(BLOCK_OFFSET))
1996 {
1997 /* If data size <= sizeof(BLOCK_OFFSET) then store data in the data offset */
1998 DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
1999 if (DataCell)
2000 {
2001 CmiDestroyCell(RegistryHive, DataCell, ValueCell->DataOffset);
2002 }
2003
2004 RtlCopyMemory(&ValueCell->DataOffset, Data, DataSize);
2005 ValueCell->DataSize = DataSize | REG_DATA_IN_OFFSET;
2006 ValueCell->DataType = Type;
2007 CmiMarkBlockDirty(RegistryHive, ValueCellOffset);
2008 }
2009 else
2010 {
2011 if (DataSize > DataCellSize)
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 Status = CmiAllocateCell (RegistryHive,
2022 sizeof(CELL_HEADER) + DataSize,
2023 (PVOID *)&NewDataCell,
2024 &NewOffset);
2025 if (!NT_SUCCESS(Status))
2026 {
2027 DPRINT("CmiAllocateBlock() failed (Status %lx)\n", Status);
2028
2029 ExReleaseResourceLite(&CmiRegistryLock);
2030 KeLeaveCriticalRegion();
2031 PostOperationInfo.Status = Status;
2032 CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
2033 ObDereferenceObject(KeyObject);
2034
2035 return Status;
2036 }
2037
2038 if (DataCell)
2039 {
2040 CmiDestroyCell(RegistryHive, DataCell, ValueCell->DataOffset);
2041 }
2042
2043 ValueCell->DataOffset = NewOffset;
2044 DataCell = NewDataCell;
2045 }
2046
2047 RtlCopyMemory(DataCell->Data, Data, DataSize);
2048 ValueCell->DataSize = DataSize & REG_DATA_SIZE_MASK;
2049 ValueCell->DataType = Type;
2050 CmiMarkBlockDirty(RegistryHive, ValueCell->DataOffset);
2051 CmiMarkBlockDirty(RegistryHive, ValueCellOffset);
2052 }
2053
2054 /* Mark link key */
2055 if ((Type == REG_LINK) &&
2056 (_wcsicmp(ValueName->Buffer, L"SymbolicLinkValue") == 0))
2057 {
2058 KeyCell->Flags |= REG_KEY_LINK_CELL;
2059 }
2060
2061 KeQuerySystemTime (&KeyCell->LastWriteTime);
2062 CmiMarkBlockDirty (RegistryHive, KeyObject->KeyCellOffset);
2063
2064 ExReleaseResourceLite(&CmiRegistryLock);
2065 KeLeaveCriticalRegion();
2066 PostOperationInfo.Status = Status;
2067 CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
2068 ObDereferenceObject(KeyObject);
2069
2070 CmiSyncHives();
2071
2072 DPRINT("Return Status 0x%X\n", Status);
2073
2074 return Status;
2075 }
2076
2077
2078 NTSTATUS STDCALL
2079 NtDeleteValueKey (IN HANDLE KeyHandle,
2080 IN PUNICODE_STRING ValueName)
2081 {
2082 PKEY_OBJECT KeyObject;
2083 NTSTATUS Status;
2084 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo;
2085 REG_POST_OPERATION_INFORMATION PostOperationInfo;
2086 KPROCESSOR_MODE PreviousMode;
2087 UNICODE_STRING CapturedValueName;
2088
2089 PAGED_CODE();
2090
2091 PreviousMode = ExGetPreviousMode();
2092
2093 /* Verify that the handle is valid and is a registry key */
2094 Status = ObReferenceObjectByHandle(KeyHandle,
2095 KEY_SET_VALUE,
2096 CmiKeyType,
2097 PreviousMode,
2098 (PVOID *)&KeyObject,
2099 NULL);
2100 if (!NT_SUCCESS(Status))
2101 {
2102 return Status;
2103 }
2104
2105 Status = ProbeAndCaptureUnicodeString(&CapturedValueName,
2106 PreviousMode,
2107 ValueName);
2108 if (!NT_SUCCESS(Status))
2109 {
2110 goto Fail;
2111 }
2112 DeleteValueKeyInfo.Object = (PVOID)KeyObject;
2113 DeleteValueKeyInfo.ValueName = &CapturedValueName;
2114
2115 /* FIXME - check if value exists before calling the callbacks? */
2116 Status = CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey, &DeleteValueKeyInfo);
2117 if (!NT_SUCCESS(Status))
2118 {
2119 ReleaseCapturedUnicodeString(&CapturedValueName,
2120 PreviousMode);
2121 Fail:
2122 ObDereferenceObject(KeyObject);
2123 return Status;
2124 }
2125
2126 /* Acquire hive lock */
2127 KeEnterCriticalRegion();
2128 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
2129
2130 VERIFY_KEY_OBJECT(KeyObject);
2131
2132 Status = CmiDeleteValueFromKey(KeyObject->RegistryHive,
2133 KeyObject->KeyCell,
2134 KeyObject->KeyCellOffset,
2135 ValueName);
2136
2137 KeQuerySystemTime (&KeyObject->KeyCell->LastWriteTime);
2138 CmiMarkBlockDirty (KeyObject->RegistryHive, KeyObject->KeyCellOffset);
2139
2140 /* Release hive lock */
2141 ExReleaseResourceLite(&CmiRegistryLock);
2142 KeLeaveCriticalRegion();
2143
2144 ReleaseCapturedUnicodeString(&CapturedValueName,
2145 PreviousMode);
2146
2147 PostOperationInfo.Object = (PVOID)KeyObject;
2148 PostOperationInfo.Status = Status;
2149
2150 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey, &PostOperationInfo);
2151
2152 ObDereferenceObject (KeyObject);
2153
2154 CmiSyncHives ();
2155
2156 return Status;
2157 }
2158
2159
2160 /*
2161 * NOTE:
2162 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2163 * KeyObjectAttributes->Name specifies the name of the key to load.
2164 */
2165 NTSTATUS STDCALL
2166 NtLoadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
2167 IN POBJECT_ATTRIBUTES FileObjectAttributes)
2168 {
2169 return NtLoadKey2 (KeyObjectAttributes,
2170 FileObjectAttributes,
2171 0);
2172 }
2173
2174
2175 /*
2176 * NOTE:
2177 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2178 * KeyObjectAttributes->Name specifies the name of the key to load.
2179 * Flags can be 0 or REG_NO_LAZY_FLUSH.
2180 */
2181 NTSTATUS STDCALL
2182 NtLoadKey2 (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
2183 IN POBJECT_ATTRIBUTES FileObjectAttributes,
2184 IN ULONG Flags)
2185 {
2186 POBJECT_NAME_INFORMATION NameInfo;
2187 PUNICODE_STRING NamePointer;
2188 PUCHAR Buffer;
2189 ULONG BufferSize;
2190 ULONG Length;
2191 NTSTATUS Status;
2192
2193 PAGED_CODE();
2194
2195 DPRINT ("NtLoadKey2() called\n");
2196
2197 #if 0
2198 if (!SeSinglePrivilegeCheck (SeRestorePrivilege, ExGetPreviousMode ()))
2199 return STATUS_PRIVILEGE_NOT_HELD;
2200 #endif
2201
2202 if (FileObjectAttributes->RootDirectory != NULL)
2203 {
2204 BufferSize =
2205 sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
2206 Buffer = ExAllocatePool (NonPagedPool,
2207 BufferSize);
2208 if (Buffer == NULL)
2209 return STATUS_INSUFFICIENT_RESOURCES;
2210
2211 Status = ZwQueryObject (FileObjectAttributes->RootDirectory,
2212 ObjectNameInformation,
2213 Buffer,
2214 BufferSize,
2215 &Length);
2216 if (!NT_SUCCESS(Status))
2217 {
2218 DPRINT1 ("NtQueryObject() failed (Status %lx)\n", Status);
2219 ExFreePool (Buffer);
2220 return Status;
2221 }
2222
2223 NameInfo = (POBJECT_NAME_INFORMATION)Buffer;
2224 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2225 &NameInfo->Name, NameInfo->Name.Length);
2226
2227 NameInfo->Name.MaximumLength = MAX_PATH * sizeof(WCHAR);
2228 if (FileObjectAttributes->ObjectName->Buffer[0] != L'\\')
2229 {
2230 RtlAppendUnicodeToString (&NameInfo->Name,
2231 L"\\");
2232 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2233 &NameInfo->Name, NameInfo->Name.Length);
2234 }
2235 RtlAppendUnicodeStringToString (&NameInfo->Name,
2236 FileObjectAttributes->ObjectName);
2237
2238 DPRINT ("ObjectPath: '%wZ' Length %hu\n",
2239 &NameInfo->Name, NameInfo->Name.Length);
2240 NamePointer = &NameInfo->Name;
2241 }
2242 else
2243 {
2244 if (FileObjectAttributes->ObjectName->Buffer[0] == L'\\')
2245 {
2246 Buffer = NULL;
2247 NamePointer = FileObjectAttributes->ObjectName;
2248 }
2249 else
2250 {
2251 BufferSize =
2252 sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
2253 Buffer = ExAllocatePool (NonPagedPool,
2254 BufferSize);
2255 if (Buffer == NULL)
2256 return STATUS_INSUFFICIENT_RESOURCES;
2257
2258 NameInfo = (POBJECT_NAME_INFORMATION)Buffer;
2259 NameInfo->Name.MaximumLength = MAX_PATH * sizeof(WCHAR);
2260 NameInfo->Name.Length = 0;
2261 NameInfo->Name.Buffer = (PWSTR)((ULONG_PTR)Buffer + sizeof(OBJECT_NAME_INFORMATION));
2262 NameInfo->Name.Buffer[0] = 0;
2263
2264 RtlAppendUnicodeToString (&NameInfo->Name,
2265 L"\\");
2266 RtlAppendUnicodeStringToString (&NameInfo->Name,
2267 FileObjectAttributes->ObjectName);
2268
2269 NamePointer = &NameInfo->Name;
2270 }
2271 }
2272
2273 DPRINT ("Full name: '%wZ'\n", NamePointer);
2274
2275 /* Acquire hive lock */
2276 KeEnterCriticalRegion();
2277 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
2278
2279 Status = CmiLoadHive (KeyObjectAttributes,
2280 NamePointer,
2281 Flags);
2282 if (!NT_SUCCESS (Status))
2283 {
2284 DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status);
2285 }
2286
2287 /* Release hive lock */
2288 ExReleaseResourceLite(&CmiRegistryLock);
2289 KeLeaveCriticalRegion();
2290
2291 if (Buffer != NULL)
2292 ExFreePool (Buffer);
2293
2294 return Status;
2295 }
2296
2297
2298 NTSTATUS STDCALL
2299 NtNotifyChangeKey (IN HANDLE KeyHandle,
2300 IN HANDLE Event,
2301 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
2302 IN PVOID ApcContext OPTIONAL,
2303 OUT PIO_STATUS_BLOCK IoStatusBlock,
2304 IN ULONG CompletionFilter,
2305 IN BOOLEAN WatchSubtree,
2306 OUT PVOID Buffer,
2307 IN ULONG Length,
2308 IN BOOLEAN Asynchronous)
2309 {
2310 UNIMPLEMENTED;
2311 return(STATUS_NOT_IMPLEMENTED);
2312 }
2313
2314 #if 0
2315 NTSTATUS STDCALL
2316 NtNotifyChangeKey (IN HANDLE KeyHandle,
2317 IN HANDLE Event,
2318 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
2319 IN PVOID ApcContext OPTIONAL,
2320 OUT PIO_STATUS_BLOCK IoStatusBlock,
2321 IN ULONG CompletionFilter,
2322 IN BOOLEAN WatchSubtree,
2323 OUT PVOID Buffer,
2324 IN ULONG Length,
2325 IN BOOLEAN Asynchronous)
2326 {
2327 return NtNotifyChangeMultipleKeys(KeyHandle,
2328 0,
2329 NULL,
2330 Event,
2331 ApcRoutine,
2332 ApcContext,
2333 IoStatusBlock,
2334 CompletionFilter,
2335 WatchTree,
2336 Buffer,
2337 Length,
2338 Asynchronous);
2339 }
2340
2341 #endif
2342
2343 NTSTATUS STDCALL
2344 NtQueryMultipleValueKey (IN HANDLE KeyHandle,
2345 IN OUT PKEY_VALUE_ENTRY ValueList,
2346 IN ULONG NumberOfValues,
2347 OUT PVOID Buffer,
2348 IN OUT PULONG Length,
2349 OUT PULONG ReturnLength)
2350 {
2351 PREGISTRY_HIVE RegistryHive;
2352 PVALUE_CELL ValueCell;
2353 PKEY_OBJECT KeyObject;
2354 PDATA_CELL DataCell;
2355 ULONG BufferLength = 0;
2356 PKEY_CELL KeyCell;
2357 NTSTATUS Status;
2358 PUCHAR DataPtr;
2359 ULONG i;
2360 REG_QUERY_MULTIPLE_VALUE_KEY_INFORMATION QueryMultipleValueKeyInfo;
2361 REG_POST_OPERATION_INFORMATION PostOperationInfo;
2362
2363 PAGED_CODE();
2364
2365 /* Verify that the handle is valid and is a registry key */
2366 Status = ObReferenceObjectByHandle(KeyHandle,
2367 KEY_QUERY_VALUE,
2368 CmiKeyType,
2369 ExGetPreviousMode(),
2370 (PVOID *) &KeyObject,
2371 NULL);
2372 if (!NT_SUCCESS(Status))
2373 {
2374 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
2375 return(Status);
2376 }
2377
2378 PostOperationInfo.Object = (PVOID)KeyObject;
2379 QueryMultipleValueKeyInfo.Object = (PVOID)KeyObject;
2380 QueryMultipleValueKeyInfo.ValueEntries = ValueList;
2381 QueryMultipleValueKeyInfo.EntryCount = NumberOfValues;
2382 QueryMultipleValueKeyInfo.ValueBuffer = Buffer;
2383 QueryMultipleValueKeyInfo.BufferLength = Length;
2384 QueryMultipleValueKeyInfo.RequiredBufferLength = ReturnLength;
2385
2386 Status = CmiCallRegisteredCallbacks(RegNtPreQueryMultipleValueKey, &QueryMultipleValueKeyInfo);
2387 if (!NT_SUCCESS(Status))
2388 {
2389 ObDereferenceObject(KeyObject);
2390 return Status;
2391 }
2392
2393 /* Acquire hive lock */
2394 KeEnterCriticalRegion();
2395 ExAcquireResourceSharedLite(&CmiRegistryLock, TRUE);
2396
2397 VERIFY_KEY_OBJECT(KeyObject);
2398
2399 /* Get pointer to KeyCell */
2400 KeyCell = KeyObject->KeyCell;
2401 RegistryHive = KeyObject->RegistryHive;
2402
2403 DataPtr = (PUCHAR) Buffer;
2404
2405 for (i = 0; i < NumberOfValues; i++)
2406 {
2407 DPRINT("ValueName: '%wZ'\n", ValueList[i].ValueName);
2408
2409 /* Get Value block of interest */
2410 Status = CmiScanKeyForValue(RegistryHive,
2411 KeyCell,
2412 ValueList[i].ValueName,
2413 &ValueCell,
2414 NULL);
2415
2416 if (!NT_SUCCESS(Status))
2417 {
2418 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status);
2419 break;
2420 }
2421 else if (ValueCell == NULL)
2422 {
2423 Status = STATUS_OBJECT_NAME_NOT_FOUND;
2424 break;
2425 }
2426
2427 BufferLength = ROUND_UP(BufferLength, sizeof(PVOID));
2428
2429 if (BufferLength + (ValueCell->DataSize & REG_DATA_SIZE_MASK) <= *Length)
2430 {
2431 DataPtr = (PUCHAR)ROUND_UP((ULONG_PTR)DataPtr, sizeof(PVOID));
2432
2433 ValueList[i].Type = ValueCell->DataType;
2434 ValueList[i].DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK;
2435 ValueList[i].DataOffset = (ULONG_PTR)DataPtr - (ULONG_PTR)Buffer;
2436
2437 if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
2438 {
2439 DataCell = CmiGetCell (RegistryHive,
2440 ValueCell->DataOffset,
2441 NULL);
2442 RtlCopyMemory(DataPtr,
2443 DataCell->Data,
2444 ValueCell->DataSize & REG_DATA_SIZE_MASK);
2445 }
2446 else
2447 {
2448 RtlCopyMemory(DataPtr,
2449 &ValueCell->DataOffset,
2450 ValueCell->DataSize & REG_DATA_SIZE_MASK);
2451 }
2452
2453 DataPtr += ValueCell->DataSize & REG_DATA_SIZE_MASK;
2454 }
2455 else
2456 {
2457 Status = STATUS_BUFFER_TOO_SMALL;
2458 }
2459
2460 BufferLength += ValueCell->DataSize & REG_DATA_SIZE_MASK;
2461 }
2462
2463 if (NT_SUCCESS(Status))
2464 *Length = BufferLength;
2465
2466 *ReturnLength = BufferLength;
2467
2468 /* Release hive lock */
2469 ExReleaseResourceLite(&CmiRegistryLock);
2470 KeLeaveCriticalRegion();
2471
2472 PostOperationInfo.Status = Status;
2473 CmiCallRegisteredCallbacks(RegNtPostQueryMultipleValueKey, &PostOperationInfo);
2474
2475 ObDereferenceObject(KeyObject);
2476
2477 DPRINT("Return Status 0x%X\n", Status);
2478
2479 return Status;
2480 }
2481
2482
2483 NTSTATUS STDCALL
2484 NtReplaceKey (IN POBJECT_ATTRIBUTES ObjectAttributes,
2485 IN HANDLE Key,
2486 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
2487 {
2488 UNIMPLEMENTED;
2489 return(STATUS_NOT_IMPLEMENTED);
2490 }
2491
2492
2493 NTSTATUS STDCALL
2494 NtRestoreKey (IN HANDLE KeyHandle,
2495 IN HANDLE FileHandle,
2496 IN ULONG RestoreFlags)
2497 {
2498 UNIMPLEMENTED;
2499 return(STATUS_NOT_IMPLEMENTED);
2500 }
2501
2502
2503 NTSTATUS STDCALL
2504 NtSaveKey (IN HANDLE KeyHandle,
2505 IN HANDLE FileHandle)
2506 {
2507 PREGISTRY_HIVE TempHive;
2508 PKEY_OBJECT KeyObject;
2509 NTSTATUS Status;
2510
2511 PAGED_CODE();
2512
2513 DPRINT ("NtSaveKey() called\n");
2514
2515 #if 0
2516 if (!SeSinglePrivilegeCheck (SeBackupPrivilege, ExGetPreviousMode ()))
2517 return STATUS_PRIVILEGE_NOT_HELD;
2518 #endif
2519
2520 Status = ObReferenceObjectByHandle (KeyHandle,
2521 0,
2522 CmiKeyType,
2523 ExGetPreviousMode(),
2524 (PVOID *)&KeyObject,
2525 NULL);
2526 if (!NT_SUCCESS(Status))
2527 {
2528 DPRINT1 ("ObReferenceObjectByHandle() failed (Status %lx)\n", Status);
2529 return Status;
2530 }
2531
2532 /* Acquire hive lock exclucively */
2533 KeEnterCriticalRegion();
2534 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
2535
2536 /* Refuse to save a volatile key */
2537 if (KeyObject->RegistryHive == CmiVolatileHive)
2538 {
2539 DPRINT1 ("Cannot save a volatile key\n");
2540 ExReleaseResourceLite(&CmiRegistryLock);
2541 KeLeaveCriticalRegion();
2542 ObDereferenceObject (KeyObject);
2543 return STATUS_ACCESS_DENIED;
2544 }
2545
2546 Status = CmiCreateTempHive(&TempHive);
2547 if (!NT_SUCCESS(Status))
2548 {
2549 DPRINT1 ("CmiCreateTempHive() failed (Status %lx)\n", Status);
2550 ExReleaseResourceLite(&CmiRegistryLock);
2551 KeLeaveCriticalRegion();
2552 ObDereferenceObject (KeyObject);
2553 return(Status);
2554 }
2555
2556 Status = CmiCopyKey (TempHive,
2557 NULL,
2558 KeyObject->RegistryHive,
2559 KeyObject->KeyCell);
2560 if (!NT_SUCCESS(Status))
2561 {
2562 DPRINT1 ("CmiCopyKey() failed (Status %lx)\n", Status);
2563 CmiRemoveRegistryHive (TempHive);
2564 ExReleaseResourceLite(&CmiRegistryLock);
2565 KeLeaveCriticalRegion();
2566 ObDereferenceObject (KeyObject);
2567 return(Status);
2568 }
2569
2570 Status = CmiSaveTempHive (TempHive,
2571 FileHandle);
2572 if (!NT_SUCCESS(Status))
2573 {
2574 DPRINT1 ("CmiSaveTempHive() failed (Status %lx)\n", Status);
2575 }
2576
2577 CmiRemoveRegistryHive (TempHive);
2578
2579 /* Release hive lock */
2580 ExReleaseResourceLite(&CmiRegistryLock);
2581 KeLeaveCriticalRegion();
2582
2583 ObDereferenceObject (KeyObject);
2584
2585 DPRINT ("NtSaveKey() done\n");
2586
2587 return STATUS_SUCCESS;
2588 }
2589
2590 /*
2591 * @unimplemented
2592 */
2593 NTSTATUS
2594 STDCALL
2595 NtSaveKeyEx(
2596 IN HANDLE KeyHandle,
2597 IN HANDLE FileHandle,
2598 IN ULONG Flags // REG_STANDARD_FORMAT, etc..
2599 )
2600 {
2601 UNIMPLEMENTED;
2602 return STATUS_NOT_IMPLEMENTED;
2603 }
2604
2605
2606 NTSTATUS STDCALL
2607 NtSetInformationKey (IN HANDLE KeyHandle,
2608 IN KEY_SET_INFORMATION_CLASS KeyInformationClass,
2609 IN PVOID KeyInformation,
2610 IN ULONG KeyInformationLength)
2611 {
2612 PKEY_OBJECT KeyObject;
2613 NTSTATUS Status;
2614 REG_SET_INFORMATION_KEY_INFORMATION SetInformationKeyInfo;
2615 REG_POST_OPERATION_INFORMATION PostOperationInfo;
2616
2617 PAGED_CODE();
2618
2619 /* Verify that the handle is valid and is a registry key */
2620 Status = ObReferenceObjectByHandle (KeyHandle,
2621 KEY_SET_VALUE,
2622 CmiKeyType,
2623 ExGetPreviousMode(),
2624 (PVOID *)&KeyObject,
2625 NULL);
2626 if (!NT_SUCCESS (Status))
2627 {
2628 DPRINT ("ObReferenceObjectByHandle() failed with status %x\n", Status);
2629 return Status;
2630 }
2631
2632 PostOperationInfo.Object = (PVOID)KeyObject;
2633 SetInformationKeyInfo.Object = (PVOID)KeyObject;
2634 SetInformationKeyInfo.KeySetInformationClass = KeyInformationClass;
2635 SetInformationKeyInfo.KeySetInformation = KeyInformation;
2636 SetInformationKeyInfo.KeySetInformationLength = KeyInformationLength;
2637
2638 Status = CmiCallRegisteredCallbacks(RegNtSetInformationKey, &SetInformationKeyInfo);
2639 if (!NT_SUCCESS(Status))
2640 {
2641 ObDereferenceObject (KeyObject);
2642 return Status;
2643 }
2644
2645 if (KeyInformationClass != KeyWriteTimeInformation)
2646 {
2647 Status = STATUS_INVALID_INFO_CLASS;
2648 }
2649
2650 else if (KeyInformationLength != sizeof (KEY_WRITE_TIME_INFORMATION))
2651 {
2652 Status = STATUS_INFO_LENGTH_MISMATCH;
2653 }
2654 else
2655 {
2656 /* Acquire hive lock */
2657 KeEnterCriticalRegion();
2658 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
2659
2660 VERIFY_KEY_OBJECT(KeyObject);
2661
2662 KeyObject->KeyCell->LastWriteTime.QuadPart =
2663 ((PKEY_WRITE_TIME_INFORMATION)KeyInformation)->LastWriteTime.QuadPart;
2664
2665 CmiMarkBlockDirty (KeyObject->RegistryHive,
2666 KeyObject->KeyCellOffset);
2667
2668 /* Release hive lock */
2669 ExReleaseResourceLite(&CmiRegistryLock);
2670 KeLeaveCriticalRegion();
2671 }
2672
2673 PostOperationInfo.Status = Status;
2674 CmiCallRegisteredCallbacks(RegNtPostSetInformationKey, &PostOperationInfo);
2675
2676 ObDereferenceObject (KeyObject);
2677
2678 if (NT_SUCCESS(Status))
2679 {
2680 CmiSyncHives ();
2681 }
2682
2683 DPRINT ("NtSaveKey() done\n");
2684
2685 return STATUS_SUCCESS;
2686 }
2687
2688
2689 /*
2690 * NOTE:
2691 * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
2692 * KeyObjectAttributes->Name specifies the name of the key to unload.
2693 */
2694 NTSTATUS STDCALL
2695 NtUnloadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes)
2696 {
2697 PREGISTRY_HIVE RegistryHive;
2698 NTSTATUS Status;
2699
2700 PAGED_CODE();
2701
2702 DPRINT ("NtUnloadKey() called\n");
2703
2704 #if 0
2705 if (!SeSinglePrivilegeCheck (SeRestorePrivilege, ExGetPreviousMode ()))
2706 return STATUS_PRIVILEGE_NOT_HELD;
2707 #endif
2708
2709 /* Acquire registry lock exclusively */
2710 KeEnterCriticalRegion();
2711 ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
2712
2713 Status = CmiDisconnectHive (KeyObjectAttributes,
2714 &RegistryHive);
2715 if (!NT_SUCCESS (Status))
2716 {
2717 DPRINT1 ("CmiDisconnectHive() failed (Status %lx)\n", Status);
2718 ExReleaseResourceLite (&CmiRegistryLock);
2719 KeLeaveCriticalRegion();
2720 return Status;
2721 }
2722
2723 DPRINT ("RegistryHive %p\n", RegistryHive);
2724
2725 #if 0
2726 /* Flush hive */
2727 if (!IsNoFileHive (RegistryHive))
2728 CmiFlushRegistryHive (RegistryHive);
2729 #endif
2730
2731 CmiRemoveRegistryHive (RegistryHive);
2732
2733 /* Release registry lock */
2734 ExReleaseResourceLite (&CmiRegistryLock);
2735 KeLeaveCriticalRegion();
2736
2737 DPRINT ("NtUnloadKey() done\n");
2738
2739 return STATUS_SUCCESS;
2740 }
2741
2742
2743 NTSTATUS STDCALL
2744 NtInitializeRegistry (IN BOOLEAN SetUpBoot)
2745 {
2746 NTSTATUS Status;
2747
2748 PAGED_CODE();
2749
2750 if (CmiRegistryInitialized == TRUE)
2751 return STATUS_ACCESS_DENIED;
2752
2753 /* Save boot log file */
2754 IopSaveBootLogToFile();
2755
2756 Status = CmiInitHives (SetUpBoot);
2757
2758 CmiRegistryInitialized = TRUE;
2759
2760 return Status;
2761 }
2762
2763 /* EOF */