* Implemented/fixed NtSetSecurityObject() and NtQuerySecurityObject().
[reactos.git] / reactos / ntoskrnl / cm / ntfunc.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cm/ntfunc.c
5 * PURPOSE: Ntxxx function for registry access
6 * UPDATE HISTORY:
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #ifdef WIN32_REGDBG
12 #include "cm_win32.h"
13 #else
14 #include <ddk/ntddk.h>
15 #include <roscfg.h>
16 #include <internal/ob.h>
17 #include <limits.h>
18 #include <string.h>
19 #include <internal/pool.h>
20 #include <internal/registry.h>
21
22 #define NDEBUG
23 #include <internal/debug.h>
24
25 #include "cm.h"
26 #endif
27
28
29 /* GLOBALS ******************************************************************/
30
31 extern POBJECT_TYPE CmiKeyType;
32 extern PREGISTRY_HIVE CmiVolatileHive;
33
34 static BOOLEAN CmiRegistryInitialized = FALSE;
35
36
37 /* FUNCTIONS ****************************************************************/
38
39 NTSTATUS STDCALL
40 NtCreateKey(OUT PHANDLE KeyHandle,
41 IN ACCESS_MASK DesiredAccess,
42 IN POBJECT_ATTRIBUTES ObjectAttributes,
43 IN ULONG TitleIndex,
44 IN PUNICODE_STRING Class,
45 IN ULONG CreateOptions,
46 OUT PULONG Disposition)
47 {
48 UNICODE_STRING RemainingPath;
49 PKEY_OBJECT KeyObject;
50 NTSTATUS Status;
51 PVOID Object;
52 PWSTR End;
53
54 DPRINT("NtCreateKey (Name %wZ KeyHandle %x Root %x)\n",
55 ObjectAttributes->ObjectName,
56 KeyHandle,
57 ObjectAttributes->RootDirectory);
58
59 /* FIXME: check for standard handle prefix and adjust objectAttributes accordingly */
60
61 Status = ObFindObject(ObjectAttributes,
62 &Object,
63 &RemainingPath,
64 CmiKeyType);
65 if (!NT_SUCCESS(Status))
66 {
67 return(Status);
68 }
69
70 DPRINT("RemainingPath %wZ\n", &RemainingPath);
71
72 if ((RemainingPath.Buffer == NULL) || (RemainingPath.Buffer[0] == 0))
73 {
74 /* Fail if the key has been deleted */
75 if (((PKEY_OBJECT) Object)->Flags & KO_MARKED_FOR_DELETE)
76 {
77 ObDereferenceObject(Object);
78 return(STATUS_UNSUCCESSFUL);
79 }
80
81 if (Disposition)
82 *Disposition = REG_OPENED_EXISTING_KEY;
83
84 Status = ObCreateHandle(PsGetCurrentProcess(),
85 Object,
86 DesiredAccess,
87 FALSE,
88 KeyHandle);
89
90 DPRINT("Status %x\n", Status);
91 ObDereferenceObject(Object);
92 return Status;
93 }
94
95 /* If RemainingPath contains \ we must return error
96 because NtCreateKey don't create trees */
97 if (RemainingPath.Buffer[0] == '\\')
98 End = wcschr(RemainingPath.Buffer + 1, '\\');
99 else
100 End = wcschr(RemainingPath.Buffer, '\\');
101
102 if (End != NULL)
103 {
104 ObDereferenceObject(Object);
105 return STATUS_UNSUCCESSFUL;
106 }
107
108 DPRINT("RemainingPath %S ParentObject %x\n", RemainingPath.Buffer, Object);
109
110 Status = ObCreateObject(KeyHandle,
111 DesiredAccess,
112 NULL,
113 CmiKeyType,
114 (PVOID*)&KeyObject);
115 if (!NT_SUCCESS(Status))
116 {
117 return(Status);
118 }
119
120 KeyObject->ParentKey = Object;
121
122 if (CreateOptions & REG_OPTION_VOLATILE)
123 KeyObject->RegistryHive = CmiVolatileHive;
124 else
125 KeyObject->RegistryHive = KeyObject->ParentKey->RegistryHive;
126
127 KeyObject->Flags = 0;
128 KeyObject->NumberOfSubKeys = 0;
129 KeyObject->SizeOfSubKeys = 0;
130 KeyObject->SubKeys = NULL;
131
132 /* Acquire hive lock */
133 ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
134
135 /* add key to subkeys of parent if needed */
136 Status = CmiAddSubKey(KeyObject->RegistryHive,
137 KeyObject->ParentKey,
138 KeyObject,
139 RemainingPath.Buffer,
140 RemainingPath.Length,
141 TitleIndex,
142 Class,
143 CreateOptions);
144 if (!NT_SUCCESS(Status))
145 {
146 /* Release hive lock */
147 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
148 ObDereferenceObject(KeyObject);
149 ObDereferenceObject(Object);
150 return STATUS_UNSUCCESSFUL;
151 }
152
153 KeyObject->Name = KeyObject->KeyCell->Name;
154 KeyObject->NameSize = KeyObject->KeyCell->NameSize;
155
156 if (KeyObject->RegistryHive == KeyObject->ParentKey->RegistryHive)
157 {
158 KeyObject->KeyCell->ParentKeyOffset = KeyObject->ParentKey->BlockOffset;
159 KeyObject->KeyCell->SecurityKeyOffset = KeyObject->ParentKey->KeyCell->SecurityKeyOffset;
160 }
161 else
162 {
163 KeyObject->KeyCell->ParentKeyOffset = -1;
164 KeyObject->KeyCell->SecurityKeyOffset = -1;
165 /* This key must remain in memory unless it is deleted
166 or file is unloaded */
167 ObReferenceObjectByPointer(KeyObject,
168 STANDARD_RIGHTS_REQUIRED,
169 NULL,
170 UserMode);
171 }
172
173 CmiAddKeyToList(KeyObject->ParentKey, KeyObject);
174
175 VERIFY_KEY_OBJECT(KeyObject);
176
177 /* Release hive lock */
178 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
179
180 ObDereferenceObject(KeyObject);
181 ObDereferenceObject(Object);
182
183 if (Disposition)
184 *Disposition = REG_CREATED_NEW_KEY;
185
186 CmiSyncHives();
187
188 return Status;
189 }
190
191
192 NTSTATUS STDCALL
193 NtDeleteKey(IN HANDLE KeyHandle)
194 {
195 PKEY_OBJECT KeyObject;
196 NTSTATUS Status;
197
198 DPRINT("KeyHandle %x\n", KeyHandle);
199
200 /* Verify that the handle is valid and is a registry key */
201 Status = ObReferenceObjectByHandle(KeyHandle,
202 KEY_WRITE,
203 CmiKeyType,
204 UserMode,
205 (PVOID *)&KeyObject,
206 NULL);
207 if (!NT_SUCCESS(Status))
208 {
209 return(Status);
210 }
211
212 /* Acquire hive lock */
213 ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
214
215 VERIFY_KEY_OBJECT(KeyObject);
216
217 /* Check for subkeys */
218 if (KeyObject->NumberOfSubKeys != 0)
219 {
220 Status = STATUS_CANNOT_DELETE;
221 }
222 else
223 {
224 /* Set the marked for delete bit in the key object */
225 KeyObject->Flags |= KO_MARKED_FOR_DELETE;
226 Status = STATUS_SUCCESS;
227 }
228
229 /* Release hive lock */
230 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
231
232 DPRINT1("PointerCount %lu\n", ObGetObjectPointerCount((PVOID)KeyObject));
233
234 /* Dereference the object */
235 ObDereferenceObject(KeyObject);
236 if(KeyObject->RegistryHive != KeyObject->ParentKey->RegistryHive)
237 ObDereferenceObject(KeyObject);
238
239 DPRINT1("PointerCount %lu\n", ObGetObjectPointerCount((PVOID)KeyObject));
240
241 /*
242 * Note:
243 * Hive-Synchronization will not be triggered here. This is done in
244 * CmiObjectDelete() (in regobj.c) after all key-related structures
245 * have been released.
246 */
247
248 return(Status);
249 }
250
251
252 NTSTATUS STDCALL
253 NtEnumerateKey(
254 IN HANDLE KeyHandle,
255 IN ULONG Index,
256 IN KEY_INFORMATION_CLASS KeyInformationClass,
257 OUT PVOID KeyInformation,
258 IN ULONG Length,
259 OUT PULONG ResultLength
260 )
261 {
262 NTSTATUS Status;
263 PKEY_OBJECT KeyObject;
264 PREGISTRY_HIVE RegistryHive;
265 PKEY_CELL KeyCell, SubKeyCell;
266 PHASH_TABLE_CELL HashTableBlock;
267 PKEY_BASIC_INFORMATION BasicInformation;
268 PKEY_NODE_INFORMATION NodeInformation;
269 PKEY_FULL_INFORMATION FullInformation;
270 PDATA_CELL pClassData;
271
272 DPRINT("KH %x I %d KIC %x KI %x L %d RL %x\n",
273 KeyHandle,
274 Index,
275 KeyInformationClass,
276 KeyInformation,
277 Length,
278 ResultLength);
279
280 /* Verify that the handle is valid and is a registry key */
281 Status = ObReferenceObjectByHandle(KeyHandle,
282 KEY_ENUMERATE_SUB_KEYS,
283 CmiKeyType,
284 UserMode,
285 (PVOID *) &KeyObject,
286 NULL);
287 if (!NT_SUCCESS(Status))
288 {
289 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
290 return(Status);
291 }
292
293 /* Acquire hive lock */
294 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
295
296 VERIFY_KEY_OBJECT(KeyObject);
297
298 /* Get pointer to KeyCell */
299 KeyCell = KeyObject->KeyCell;
300 RegistryHive = KeyObject->RegistryHive;
301
302 /* Get pointer to SubKey */
303 if (Index >= KeyCell->NumberOfSubKeys)
304 {
305 if (RegistryHive == CmiVolatileHive)
306 {
307 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
308 ObDereferenceObject(KeyObject);
309 DPRINT("No more volatile entries\n");
310 return(STATUS_NO_MORE_ENTRIES);
311 }
312 else
313 {
314 ULONG i;
315 PKEY_OBJECT CurKey = NULL;
316
317 /* Search volatile keys */
318 for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
319 {
320 CurKey = KeyObject->SubKeys[i];
321 if (CurKey->RegistryHive == CmiVolatileHive)
322 {
323 if (Index-- == KeyObject->NumberOfSubKeys)
324 break;
325 }
326 }
327 if (Index >= KeyCell->NumberOfSubKeys)
328 {
329 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
330 ObDereferenceObject(KeyObject);
331 DPRINT("No more non-volatile entries\n");
332 return(STATUS_NO_MORE_ENTRIES);
333 }
334 SubKeyCell = CurKey->KeyCell;
335 }
336 }
337 else
338 {
339 HashTableBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
340 SubKeyCell = CmiGetKeyFromHashByIndex(RegistryHive,
341 HashTableBlock,
342 Index);
343 }
344
345 if (SubKeyCell == NULL)
346 {
347 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
348 ObDereferenceObject(KeyObject);
349 DPRINT("No more entries\n");
350 return(STATUS_NO_MORE_ENTRIES);
351 }
352
353 Status = STATUS_SUCCESS;
354 switch (KeyInformationClass)
355 {
356 case KeyBasicInformation:
357 /* Check size of buffer */
358 *ResultLength = sizeof(KEY_BASIC_INFORMATION) +
359 (SubKeyCell->NameSize ) * sizeof(WCHAR);
360 if (Length < *ResultLength)
361 {
362 Status = STATUS_BUFFER_OVERFLOW;
363 }
364 else
365 {
366 /* Fill buffer with requested info */
367 BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
368 BasicInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.dwLowDateTime;
369 BasicInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.dwHighDateTime;
370 BasicInformation->TitleIndex = Index;
371 BasicInformation->NameLength = SubKeyCell->NameSize * sizeof(WCHAR);
372 mbstowcs(BasicInformation->Name,
373 SubKeyCell->Name,
374 SubKeyCell->NameSize * 2);
375 // BasicInformation->Name[SubKeyCell->NameSize] = 0;
376 }
377 break;
378
379 case KeyNodeInformation:
380 /* Check size of buffer */
381 *ResultLength = sizeof(KEY_NODE_INFORMATION) +
382 SubKeyCell->NameSize * sizeof(WCHAR) +
383 SubKeyCell->ClassSize;
384 if (Length < *ResultLength)
385 {
386 Status = STATUS_BUFFER_OVERFLOW;
387 }
388 else
389 {
390 /* Fill buffer with requested info */
391 NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
392 NodeInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.dwLowDateTime;
393 NodeInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.dwHighDateTime;
394 NodeInformation->TitleIndex = Index;
395 NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) +
396 SubKeyCell->NameSize * sizeof(WCHAR);
397 NodeInformation->ClassLength = SubKeyCell->ClassSize;
398 NodeInformation->NameLength = SubKeyCell->NameSize * sizeof(WCHAR);
399 mbstowcs(NodeInformation->Name,
400 SubKeyCell->Name,
401 SubKeyCell->NameSize * 2);
402 // NodeInformation->Name[SubKeyCell->NameSize] = 0;
403 if (SubKeyCell->ClassSize != 0)
404 {
405 pClassData=CmiGetBlock(KeyObject->RegistryHive,
406 SubKeyCell->ClassNameOffset,
407 NULL);
408 wcsncpy(NodeInformation->Name + SubKeyCell->NameSize ,
409 (PWCHAR) pClassData->Data,
410 SubKeyCell->ClassSize);
411 CmiReleaseBlock(RegistryHive, pClassData);
412 }
413 }
414 break;
415
416 case KeyFullInformation:
417 /* check size of buffer */
418 *ResultLength = sizeof(KEY_FULL_INFORMATION) +
419 SubKeyCell->ClassSize;
420 if (Length < *ResultLength)
421 {
422 Status = STATUS_BUFFER_OVERFLOW;
423 }
424 else
425 {
426 /* fill buffer with requested info */
427 FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
428 FullInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.dwLowDateTime;
429 FullInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.dwHighDateTime;
430 FullInformation->TitleIndex = Index;
431 FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) -
432 sizeof(WCHAR);
433 FullInformation->ClassLength = SubKeyCell->ClassSize;
434 FullInformation->SubKeys = SubKeyCell->NumberOfSubKeys;
435 FullInformation->MaxNameLen =
436 CmiGetMaxNameLength(RegistryHive, SubKeyCell);
437 FullInformation->MaxClassLen =
438 CmiGetMaxClassLength(RegistryHive, SubKeyCell);
439 FullInformation->Values = SubKeyCell->NumberOfValues;
440 FullInformation->MaxValueNameLen =
441 CmiGetMaxValueNameLength(RegistryHive, SubKeyCell);
442 FullInformation->MaxValueDataLen =
443 CmiGetMaxValueDataLength(RegistryHive, SubKeyCell);
444 if (SubKeyCell->ClassSize != 0)
445 {
446 pClassData = CmiGetBlock(KeyObject->RegistryHive,
447 SubKeyCell->ClassNameOffset,
448 NULL);
449 wcsncpy(FullInformation->Class,
450 (PWCHAR) pClassData->Data,
451 SubKeyCell->ClassSize);
452 CmiReleaseBlock(RegistryHive, pClassData);
453 }
454 }
455 break;
456 }
457 CmiReleaseBlock(RegistryHive, SubKeyCell);
458
459 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
460 ObDereferenceObject(KeyObject);
461
462 DPRINT("Returning status %x\n", Status);
463
464 return(Status);
465 }
466
467
468 NTSTATUS STDCALL
469 NtEnumerateValueKey(IN HANDLE KeyHandle,
470 IN ULONG Index,
471 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
472 OUT PVOID KeyValueInformation,
473 IN ULONG Length,
474 OUT PULONG ResultLength)
475 {
476 NTSTATUS Status;
477 PKEY_OBJECT KeyObject;
478 PREGISTRY_HIVE RegistryHive;
479 PKEY_CELL KeyCell;
480 PVALUE_CELL ValueCell;
481 PDATA_CELL DataCell;
482 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation;
483 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
484 PKEY_VALUE_FULL_INFORMATION ValueFullInformation;
485
486 DPRINT("KH %x I %d KVIC %x KVI %x L %d RL %x\n",
487 KeyHandle,
488 Index,
489 KeyValueInformationClass,
490 KeyValueInformation,
491 Length,
492 ResultLength);
493
494 /* Verify that the handle is valid and is a registry key */
495 Status = ObReferenceObjectByHandle(KeyHandle,
496 KEY_QUERY_VALUE,
497 CmiKeyType,
498 UserMode,
499 (PVOID *) &KeyObject,
500 NULL);
501
502 if (!NT_SUCCESS(Status))
503 {
504 return Status;
505 }
506
507 /* Acquire hive lock */
508 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
509
510 VERIFY_KEY_OBJECT(KeyObject);
511
512 /* Get pointer to KeyCell */
513 KeyCell = KeyObject->KeyCell;
514 RegistryHive = KeyObject->RegistryHive;
515
516 /* Get Value block of interest */
517 Status = CmiGetValueFromKeyByIndex(RegistryHive,
518 KeyCell,
519 Index,
520 &ValueCell);
521
522 if (!NT_SUCCESS(Status))
523 {
524 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
525 ObDereferenceObject(KeyObject);
526 return Status;
527 }
528
529 if (ValueCell != NULL)
530 {
531 switch (KeyValueInformationClass)
532 {
533 case KeyValueBasicInformation:
534 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
535 {
536 *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) +
537 (ValueCell->NameSize + 1) * sizeof(WCHAR);
538 }
539 else
540 {
541 *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) +
542 ValueCell->NameSize + sizeof(WCHAR);
543 }
544 if (Length < *ResultLength)
545 {
546 Status = STATUS_BUFFER_OVERFLOW;
547 }
548 else
549 {
550 ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION)
551 KeyValueInformation;
552 ValueBasicInformation->TitleIndex = 0;
553 ValueBasicInformation->Type = ValueCell->DataType;
554 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
555 {
556 ValueBasicInformation->NameLength =
557 (ValueCell->NameSize + 1) * sizeof(WCHAR);
558 CmiCopyPackedName(ValueBasicInformation->Name,
559 ValueCell->Name,
560 ValueCell->NameSize);
561 ValueBasicInformation->Name[ValueCell->NameSize] = 0;
562 }
563 else
564 {
565 ValueBasicInformation->NameLength =
566 ValueCell->NameSize + sizeof(WCHAR);
567 RtlCopyMemory(ValueBasicInformation->Name,
568 ValueCell->Name,
569 ValueCell->NameSize * sizeof(WCHAR));
570 ValueBasicInformation->Name[ValueCell->NameSize / sizeof(WCHAR)] = 0;
571 }
572 }
573 break;
574
575 case KeyValuePartialInformation:
576 *ResultLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
577 (ValueCell->DataSize & LONG_MAX);
578 if (Length < *ResultLength)
579 {
580 Status = STATUS_BUFFER_OVERFLOW;
581 }
582 else
583 {
584 ValuePartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)
585 KeyValueInformation;
586 ValuePartialInformation->TitleIndex = 0;
587 ValuePartialInformation->Type = ValueCell->DataType;
588 ValuePartialInformation->DataLength = ValueCell->DataSize & LONG_MAX;
589 if(ValueCell->DataSize >0)
590 {
591 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
592 RtlCopyMemory(ValuePartialInformation->Data,
593 DataCell->Data,
594 ValueCell->DataSize & LONG_MAX);
595 CmiReleaseBlock(RegistryHive, DataCell);
596 }
597 else
598 {
599 RtlCopyMemory(ValuePartialInformation->Data,
600 &ValueCell->DataOffset,
601 ValueCell->DataSize & LONG_MAX);
602 }
603 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
604 }
605 break;
606
607 case KeyValueFullInformation:
608 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
609 {
610 *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) +
611 (ValueCell->NameSize + 1) * sizeof(WCHAR) +
612 (ValueCell->DataSize & LONG_MAX);
613 }
614 else
615 {
616 *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) +
617 ValueCell->NameSize + sizeof(WCHAR) +
618 (ValueCell->DataSize & LONG_MAX);
619 }
620 if (Length < *ResultLength)
621 {
622 Status = STATUS_BUFFER_OVERFLOW;
623 }
624 else
625 {
626 ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)
627 KeyValueInformation;
628 ValueFullInformation->TitleIndex = 0;
629 ValueFullInformation->Type = ValueCell->DataType;
630 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
631 {
632 ValueFullInformation->NameLength =
633 (ValueCell->NameSize + 1) * sizeof(WCHAR);
634
635 CmiCopyPackedName(ValueFullInformation->Name,
636 ValueCell->Name,
637 ValueCell->NameSize);
638 ValueFullInformation->Name[ValueCell->NameSize] = 0;
639 }
640 else
641 {
642 ValueFullInformation->NameLength =
643 ValueCell->NameSize + sizeof(WCHAR);
644 RtlCopyMemory(ValueFullInformation->Name,
645 ValueCell->Name,
646 ValueCell->NameSize);
647 ValueFullInformation->Name[ValueCell->NameSize / sizeof(WCHAR)] = 0;
648 }
649 ValueFullInformation->DataOffset =
650 (ULONG)ValueFullInformation->Name - (ULONG)ValueFullInformation +
651 ValueFullInformation->NameLength;
652 ValueFullInformation->DataOffset =
653 (ValueFullInformation->DataOffset + 3) & 0xfffffffc;
654 ValueFullInformation->DataLength = ValueCell->DataSize & LONG_MAX;
655 if (ValueCell->DataSize > 0)
656 {
657 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
658 RtlCopyMemory((PCHAR) ValueFullInformation
659 + ValueFullInformation->DataOffset,
660 DataCell->Data,
661 ValueCell->DataSize & LONG_MAX);
662 CmiReleaseBlock(RegistryHive, DataCell);
663 }
664 else
665 {
666 RtlCopyMemory((PCHAR) ValueFullInformation
667 + ValueFullInformation->DataOffset,
668 &ValueCell->DataOffset,
669 ValueCell->DataSize & LONG_MAX);
670 }
671 }
672 break;
673 }
674 }
675 else
676 {
677 Status = STATUS_UNSUCCESSFUL;
678 }
679
680 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
681 ObDereferenceObject(KeyObject);
682
683 return Status;
684 }
685
686
687 NTSTATUS STDCALL
688 NtFlushKey(IN HANDLE KeyHandle)
689 {
690 NTSTATUS Status;
691 PKEY_OBJECT KeyObject;
692 PREGISTRY_HIVE RegistryHive;
693 #if 0
694 WCHAR LogName[MAX_PATH];
695 UNICODE_STRING TmpFileName;
696 HANDLE FileHandle;
697 // HANDLE FileHandleLog;
698 OBJECT_ATTRIBUTES ObjectAttributes;
699 LARGE_INTEGER fileOffset;
700 DWORD * pEntDword;
701 ULONG i;
702 #endif
703
704 DPRINT("KeyHandle %x\n", KeyHandle);
705
706 /* Verify that the handle is valid and is a registry key */
707 Status = ObReferenceObjectByHandle(KeyHandle,
708 KEY_QUERY_VALUE,
709 CmiKeyType,
710 UserMode,
711 (PVOID *)&KeyObject,
712 NULL);
713 if (!NT_SUCCESS(Status))
714 {
715 return(Status);
716 }
717
718 VERIFY_KEY_OBJECT(KeyObject);
719
720 RegistryHive = KeyObject->RegistryHive;
721
722 /* Acquire hive lock */
723 ExAcquireResourceExclusiveLite(&RegistryHive->HiveResource,
724 TRUE);
725
726 if (IsPermanentHive(RegistryHive))
727 {
728 /* Flush non-volatile hive */
729 Status = CmiFlushRegistryHive(RegistryHive);
730 }
731 else
732 {
733 Status = STATUS_SUCCESS;
734 }
735
736
737 #if 0
738 /* Then write changed blocks in .log */
739 wcscpy(LogName,RegistryHive->Filename.Buffer);
740 wcscat(LogName,L".log");
741 RtlInitUnicodeString (&TmpFileName, LogName);
742 InitializeObjectAttributes(&ObjectAttributes,
743 &TmpFileName,
744 0,
745 NULL,
746 NULL);
747
748 /* BEGIN FIXME : actually (26 November 200) vfatfs.sys can't create new files
749 so we can't create log file
750 Status = ZwCreateFile(&FileHandleLog,
751 FILE_ALL_ACCESS,
752 &ObjectAttributes,
753 NULL,
754 0,
755 FILE_ATTRIBUTE_NORMAL,
756 0,
757 FILE_SUPERSEDE,
758 0,
759 NULL,
760 0);
761
762 if (!NT_SUCCESS(Status))
763 {
764 ObDereferenceObject(KeyObject);
765 return Status;
766 }
767
768 Status = ZwWriteFile(FileHandleLog,
769 0,
770 0,
771 0,
772 0,
773 RegistryHive->HiveHeader,
774 sizeof(HIVE_HEADER),
775 0,
776 0);
777
778 if (!NT_SUCCESS(Status))
779 {
780 ZwClose(FileHandleLog);
781 ObDereferenceObject(KeyObject);
782 return Status;
783 }
784
785 for (i = 0; i < RegistryHive->BlockListSize ; i++)
786 {
787 if ( RegistryHive->BlockList[i]->DateModified.dwHighDateTime
788 > RegistryHive->HiveHeader->DateModified.dwHighDateTime
789 || (RegistryHive->BlockList[i]->DateModified.dwHighDateTime
790 == RegistryHive->HiveHeader->DateModified.dwHighDateTime
791 && RegistryHive->BlockList[i]->DateModified.dwLowDateTime
792 > RegistryHive->HiveHeader->DateModified.dwLowDateTime
793 )
794 )
795
796 Status = ZwWriteFile(FileHandleLog,
797 0,
798 0,
799 0,
800 0,
801 RegistryHive->BlockList[i],
802 RegistryHive->BlockList[i]->BlockSize ,
803 0,
804 0);
805
806 if (!NT_SUCCESS(Status))
807 {
808 ZwClose(FileHandleLog);
809 ObDereferenceObject(KeyObject);
810 return Status;
811 }
812 }
813 ZwClose(FileHandleLog);
814 END FIXME*/
815
816 /* Update header of RegistryHive with Version >VersionOld */
817 /* this allow recover if system crash while updating hove file */
818 InitializeObjectAttributes(&ObjectAttributes,
819 &RegistryHive->Filename,
820 0,
821 NULL,
822 NULL);
823
824 Status = NtOpenFile(&FileHandle,
825 FILE_ALL_ACCESS,
826 &ObjectAttributes,
827 NULL,
828 0,
829 FILE_SYNCHRONOUS_IO_NONALERT);
830 if (!NT_SUCCESS(Status))
831 {
832 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
833 ObDereferenceObject(KeyObject);
834 return Status;
835 }
836
837 RegistryHive->HiveHeader->Version++;
838
839 Status = ZwWriteFile(FileHandle,
840 0,
841 0,
842 0,
843 0,
844 RegistryHive->HiveHeader,
845 sizeof(HIVE_HEADER),
846 0,
847 0);
848 if (!NT_SUCCESS(Status))
849 {
850 ZwClose(FileHandle);
851 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
852 ObDereferenceObject(KeyObject);
853 return Status;
854 }
855
856 /* Update changed blocks in file */
857 fileOffset.u.HighPart = 0;
858 for (i = 0; i < RegistryHive->BlockListSize ; i++)
859 {
860 if (RegistryHive->BlockList[i]->DateModified.dwHighDateTime
861 > RegistryHive->HiveHeader->DateModified.dwHighDateTime
862 || (RegistryHive->BlockList[i]->DateModified.dwHighDateTime
863 == RegistryHive->HiveHeader->DateModified.dwHighDateTime
864 && RegistryHive->BlockList[i]->DateModified.dwLowDateTime
865 > RegistryHive->HiveHeader->DateModified.dwLowDateTime))
866 {
867 fileOffset.u.LowPart = RegistryHive->BlockList[i]->BlockOffset+4096;
868 Status = NtWriteFile(FileHandle,
869 0,
870 0,
871 0,
872 0,
873 RegistryHive->BlockList[i],
874 RegistryHive->BlockList[i]->BlockSize,
875 &fileOffset,
876 0);
877 if (!NT_SUCCESS(Status))
878 {
879 ZwClose(FileHandle);
880 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
881 ObDereferenceObject(KeyObject);
882 return(Status);
883 }
884 }
885 }
886
887 /* Change version in header */
888 RegistryHive->HiveHeader->VersionOld = RegistryHive->HiveHeader->Version;
889 ZwQuerySystemTime((PTIME) &RegistryHive->HiveHeader->DateModified);
890
891 /* Calculate checksum */
892 RegistryHive->HiveHeader->Checksum = 0;
893 pEntDword = (DWORD *) RegistryHive->HiveHeader;
894 for (i = 0; i < 127 ; i++)
895 {
896 RegistryHive->HiveHeader->Checksum ^= pEntDword[i];
897 }
898
899 /* Write new header */
900 fileOffset.u.LowPart = 0;
901 Status = ZwWriteFile(FileHandle,
902 0,
903 0,
904 0,
905 0,
906 RegistryHive->HiveHeader,
907 sizeof(HIVE_HEADER),
908 &fileOffset,
909 0);
910
911 if (!NT_SUCCESS(Status))
912 {
913 ZwClose(FileHandle);
914 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
915 ObDereferenceObject(KeyObject);
916 return Status;
917 }
918
919 ZwClose(FileHandle);
920 #endif
921
922 ExReleaseResourceLite(&RegistryHive->HiveResource);
923
924 ObDereferenceObject(KeyObject);
925
926 return STATUS_SUCCESS;
927 }
928
929
930 NTSTATUS STDCALL
931 NtOpenKey(OUT PHANDLE KeyHandle,
932 IN ACCESS_MASK DesiredAccess,
933 IN POBJECT_ATTRIBUTES ObjectAttributes)
934 {
935 UNICODE_STRING RemainingPath;
936 NTSTATUS Status;
937 PVOID Object;
938
939 DPRINT("NtOpenFile(KH %x DA %x OA %x OA->ON '%wZ'\n",
940 KeyHandle,
941 DesiredAccess,
942 ObjectAttributes,
943 ObjectAttributes ? ObjectAttributes->ObjectName : NULL);
944
945 RemainingPath.Buffer = NULL;
946 Status = ObFindObject(ObjectAttributes,
947 &Object,
948 &RemainingPath,
949 CmiKeyType);
950 if (!NT_SUCCESS(Status))
951 {
952 return(Status);
953 }
954
955 VERIFY_KEY_OBJECT((PKEY_OBJECT) Object);
956
957 DPRINT("RemainingPath '%wZ'\n", &RemainingPath);
958
959 if ((RemainingPath.Buffer != NULL) && (RemainingPath.Buffer[0] != 0))
960 {
961 ObDereferenceObject(Object);
962 return(STATUS_UNSUCCESSFUL);
963 }
964
965 /* Fail if the key has been deleted */
966 if (((PKEY_OBJECT)Object)->Flags & KO_MARKED_FOR_DELETE)
967 {
968 ObDereferenceObject(Object);
969 return(STATUS_UNSUCCESSFUL);
970 }
971
972 Status = ObCreateHandle(PsGetCurrentProcess(),
973 Object,
974 DesiredAccess,
975 FALSE,
976 KeyHandle);
977 ObDereferenceObject(Object);
978
979 if (!NT_SUCCESS(Status))
980 {
981 return(Status);
982 }
983
984 return(STATUS_SUCCESS);
985 }
986
987
988 NTSTATUS STDCALL
989 NtQueryKey(IN HANDLE KeyHandle,
990 IN KEY_INFORMATION_CLASS KeyInformationClass,
991 OUT PVOID KeyInformation,
992 IN ULONG Length,
993 OUT PULONG ResultLength)
994 {
995 PKEY_BASIC_INFORMATION BasicInformation;
996 PKEY_NODE_INFORMATION NodeInformation;
997 PKEY_FULL_INFORMATION FullInformation;
998 PREGISTRY_HIVE RegistryHive;
999 PDATA_CELL pClassData;
1000 PKEY_OBJECT KeyObject;
1001 PKEY_CELL KeyCell;
1002 NTSTATUS Status;
1003
1004 DPRINT("KH %x KIC %x KI %x L %d RL %x\n",
1005 KeyHandle,
1006 KeyInformationClass,
1007 KeyInformation,
1008 Length,
1009 ResultLength);
1010
1011 /* Verify that the handle is valid and is a registry key */
1012 Status = ObReferenceObjectByHandle(KeyHandle,
1013 KEY_READ,
1014 CmiKeyType,
1015 UserMode,
1016 (PVOID *) &KeyObject,
1017 NULL);
1018 if (!NT_SUCCESS(Status))
1019 {
1020 CHECKPOINT1;
1021 return Status;
1022 }
1023 CHECKPOINT1;
1024
1025 /* Acquire hive lock */
1026 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1027 CHECKPOINT1;
1028
1029 VERIFY_KEY_OBJECT(KeyObject);
1030
1031 /* Get pointer to KeyCell */
1032 KeyCell = KeyObject->KeyCell;
1033 RegistryHive = KeyObject->RegistryHive;
1034
1035 Status = STATUS_SUCCESS;
1036 switch (KeyInformationClass)
1037 {
1038 case KeyBasicInformation:
1039 CHECKPOINT1;
1040 /* Check size of buffer */
1041 if (Length < sizeof(KEY_BASIC_INFORMATION) +
1042 KeyObject->NameSize * sizeof(WCHAR))
1043 {
1044 Status = STATUS_BUFFER_OVERFLOW;
1045 }
1046 else
1047 {
1048 /* Fill buffer with requested info */
1049 BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
1050 BasicInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.dwLowDateTime;
1051 BasicInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.dwHighDateTime;
1052 BasicInformation->TitleIndex = 0;
1053 BasicInformation->NameLength = (KeyObject->NameSize) * sizeof(WCHAR);
1054 mbstowcs(BasicInformation->Name,
1055 KeyObject->Name,
1056 KeyObject->NameSize*sizeof(WCHAR));
1057 *ResultLength = sizeof(KEY_BASIC_INFORMATION) +
1058 KeyObject->NameSize * sizeof(WCHAR);
1059 }
1060 CHECKPOINT1;
1061 break;
1062
1063 case KeyNodeInformation:
1064 /* Check size of buffer */
1065 if (Length < sizeof(KEY_NODE_INFORMATION)
1066 + KeyObject->NameSize * sizeof(WCHAR)
1067 + KeyCell->ClassSize)
1068 {
1069 Status = STATUS_BUFFER_OVERFLOW;
1070 }
1071 else
1072 {
1073 /* Fill buffer with requested info */
1074 NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
1075 NodeInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.dwLowDateTime;
1076 NodeInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.dwHighDateTime;
1077 NodeInformation->TitleIndex = 0;
1078 NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) +
1079 KeyObject->NameSize * sizeof(WCHAR);
1080 NodeInformation->ClassLength = KeyCell->ClassSize;
1081 NodeInformation->NameLength = KeyObject->NameSize * sizeof(WCHAR);
1082 mbstowcs(NodeInformation->Name,
1083 KeyObject->Name,
1084 KeyObject->NameSize * sizeof(WCHAR));
1085
1086 if (KeyCell->ClassSize != 0)
1087 {
1088 pClassData = CmiGetBlock(KeyObject->RegistryHive,
1089 KeyCell->ClassNameOffset,
1090 NULL);
1091 wcsncpy(NodeInformation->Name + KeyObject->NameSize * sizeof(WCHAR),
1092 (PWCHAR)pClassData->Data,
1093 KeyCell->ClassSize);
1094 CmiReleaseBlock(RegistryHive, pClassData);
1095 }
1096 *ResultLength = sizeof(KEY_NODE_INFORMATION)
1097 + KeyObject->NameSize * sizeof(WCHAR)
1098 + KeyCell->ClassSize;
1099 }
1100 break;
1101
1102 case KeyFullInformation:
1103 /* Check size of buffer */
1104 if (Length < sizeof(KEY_FULL_INFORMATION) + KeyCell->ClassSize)
1105 {
1106 Status = STATUS_BUFFER_OVERFLOW;
1107 }
1108 else
1109 {
1110 /* Fill buffer with requested info */
1111 FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
1112 FullInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.dwLowDateTime;
1113 FullInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.dwHighDateTime;
1114 FullInformation->TitleIndex = 0;
1115 FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) - sizeof(WCHAR);
1116 FullInformation->ClassLength = KeyCell->ClassSize;
1117 FullInformation->SubKeys = KeyCell->NumberOfSubKeys;
1118 FullInformation->MaxNameLen =
1119 CmiGetMaxNameLength(RegistryHive, KeyCell);
1120 FullInformation->MaxClassLen =
1121 CmiGetMaxClassLength(RegistryHive, KeyCell);
1122 FullInformation->Values = KeyCell->NumberOfValues;
1123 FullInformation->MaxValueNameLen =
1124 CmiGetMaxValueNameLength(RegistryHive, KeyCell);
1125 FullInformation->MaxValueDataLen =
1126 CmiGetMaxValueDataLength(RegistryHive, KeyCell);
1127 if (KeyCell->ClassSize != 0)
1128 {
1129 pClassData=CmiGetBlock(KeyObject->RegistryHive,
1130 KeyCell->ClassNameOffset,
1131 NULL);
1132 wcsncpy(FullInformation->Class,
1133 (PWCHAR)pClassData->Data,
1134 KeyCell->ClassSize);
1135 CmiReleaseBlock(RegistryHive, pClassData);
1136 }
1137 *ResultLength = sizeof(KEY_FULL_INFORMATION) + KeyCell->ClassSize;
1138 }
1139 break;
1140 }
1141
1142 CHECKPOINT1;
1143 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1144 CHECKPOINT1;
1145 ObDereferenceObject(KeyObject);
1146 CHECKPOINT1;
1147
1148 return(Status);
1149 }
1150
1151
1152 NTSTATUS STDCALL
1153 NtQueryValueKey(IN HANDLE KeyHandle,
1154 IN PUNICODE_STRING ValueName,
1155 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
1156 OUT PVOID KeyValueInformation,
1157 IN ULONG Length,
1158 OUT PULONG ResultLength)
1159 {
1160 NTSTATUS Status;
1161 PKEY_OBJECT KeyObject;
1162 PREGISTRY_HIVE RegistryHive;
1163 PKEY_CELL KeyCell;
1164 PVALUE_CELL ValueCell;
1165 PDATA_CELL DataCell;
1166 PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation;
1167 PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
1168 PKEY_VALUE_FULL_INFORMATION ValueFullInformation;
1169
1170 DPRINT("NtQueryValueKey(KeyHandle %x ValueName %S Length %x)\n",
1171 KeyHandle, ValueName->Buffer, Length);
1172
1173 /* Verify that the handle is valid and is a registry key */
1174 Status = ObReferenceObjectByHandle(KeyHandle,
1175 KEY_QUERY_VALUE,
1176 CmiKeyType,
1177 UserMode,
1178 (PVOID *)&KeyObject,
1179 NULL);
1180
1181 if (!NT_SUCCESS(Status))
1182 {
1183 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
1184 return Status;
1185 }
1186
1187 /* Acquire hive lock */
1188 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1189
1190 VERIFY_KEY_OBJECT(KeyObject);
1191
1192 /* Get pointer to KeyCell */
1193 KeyCell = KeyObject->KeyCell;
1194 RegistryHive = KeyObject->RegistryHive;
1195
1196 /* Get Value block of interest */
1197 Status = CmiScanKeyForValue(RegistryHive,
1198 KeyCell,
1199 ValueName,
1200 &ValueCell,
1201 NULL);
1202 if (!NT_SUCCESS(Status))
1203 {
1204 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status);
1205 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1206 ObDereferenceObject(KeyObject);
1207 return(Status);
1208 }
1209 else if (ValueCell != NULL)
1210 {
1211 switch (KeyValueInformationClass)
1212 {
1213 case KeyValueBasicInformation:
1214 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1215 {
1216 *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) +
1217 (ValueCell->NameSize + 1) * sizeof(WCHAR);
1218 }
1219 else
1220 {
1221 *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) +
1222 ValueCell->NameSize + sizeof(WCHAR);
1223 }
1224 if (Length < *ResultLength)
1225 {
1226 Status = STATUS_BUFFER_TOO_SMALL;
1227 }
1228 else
1229 {
1230 ValueBasicInformation = (PKEY_VALUE_BASIC_INFORMATION)
1231 KeyValueInformation;
1232 ValueBasicInformation->TitleIndex = 0;
1233 ValueBasicInformation->Type = ValueCell->DataType;
1234 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1235 {
1236 ValueBasicInformation->NameLength =
1237 (ValueCell->NameSize + 1) * sizeof(WCHAR);
1238 CmiCopyPackedName(ValueBasicInformation->Name,
1239 ValueCell->Name,
1240 ValueCell->NameSize);
1241 ValueBasicInformation->Name[ValueCell->NameSize] = 0;
1242 }
1243 else
1244 {
1245 ValueBasicInformation->NameLength =
1246 ValueCell->NameSize + sizeof(WCHAR);
1247 RtlCopyMemory(ValueBasicInformation->Name,
1248 ValueCell->Name,
1249 ValueCell->NameSize * sizeof(WCHAR));
1250 ValueBasicInformation->Name[ValueCell->NameSize / sizeof(WCHAR)] = 0;
1251 }
1252 }
1253 break;
1254
1255 case KeyValuePartialInformation:
1256 *ResultLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION)
1257 + (ValueCell->DataSize & LONG_MAX);
1258 if (Length < *ResultLength)
1259 {
1260 Status = STATUS_BUFFER_TOO_SMALL;
1261 }
1262 else
1263 {
1264 ValuePartialInformation = (PKEY_VALUE_PARTIAL_INFORMATION)
1265 KeyValueInformation;
1266 ValuePartialInformation->TitleIndex = 0;
1267 ValuePartialInformation->Type = ValueCell->DataType;
1268 ValuePartialInformation->DataLength = ValueCell->DataSize & LONG_MAX;
1269 if (ValueCell->DataSize > 0)
1270 {
1271 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
1272 RtlCopyMemory(ValuePartialInformation->Data,
1273 DataCell->Data,
1274 ValueCell->DataSize & LONG_MAX);
1275 CmiReleaseBlock(RegistryHive, DataCell);
1276 }
1277 else
1278 {
1279 RtlCopyMemory(ValuePartialInformation->Data,
1280 &ValueCell->DataOffset,
1281 ValueCell->DataSize & LONG_MAX);
1282 }
1283 }
1284 break;
1285
1286 case KeyValueFullInformation:
1287 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1288 {
1289 *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) +
1290 (ValueCell->NameSize + 1) * sizeof(WCHAR) +
1291 (ValueCell->DataSize & LONG_MAX);
1292 }
1293 else
1294 {
1295 *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) +
1296 ValueCell->NameSize + sizeof(WCHAR) +
1297 (ValueCell->DataSize & LONG_MAX);
1298 }
1299 if (Length < *ResultLength)
1300 {
1301 Status = STATUS_BUFFER_TOO_SMALL;
1302 }
1303 else
1304 {
1305 ValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)
1306 KeyValueInformation;
1307 ValueFullInformation->TitleIndex = 0;
1308 ValueFullInformation->Type = ValueCell->DataType;
1309 if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
1310 {
1311 ValueFullInformation->NameLength =
1312 (ValueCell->NameSize + 1) * sizeof(WCHAR);
1313 CmiCopyPackedName(ValueFullInformation->Name,
1314 ValueCell->Name,
1315 ValueCell->NameSize);
1316 ValueFullInformation->Name[ValueCell->NameSize] = 0;
1317 }
1318 else
1319 {
1320 ValueFullInformation->NameLength =
1321 ValueCell->NameSize + sizeof(WCHAR);
1322 RtlCopyMemory(ValueFullInformation->Name,
1323 ValueCell->Name,
1324 ValueCell->NameSize);
1325 ValueFullInformation->Name[ValueCell->NameSize / sizeof(WCHAR)] = 0;
1326 }
1327 ValueFullInformation->DataOffset =
1328 (ULONG)ValueFullInformation->Name - (ULONG)ValueFullInformation +
1329 ValueFullInformation->NameLength;
1330 ValueFullInformation->DataOffset =
1331 (ValueFullInformation->DataOffset + 3) & 0xfffffffc;
1332 ValueFullInformation->DataLength = ValueCell->DataSize & LONG_MAX;
1333 if (ValueCell->DataSize > 0)
1334 {
1335 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
1336 RtlCopyMemory((PCHAR) ValueFullInformation
1337 + ValueFullInformation->DataOffset,
1338 DataCell->Data,
1339 ValueCell->DataSize & LONG_MAX);
1340 CmiReleaseBlock(RegistryHive, DataCell);
1341 }
1342 else
1343 {
1344 RtlCopyMemory((PCHAR) ValueFullInformation
1345 + ValueFullInformation->DataOffset,
1346 &ValueCell->DataOffset,
1347 ValueCell->DataSize & LONG_MAX);
1348 }
1349 }
1350 break;
1351 }
1352 }
1353 else
1354 {
1355 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1356 }
1357
1358 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1359 ObDereferenceObject(KeyObject);
1360
1361 return Status;
1362 }
1363
1364
1365 NTSTATUS STDCALL
1366 NtSetValueKey(IN HANDLE KeyHandle,
1367 IN PUNICODE_STRING ValueName,
1368 IN ULONG TitleIndex,
1369 IN ULONG Type,
1370 IN PVOID Data,
1371 IN ULONG DataSize)
1372 {
1373 NTSTATUS Status;
1374 PKEY_OBJECT KeyObject;
1375 PREGISTRY_HIVE RegistryHive;
1376 PKEY_CELL KeyCell;
1377 PVALUE_CELL ValueCell;
1378 BLOCK_OFFSET VBOffset;
1379 PDATA_CELL DataCell;
1380 PDATA_CELL NewDataCell;
1381 PHBIN pBin;
1382 ULONG DesiredAccess;
1383
1384 DPRINT("NtSetValueKey(KeyHandle %x ValueName %S Type %d)\n",
1385 KeyHandle, ValueName? ValueName->Buffer : NULL, Type);
1386
1387 DesiredAccess = KEY_SET_VALUE;
1388 if (Type == REG_LINK)
1389 DesiredAccess |= KEY_CREATE_LINK;
1390
1391 /* Verify that the handle is valid and is a registry key */
1392 Status = ObReferenceObjectByHandle(KeyHandle,
1393 DesiredAccess,
1394 CmiKeyType,
1395 UserMode,
1396 (PVOID *)&KeyObject,
1397 NULL);
1398 if (!NT_SUCCESS(Status))
1399 return(Status);
1400
1401 /* Acquire hive lock exclucively */
1402 ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1403
1404 VERIFY_KEY_OBJECT(KeyObject);
1405
1406 /* Get pointer to key cell */
1407 KeyCell = KeyObject->KeyCell;
1408 RegistryHive = KeyObject->RegistryHive;
1409 Status = CmiScanKeyForValue(RegistryHive,
1410 KeyCell,
1411 ValueName,
1412 &ValueCell,
1413 &VBOffset);
1414 if (!NT_SUCCESS(Status))
1415 {
1416 DPRINT1("Value not found. Status 0x%X\n", Status);
1417
1418 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1419 ObDereferenceObject(KeyObject);
1420 return(Status);
1421 }
1422
1423 if (ValueCell == NULL)
1424 {
1425 DPRINT("Allocate new value cell\n");
1426 Status = CmiAddValueToKey(RegistryHive,
1427 KeyCell,
1428 ValueName,
1429 &ValueCell,
1430 &VBOffset);
1431 if (NT_SUCCESS(Status))
1432 {
1433 CmiMarkBlockDirty(RegistryHive, VBOffset);
1434 }
1435 }
1436
1437 if (!NT_SUCCESS(Status))
1438 {
1439 DPRINT1("Cannot add value. Status 0x%X\n", Status);
1440
1441 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1442 ObDereferenceObject(KeyObject);
1443 return(Status);
1444 }
1445
1446 DPRINT("DataSize %lu\n", DataSize);
1447 DPRINT("ValueCell %p\n", ValueCell);
1448 DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
1449
1450 if (DataSize <= 4)
1451 {
1452 /* If datasize <= 4 then write in valueblock directly */
1453 DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
1454 if ((ValueCell->DataSize >= 0) &&
1455 (DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL)))
1456 {
1457 CmiDestroyBlock(RegistryHive, DataCell, ValueCell->DataOffset);
1458 }
1459
1460 RtlCopyMemory(&ValueCell->DataOffset, Data, DataSize);
1461 ValueCell->DataSize = DataSize | 0x80000000;
1462 ValueCell->DataType = Type;
1463 RtlMoveMemory(&ValueCell->DataOffset, Data, DataSize);
1464 CmiMarkBlockDirty(RegistryHive, VBOffset);
1465 }
1466 else if (DataSize <= (ULONG) (ValueCell->DataSize & 0x7fffffff))
1467 {
1468 /* If new data size is <= current then overwrite current data */
1469 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset,&pBin);
1470 RtlZeroMemory(DataCell->Data, ValueCell->DataSize);
1471 RtlCopyMemory(DataCell->Data, Data, DataSize);
1472 ValueCell->DataSize = DataSize;
1473 ValueCell->DataType = Type;
1474 CmiReleaseBlock(RegistryHive, DataCell);
1475
1476 /* Update time of heap */
1477 if (IsPermanentHive(RegistryHive))
1478 {
1479 ZwQuerySystemTime((PTIME) &pBin->DateModified);
1480 }
1481 CmiMarkBlockDirty(RegistryHive, ValueCell->DataOffset);
1482 }
1483 else
1484 {
1485 /*
1486 * New data size is larger than the current, destroy current
1487 * data block and allocate a new one.
1488 */
1489 BLOCK_OFFSET NewOffset;
1490
1491 DPRINT("ValueCell->DataSize %lu\n", ValueCell->DataSize);
1492
1493 if ((ValueCell->DataSize >= 0) &&
1494 (DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL)))
1495 {
1496 CmiDestroyBlock(RegistryHive, DataCell, ValueCell->DataOffset);
1497 ValueCell->DataSize = 0;
1498 ValueCell->DataType = 0;
1499 ValueCell->DataOffset = 0xffffffff;
1500 }
1501
1502 Status = CmiAllocateBlock(RegistryHive,
1503 (PVOID *)&NewDataCell,
1504 DataSize,
1505 &NewOffset);
1506 if (!NT_SUCCESS(Status))
1507 {
1508 DPRINT("CmiAllocateBlock() failed (Status %lx)\n", Status);
1509
1510 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1511 ObDereferenceObject(KeyObject);
1512
1513 return(Status);
1514 }
1515
1516 RtlCopyMemory(&NewDataCell->Data[0], Data, DataSize);
1517 ValueCell->DataSize = DataSize;
1518 ValueCell->DataType = Type;
1519 CmiReleaseBlock(RegistryHive, NewDataCell);
1520 ValueCell->DataOffset = NewOffset;
1521 CmiMarkBlockDirty(RegistryHive, ValueCell->DataOffset);
1522 }
1523
1524 /* Mark link key */
1525 if ((_wcsicmp(ValueName->Buffer, L"SymbolicLinkValue") == 0) &&
1526 (Type == REG_LINK))
1527 {
1528 KeyCell->Type = REG_LINK_KEY_CELL_TYPE;
1529 CmiMarkBlockDirty(RegistryHive, KeyObject->BlockOffset);
1530 }
1531
1532 /* Update time of heap */
1533 if (IsPermanentHive(RegistryHive) && CmiGetBlock(RegistryHive, VBOffset, &pBin))
1534 {
1535 ZwQuerySystemTime((PTIME) &pBin->DateModified);
1536 }
1537
1538 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1539 ObDereferenceObject(KeyObject);
1540
1541 CmiSyncHives();
1542
1543 DPRINT("Return Status 0x%X\n", Status);
1544
1545 return(Status);
1546 }
1547
1548
1549 NTSTATUS STDCALL
1550 NtDeleteValueKey(IN HANDLE KeyHandle,
1551 IN PUNICODE_STRING ValueName)
1552 {
1553 PKEY_OBJECT KeyObject;
1554 NTSTATUS Status;
1555
1556 /* Verify that the handle is valid and is a registry key */
1557 Status = ObReferenceObjectByHandle(KeyHandle,
1558 KEY_QUERY_VALUE,
1559 CmiKeyType,
1560 UserMode,
1561 (PVOID *)&KeyObject,
1562 NULL);
1563 if (!NT_SUCCESS(Status))
1564 {
1565 return Status;
1566 }
1567
1568 /* Acquire hive lock */
1569 ExAcquireResourceExclusiveLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1570
1571 VERIFY_KEY_OBJECT(KeyObject);
1572
1573 Status = CmiDeleteValueFromKey(KeyObject->RegistryHive,
1574 KeyObject->KeyCell,
1575 KeyObject->BlockOffset,
1576 ValueName);
1577
1578 /* Release hive lock */
1579 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1580
1581 ObDereferenceObject(KeyObject);
1582
1583 CmiSyncHives();
1584
1585 return Status;
1586 }
1587
1588
1589 NTSTATUS STDCALL
1590 NtLoadKey(PHANDLE KeyHandle,
1591 POBJECT_ATTRIBUTES ObjectAttributes)
1592 {
1593 return NtLoadKey2(KeyHandle, ObjectAttributes, 0);
1594 }
1595
1596
1597 NTSTATUS STDCALL
1598 NtLoadKey2(IN PHANDLE KeyHandle,
1599 IN POBJECT_ATTRIBUTES ObjectAttributes,
1600 IN ULONG Flags)
1601 {
1602 UNIMPLEMENTED;
1603 }
1604
1605
1606 NTSTATUS STDCALL
1607 NtNotifyChangeKey(
1608 IN HANDLE KeyHandle,
1609 IN HANDLE Event,
1610 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1611 IN PVOID ApcContext OPTIONAL,
1612 OUT PIO_STATUS_BLOCK IoStatusBlock,
1613 IN ULONG CompletionFilter,
1614 IN BOOLEAN Asynchroneous,
1615 OUT PVOID ChangeBuffer,
1616 IN ULONG Length,
1617 IN BOOLEAN WatchSubtree)
1618 {
1619 UNIMPLEMENTED;
1620 }
1621
1622
1623 NTSTATUS STDCALL
1624 NtQueryMultipleValueKey(IN HANDLE KeyHandle,
1625 IN OUT PKEY_VALUE_ENTRY ValueList,
1626 IN ULONG NumberOfValues,
1627 OUT PVOID Buffer,
1628 IN OUT PULONG Length,
1629 OUT PULONG ReturnLength)
1630 {
1631 PREGISTRY_HIVE RegistryHive;
1632 PVALUE_CELL ValueCell;
1633 PKEY_OBJECT KeyObject;
1634 PDATA_CELL DataCell;
1635 ULONG BufferLength = 0;
1636 PKEY_CELL KeyCell;
1637 NTSTATUS Status;
1638 PUCHAR DataPtr;
1639 ULONG i;
1640
1641 /* Verify that the handle is valid and is a registry key */
1642 Status = ObReferenceObjectByHandle(KeyHandle,
1643 KEY_QUERY_VALUE,
1644 CmiKeyType,
1645 UserMode,
1646 (PVOID *) &KeyObject,
1647 NULL);
1648 if (!NT_SUCCESS(Status))
1649 {
1650 DPRINT("ObReferenceObjectByHandle() failed with status %x\n", Status);
1651 return(Status);
1652 }
1653
1654 /* Acquire hive lock */
1655 ExAcquireResourceSharedLite(&KeyObject->RegistryHive->HiveResource, TRUE);
1656
1657 VERIFY_KEY_OBJECT(KeyObject);
1658
1659 /* Get pointer to KeyCell */
1660 KeyCell = KeyObject->KeyCell;
1661 RegistryHive = KeyObject->RegistryHive;
1662
1663 DataPtr = (PUCHAR) Buffer;
1664
1665 for (i = 0; i < NumberOfValues; i++)
1666 {
1667 DPRINT("ValueName: '%wZ'\n", ValueList[i].ValueName);
1668
1669 /* Get Value block of interest */
1670 Status = CmiScanKeyForValue(RegistryHive,
1671 KeyCell,
1672 ValueList[i].ValueName,
1673 &ValueCell,
1674 NULL);
1675
1676 if (!NT_SUCCESS(Status))
1677 {
1678 DPRINT("CmiScanKeyForValue() failed with status %x\n", Status);
1679 break;
1680 }
1681 else if (ValueCell == NULL)
1682 {
1683 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1684 break;
1685 }
1686
1687 BufferLength = (BufferLength + 3) & 0xfffffffc;
1688
1689 if (BufferLength + (ValueCell->DataSize & LONG_MAX) <= *Length)
1690 {
1691 DataPtr = (PUCHAR)(((ULONG)DataPtr + 3) & 0xfffffffc);
1692
1693 ValueList[i].Type = ValueCell->DataType;
1694 ValueList[i].DataLength = ValueCell->DataSize & LONG_MAX;
1695 ValueList[i].DataOffset = (ULONG) DataPtr - (ULONG) Buffer;
1696
1697 if (ValueCell->DataSize > 0)
1698 {
1699 DataCell = CmiGetBlock(RegistryHive, ValueCell->DataOffset, NULL);
1700 RtlCopyMemory(DataPtr, DataCell->Data, ValueCell->DataSize & LONG_MAX);
1701 CmiReleaseBlock(RegistryHive, DataCell);
1702 }
1703 else
1704 {
1705 RtlCopyMemory(DataPtr,
1706 &ValueCell->DataOffset,
1707 ValueCell->DataSize & LONG_MAX);
1708 }
1709
1710 DataPtr += ValueCell->DataSize & LONG_MAX;
1711 }
1712 else
1713 {
1714 Status = STATUS_BUFFER_TOO_SMALL;
1715 }
1716
1717 BufferLength += ValueCell->DataSize & LONG_MAX;
1718 }
1719
1720 if (NT_SUCCESS(Status))
1721 *Length = BufferLength;
1722
1723 *ReturnLength = BufferLength;
1724
1725 /* Release hive lock */
1726 ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
1727
1728 ObDereferenceObject(KeyObject);
1729
1730 DPRINT("Return Status 0x%X\n", Status);
1731
1732 return(Status);
1733 }
1734
1735
1736 NTSTATUS STDCALL
1737 NtReplaceKey(
1738 IN POBJECT_ATTRIBUTES ObjectAttributes,
1739 IN HANDLE Key,
1740 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
1741 )
1742 {
1743 UNIMPLEMENTED;
1744 }
1745
1746
1747 NTSTATUS STDCALL
1748 NtRestoreKey(
1749 IN HANDLE KeyHandle,
1750 IN HANDLE FileHandle,
1751 IN ULONG RestoreFlags
1752 )
1753 {
1754 UNIMPLEMENTED;
1755 }
1756
1757
1758 NTSTATUS STDCALL
1759 NtSaveKey(
1760 IN HANDLE KeyHandle,
1761 IN HANDLE FileHandle)
1762 {
1763 UNIMPLEMENTED;
1764 }
1765
1766
1767 NTSTATUS STDCALL
1768 NtSetInformationKey(
1769 IN HANDLE KeyHandle,
1770 IN CINT KeyInformationClass,
1771 IN PVOID KeyInformation,
1772 IN ULONG KeyInformationLength)
1773 {
1774 UNIMPLEMENTED;
1775 }
1776
1777
1778 NTSTATUS STDCALL
1779 NtUnloadKey(IN HANDLE KeyHandle)
1780 {
1781 UNIMPLEMENTED;
1782 }
1783
1784
1785 NTSTATUS STDCALL
1786 NtInitializeRegistry(IN BOOLEAN SetUpBoot)
1787 {
1788 NTSTATUS Status = STATUS_ACCESS_DENIED;
1789
1790 if (CmiRegistryInitialized == FALSE)
1791 {
1792 /* FIXME: save boot log file */
1793
1794 Status = CmiInitHives(SetUpBoot);
1795
1796 CmiRegistryInitialized = TRUE;
1797 }
1798
1799 return(Status);
1800 }
1801
1802 /* EOF */