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