[NTOS] Configuration Manager fixes.
[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)
1306 return ZwInitializeRegistry(Flag);
1307
1308 /* Enough of the system has booted by now */
1309 Ki386PerfEnd();
1310
1311 /* Validate flag */
1312 if (Flag > CM_BOOT_FLAG_MAX) return STATUS_INVALID_PARAMETER;
1313
1314 /* Check if boot was accepted */
1315 if ((Flag >= CM_BOOT_FLAG_ACCEPTED) && (Flag <= CM_BOOT_FLAG_MAX))
1316 {
1317 /* Only allow once */
1318 if (!CmBootAcceptFirstTime) return STATUS_ACCESS_DENIED;
1319 CmBootAcceptFirstTime = FALSE;
1320
1321 /* Get the control set accepted */
1322 Flag -= CM_BOOT_FLAG_ACCEPTED;
1323 if (Flag)
1324 {
1325 /* FIXME: Save the last known good boot */
1326 //Status = CmpSaveBootControlSet(Flag);
1327
1328 /* Notify HAL */
1329 HalEndOfBoot();
1330
1331 /* Enable lazy flush */
1332 CmpHoldLazyFlush = FALSE;
1333 CmpLazyFlush();
1334 return Status;
1335 }
1336
1337 /* Otherwise, invalid boot */
1338 return STATUS_INVALID_PARAMETER;
1339 }
1340
1341 /* Check if this was a setup boot */
1342 SetupBoot = (Flag == CM_BOOT_FLAG_SETUP ? TRUE : FALSE);
1343
1344 /* Make sure we're only called once */
1345 if (!CmFirstTime) return STATUS_ACCESS_DENIED;
1346 CmFirstTime = FALSE;
1347
1348 /* Lock the registry exclusively */
1349 CmpLockRegistryExclusive();
1350
1351 /* Initialize the hives and lazy flusher */
1352 CmpCmdInit(SetupBoot);
1353
1354 /* Save version data */
1355 CmpSetVersionData();
1356
1357 /* Release the registry lock */
1358 CmpUnlockRegistry();
1359 return STATUS_SUCCESS;
1360 }
1361
1362 NTSTATUS
1363 NTAPI
1364 NtCompactKeys(IN ULONG Count,
1365 IN PHANDLE KeyArray)
1366 {
1367 UNIMPLEMENTED;
1368 return STATUS_NOT_IMPLEMENTED;
1369 }
1370
1371 NTSTATUS
1372 NTAPI
1373 NtCompressKey(IN HANDLE Key)
1374 {
1375 UNIMPLEMENTED;
1376 return STATUS_NOT_IMPLEMENTED;
1377 }
1378
1379 // FIXME: different for different windows versions!
1380 #define PRODUCT_ACTIVATION_VERSION 7749
1381
1382 NTSTATUS
1383 NTAPI
1384 NtLockProductActivationKeys(IN PULONG pPrivateVer,
1385 IN PULONG pSafeMode)
1386 {
1387 KPROCESSOR_MODE PreviousMode;
1388
1389 PreviousMode = ExGetPreviousMode();
1390 _SEH2_TRY
1391 {
1392 /* Check if the caller asked for the version */
1393 if (pPrivateVer != NULL)
1394 {
1395 /* For user mode, probe it */
1396 if (PreviousMode != KernelMode)
1397 {
1398 ProbeForRead(pPrivateVer, sizeof(ULONG), sizeof(ULONG));
1399 }
1400
1401 /* Return the expected version */
1402 *pPrivateVer = PRODUCT_ACTIVATION_VERSION;
1403 }
1404
1405 /* Check if the caller asked for safe mode mode state */
1406 if (pSafeMode != NULL)
1407 {
1408 /* For user mode, probe it */
1409 if (PreviousMode != KernelMode)
1410 {
1411 ProbeForRead(pSafeMode, sizeof(ULONG), sizeof(ULONG));
1412 }
1413
1414 /* Return the safe boot mode state */
1415 *pSafeMode = InitSafeBootMode;
1416 }
1417 }
1418 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1419 {
1420 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1421 }
1422 _SEH2_END;
1423
1424 return STATUS_SUCCESS;
1425 }
1426
1427 NTSTATUS
1428 NTAPI
1429 NtLockRegistryKey(IN HANDLE KeyHandle)
1430 {
1431 UNIMPLEMENTED;
1432 return STATUS_NOT_IMPLEMENTED;
1433 }
1434
1435 NTSTATUS
1436 NTAPI
1437 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle,
1438 IN ULONG Count,
1439 IN POBJECT_ATTRIBUTES SlaveObjects,
1440 IN HANDLE Event,
1441 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1442 IN PVOID ApcContext OPTIONAL,
1443 OUT PIO_STATUS_BLOCK IoStatusBlock,
1444 IN ULONG CompletionFilter,
1445 IN BOOLEAN WatchTree,
1446 OUT PVOID Buffer,
1447 IN ULONG Length,
1448 IN BOOLEAN Asynchronous)
1449 {
1450 UNIMPLEMENTED_ONCE;
1451 return STATUS_NOT_IMPLEMENTED;
1452 }
1453
1454 NTSTATUS
1455 NTAPI
1456 NtQueryMultipleValueKey(IN HANDLE KeyHandle,
1457 IN OUT PKEY_VALUE_ENTRY ValueList,
1458 IN ULONG NumberOfValues,
1459 OUT PVOID Buffer,
1460 IN OUT PULONG Length,
1461 OUT PULONG ReturnLength)
1462 {
1463 UNIMPLEMENTED;
1464 return STATUS_NOT_IMPLEMENTED;
1465 }
1466
1467 NTSTATUS
1468 NTAPI
1469 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey,
1470 OUT PULONG HandleCount)
1471 {
1472 KPROCESSOR_MODE PreviousMode;
1473 PCM_KEY_BODY KeyBody = NULL;
1474 HANDLE KeyHandle;
1475 NTSTATUS Status;
1476
1477 DPRINT("NtQueryOpenSubKeys()\n");
1478
1479 PAGED_CODE();
1480
1481 /* Get the processor mode */
1482 PreviousMode = KeGetPreviousMode();
1483
1484 /* Check for user-mode caller */
1485 if (PreviousMode != KernelMode)
1486 {
1487 /* Prepare to probe parameters */
1488 _SEH2_TRY
1489 {
1490 /* Probe target key */
1491 ProbeForRead(TargetKey,
1492 sizeof(OBJECT_ATTRIBUTES),
1493 sizeof(ULONG));
1494
1495 /* Probe handle count */
1496 ProbeForWriteUlong(HandleCount);
1497 }
1498 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1499 {
1500 /* Return the exception code */
1501 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1502 }
1503 _SEH2_END;
1504 }
1505
1506 /* Open a handle to the key */
1507 Status = ObOpenObjectByName(TargetKey,
1508 CmpKeyObjectType,
1509 PreviousMode,
1510 NULL,
1511 KEY_READ,
1512 NULL,
1513 &KeyHandle);
1514 if (NT_SUCCESS(Status))
1515 {
1516 /* Reference the key object */
1517 Status = ObReferenceObjectByHandle(KeyHandle,
1518 KEY_READ,
1519 CmpKeyObjectType,
1520 PreviousMode,
1521 (PVOID*)&KeyBody,
1522 NULL);
1523
1524 /* Close the handle */
1525 NtClose(KeyHandle);
1526 }
1527
1528 /* Fail, if the key object could not be referenced */
1529 if (!NT_SUCCESS(Status))
1530 return Status;
1531
1532 /* Lock the registry exclusively */
1533 CmpLockRegistryExclusive();
1534
1535 /* Fail, if we did not open a hive root key */
1536 if (KeyBody->KeyControlBlock->KeyCell !=
1537 KeyBody->KeyControlBlock->KeyHive->BaseBlock->RootCell)
1538 {
1539 DPRINT("Error: Key is not a hive root key!\n");
1540 CmpUnlockRegistry();
1541 ObDereferenceObject(KeyBody);
1542 return STATUS_INVALID_PARAMETER;
1543 }
1544
1545 /* Call the internal API */
1546 *HandleCount = CmpEnumerateOpenSubKeys(KeyBody->KeyControlBlock,
1547 FALSE, FALSE);
1548
1549 /* Unlock the registry */
1550 CmpUnlockRegistry();
1551
1552 /* Dereference the key object */
1553 ObDereferenceObject(KeyBody);
1554
1555 DPRINT("Done.\n");
1556
1557 return Status;
1558 }
1559
1560 NTSTATUS
1561 NTAPI
1562 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey,
1563 IN ULONG BufferLength,
1564 IN PVOID Buffer,
1565 IN PULONG RequiredSize)
1566 {
1567 UNIMPLEMENTED;
1568 return STATUS_NOT_IMPLEMENTED;
1569 }
1570
1571 NTSTATUS
1572 NTAPI
1573 NtRenameKey(IN HANDLE KeyHandle,
1574 IN PUNICODE_STRING ReplacementName)
1575 {
1576 UNIMPLEMENTED;
1577 return STATUS_NOT_IMPLEMENTED;
1578 }
1579
1580 NTSTATUS
1581 NTAPI
1582 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes,
1583 IN HANDLE Key,
1584 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
1585 {
1586 UNIMPLEMENTED;
1587 return STATUS_NOT_IMPLEMENTED;
1588 }
1589
1590 NTSTATUS
1591 NTAPI
1592 NtRestoreKey(IN HANDLE KeyHandle,
1593 IN HANDLE FileHandle,
1594 IN ULONG RestoreFlags)
1595 {
1596 UNIMPLEMENTED;
1597 return STATUS_NOT_IMPLEMENTED;
1598 }
1599
1600 NTSTATUS
1601 NTAPI
1602 NtSaveKey(IN HANDLE KeyHandle,
1603 IN HANDLE FileHandle)
1604 {
1605 /* Call the extended API */
1606 return NtSaveKeyEx(KeyHandle, FileHandle, REG_STANDARD_FORMAT);
1607 }
1608
1609 NTSTATUS
1610 NTAPI
1611 NtSaveKeyEx(IN HANDLE KeyHandle,
1612 IN HANDLE FileHandle,
1613 IN ULONG Flags)
1614 {
1615 NTSTATUS Status;
1616 HANDLE KmFileHandle = NULL;
1617 PCM_KEY_BODY KeyObject;
1618 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1619
1620 PAGED_CODE();
1621
1622 DPRINT("NtSaveKeyEx(0x%p, 0x%p, %lu)\n", KeyHandle, FileHandle, Flags);
1623
1624 /* Verify the flags */
1625 if ((Flags != REG_STANDARD_FORMAT)
1626 && (Flags != REG_LATEST_FORMAT)
1627 && (Flags != REG_NO_COMPRESSION))
1628 {
1629 /* Only one of these values can be specified */
1630 return STATUS_INVALID_PARAMETER;
1631 }
1632
1633 /* Validate privilege */
1634 if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode))
1635 {
1636 return STATUS_PRIVILEGE_NOT_HELD;
1637 }
1638
1639 /* Make sure the target file handle is a kernel handle */
1640 Status = CmpConvertHandleToKernelHandle(FileHandle,
1641 IoFileObjectType,
1642 FILE_WRITE_DATA,
1643 PreviousMode,
1644 &KmFileHandle);
1645 if (!NT_SUCCESS(Status))
1646 goto Quit;
1647
1648 /* Verify that the handle is valid and is a registry key */
1649 Status = ObReferenceObjectByHandle(KeyHandle,
1650 KEY_READ,
1651 CmpKeyObjectType,
1652 PreviousMode,
1653 (PVOID*)&KeyObject,
1654 NULL);
1655 if (!NT_SUCCESS(Status))
1656 goto Quit;
1657
1658 /* Call the internal API */
1659 Status = CmSaveKey(KeyObject->KeyControlBlock, KmFileHandle, Flags);
1660
1661 /* Dereference the registry key */
1662 ObDereferenceObject(KeyObject);
1663
1664 Quit:
1665 /* Close the local kernel handle */
1666 if (KmFileHandle)
1667 ObCloseHandle(KmFileHandle, KernelMode);
1668
1669 return Status;
1670 }
1671
1672 NTSTATUS
1673 NTAPI
1674 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle,
1675 IN HANDLE LowPrecedenceKeyHandle,
1676 IN HANDLE FileHandle)
1677 {
1678 NTSTATUS Status;
1679 KPROCESSOR_MODE PreviousMode;
1680 HANDLE KmFileHandle = NULL;
1681 PCM_KEY_BODY HighPrecedenceKeyObject = NULL;
1682 PCM_KEY_BODY LowPrecedenceKeyObject = NULL;
1683
1684 PAGED_CODE();
1685
1686 DPRINT("NtSaveMergedKeys(0x%p, 0x%p, 0x%p)\n",
1687 HighPrecedenceKeyHandle, LowPrecedenceKeyHandle, FileHandle);
1688
1689 PreviousMode = ExGetPreviousMode();
1690
1691 /* Validate privilege */
1692 if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode))
1693 {
1694 return STATUS_PRIVILEGE_NOT_HELD;
1695 }
1696
1697 /* Make sure the target file handle is a kernel handle */
1698 Status = CmpConvertHandleToKernelHandle(FileHandle,
1699 IoFileObjectType,
1700 FILE_WRITE_DATA,
1701 PreviousMode,
1702 &KmFileHandle);
1703 if (!NT_SUCCESS(Status))
1704 goto Quit;
1705
1706 /* Verify that the handles are valid and are registry keys */
1707 Status = ObReferenceObjectByHandle(HighPrecedenceKeyHandle,
1708 KEY_READ,
1709 CmpKeyObjectType,
1710 PreviousMode,
1711 (PVOID*)&HighPrecedenceKeyObject,
1712 NULL);
1713 if (!NT_SUCCESS(Status))
1714 goto Quit;
1715
1716 Status = ObReferenceObjectByHandle(LowPrecedenceKeyHandle,
1717 KEY_READ,
1718 CmpKeyObjectType,
1719 PreviousMode,
1720 (PVOID*)&LowPrecedenceKeyObject,
1721 NULL);
1722 if (!NT_SUCCESS(Status))
1723 goto Quit;
1724
1725 /* Call the internal API */
1726 Status = CmSaveMergedKeys(HighPrecedenceKeyObject->KeyControlBlock,
1727 LowPrecedenceKeyObject->KeyControlBlock,
1728 KmFileHandle);
1729
1730 Quit:
1731 /* Dereference the opened key objects */
1732 if (LowPrecedenceKeyObject)
1733 ObDereferenceObject(LowPrecedenceKeyObject);
1734 if (HighPrecedenceKeyObject)
1735 ObDereferenceObject(HighPrecedenceKeyObject);
1736
1737 /* Close the local kernel handle */
1738 if (KmFileHandle)
1739 ObCloseHandle(KmFileHandle, KernelMode);
1740
1741 return Status;
1742 }
1743
1744 NTSTATUS
1745 NTAPI
1746 NtSetInformationKey(IN HANDLE KeyHandle,
1747 IN KEY_SET_INFORMATION_CLASS KeyInformationClass,
1748 IN PVOID KeyInformation,
1749 IN ULONG KeyInformationLength)
1750 {
1751 UNIMPLEMENTED;
1752 return STATUS_NOT_IMPLEMENTED;
1753 }
1754
1755 NTSTATUS
1756 NTAPI
1757 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes)
1758 {
1759 return NtUnloadKey2(KeyObjectAttributes, 0);
1760 }
1761
1762 NTSTATUS
1763 NTAPI
1764 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
1765 IN ULONG Flags)
1766 {
1767 NTSTATUS Status;
1768 OBJECT_ATTRIBUTES CapturedTargetKey;
1769 UNICODE_STRING ObjectName;
1770 HANDLE KmTargetKeyRootDir = NULL;
1771 CM_PARSE_CONTEXT ParseContext = {0};
1772 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1773 PCM_KEY_BODY KeyBody = NULL;
1774 ULONG ParentConv = 0, ChildConv = 0;
1775 HANDLE Handle;
1776
1777 PAGED_CODE();
1778
1779 /* Validate privilege */
1780 if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode))
1781 {
1782 DPRINT1("Restore Privilege missing!\n");
1783 return STATUS_PRIVILEGE_NOT_HELD;
1784 }
1785
1786 /* Check for user-mode caller */
1787 if (PreviousMode != KernelMode)
1788 {
1789 /* Prepare to probe parameters */
1790 _SEH2_TRY
1791 {
1792 /* Probe object attributes */
1793 ProbeForRead(TargetKey,
1794 sizeof(OBJECT_ATTRIBUTES),
1795 sizeof(ULONG));
1796
1797 CapturedTargetKey = *TargetKey;
1798
1799 /* Probe the string */
1800 ObjectName = ProbeForReadUnicodeString(CapturedTargetKey.ObjectName);
1801 ProbeForRead(ObjectName.Buffer,
1802 ObjectName.Length,
1803 sizeof(WCHAR));
1804
1805 CapturedTargetKey.ObjectName = &ObjectName;
1806 }
1807 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1808 {
1809 /* Return the exception code */
1810 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1811 }
1812 _SEH2_END;
1813 }
1814 else
1815 {
1816 /* Save the target attributes directly */
1817 CapturedTargetKey = *TargetKey;
1818 }
1819
1820 /* Make sure the target key root directory handle is a kernel handle */
1821 Status = CmpConvertHandleToKernelHandle(CapturedTargetKey.RootDirectory,
1822 CmpKeyObjectType,
1823 KEY_WRITE,
1824 PreviousMode,
1825 &KmTargetKeyRootDir);
1826 if (!NT_SUCCESS(Status))
1827 return Status;
1828 CapturedTargetKey.RootDirectory = KmTargetKeyRootDir;
1829 CapturedTargetKey.Attributes |= OBJ_KERNEL_HANDLE;
1830
1831 /* Setup the parse context */
1832 ParseContext.CreateOperation = TRUE;
1833 ParseContext.CreateOptions = REG_OPTION_BACKUP_RESTORE;
1834
1835 /* Do the create */
1836 /* Open a local handle to the key */
1837 Status = ObOpenObjectByName(&CapturedTargetKey,
1838 CmpKeyObjectType,
1839 KernelMode,
1840 NULL,
1841 KEY_WRITE,
1842 &ParseContext,
1843 &Handle);
1844 if (NT_SUCCESS(Status))
1845 {
1846 /* Reference the key object */
1847 Status = ObReferenceObjectByHandle(Handle,
1848 KEY_WRITE,
1849 CmpKeyObjectType,
1850 KernelMode,
1851 (PVOID*)&KeyBody,
1852 NULL);
1853
1854 /* Close the handle */
1855 ObCloseHandle(Handle, KernelMode);
1856 }
1857
1858 /* Close the local kernel handle */
1859 if (KmTargetKeyRootDir)
1860 ObCloseHandle(KmTargetKeyRootDir, KernelMode);
1861
1862 /* Return if a failure was encountered */
1863 if (!NT_SUCCESS(Status))
1864 return Status;
1865
1866 /* Acquire the lock depending on flags */
1867 if (Flags == REG_FORCE_UNLOAD)
1868 {
1869 /* Lock registry exclusively */
1870 CmpLockRegistryExclusive();
1871 }
1872 else
1873 {
1874 /* Lock registry */
1875 CmpLockRegistry();
1876
1877 /* Acquire the hive loading lock */
1878 ExAcquirePushLockExclusive(&CmpLoadHiveLock);
1879
1880 /* Lock parent and child */
1881 if (KeyBody->KeyControlBlock->ParentKcb)
1882 ParentConv = KeyBody->KeyControlBlock->ParentKcb->ConvKey;
1883 else
1884 ParentConv = KeyBody->KeyControlBlock->ConvKey;
1885
1886 ChildConv = KeyBody->KeyControlBlock->ConvKey;
1887
1888 CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv, ParentConv);
1889 }
1890
1891 /* Check if it's being deleted already */
1892 if (KeyBody->KeyControlBlock->Delete)
1893 {
1894 /* Return appropriate status */
1895 Status = STATUS_KEY_DELETED;
1896 goto Quit;
1897 }
1898
1899 /* Check if it's a read-only key */
1900 if (KeyBody->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
1901 {
1902 /* Return appropriate status */
1903 Status = STATUS_ACCESS_DENIED;
1904 goto Quit;
1905 }
1906
1907 /* Call the internal API. Note that CmUnloadKey() unlocks the registry only on success. */
1908 Status = CmUnloadKey(KeyBody->KeyControlBlock, Flags);
1909
1910 /* Check if we failed, but really need to succeed */
1911 if ((Status == STATUS_CANNOT_DELETE) && (Flags == REG_FORCE_UNLOAD))
1912 {
1913 /* TODO: We should perform another attempt here */
1914 _SEH2_TRY
1915 {
1916 DPRINT1("NtUnloadKey2(%wZ): We want to force-unload the hive but couldn't unload it: Retrying is UNIMPLEMENTED!\n", TargetKey->ObjectName);
1917 }
1918 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1919 {
1920 }
1921 _SEH2_END;
1922 }
1923
1924 /* If CmUnloadKey() failed we need to unlock registry ourselves */
1925 if (!NT_SUCCESS(Status))
1926 {
1927 if (Flags != REG_FORCE_UNLOAD)
1928 {
1929 /* Release the KCB locks */
1930 CmpReleaseTwoKcbLockByKey(ChildConv, ParentConv);
1931
1932 /* Release the hive loading lock */
1933 ExReleasePushLockExclusive(&CmpLoadHiveLock);
1934 }
1935
1936 /* Unlock the registry */
1937 CmpUnlockRegistry();
1938 }
1939
1940 Quit:
1941 /* Dereference the key */
1942 ObDereferenceObject(KeyBody);
1943
1944 /* Return status */
1945 return Status;
1946 }
1947
1948 NTSTATUS
1949 NTAPI
1950 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
1951 IN HANDLE Event)
1952 {
1953 UNIMPLEMENTED;
1954 return STATUS_NOT_IMPLEMENTED;
1955 }
1956
1957 /* EOF */