[NTOS:CM] Add extra validation for the information class parameter in NtEnumerateValu...
[reactos.git] / ntoskrnl / config / ntapi.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/ntapi.c
5 * PURPOSE: Configuration Manager - Internal Registry APIs
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Eric Kohl
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include "ntoskrnl.h"
13 #define NDEBUG
14 #include "debug.h"
15
16 BOOLEAN CmBootAcceptFirstTime = TRUE;
17 BOOLEAN CmFirstTime = TRUE;
18 extern ULONG InitSafeBootMode;
19
20
21 /* PRIVATE FUNCTIONS *********************************************************/
22
23 /*
24 * Adapted from ntoskrnl/include/internal/ob_x.h:ObpReleaseObjectCreateInformation()
25 */
26 VOID
27 ReleaseCapturedObjectAttributes(
28 _In_ POBJECT_ATTRIBUTES CapturedObjectAttributes,
29 _In_ KPROCESSOR_MODE AccessMode)
30 {
31 /* Check if we have a security descriptor */
32 if (CapturedObjectAttributes->SecurityDescriptor)
33 {
34 /* Release it */
35 SeReleaseSecurityDescriptor(CapturedObjectAttributes->SecurityDescriptor,
36 AccessMode,
37 TRUE);
38 CapturedObjectAttributes->SecurityDescriptor = NULL;
39 }
40
41 /* Check if we have an object name */
42 if (CapturedObjectAttributes->ObjectName)
43 {
44 /* Release it */
45 ReleaseCapturedUnicodeString(CapturedObjectAttributes->ObjectName, AccessMode);
46 }
47 }
48
49 /*
50 * Adapted from ntoskrnl/ob/oblife.c:ObpCaptureObjectCreateInformation()
51 */
52 NTSTATUS
53 ProbeAndCaptureObjectAttributes(
54 _Out_ POBJECT_ATTRIBUTES CapturedObjectAttributes,
55 _Out_ PUNICODE_STRING ObjectName,
56 _In_ KPROCESSOR_MODE AccessMode,
57 _In_ POBJECT_ATTRIBUTES ObjectAttributes,
58 _In_ BOOLEAN CaptureSecurity)
59 {
60 NTSTATUS Status = STATUS_SUCCESS;
61 PSECURITY_DESCRIPTOR SecurityDescriptor;
62 // PSECURITY_QUALITY_OF_SERVICE SecurityQos;
63 PUNICODE_STRING LocalObjectName = NULL;
64
65 /* Zero out the Capture Data */
66 RtlZeroMemory(CapturedObjectAttributes, sizeof(*CapturedObjectAttributes));
67
68 /* SEH everything here for protection */
69 _SEH2_TRY
70 {
71 /* Check if we got attributes */
72 if (ObjectAttributes)
73 {
74 /* Check if we're in user mode */
75 if (AccessMode != KernelMode)
76 {
77 /* Probe the attributes */
78 ProbeForRead(ObjectAttributes,
79 sizeof(OBJECT_ATTRIBUTES),
80 sizeof(ULONG));
81 }
82
83 /* Validate the Size and Attributes */
84 if ((ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) ||
85 (ObjectAttributes->Attributes & ~OBJ_VALID_KERNEL_ATTRIBUTES)) // Understood as all the possible valid attributes
86 {
87 /* Invalid combination, fail */
88 _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
89 }
90
91 /* Set some Create Info and do not allow user-mode kernel handles */
92 CapturedObjectAttributes->Length = sizeof(OBJECT_ATTRIBUTES);
93 CapturedObjectAttributes->RootDirectory = ObjectAttributes->RootDirectory;
94 CapturedObjectAttributes->Attributes = ObpValidateAttributes(ObjectAttributes->Attributes, AccessMode);
95 LocalObjectName = ObjectAttributes->ObjectName;
96 SecurityDescriptor = ObjectAttributes->SecurityDescriptor;
97 // SecurityQos = ObjectAttributes->SecurityQualityOfService;
98
99 /* Check if we have a security descriptor */
100 if (CaptureSecurity && SecurityDescriptor)
101 {
102 /*
103 * Capture it.
104 * Note: This has an implicit memory barrier due
105 * to the function call, so cleanup is safe here.
106 */
107 Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
108 AccessMode,
109 NonPagedPool,
110 TRUE,
111 &CapturedObjectAttributes->
112 SecurityDescriptor);
113 if (!NT_SUCCESS(Status))
114 {
115 /* Capture failed, quit */
116 CapturedObjectAttributes->SecurityDescriptor = NULL;
117 _SEH2_YIELD(return Status);
118 }
119 }
120 else
121 {
122 CapturedObjectAttributes->SecurityDescriptor = NULL;
123 }
124
125 #if 0
126 // We don't use the QoS!
127
128 /* Check if we have QoS */
129 if (SecurityQos)
130 {
131 /* Check if we came from user mode */
132 if (AccessMode != KernelMode)
133 {
134 /* Validate the QoS */
135 ProbeForRead(SecurityQos,
136 sizeof(SECURITY_QUALITY_OF_SERVICE),
137 sizeof(ULONG));
138 }
139
140 /* Save Info */
141 CapturedObjectAttributes->SecurityQualityOfService = *SecurityQos;
142 CapturedObjectAttributes->SecurityQos =
143 &CapturedObjectAttributes->SecurityQualityOfService;
144 }
145 #else
146 CapturedObjectAttributes->SecurityQualityOfService = NULL;
147 #endif
148 }
149 else
150 {
151 /* We don't have a name */
152 LocalObjectName = NULL;
153 }
154 }
155 _SEH2_EXCEPT(ExSystemExceptionFilter())
156 {
157 /* Cleanup and return the exception code */
158 ReleaseCapturedObjectAttributes(CapturedObjectAttributes, AccessMode);
159 _SEH2_YIELD(return _SEH2_GetExceptionCode());
160 }
161 _SEH2_END;
162
163 /* Now check if the Object Attributes had an Object Name */
164 if (LocalObjectName)
165 {
166 Status = ProbeAndCaptureUnicodeString(ObjectName, AccessMode, LocalObjectName);
167 }
168 else
169 {
170 /* Clear the string */
171 RtlInitEmptyUnicodeString(ObjectName, NULL, 0);
172
173 /* It cannot have specified a Root Directory */
174 if (CapturedObjectAttributes->RootDirectory)
175 {
176 Status = STATUS_OBJECT_NAME_INVALID;
177 }
178 }
179
180 /* Set the caputured object attributes name pointer to the one the user gave to us */
181 CapturedObjectAttributes->ObjectName = ObjectName;
182
183 /* Cleanup if we failed */
184 if (!NT_SUCCESS(Status))
185 {
186 ReleaseCapturedObjectAttributes(CapturedObjectAttributes, AccessMode);
187 }
188
189 /* Return status to caller */
190 return Status;
191 }
192
193 static
194 NTSTATUS
195 CmpConvertHandleToKernelHandle(
196 _In_ HANDLE SourceHandle,
197 _In_opt_ POBJECT_TYPE ObjectType,
198 _In_ ACCESS_MASK DesiredAccess,
199 _In_ KPROCESSOR_MODE AccessMode,
200 _Out_ PHANDLE KernelHandle)
201 {
202 NTSTATUS Status;
203 PVOID Object;
204
205 *KernelHandle = NULL;
206
207 /* NULL handle is valid */
208 if (SourceHandle == NULL)
209 return STATUS_SUCCESS;
210
211 /* Get the object pointer */
212 Status = ObReferenceObjectByHandle(SourceHandle,
213 DesiredAccess,
214 ObjectType,
215 AccessMode,
216 &Object,
217 NULL);
218 if (!NT_SUCCESS(Status))
219 return Status;
220
221 /* Create a kernel handle from the pointer */
222 Status = ObOpenObjectByPointer(Object,
223 OBJ_KERNEL_HANDLE,
224 NULL,
225 DesiredAccess,
226 ObjectType,
227 KernelMode,
228 KernelHandle);
229
230 /* Dereference the object */
231 ObDereferenceObject(Object);
232 return Status;
233 }
234
235
236 /* FUNCTIONS *****************************************************************/
237
238 NTSTATUS
239 NTAPI
240 NtCreateKey(OUT PHANDLE KeyHandle,
241 IN ACCESS_MASK DesiredAccess,
242 IN POBJECT_ATTRIBUTES ObjectAttributes,
243 IN ULONG TitleIndex,
244 IN PUNICODE_STRING Class OPTIONAL,
245 IN ULONG CreateOptions,
246 OUT PULONG Disposition OPTIONAL)
247 {
248 NTSTATUS Status;
249 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
250 CM_PARSE_CONTEXT ParseContext = {0};
251 HANDLE Handle;
252 PAGED_CODE();
253
254 DPRINT("NtCreateKey(Path: %wZ, Root %x, Access: %x, CreateOptions %x)\n",
255 ObjectAttributes->ObjectName, ObjectAttributes->RootDirectory,
256 DesiredAccess, CreateOptions);
257
258 /* Ignore the WOW64 flag, it's not valid in the kernel */
259 DesiredAccess &= ~KEY_WOW64_RES;
260
261 /* Check for user-mode caller */
262 if (PreviousMode != KernelMode)
263 {
264 /* Prepare to probe parameters */
265 _SEH2_TRY
266 {
267 /* Check if we have a class */
268 if (Class)
269 {
270 /* Probe it */
271 ParseContext.Class = ProbeForReadUnicodeString(Class);
272 ProbeForRead(ParseContext.Class.Buffer,
273 ParseContext.Class.Length,
274 sizeof(WCHAR));
275 }
276
277 /* Probe the key handle */
278 ProbeForWriteHandle(KeyHandle);
279 *KeyHandle = NULL;
280
281 /* Probe object attributes */
282 ProbeForRead(ObjectAttributes,
283 sizeof(OBJECT_ATTRIBUTES),
284 sizeof(ULONG));
285
286 if (Disposition)
287 ProbeForWriteUlong(Disposition);
288 }
289 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
290 {
291 /* Return the exception code */
292 _SEH2_YIELD(return _SEH2_GetExceptionCode());
293 }
294 _SEH2_END;
295 }
296 else
297 {
298 /* Save the class directly */
299 if (Class) ParseContext.Class = *Class;
300 }
301
302 /* Setup the parse context */
303 ParseContext.CreateOperation = TRUE;
304 ParseContext.CreateOptions = CreateOptions;
305
306 /* Do the create */
307 Status = ObOpenObjectByName(ObjectAttributes,
308 CmpKeyObjectType,
309 PreviousMode,
310 NULL,
311 DesiredAccess,
312 &ParseContext,
313 &Handle);
314
315 _SEH2_TRY
316 {
317 /* Return data to user */
318 if (NT_SUCCESS(Status)) *KeyHandle = Handle;
319 if (Disposition) *Disposition = ParseContext.Disposition;
320 }
321 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
322 {
323 /* Get the status */
324 Status = _SEH2_GetExceptionCode();
325 }
326 _SEH2_END;
327
328 DPRINT("Returning handle %x, Status %x.\n", Handle, Status);
329
330 /* Return status */
331 return Status;
332 }
333
334 NTSTATUS
335 NTAPI
336 NtOpenKey(OUT PHANDLE KeyHandle,
337 IN ACCESS_MASK DesiredAccess,
338 IN POBJECT_ATTRIBUTES ObjectAttributes)
339 {
340 CM_PARSE_CONTEXT ParseContext = {0};
341 HANDLE Handle;
342 NTSTATUS Status;
343 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
344 PAGED_CODE();
345 DPRINT("NtOpenKey(Path: %wZ, Root %x, Access: %x)\n",
346 ObjectAttributes->ObjectName, ObjectAttributes->RootDirectory, DesiredAccess);
347
348 /* Ignore the WOW64 flag, it's not valid in the kernel */
349 DesiredAccess &= ~KEY_WOW64_RES;
350
351 /* Check for user-mode caller */
352 if (PreviousMode != KernelMode)
353 {
354 /* Prepare to probe parameters */
355 _SEH2_TRY
356 {
357 /* Probe the key handle */
358 ProbeForWriteHandle(KeyHandle);
359 *KeyHandle = NULL;
360
361 /* Probe object attributes */
362 ProbeForRead(ObjectAttributes,
363 sizeof(OBJECT_ATTRIBUTES),
364 sizeof(ULONG));
365 }
366 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
367 {
368 /* Return the exception code */
369 _SEH2_YIELD(return _SEH2_GetExceptionCode());
370 }
371 _SEH2_END;
372 }
373
374 /* Just let the object manager handle this */
375 Status = ObOpenObjectByName(ObjectAttributes,
376 CmpKeyObjectType,
377 PreviousMode,
378 NULL,
379 DesiredAccess,
380 &ParseContext,
381 &Handle);
382
383 /* Only do this if we succeeded */
384 if (NT_SUCCESS(Status))
385 {
386 _SEH2_TRY
387 {
388 /* Return the handle to caller */
389 *KeyHandle = Handle;
390 }
391 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
392 {
393 /* Get the status */
394 Status = _SEH2_GetExceptionCode();
395 }
396 _SEH2_END;
397 }
398
399 DPRINT("Returning handle %x, Status %x.\n", Handle, Status);
400
401 /* Return status */
402 return Status;
403 }
404
405
406 NTSTATUS
407 NTAPI
408 NtDeleteKey(IN HANDLE KeyHandle)
409 {
410 PCM_KEY_BODY KeyObject;
411 NTSTATUS Status;
412 REG_DELETE_KEY_INFORMATION DeleteKeyInfo;
413 REG_POST_OPERATION_INFORMATION PostOperationInfo;
414 PAGED_CODE();
415 DPRINT("NtDeleteKey(KH 0x%p)\n", KeyHandle);
416
417 /* Verify that the handle is valid and is a registry key */
418 Status = ObReferenceObjectByHandle(KeyHandle,
419 DELETE,
420 CmpKeyObjectType,
421 ExGetPreviousMode(),
422 (PVOID*)&KeyObject,
423 NULL);
424 if (!NT_SUCCESS(Status)) return Status;
425
426 /* Setup the callback */
427 PostOperationInfo.Object = (PVOID)KeyObject;
428 DeleteKeyInfo.Object = (PVOID)KeyObject;
429 Status = CmiCallRegisteredCallbacks(RegNtPreDeleteKey, &DeleteKeyInfo);
430 if (NT_SUCCESS(Status))
431 {
432 /* Check if we are read-only */
433 if ((KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) ||
434 (KeyObject->KeyControlBlock->ParentKcb->ExtFlags & CM_KCB_READ_ONLY_KEY))
435 {
436 /* Fail */
437 Status = STATUS_ACCESS_DENIED;
438 }
439 else
440 {
441 /* Call the internal API */
442 Status = CmDeleteKey(KeyObject);
443 }
444
445 /* Do post callback */
446 PostOperationInfo.Status = Status;
447 CmiCallRegisteredCallbacks(RegNtPostDeleteKey, &PostOperationInfo);
448 }
449
450 /* Dereference and return status */
451 ObDereferenceObject(KeyObject);
452 return Status;
453 }
454
455 NTSTATUS
456 NTAPI
457 NtEnumerateKey(IN HANDLE KeyHandle,
458 IN ULONG Index,
459 IN KEY_INFORMATION_CLASS KeyInformationClass,
460 OUT PVOID KeyInformation,
461 IN ULONG Length,
462 OUT PULONG ResultLength)
463 {
464 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
465 NTSTATUS Status;
466 PCM_KEY_BODY KeyObject;
467 REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo;
468 REG_POST_OPERATION_INFORMATION PostOperationInfo;
469 PAGED_CODE();
470 DPRINT("NtEnumerateKey() KH 0x%p, Index 0x%x, KIC %d, Length %lu\n",
471 KeyHandle, Index, KeyInformationClass, Length);
472
473 /* Reject classes we don't know about */
474 if ((KeyInformationClass != KeyBasicInformation) &&
475 (KeyInformationClass != KeyNodeInformation) &&
476 (KeyInformationClass != KeyFullInformation))
477 {
478 /* Fail */
479 return STATUS_INVALID_PARAMETER;
480 }
481
482 /* Verify that the handle is valid and is a registry key */
483 Status = ObReferenceObjectByHandle(KeyHandle,
484 KEY_ENUMERATE_SUB_KEYS,
485 CmpKeyObjectType,
486 PreviousMode,
487 (PVOID*)&KeyObject,
488 NULL);
489 if (!NT_SUCCESS(Status)) return Status;
490
491 if (PreviousMode != KernelMode)
492 {
493 _SEH2_TRY
494 {
495 ProbeForWriteUlong(ResultLength);
496 ProbeForWrite(KeyInformation,
497 Length,
498 sizeof(ULONG));
499 }
500 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
501 {
502 /* Dereference and return status */
503 ObDereferenceObject(KeyObject);
504 _SEH2_YIELD(return _SEH2_GetExceptionCode());
505 }
506 _SEH2_END;
507 }
508
509 /* Setup the callback */
510 PostOperationInfo.Object = (PVOID)KeyObject;
511 EnumerateKeyInfo.Object = (PVOID)KeyObject;
512 EnumerateKeyInfo.Index = Index;
513 EnumerateKeyInfo.KeyInformationClass = KeyInformationClass;
514 EnumerateKeyInfo.Length = Length;
515 EnumerateKeyInfo.ResultLength = ResultLength;
516
517 /* Do the callback */
518 Status = CmiCallRegisteredCallbacks(RegNtPreEnumerateKey, &EnumerateKeyInfo);
519 if (NT_SUCCESS(Status))
520 {
521 /* Call the internal API */
522 Status = CmEnumerateKey(KeyObject->KeyControlBlock,
523 Index,
524 KeyInformationClass,
525 KeyInformation,
526 Length,
527 ResultLength);
528
529 /* Do the post callback */
530 PostOperationInfo.Status = Status;
531 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey, &PostOperationInfo);
532 }
533
534 /* Dereference and return status */
535 ObDereferenceObject(KeyObject);
536 DPRINT("Returning status %x.\n", Status);
537 return Status;
538 }
539
540 NTSTATUS
541 NTAPI
542 NtEnumerateValueKey(IN HANDLE KeyHandle,
543 IN ULONG Index,
544 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
545 OUT PVOID KeyValueInformation,
546 IN ULONG Length,
547 OUT PULONG ResultLength)
548 {
549 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
550 NTSTATUS Status;
551 PCM_KEY_BODY KeyObject;
552 REG_ENUMERATE_VALUE_KEY_INFORMATION EnumerateValueKeyInfo;
553 REG_POST_OPERATION_INFORMATION PostOperationInfo;
554
555 PAGED_CODE();
556
557 DPRINT("NtEnumerateValueKey() KH 0x%p, Index 0x%x, KVIC %d, Length %lu\n",
558 KeyHandle, Index, KeyValueInformationClass, Length);
559
560 /* Reject classes we don't know about */
561 if ((KeyValueInformationClass != KeyValueBasicInformation) &&
562 (KeyValueInformationClass != KeyValueFullInformation) &&
563 (KeyValueInformationClass != KeyValuePartialInformation) &&
564 (KeyValueInformationClass != KeyValueFullInformationAlign64) &&
565 (KeyValueInformationClass != KeyValuePartialInformationAlign64))
566 {
567 /* Fail */
568 return STATUS_INVALID_PARAMETER;
569 }
570
571 /* Verify that the handle is valid and is a registry key */
572 Status = ObReferenceObjectByHandle(KeyHandle,
573 KEY_QUERY_VALUE,
574 CmpKeyObjectType,
575 PreviousMode,
576 (PVOID*)&KeyObject,
577 NULL);
578 if (!NT_SUCCESS(Status)) return Status;
579
580 if (PreviousMode != KernelMode)
581 {
582 _SEH2_TRY
583 {
584 ProbeForWriteUlong(ResultLength);
585 ProbeForWrite(KeyValueInformation,
586 Length,
587 sizeof(ULONG));
588 }
589 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
590 {
591 /* Dereference and return status */
592 ObDereferenceObject(KeyObject);
593 _SEH2_YIELD(return _SEH2_GetExceptionCode());
594 }
595 _SEH2_END;
596 }
597
598 /* Setup the callback */
599 PostOperationInfo.Object = (PVOID)KeyObject;
600 EnumerateValueKeyInfo.Object = (PVOID)KeyObject;
601 EnumerateValueKeyInfo.Index = Index;
602 EnumerateValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass;
603 EnumerateValueKeyInfo.KeyValueInformation = KeyValueInformation;
604 EnumerateValueKeyInfo.Length = Length;
605 EnumerateValueKeyInfo.ResultLength = ResultLength;
606
607 /* Do the callback */
608 Status = CmiCallRegisteredCallbacks(RegNtPreEnumerateValueKey,
609 &EnumerateValueKeyInfo);
610 if (NT_SUCCESS(Status))
611 {
612 /* Call the internal API */
613 Status = CmEnumerateValueKey(KeyObject->KeyControlBlock,
614 Index,
615 KeyValueInformationClass,
616 KeyValueInformation,
617 Length,
618 ResultLength);
619
620 /* Do the post callback */
621 PostOperationInfo.Status = Status;
622 CmiCallRegisteredCallbacks(RegNtPostEnumerateValueKey, &PostOperationInfo);
623 }
624
625 /* Dereference and return status */
626 ObDereferenceObject(KeyObject);
627 return Status;
628 }
629
630 NTSTATUS
631 NTAPI
632 NtQueryKey(IN HANDLE KeyHandle,
633 IN KEY_INFORMATION_CLASS KeyInformationClass,
634 OUT PVOID KeyInformation,
635 IN ULONG Length,
636 OUT PULONG ResultLength)
637 {
638 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
639 NTSTATUS Status;
640 PCM_KEY_BODY KeyObject;
641 REG_QUERY_KEY_INFORMATION QueryKeyInfo;
642 REG_POST_OPERATION_INFORMATION PostOperationInfo;
643 OBJECT_HANDLE_INFORMATION HandleInfo;
644 PAGED_CODE();
645 DPRINT("NtQueryKey() KH 0x%p, KIC %d, Length %lu\n",
646 KeyHandle, KeyInformationClass, Length);
647
648 /* Reject invalid classes */
649 if ((KeyInformationClass != KeyBasicInformation) &&
650 (KeyInformationClass != KeyNodeInformation) &&
651 (KeyInformationClass != KeyFullInformation) &&
652 (KeyInformationClass != KeyNameInformation) &&
653 (KeyInformationClass != KeyCachedInformation) &&
654 (KeyInformationClass != KeyFlagsInformation))
655 {
656 /* Fail */
657 return STATUS_INVALID_PARAMETER;
658 }
659
660 /* Check if just the name is required */
661 if (KeyInformationClass == KeyNameInformation)
662 {
663 /* Ignore access level */
664 Status = ObReferenceObjectByHandle(KeyHandle,
665 0,
666 CmpKeyObjectType,
667 PreviousMode,
668 (PVOID*)&KeyObject,
669 &HandleInfo);
670 if (NT_SUCCESS(Status))
671 {
672 /* At least a single bit of access is required */
673 if (!HandleInfo.GrantedAccess)
674 {
675 /* No such luck */
676 ObDereferenceObject(KeyObject);
677 Status = STATUS_ACCESS_DENIED;
678 }
679 }
680 }
681 else
682 {
683 /* Get a reference */
684 Status = ObReferenceObjectByHandle(KeyHandle,
685 KEY_QUERY_VALUE,
686 CmpKeyObjectType,
687 PreviousMode,
688 (PVOID*)&KeyObject,
689 NULL);
690 }
691
692 /* Quit on failure */
693 if (!NT_SUCCESS(Status)) return Status;
694
695 if (PreviousMode != KernelMode)
696 {
697 _SEH2_TRY
698 {
699 ProbeForWriteUlong(ResultLength);
700 ProbeForWrite(KeyInformation,
701 Length,
702 sizeof(ULONG));
703 }
704 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
705 {
706 /* Dereference and return status */
707 ObDereferenceObject(KeyObject);
708 _SEH2_YIELD(return _SEH2_GetExceptionCode());
709 }
710 _SEH2_END;
711 }
712
713 /* Setup the callback */
714 PostOperationInfo.Object = (PVOID)KeyObject;
715 QueryKeyInfo.Object = (PVOID)KeyObject;
716 QueryKeyInfo.KeyInformationClass = KeyInformationClass;
717 QueryKeyInfo.KeyInformation = KeyInformation;
718 QueryKeyInfo.Length = Length;
719 QueryKeyInfo.ResultLength = ResultLength;
720
721 /* Do the callback */
722 Status = CmiCallRegisteredCallbacks(RegNtPreQueryKey, &QueryKeyInfo);
723 if (NT_SUCCESS(Status))
724 {
725 /* Call the internal API */
726 Status = CmQueryKey(KeyObject->KeyControlBlock,
727 KeyInformationClass,
728 KeyInformation,
729 Length,
730 ResultLength);
731
732 /* Do the post callback */
733 PostOperationInfo.Status = Status;
734 CmiCallRegisteredCallbacks(RegNtPostQueryKey, &PostOperationInfo);
735 }
736
737 /* Dereference and return status */
738 ObDereferenceObject(KeyObject);
739 return Status;
740 }
741
742 NTSTATUS
743 NTAPI
744 NtQueryValueKey(IN HANDLE KeyHandle,
745 IN PUNICODE_STRING ValueName,
746 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
747 OUT PVOID KeyValueInformation,
748 IN ULONG Length,
749 OUT PULONG ResultLength)
750 {
751 NTSTATUS Status;
752 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
753 PCM_KEY_BODY KeyObject;
754 REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo;
755 REG_POST_OPERATION_INFORMATION PostOperationInfo;
756 UNICODE_STRING ValueNameCopy;
757
758 PAGED_CODE();
759
760 DPRINT("NtQueryValueKey() KH 0x%p, VN '%wZ', KVIC %d, Length %lu\n",
761 KeyHandle, ValueName, KeyValueInformationClass, Length);
762
763 /* Reject classes we don't know about */
764 if ((KeyValueInformationClass != KeyValueBasicInformation) &&
765 (KeyValueInformationClass != KeyValueFullInformation) &&
766 (KeyValueInformationClass != KeyValuePartialInformation) &&
767 (KeyValueInformationClass != KeyValueFullInformationAlign64) &&
768 (KeyValueInformationClass != KeyValuePartialInformationAlign64))
769 {
770 /* Fail */
771 return STATUS_INVALID_PARAMETER;
772 }
773
774 /* Verify that the handle is valid and is a registry key */
775 Status = ObReferenceObjectByHandle(KeyHandle,
776 KEY_QUERY_VALUE,
777 CmpKeyObjectType,
778 PreviousMode,
779 (PVOID*)&KeyObject,
780 NULL);
781 if (!NT_SUCCESS(Status))
782 return Status;
783
784 if (PreviousMode != KernelMode)
785 {
786 _SEH2_TRY
787 {
788 ProbeForWriteUlong(ResultLength);
789 ProbeForWrite(KeyValueInformation,
790 Length,
791 sizeof(ULONG));
792 }
793 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
794 {
795 /* Dereference and return status */
796 ObDereferenceObject(KeyObject);
797 _SEH2_YIELD(return _SEH2_GetExceptionCode());
798 }
799 _SEH2_END;
800 }
801
802 /* Capture the string */
803 Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName);
804 if (!NT_SUCCESS(Status))
805 goto Quit;
806
807 /* Make sure the name is aligned properly */
808 if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1)))
809 {
810 /* It isn't, so we'll fail */
811 Status = STATUS_INVALID_PARAMETER;
812 goto Quit;
813 }
814
815 /* Ignore any null characters at the end */
816 while ((ValueNameCopy.Length) &&
817 !(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1]))
818 {
819 /* Skip it */
820 ValueNameCopy.Length -= sizeof(WCHAR);
821 }
822
823 /* Setup the callback */
824 PostOperationInfo.Object = (PVOID)KeyObject;
825 QueryValueKeyInfo.Object = (PVOID)KeyObject;
826 QueryValueKeyInfo.ValueName = &ValueNameCopy;
827 QueryValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass;
828 QueryValueKeyInfo.Length = Length;
829 QueryValueKeyInfo.ResultLength = ResultLength;
830
831 /* Do the callback */
832 Status = CmiCallRegisteredCallbacks(RegNtPreQueryValueKey, &QueryValueKeyInfo);
833 if (NT_SUCCESS(Status))
834 {
835 /* Call the internal API */
836 Status = CmQueryValueKey(KeyObject->KeyControlBlock,
837 ValueNameCopy,
838 KeyValueInformationClass,
839 KeyValueInformation,
840 Length,
841 ResultLength);
842
843 /* Do the post callback */
844 PostOperationInfo.Status = Status;
845 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey, &PostOperationInfo);
846 }
847
848 Quit:
849 if (ValueNameCopy.Buffer)
850 ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
851
852 /* Dereference and return status */
853 ObDereferenceObject(KeyObject);
854 return Status;
855 }
856
857 NTSTATUS
858 NTAPI
859 NtSetValueKey(IN HANDLE KeyHandle,
860 IN PUNICODE_STRING ValueName,
861 IN ULONG TitleIndex,
862 IN ULONG Type,
863 IN PVOID Data,
864 IN ULONG DataSize)
865 {
866 NTSTATUS Status = STATUS_SUCCESS;
867 KPROCESSOR_MODE PreviousMode;
868 PCM_KEY_BODY KeyObject;
869 REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo;
870 REG_POST_OPERATION_INFORMATION PostOperationInfo;
871 UNICODE_STRING ValueNameCopy;
872
873 PAGED_CODE();
874
875 PreviousMode = ExGetPreviousMode();
876
877 /* Verify that the handle is valid and is a registry key */
878 Status = ObReferenceObjectByHandle(KeyHandle,
879 KEY_SET_VALUE,
880 CmpKeyObjectType,
881 PreviousMode,
882 (PVOID*)&KeyObject,
883 NULL);
884 if (!NT_SUCCESS(Status))
885 return Status;
886
887 if (!DataSize)
888 Data = NULL;
889
890 /* Probe and copy the data */
891 if ((PreviousMode != KernelMode) && (DataSize != 0))
892 {
893 PVOID DataCopy = ExAllocatePoolWithTag(PagedPool, DataSize, TAG_CM);
894 if (!DataCopy)
895 {
896 /* Dereference and return status */
897 ObDereferenceObject(KeyObject);
898 return STATUS_INSUFFICIENT_RESOURCES;
899 }
900 _SEH2_TRY
901 {
902 ProbeForRead(Data, DataSize, 1);
903 RtlCopyMemory(DataCopy, Data, DataSize);
904 }
905 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
906 {
907 Status = _SEH2_GetExceptionCode();
908 }
909 _SEH2_END;
910
911 if (!NT_SUCCESS(Status))
912 {
913 /* Dereference and return status */
914 ExFreePoolWithTag(DataCopy, TAG_CM);
915 ObDereferenceObject(KeyObject);
916 return Status;
917 }
918 Data = DataCopy;
919 }
920
921 /* Capture the string */
922 Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName);
923 if (!NT_SUCCESS(Status))
924 goto Quit;
925
926 DPRINT("NtSetValueKey() KH 0x%p, VN '%wZ', TI %x, T %lu, DS %lu\n",
927 KeyHandle, &ValueNameCopy, TitleIndex, Type, DataSize);
928
929 /* Make sure the name is aligned, not too long, and the data under 4GB */
930 if ( (ValueNameCopy.Length > 32767) ||
931 ((ValueNameCopy.Length & (sizeof(WCHAR) - 1))) ||
932 (DataSize > 0x80000000))
933 {
934 /* Fail */
935 Status = STATUS_INVALID_PARAMETER;
936 goto Quit;
937 }
938
939 /* Ignore any null characters at the end */
940 while ((ValueNameCopy.Length) &&
941 !(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1]))
942 {
943 /* Skip it */
944 ValueNameCopy.Length -= sizeof(WCHAR);
945 }
946
947 /* Don't touch read-only keys */
948 if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
949 {
950 /* Fail */
951 Status = STATUS_ACCESS_DENIED;
952 goto Quit;
953 }
954
955 /* Setup callback */
956 PostOperationInfo.Object = (PVOID)KeyObject;
957 SetValueKeyInfo.Object = (PVOID)KeyObject;
958 SetValueKeyInfo.ValueName = &ValueNameCopy;
959 SetValueKeyInfo.TitleIndex = TitleIndex;
960 SetValueKeyInfo.Type = Type;
961 SetValueKeyInfo.Data = Data;
962 SetValueKeyInfo.DataSize = DataSize;
963
964 /* Do the callback */
965 Status = CmiCallRegisteredCallbacks(RegNtPreSetValueKey, &SetValueKeyInfo);
966 if (NT_SUCCESS(Status))
967 {
968 /* Call the internal API */
969 Status = CmSetValueKey(KeyObject->KeyControlBlock,
970 &ValueNameCopy,
971 Type,
972 Data,
973 DataSize);
974
975 /* Do the post-callback */
976 PostOperationInfo.Status = Status;
977 CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
978 }
979
980 Quit:
981 if (ValueNameCopy.Buffer)
982 ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
983
984 if ((PreviousMode != KernelMode) && Data)
985 ExFreePoolWithTag(Data, TAG_CM);
986
987 /* Dereference and return status */
988 ObDereferenceObject(KeyObject);
989 return Status;
990 }
991
992 NTSTATUS
993 NTAPI
994 NtDeleteValueKey(IN HANDLE KeyHandle,
995 IN PUNICODE_STRING ValueName)
996 {
997 NTSTATUS Status;
998 PCM_KEY_BODY KeyObject;
999 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo;
1000 REG_POST_OPERATION_INFORMATION PostOperationInfo;
1001 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1002 UNICODE_STRING ValueNameCopy;
1003
1004 PAGED_CODE();
1005
1006 /* Verify that the handle is valid and is a registry key */
1007 Status = ObReferenceObjectByHandle(KeyHandle,
1008 KEY_SET_VALUE,
1009 CmpKeyObjectType,
1010 PreviousMode,
1011 (PVOID*)&KeyObject,
1012 NULL);
1013 if (!NT_SUCCESS(Status))
1014 return Status;
1015
1016 /* Capture the string */
1017 Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName);
1018 if (!NT_SUCCESS(Status))
1019 goto Quit;
1020
1021 /* Make sure the name is aligned properly */
1022 if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1)))
1023 {
1024 /* It isn't, so we'll fail */
1025 Status = STATUS_INVALID_PARAMETER;
1026 goto Quit;
1027 }
1028
1029 /* Don't touch read-only keys */
1030 if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
1031 {
1032 /* Fail */
1033 Status = STATUS_ACCESS_DENIED;
1034 goto Quit;
1035 }
1036
1037 /* Do the callback */
1038 DeleteValueKeyInfo.Object = (PVOID)KeyObject;
1039 DeleteValueKeyInfo.ValueName = ValueName;
1040 Status = CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey,
1041 &DeleteValueKeyInfo);
1042 if (NT_SUCCESS(Status))
1043 {
1044 /* Call the internal API */
1045 Status = CmDeleteValueKey(KeyObject->KeyControlBlock, ValueNameCopy);
1046
1047 /* Do the post callback */
1048 PostOperationInfo.Object = (PVOID)KeyObject;
1049 PostOperationInfo.Status = Status;
1050 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey,
1051 &PostOperationInfo);
1052 }
1053
1054 Quit:
1055 if (ValueNameCopy.Buffer)
1056 ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
1057
1058 /* Dereference and return status */
1059 ObDereferenceObject(KeyObject);
1060 return Status;
1061 }
1062
1063 NTSTATUS
1064 NTAPI
1065 NtFlushKey(IN HANDLE KeyHandle)
1066 {
1067 NTSTATUS Status;
1068 PCM_KEY_BODY KeyObject;
1069 PAGED_CODE();
1070
1071 /* Get the key object */
1072 Status = ObReferenceObjectByHandle(KeyHandle,
1073 0,
1074 CmpKeyObjectType,
1075 ExGetPreviousMode(),
1076 (PVOID*)&KeyObject,
1077 NULL);
1078 if (!NT_SUCCESS(Status)) return Status;
1079
1080 /* Lock the registry */
1081 CmpLockRegistry();
1082
1083 /* Lock the KCB */
1084 CmpAcquireKcbLockShared(KeyObject->KeyControlBlock);
1085
1086 /* Make sure KCB isn't deleted */
1087 if (KeyObject->KeyControlBlock->Delete)
1088 {
1089 /* Fail */
1090 Status = STATUS_KEY_DELETED;
1091 }
1092 else
1093 {
1094 /* Call the internal API */
1095 Status = CmFlushKey(KeyObject->KeyControlBlock, FALSE);
1096 }
1097
1098 /* Release the locks */
1099 CmpReleaseKcbLock(KeyObject->KeyControlBlock);
1100 CmpUnlockRegistry();
1101
1102 /* Dereference the object and return status */
1103 ObDereferenceObject(KeyObject);
1104 return Status;
1105 }
1106
1107 NTSTATUS
1108 NTAPI
1109 NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
1110 IN POBJECT_ATTRIBUTES FileObjectAttributes)
1111 {
1112 /* Call the newer API */
1113 return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, 0, NULL);
1114 }
1115
1116 NTSTATUS
1117 NTAPI
1118 NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
1119 IN POBJECT_ATTRIBUTES FileObjectAttributes,
1120 IN ULONG Flags)
1121 {
1122 /* Call the newer API */
1123 return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, Flags, NULL);
1124 }
1125
1126 NTSTATUS
1127 NTAPI
1128 NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
1129 IN POBJECT_ATTRIBUTES SourceFile,
1130 IN ULONG Flags,
1131 IN HANDLE TrustClassKey)
1132 {
1133 NTSTATUS Status;
1134 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1135 OBJECT_ATTRIBUTES CapturedTargetKey;
1136 OBJECT_ATTRIBUTES CapturedSourceFile;
1137 UNICODE_STRING TargetKeyName, SourceFileName;
1138 HANDLE KmTargetKeyRootDir = NULL, KmSourceFileRootDir = NULL;
1139 PCM_KEY_BODY KeyBody = NULL;
1140
1141 PAGED_CODE();
1142
1143 /* Validate flags */
1144 if (Flags & ~REG_NO_LAZY_FLUSH)
1145 return STATUS_INVALID_PARAMETER;
1146
1147 /* Validate privilege */
1148 if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode))
1149 {
1150 DPRINT1("Restore Privilege missing!\n");
1151 return STATUS_PRIVILEGE_NOT_HELD;
1152 }
1153
1154 /* Block APCs */
1155 KeEnterCriticalRegion();
1156
1157 /* Check for user-mode caller */
1158 if (PreviousMode != KernelMode)
1159 {
1160 /* Prepare to probe parameters */
1161 _SEH2_TRY
1162 {
1163 /* Probe target key */
1164 ProbeForRead(TargetKey,
1165 sizeof(OBJECT_ATTRIBUTES),
1166 sizeof(ULONG));
1167
1168 /* Probe source file */
1169 ProbeForRead(SourceFile,
1170 sizeof(OBJECT_ATTRIBUTES),
1171 sizeof(ULONG));
1172 }
1173 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1174 {
1175 /* Return the exception code */
1176 Status = _SEH2_GetExceptionCode();
1177 _SEH2_YIELD(goto Quit);
1178 }
1179 _SEH2_END;
1180 }
1181
1182 /* Probe and capture the target key attributes, including the security */
1183 Status = ProbeAndCaptureObjectAttributes(&CapturedTargetKey,
1184 &TargetKeyName,
1185 PreviousMode,
1186 TargetKey,
1187 TRUE);
1188 if (!NT_SUCCESS(Status))
1189 goto Quit;
1190
1191 /*
1192 * Probe and capture the source file attributes, but not the security.
1193 * A proper security context is built by CmLoadKey().
1194 */
1195 Status = ProbeAndCaptureObjectAttributes(&CapturedSourceFile,
1196 &SourceFileName,
1197 PreviousMode,
1198 SourceFile,
1199 FALSE);
1200 if (!NT_SUCCESS(Status))
1201 {
1202 ReleaseCapturedObjectAttributes(&CapturedTargetKey, PreviousMode);
1203 goto Quit;
1204 }
1205
1206 /* Make sure the target key root directory handle is a kernel handle */
1207 Status = CmpConvertHandleToKernelHandle(CapturedTargetKey.RootDirectory,
1208 CmpKeyObjectType,
1209 KEY_READ,
1210 PreviousMode,
1211 &KmTargetKeyRootDir);
1212 if (!NT_SUCCESS(Status))
1213 goto Cleanup;
1214 CapturedTargetKey.RootDirectory = KmTargetKeyRootDir;
1215 CapturedTargetKey.Attributes |= OBJ_KERNEL_HANDLE;
1216
1217 /* Make sure the source file root directory handle is a kernel handle */
1218 Status = CmpConvertHandleToKernelHandle(CapturedSourceFile.RootDirectory,
1219 IoFileObjectType,
1220 FILE_TRAVERSE,
1221 PreviousMode,
1222 &KmSourceFileRootDir);
1223 if (!NT_SUCCESS(Status))
1224 goto Cleanup;
1225 CapturedSourceFile.RootDirectory = KmSourceFileRootDir;
1226 CapturedSourceFile.Attributes |= OBJ_KERNEL_HANDLE;
1227
1228 /* Check if we have a trust class */
1229 if (TrustClassKey)
1230 {
1231 /* Reference it */
1232 Status = ObReferenceObjectByHandle(TrustClassKey,
1233 0,
1234 CmpKeyObjectType,
1235 PreviousMode,
1236 (PVOID*)&KeyBody,
1237 NULL);
1238 }
1239
1240 /* Call the internal API */
1241 Status = CmLoadKey(&CapturedTargetKey,
1242 &CapturedSourceFile,
1243 Flags,
1244 KeyBody);
1245
1246 /* Dereference the trust key, if any */
1247 if (KeyBody) ObDereferenceObject(KeyBody);
1248
1249 Cleanup:
1250 /* Close the local kernel handles */
1251 if (KmSourceFileRootDir)
1252 ObCloseHandle(KmSourceFileRootDir, KernelMode);
1253 if (KmTargetKeyRootDir)
1254 ObCloseHandle(KmTargetKeyRootDir, KernelMode);
1255
1256 /* Release the captured object attributes */
1257 ReleaseCapturedObjectAttributes(&CapturedSourceFile, PreviousMode);
1258 ReleaseCapturedObjectAttributes(&CapturedTargetKey, PreviousMode);
1259
1260 Quit:
1261 /* Bring back APCs */
1262 KeLeaveCriticalRegion();
1263
1264 /* Return status */
1265 return Status;
1266 }
1267
1268 NTSTATUS
1269 NTAPI
1270 NtNotifyChangeKey(IN HANDLE KeyHandle,
1271 IN HANDLE Event,
1272 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1273 IN PVOID ApcContext OPTIONAL,
1274 OUT PIO_STATUS_BLOCK IoStatusBlock,
1275 IN ULONG CompletionFilter,
1276 IN BOOLEAN WatchTree,
1277 OUT PVOID Buffer,
1278 IN ULONG Length,
1279 IN BOOLEAN Asynchronous)
1280 {
1281 /* Call the newer API */
1282 return NtNotifyChangeMultipleKeys(KeyHandle,
1283 0,
1284 NULL,
1285 Event,
1286 ApcRoutine,
1287 ApcContext,
1288 IoStatusBlock,
1289 CompletionFilter,
1290 WatchTree,
1291 Buffer,
1292 Length,
1293 Asynchronous);
1294 }
1295
1296 NTSTATUS
1297 NTAPI
1298 NtInitializeRegistry(IN USHORT Flag)
1299 {
1300 BOOLEAN SetupBoot;
1301 NTSTATUS Status = STATUS_SUCCESS;
1302 PAGED_CODE();
1303
1304 /* Always do this as kernel mode */
1305 if (KeGetPreviousMode() == UserMode) return ZwInitializeRegistry(Flag);
1306
1307 /* Enough of the system has booted by now */
1308 Ki386PerfEnd();
1309
1310 /* Validate flag */
1311 if (Flag > CM_BOOT_FLAG_MAX) return STATUS_INVALID_PARAMETER;
1312
1313 /* Check if boot was accepted */
1314 if ((Flag >= CM_BOOT_FLAG_ACCEPTED) && (Flag <= CM_BOOT_FLAG_MAX))
1315 {
1316 /* Only allow once */
1317 if (!CmBootAcceptFirstTime) return STATUS_ACCESS_DENIED;
1318 CmBootAcceptFirstTime = FALSE;
1319
1320 /* Get the control set accepted */
1321 Flag -= CM_BOOT_FLAG_ACCEPTED;
1322 if (Flag)
1323 {
1324 /* FIXME: Save the last known good boot */
1325 //Status = CmpSaveBootControlSet(Flag);
1326
1327 /* Notify HAL */
1328 HalEndOfBoot();
1329
1330 /* Enable lazy flush */
1331 CmpHoldLazyFlush = FALSE;
1332 CmpLazyFlush();
1333 return Status;
1334 }
1335
1336 /* Otherwise, invalid boot */
1337 return STATUS_INVALID_PARAMETER;
1338 }
1339
1340 /* Check if this was a setup boot */
1341 SetupBoot = (Flag == CM_BOOT_FLAG_SETUP ? TRUE : FALSE);
1342
1343 /* Make sure we're only called once */
1344 if (!CmFirstTime) return STATUS_ACCESS_DENIED;
1345 CmFirstTime = FALSE;
1346
1347 /* Acquire registry lock */
1348 //CmpLockRegistryExclusive();
1349
1350 /* Initialize the hives and lazy flusher */
1351 CmpCmdInit(SetupBoot);
1352
1353 /* Save version data */
1354 CmpSetVersionData();
1355
1356 /* Release the registry lock */
1357 //CmpUnlockRegistry();
1358 return STATUS_SUCCESS;
1359 }
1360
1361 NTSTATUS
1362 NTAPI
1363 NtCompactKeys(IN ULONG Count,
1364 IN PHANDLE KeyArray)
1365 {
1366 UNIMPLEMENTED;
1367 return STATUS_NOT_IMPLEMENTED;
1368 }
1369
1370 NTSTATUS
1371 NTAPI
1372 NtCompressKey(IN HANDLE Key)
1373 {
1374 UNIMPLEMENTED;
1375 return STATUS_NOT_IMPLEMENTED;
1376 }
1377
1378 // FIXME: different for different windows versions!
1379 #define PRODUCT_ACTIVATION_VERSION 7749
1380
1381 NTSTATUS
1382 NTAPI
1383 NtLockProductActivationKeys(IN PULONG pPrivateVer,
1384 IN PULONG pSafeMode)
1385 {
1386 KPROCESSOR_MODE PreviousMode;
1387
1388 PreviousMode = ExGetPreviousMode();
1389 _SEH2_TRY
1390 {
1391 /* Check if the caller asked for the version */
1392 if (pPrivateVer != NULL)
1393 {
1394 /* For user mode, probe it */
1395 if (PreviousMode != KernelMode)
1396 {
1397 ProbeForRead(pPrivateVer, sizeof(ULONG), sizeof(ULONG));
1398 }
1399
1400 /* Return the expected version */
1401 *pPrivateVer = PRODUCT_ACTIVATION_VERSION;
1402 }
1403
1404 /* Check if the caller asked for safe mode mode state */
1405 if (pSafeMode != NULL)
1406 {
1407 /* For user mode, probe it */
1408 if (PreviousMode != KernelMode)
1409 {
1410 ProbeForRead(pSafeMode, sizeof(ULONG), sizeof(ULONG));
1411 }
1412
1413 /* Return the safe boot mode state */
1414 *pSafeMode = InitSafeBootMode;
1415 }
1416 }
1417 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1418 {
1419 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1420 }
1421 _SEH2_END;
1422
1423 return STATUS_SUCCESS;
1424 }
1425
1426 NTSTATUS
1427 NTAPI
1428 NtLockRegistryKey(IN HANDLE KeyHandle)
1429 {
1430 UNIMPLEMENTED;
1431 return STATUS_NOT_IMPLEMENTED;
1432 }
1433
1434 NTSTATUS
1435 NTAPI
1436 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle,
1437 IN ULONG Count,
1438 IN POBJECT_ATTRIBUTES SlaveObjects,
1439 IN HANDLE Event,
1440 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1441 IN PVOID ApcContext OPTIONAL,
1442 OUT PIO_STATUS_BLOCK IoStatusBlock,
1443 IN ULONG CompletionFilter,
1444 IN BOOLEAN WatchTree,
1445 OUT PVOID Buffer,
1446 IN ULONG Length,
1447 IN BOOLEAN Asynchronous)
1448 {
1449 UNIMPLEMENTED_ONCE;
1450 return STATUS_NOT_IMPLEMENTED;
1451 }
1452
1453 NTSTATUS
1454 NTAPI
1455 NtQueryMultipleValueKey(IN HANDLE KeyHandle,
1456 IN OUT PKEY_VALUE_ENTRY ValueList,
1457 IN ULONG NumberOfValues,
1458 OUT PVOID Buffer,
1459 IN OUT PULONG Length,
1460 OUT PULONG ReturnLength)
1461 {
1462 UNIMPLEMENTED;
1463 return STATUS_NOT_IMPLEMENTED;
1464 }
1465
1466 NTSTATUS
1467 NTAPI
1468 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey,
1469 OUT PULONG HandleCount)
1470 {
1471 KPROCESSOR_MODE PreviousMode;
1472 PCM_KEY_BODY KeyBody = NULL;
1473 HANDLE KeyHandle;
1474 NTSTATUS Status;
1475
1476 DPRINT("NtQueryOpenSubKeys()\n");
1477
1478 PAGED_CODE();
1479
1480 /* Get the processor mode */
1481 PreviousMode = KeGetPreviousMode();
1482
1483 /* Check for user-mode caller */
1484 if (PreviousMode != KernelMode)
1485 {
1486 /* Prepare to probe parameters */
1487 _SEH2_TRY
1488 {
1489 /* Probe target key */
1490 ProbeForRead(TargetKey,
1491 sizeof(OBJECT_ATTRIBUTES),
1492 sizeof(ULONG));
1493
1494 /* Probe handle count */
1495 ProbeForWriteUlong(HandleCount);
1496 }
1497 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1498 {
1499 /* Return the exception code */
1500 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1501 }
1502 _SEH2_END;
1503 }
1504
1505 /* Open a handle to the key */
1506 Status = ObOpenObjectByName(TargetKey,
1507 CmpKeyObjectType,
1508 PreviousMode,
1509 NULL,
1510 KEY_READ,
1511 NULL,
1512 &KeyHandle);
1513 if (NT_SUCCESS(Status))
1514 {
1515 /* Reference the key object */
1516 Status = ObReferenceObjectByHandle(KeyHandle,
1517 KEY_READ,
1518 CmpKeyObjectType,
1519 PreviousMode,
1520 (PVOID*)&KeyBody,
1521 NULL);
1522
1523 /* Close the handle */
1524 NtClose(KeyHandle);
1525 }
1526
1527 /* Fail, if the key object could not be referenced */
1528 if (!NT_SUCCESS(Status))
1529 return Status;
1530
1531 /* Lock the registry exclusively */
1532 CmpLockRegistryExclusive();
1533
1534 /* Fail, if we did not open a hive root key */
1535 if (KeyBody->KeyControlBlock->KeyCell !=
1536 KeyBody->KeyControlBlock->KeyHive->BaseBlock->RootCell)
1537 {
1538 DPRINT("Error: Key is not a hive root key!\n");
1539 CmpUnlockRegistry();
1540 ObDereferenceObject(KeyBody);
1541 return STATUS_INVALID_PARAMETER;
1542 }
1543
1544 /* Call the internal API */
1545 *HandleCount = CmCountOpenSubKeys(KeyBody->KeyControlBlock,
1546 FALSE);
1547
1548 /* Unlock the registry */
1549 CmpUnlockRegistry();
1550
1551 /* Dereference the key object */
1552 ObDereferenceObject(KeyBody);
1553
1554 DPRINT("Done.\n");
1555
1556 return Status;
1557 }
1558
1559 NTSTATUS
1560 NTAPI
1561 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey,
1562 IN ULONG BufferLength,
1563 IN PVOID Buffer,
1564 IN PULONG RequiredSize)
1565 {
1566 UNIMPLEMENTED;
1567 return STATUS_NOT_IMPLEMENTED;
1568 }
1569
1570 NTSTATUS
1571 NTAPI
1572 NtRenameKey(IN HANDLE KeyHandle,
1573 IN PUNICODE_STRING ReplacementName)
1574 {
1575 UNIMPLEMENTED;
1576 return STATUS_NOT_IMPLEMENTED;
1577 }
1578
1579 NTSTATUS
1580 NTAPI
1581 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes,
1582 IN HANDLE Key,
1583 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
1584 {
1585 UNIMPLEMENTED;
1586 return STATUS_NOT_IMPLEMENTED;
1587 }
1588
1589 NTSTATUS
1590 NTAPI
1591 NtRestoreKey(IN HANDLE KeyHandle,
1592 IN HANDLE FileHandle,
1593 IN ULONG RestoreFlags)
1594 {
1595 UNIMPLEMENTED;
1596 return STATUS_NOT_IMPLEMENTED;
1597 }
1598
1599 NTSTATUS
1600 NTAPI
1601 NtSaveKey(IN HANDLE KeyHandle,
1602 IN HANDLE FileHandle)
1603 {
1604 /* Call the extended API */
1605 return NtSaveKeyEx(KeyHandle, FileHandle, REG_STANDARD_FORMAT);
1606 }
1607
1608 NTSTATUS
1609 NTAPI
1610 NtSaveKeyEx(IN HANDLE KeyHandle,
1611 IN HANDLE FileHandle,
1612 IN ULONG Flags)
1613 {
1614 NTSTATUS Status;
1615 HANDLE KmFileHandle = NULL;
1616 PCM_KEY_BODY KeyObject;
1617 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1618
1619 PAGED_CODE();
1620
1621 DPRINT("NtSaveKeyEx(0x%p, 0x%p, %lu)\n", KeyHandle, FileHandle, Flags);
1622
1623 /* Verify the flags */
1624 if ((Flags != REG_STANDARD_FORMAT)
1625 && (Flags != REG_LATEST_FORMAT)
1626 && (Flags != REG_NO_COMPRESSION))
1627 {
1628 /* Only one of these values can be specified */
1629 return STATUS_INVALID_PARAMETER;
1630 }
1631
1632 /* Validate privilege */
1633 if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode))
1634 {
1635 return STATUS_PRIVILEGE_NOT_HELD;
1636 }
1637
1638 /* Make sure the target file handle is a kernel handle */
1639 Status = CmpConvertHandleToKernelHandle(FileHandle,
1640 IoFileObjectType,
1641 FILE_WRITE_DATA,
1642 PreviousMode,
1643 &KmFileHandle);
1644 if (!NT_SUCCESS(Status))
1645 goto Quit;
1646
1647 /* Verify that the handle is valid and is a registry key */
1648 Status = ObReferenceObjectByHandle(KeyHandle,
1649 KEY_READ,
1650 CmpKeyObjectType,
1651 PreviousMode,
1652 (PVOID*)&KeyObject,
1653 NULL);
1654 if (!NT_SUCCESS(Status))
1655 goto Quit;
1656
1657 /* Call the internal API */
1658 Status = CmSaveKey(KeyObject->KeyControlBlock, KmFileHandle, Flags);
1659
1660 /* Dereference the registry key */
1661 ObDereferenceObject(KeyObject);
1662
1663 Quit:
1664 /* Close the local kernel handle */
1665 if (KmFileHandle)
1666 ObCloseHandle(KmFileHandle, KernelMode);
1667
1668 return Status;
1669 }
1670
1671 NTSTATUS
1672 NTAPI
1673 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle,
1674 IN HANDLE LowPrecedenceKeyHandle,
1675 IN HANDLE FileHandle)
1676 {
1677 NTSTATUS Status;
1678 KPROCESSOR_MODE PreviousMode;
1679 HANDLE KmFileHandle = NULL;
1680 PCM_KEY_BODY HighPrecedenceKeyObject = NULL;
1681 PCM_KEY_BODY LowPrecedenceKeyObject = NULL;
1682
1683 PAGED_CODE();
1684
1685 DPRINT("NtSaveMergedKeys(0x%p, 0x%p, 0x%p)\n",
1686 HighPrecedenceKeyHandle, LowPrecedenceKeyHandle, FileHandle);
1687
1688 PreviousMode = ExGetPreviousMode();
1689
1690 /* Validate privilege */
1691 if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode))
1692 {
1693 return STATUS_PRIVILEGE_NOT_HELD;
1694 }
1695
1696 /* Make sure the target file handle is a kernel handle */
1697 Status = CmpConvertHandleToKernelHandle(FileHandle,
1698 IoFileObjectType,
1699 FILE_WRITE_DATA,
1700 PreviousMode,
1701 &KmFileHandle);
1702 if (!NT_SUCCESS(Status))
1703 goto Quit;
1704
1705 /* Verify that the handles are valid and are registry keys */
1706 Status = ObReferenceObjectByHandle(HighPrecedenceKeyHandle,
1707 KEY_READ,
1708 CmpKeyObjectType,
1709 PreviousMode,
1710 (PVOID*)&HighPrecedenceKeyObject,
1711 NULL);
1712 if (!NT_SUCCESS(Status))
1713 goto Quit;
1714
1715 Status = ObReferenceObjectByHandle(LowPrecedenceKeyHandle,
1716 KEY_READ,
1717 CmpKeyObjectType,
1718 PreviousMode,
1719 (PVOID*)&LowPrecedenceKeyObject,
1720 NULL);
1721 if (!NT_SUCCESS(Status))
1722 goto Quit;
1723
1724 /* Call the internal API */
1725 Status = CmSaveMergedKeys(HighPrecedenceKeyObject->KeyControlBlock,
1726 LowPrecedenceKeyObject->KeyControlBlock,
1727 KmFileHandle);
1728
1729 Quit:
1730 /* Dereference the opened key objects */
1731 if (LowPrecedenceKeyObject)
1732 ObDereferenceObject(LowPrecedenceKeyObject);
1733 if (HighPrecedenceKeyObject)
1734 ObDereferenceObject(HighPrecedenceKeyObject);
1735
1736 /* Close the local kernel handle */
1737 if (KmFileHandle)
1738 ObCloseHandle(KmFileHandle, KernelMode);
1739
1740 return Status;
1741 }
1742
1743 NTSTATUS
1744 NTAPI
1745 NtSetInformationKey(IN HANDLE KeyHandle,
1746 IN KEY_SET_INFORMATION_CLASS KeyInformationClass,
1747 IN PVOID KeyInformation,
1748 IN ULONG KeyInformationLength)
1749 {
1750 UNIMPLEMENTED;
1751 return STATUS_NOT_IMPLEMENTED;
1752 }
1753
1754 NTSTATUS
1755 NTAPI
1756 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes)
1757 {
1758 return NtUnloadKey2(KeyObjectAttributes, 0);
1759 }
1760
1761 NTSTATUS
1762 NTAPI
1763 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
1764 IN ULONG Flags)
1765 {
1766 NTSTATUS Status;
1767 OBJECT_ATTRIBUTES CapturedTargetKey;
1768 UNICODE_STRING ObjectName;
1769 HANDLE KmTargetKeyRootDir = NULL;
1770 CM_PARSE_CONTEXT ParseContext = {0};
1771 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1772 PCM_KEY_BODY KeyBody = NULL;
1773 ULONG ParentConv = 0, ChildConv = 0;
1774 HANDLE Handle;
1775
1776 PAGED_CODE();
1777
1778 /* Validate privilege */
1779 if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode))
1780 {
1781 DPRINT1("Restore Privilege missing!\n");
1782 return STATUS_PRIVILEGE_NOT_HELD;
1783 }
1784
1785 /* Check for user-mode caller */
1786 if (PreviousMode != KernelMode)
1787 {
1788 /* Prepare to probe parameters */
1789 _SEH2_TRY
1790 {
1791 /* Probe object attributes */
1792 ProbeForRead(TargetKey,
1793 sizeof(OBJECT_ATTRIBUTES),
1794 sizeof(ULONG));
1795
1796 CapturedTargetKey = *TargetKey;
1797
1798 /* Probe the string */
1799 ObjectName = ProbeForReadUnicodeString(CapturedTargetKey.ObjectName);
1800 ProbeForRead(ObjectName.Buffer,
1801 ObjectName.Length,
1802 sizeof(WCHAR));
1803
1804 CapturedTargetKey.ObjectName = &ObjectName;
1805 }
1806 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1807 {
1808 /* Return the exception code */
1809 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1810 }
1811 _SEH2_END;
1812 }
1813 else
1814 {
1815 /* Save the target attributes directly */
1816 CapturedTargetKey = *TargetKey;
1817 }
1818
1819 /* Make sure the target key root directory handle is a kernel handle */
1820 Status = CmpConvertHandleToKernelHandle(CapturedTargetKey.RootDirectory,
1821 CmpKeyObjectType,
1822 KEY_WRITE,
1823 PreviousMode,
1824 &KmTargetKeyRootDir);
1825 if (!NT_SUCCESS(Status))
1826 return Status;
1827 CapturedTargetKey.RootDirectory = KmTargetKeyRootDir;
1828 CapturedTargetKey.Attributes |= OBJ_KERNEL_HANDLE;
1829
1830 /* Setup the parse context */
1831 ParseContext.CreateOperation = TRUE;
1832 ParseContext.CreateOptions = REG_OPTION_BACKUP_RESTORE;
1833
1834 /* Do the create */
1835 /* Open a local handle to the key */
1836 Status = ObOpenObjectByName(&CapturedTargetKey,
1837 CmpKeyObjectType,
1838 KernelMode,
1839 NULL,
1840 KEY_WRITE,
1841 &ParseContext,
1842 &Handle);
1843 if (NT_SUCCESS(Status))
1844 {
1845 /* Reference the key object */
1846 Status = ObReferenceObjectByHandle(Handle,
1847 KEY_WRITE,
1848 CmpKeyObjectType,
1849 KernelMode,
1850 (PVOID*)&KeyBody,
1851 NULL);
1852
1853 /* Close the handle */
1854 ObCloseHandle(Handle, KernelMode);
1855 }
1856
1857 /* Close the local kernel handle */
1858 if (KmTargetKeyRootDir)
1859 ObCloseHandle(KmTargetKeyRootDir, KernelMode);
1860
1861 /* Return if a failure was encountered */
1862 if (!NT_SUCCESS(Status))
1863 return Status;
1864
1865 /* Acquire the lock depending on flags */
1866 if (Flags == REG_FORCE_UNLOAD)
1867 {
1868 /* Lock registry exclusively */
1869 CmpLockRegistryExclusive();
1870 }
1871 else
1872 {
1873 /* Lock registry */
1874 CmpLockRegistry();
1875
1876 /* Acquire the hive loading lock */
1877 ExAcquirePushLockExclusive(&CmpLoadHiveLock);
1878
1879 /* Lock parent and child */
1880 if (KeyBody->KeyControlBlock->ParentKcb)
1881 ParentConv = KeyBody->KeyControlBlock->ParentKcb->ConvKey;
1882 else
1883 ParentConv = KeyBody->KeyControlBlock->ConvKey;
1884
1885 ChildConv = KeyBody->KeyControlBlock->ConvKey;
1886
1887 CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv, ParentConv);
1888 }
1889
1890 /* Check if it's being deleted already */
1891 if (KeyBody->KeyControlBlock->Delete)
1892 {
1893 /* Return appropriate status */
1894 Status = STATUS_KEY_DELETED;
1895 goto Quit;
1896 }
1897
1898 /* Check if it's a read-only key */
1899 if (KeyBody->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
1900 {
1901 /* Return appropriate status */
1902 Status = STATUS_ACCESS_DENIED;
1903 goto Quit;
1904 }
1905
1906 /* Call the internal API. Note that CmUnloadKey() unlocks the registry only on success. */
1907 Status = CmUnloadKey(KeyBody->KeyControlBlock, Flags);
1908
1909 /* Check if we failed, but really need to succeed */
1910 if ((Status == STATUS_CANNOT_DELETE) && (Flags == REG_FORCE_UNLOAD))
1911 {
1912 /* TODO: We should perform another attempt here */
1913 _SEH2_TRY
1914 {
1915 DPRINT1("NtUnloadKey2(%wZ): We want to force-unload the hive but couldn't unload it: Retrying is UNIMPLEMENTED!\n", TargetKey->ObjectName);
1916 }
1917 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1918 {
1919 }
1920 _SEH2_END;
1921 }
1922
1923 /* If CmUnloadKey() failed we need to unlock registry ourselves */
1924 if (!NT_SUCCESS(Status))
1925 {
1926 if (Flags != REG_FORCE_UNLOAD)
1927 {
1928 /* Release the KCB locks */
1929 CmpReleaseTwoKcbLockByKey(ChildConv, ParentConv);
1930
1931 /* Release the hive loading lock */
1932 ExReleasePushLockExclusive(&CmpLoadHiveLock);
1933 }
1934
1935 /* Unlock the registry */
1936 CmpUnlockRegistry();
1937 }
1938
1939 Quit:
1940 /* Dereference the key */
1941 ObDereferenceObject(KeyBody);
1942
1943 /* Return status */
1944 return Status;
1945 }
1946
1947 NTSTATUS
1948 NTAPI
1949 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
1950 IN HANDLE Event)
1951 {
1952 UNIMPLEMENTED;
1953 return STATUS_NOT_IMPLEMENTED;
1954 }
1955
1956 /* EOF */