xref: /reactos/ntoskrnl/config/ntapi.c (revision fe23a4aa)
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
ReleaseCapturedObjectAttributes(_In_ POBJECT_ATTRIBUTES CapturedObjectAttributes,_In_ KPROCESSOR_MODE AccessMode)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
ProbeAndCaptureObjectAttributes(_Out_ POBJECT_ATTRIBUTES CapturedObjectAttributes,_Out_ PUNICODE_STRING ObjectName,_In_ KPROCESSOR_MODE AccessMode,_In_ POBJECT_ATTRIBUTES ObjectAttributes,_In_ BOOLEAN CaptureSecurity)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
CmpConvertHandleToKernelHandle(_In_ HANDLE SourceHandle,_In_opt_ POBJECT_TYPE ObjectType,_In_ ACCESS_MASK DesiredAccess,_In_ KPROCESSOR_MODE AccessMode,_Out_ PHANDLE KernelHandle)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
NtCreateKey(OUT PHANDLE KeyHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN ULONG TitleIndex,IN PUNICODE_STRING Class OPTIONAL,IN ULONG CreateOptions,OUT PULONG Disposition OPTIONAL)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
NtOpenKey(OUT PHANDLE KeyHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes)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
NtDeleteKey(IN HANDLE KeyHandle)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
NtEnumerateKey(IN HANDLE KeyHandle,IN ULONG Index,IN KEY_INFORMATION_CLASS KeyInformationClass,OUT PVOID KeyInformation,IN ULONG Length,OUT PULONG ResultLength)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
NtEnumerateValueKey(IN HANDLE KeyHandle,IN ULONG Index,IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,OUT PVOID KeyValueInformation,IN ULONG Length,OUT PULONG ResultLength)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
NtQueryKey(IN HANDLE KeyHandle,IN KEY_INFORMATION_CLASS KeyInformationClass,OUT PVOID KeyInformation,IN ULONG Length,OUT PULONG ResultLength)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
NtQueryValueKey(IN HANDLE KeyHandle,IN PUNICODE_STRING ValueName,IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,OUT PVOID KeyValueInformation,IN ULONG Length,OUT PULONG ResultLength)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
NtSetValueKey(IN HANDLE KeyHandle,IN PUNICODE_STRING ValueName,IN ULONG TitleIndex,IN ULONG Type,IN PVOID Data,IN ULONG DataSize)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 = NULL;
894 
895         _SEH2_TRY
896         {
897             ProbeForRead(Data, DataSize, 1);
898         }
899         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
900         {
901             Status = _SEH2_GetExceptionCode();
902         }
903         _SEH2_END;
904 
905         if (!NT_SUCCESS(Status))
906         {
907             /* Dereference and return status */
908             ObDereferenceObject(KeyObject);
909             return Status;
910         }
911 
912         DataCopy = ExAllocatePoolWithTag(PagedPool, DataSize, TAG_CM);
913         if (!DataCopy)
914         {
915             /* Dereference and return status */
916             ObDereferenceObject(KeyObject);
917             return STATUS_INSUFFICIENT_RESOURCES;
918         }
919 
920         _SEH2_TRY
921         {
922             RtlCopyMemory(DataCopy, Data, DataSize);
923         }
924         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
925         {
926             Status = _SEH2_GetExceptionCode();
927         }
928         _SEH2_END;
929 
930         if (!NT_SUCCESS(Status))
931         {
932             /* Dereference and return status */
933             ExFreePoolWithTag(DataCopy, TAG_CM);
934             ObDereferenceObject(KeyObject);
935             return Status;
936         }
937 
938         Data = DataCopy;
939     }
940 
941     /* Capture the string */
942     Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName);
943     if (!NT_SUCCESS(Status))
944         goto Quit;
945 
946     DPRINT("NtSetValueKey() KH 0x%p, VN '%wZ', TI %x, T %lu, DS %lu\n",
947         KeyHandle, &ValueNameCopy, TitleIndex, Type, DataSize);
948 
949     /* Make sure the name is aligned, not too long, and the data under 4GB */
950     if ((ValueNameCopy.Length > 32767) ||
951         (ValueNameCopy.Length & (sizeof(WCHAR) - 1)) ||
952         (DataSize > 0x80000000))
953     {
954         /* Fail */
955         Status = STATUS_INVALID_PARAMETER;
956         goto Quit;
957     }
958 
959     /* Ignore any null characters at the end */
960     while (ValueNameCopy.Length &&
961            !(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1]))
962     {
963         /* Skip it */
964         ValueNameCopy.Length -= sizeof(WCHAR);
965     }
966 
967     /* Don't touch read-only keys */
968     if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
969     {
970         /* Fail */
971         Status = STATUS_ACCESS_DENIED;
972         goto Quit;
973     }
974 
975     /* Setup callback */
976     PostOperationInfo.Object = (PVOID)KeyObject;
977     SetValueKeyInfo.Object = (PVOID)KeyObject;
978     SetValueKeyInfo.ValueName = &ValueNameCopy;
979     SetValueKeyInfo.TitleIndex = TitleIndex;
980     SetValueKeyInfo.Type = Type;
981     SetValueKeyInfo.Data = Data;
982     SetValueKeyInfo.DataSize = DataSize;
983 
984     /* Do the callback */
985     Status = CmiCallRegisteredCallbacks(RegNtPreSetValueKey, &SetValueKeyInfo);
986     if (NT_SUCCESS(Status))
987     {
988         /* Call the internal API */
989         Status = CmSetValueKey(KeyObject->KeyControlBlock,
990                                &ValueNameCopy,
991                                Type,
992                                Data,
993                                DataSize);
994 
995         /* Do the post-callback */
996         PostOperationInfo.Status = Status;
997         CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
998     }
999 
1000 Quit:
1001     if (ValueNameCopy.Buffer)
1002         ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
1003 
1004     if ((PreviousMode != KernelMode) && Data)
1005         ExFreePoolWithTag(Data, TAG_CM);
1006 
1007     /* Dereference and return status */
1008     ObDereferenceObject(KeyObject);
1009     return Status;
1010 }
1011 
1012 NTSTATUS
1013 NTAPI
NtDeleteValueKey(IN HANDLE KeyHandle,IN PUNICODE_STRING ValueName)1014 NtDeleteValueKey(IN HANDLE KeyHandle,
1015                  IN PUNICODE_STRING ValueName)
1016 {
1017     NTSTATUS Status;
1018     PCM_KEY_BODY KeyObject;
1019     REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo;
1020     REG_POST_OPERATION_INFORMATION PostOperationInfo;
1021     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1022     UNICODE_STRING ValueNameCopy;
1023 
1024     PAGED_CODE();
1025 
1026     /* Verify that the handle is valid and is a registry key */
1027     Status = ObReferenceObjectByHandle(KeyHandle,
1028                                        KEY_SET_VALUE,
1029                                        CmpKeyObjectType,
1030                                        PreviousMode,
1031                                        (PVOID*)&KeyObject,
1032                                        NULL);
1033     if (!NT_SUCCESS(Status))
1034         return Status;
1035 
1036     /* Capture the string */
1037     Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName);
1038     if (!NT_SUCCESS(Status))
1039         goto Quit;
1040 
1041     /* Make sure the name is aligned properly */
1042     if (ValueNameCopy.Length & (sizeof(WCHAR) - 1))
1043     {
1044         /* It isn't, so we'll fail */
1045         Status = STATUS_INVALID_PARAMETER;
1046         goto Quit;
1047     }
1048 
1049     /* Don't touch read-only keys */
1050     if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
1051     {
1052         /* Fail */
1053         Status = STATUS_ACCESS_DENIED;
1054         goto Quit;
1055     }
1056 
1057     /* Do the callback */
1058     DeleteValueKeyInfo.Object = (PVOID)KeyObject;
1059     DeleteValueKeyInfo.ValueName = ValueName;
1060     Status = CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey,
1061                                         &DeleteValueKeyInfo);
1062     if (NT_SUCCESS(Status))
1063     {
1064         /* Call the internal API */
1065         Status = CmDeleteValueKey(KeyObject->KeyControlBlock, ValueNameCopy);
1066 
1067         /* Do the post callback */
1068         PostOperationInfo.Object = (PVOID)KeyObject;
1069         PostOperationInfo.Status = Status;
1070         CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey,
1071                                    &PostOperationInfo);
1072     }
1073 
1074 Quit:
1075     if (ValueNameCopy.Buffer)
1076         ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
1077 
1078     /* Dereference and return status */
1079     ObDereferenceObject(KeyObject);
1080     return Status;
1081 }
1082 
1083 NTSTATUS
1084 NTAPI
NtFlushKey(IN HANDLE KeyHandle)1085 NtFlushKey(IN HANDLE KeyHandle)
1086 {
1087     NTSTATUS Status;
1088     PCM_KEY_BODY KeyObject;
1089     PAGED_CODE();
1090 
1091     /* Get the key object */
1092     Status = ObReferenceObjectByHandle(KeyHandle,
1093                                        0,
1094                                        CmpKeyObjectType,
1095                                        ExGetPreviousMode(),
1096                                        (PVOID*)&KeyObject,
1097                                        NULL);
1098     if (!NT_SUCCESS(Status)) return Status;
1099 
1100     /* Lock the registry */
1101     CmpLockRegistry();
1102 
1103     /* Lock the KCB */
1104     CmpAcquireKcbLockShared(KeyObject->KeyControlBlock);
1105 
1106     /* Make sure KCB isn't deleted */
1107     if (KeyObject->KeyControlBlock->Delete)
1108     {
1109         /* Fail */
1110         Status = STATUS_KEY_DELETED;
1111     }
1112     else
1113     {
1114         /* Call the internal API */
1115         Status = CmFlushKey(KeyObject->KeyControlBlock, FALSE);
1116     }
1117 
1118     /* Release the locks */
1119     CmpReleaseKcbLock(KeyObject->KeyControlBlock);
1120     CmpUnlockRegistry();
1121 
1122     /* Dereference the object and return status */
1123     ObDereferenceObject(KeyObject);
1124     return Status;
1125 }
1126 
1127 NTSTATUS
1128 NTAPI
NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes,IN POBJECT_ATTRIBUTES FileObjectAttributes)1129 NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
1130           IN POBJECT_ATTRIBUTES FileObjectAttributes)
1131 {
1132     /* Call the newer API */
1133     return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, 0, NULL);
1134 }
1135 
1136 NTSTATUS
1137 NTAPI
NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes,IN POBJECT_ATTRIBUTES FileObjectAttributes,IN ULONG Flags)1138 NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
1139            IN POBJECT_ATTRIBUTES FileObjectAttributes,
1140            IN ULONG Flags)
1141 {
1142     /* Call the newer API */
1143     return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, Flags, NULL);
1144 }
1145 
1146 NTSTATUS
1147 NTAPI
NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,IN POBJECT_ATTRIBUTES SourceFile,IN ULONG Flags,IN HANDLE TrustClassKey)1148 NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
1149             IN POBJECT_ATTRIBUTES SourceFile,
1150             IN ULONG Flags,
1151             IN HANDLE TrustClassKey)
1152 {
1153     NTSTATUS Status;
1154     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1155     OBJECT_ATTRIBUTES CapturedTargetKey;
1156     OBJECT_ATTRIBUTES CapturedSourceFile;
1157     UNICODE_STRING TargetKeyName, SourceFileName;
1158     HANDLE KmTargetKeyRootDir = NULL, KmSourceFileRootDir = NULL;
1159     PCM_KEY_BODY KeyBody = NULL;
1160 
1161     PAGED_CODE();
1162 
1163     /* Validate flags */
1164     if (Flags & ~REG_NO_LAZY_FLUSH)
1165         return STATUS_INVALID_PARAMETER;
1166 
1167     /* Validate privilege */
1168     if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode))
1169     {
1170         DPRINT1("Restore Privilege missing!\n");
1171         return STATUS_PRIVILEGE_NOT_HELD;
1172     }
1173 
1174     /* Block APCs */
1175     KeEnterCriticalRegion();
1176 
1177     /* Check for user-mode caller */
1178     if (PreviousMode != KernelMode)
1179     {
1180         /* Prepare to probe parameters */
1181         _SEH2_TRY
1182         {
1183             /* Probe target key */
1184             ProbeForRead(TargetKey,
1185                          sizeof(OBJECT_ATTRIBUTES),
1186                          sizeof(ULONG));
1187 
1188             /* Probe source file */
1189             ProbeForRead(SourceFile,
1190                          sizeof(OBJECT_ATTRIBUTES),
1191                          sizeof(ULONG));
1192         }
1193         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1194         {
1195             /* Return the exception code */
1196             Status = _SEH2_GetExceptionCode();
1197             _SEH2_YIELD(goto Quit);
1198         }
1199         _SEH2_END;
1200     }
1201 
1202     /* Probe and capture the target key attributes, including the security */
1203     Status = ProbeAndCaptureObjectAttributes(&CapturedTargetKey,
1204                                              &TargetKeyName,
1205                                              PreviousMode,
1206                                              TargetKey,
1207                                              TRUE);
1208     if (!NT_SUCCESS(Status))
1209         goto Quit;
1210 
1211     /*
1212      * Probe and capture the source file attributes, but not the security.
1213      * A proper security context is built by CmLoadKey().
1214      */
1215     Status = ProbeAndCaptureObjectAttributes(&CapturedSourceFile,
1216                                              &SourceFileName,
1217                                              PreviousMode,
1218                                              SourceFile,
1219                                              FALSE);
1220     if (!NT_SUCCESS(Status))
1221     {
1222         ReleaseCapturedObjectAttributes(&CapturedTargetKey, PreviousMode);
1223         goto Quit;
1224     }
1225 
1226     /* Make sure the target key root directory handle is a kernel handle */
1227     Status = CmpConvertHandleToKernelHandle(CapturedTargetKey.RootDirectory,
1228                                             CmpKeyObjectType,
1229                                             KEY_READ,
1230                                             PreviousMode,
1231                                             &KmTargetKeyRootDir);
1232     if (!NT_SUCCESS(Status))
1233         goto Cleanup;
1234     CapturedTargetKey.RootDirectory = KmTargetKeyRootDir;
1235     CapturedTargetKey.Attributes |= OBJ_KERNEL_HANDLE;
1236 
1237     /* Make sure the source file root directory handle is a kernel handle */
1238     Status = CmpConvertHandleToKernelHandle(CapturedSourceFile.RootDirectory,
1239                                             IoFileObjectType,
1240                                             FILE_TRAVERSE,
1241                                             PreviousMode,
1242                                             &KmSourceFileRootDir);
1243     if (!NT_SUCCESS(Status))
1244         goto Cleanup;
1245     CapturedSourceFile.RootDirectory = KmSourceFileRootDir;
1246     CapturedSourceFile.Attributes |= OBJ_KERNEL_HANDLE;
1247 
1248     /* Check if we have a trust class */
1249     if (TrustClassKey)
1250     {
1251         /* Reference it */
1252         Status = ObReferenceObjectByHandle(TrustClassKey,
1253                                            0,
1254                                            CmpKeyObjectType,
1255                                            PreviousMode,
1256                                            (PVOID*)&KeyBody,
1257                                            NULL);
1258     }
1259 
1260     /* Call the internal API */
1261     Status = CmLoadKey(&CapturedTargetKey,
1262                        &CapturedSourceFile,
1263                        Flags,
1264                        KeyBody);
1265 
1266     /* Dereference the trust key, if any */
1267     if (KeyBody) ObDereferenceObject(KeyBody);
1268 
1269 Cleanup:
1270     /* Close the local kernel handles */
1271     if (KmSourceFileRootDir)
1272         ObCloseHandle(KmSourceFileRootDir, KernelMode);
1273     if (KmTargetKeyRootDir)
1274         ObCloseHandle(KmTargetKeyRootDir, KernelMode);
1275 
1276     /* Release the captured object attributes */
1277     ReleaseCapturedObjectAttributes(&CapturedSourceFile, PreviousMode);
1278     ReleaseCapturedObjectAttributes(&CapturedTargetKey, PreviousMode);
1279 
1280 Quit:
1281     /* Bring back APCs */
1282     KeLeaveCriticalRegion();
1283 
1284     /* Return status */
1285     return Status;
1286 }
1287 
1288 NTSTATUS
1289 NTAPI
NtNotifyChangeKey(IN HANDLE KeyHandle,IN HANDLE Event,IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,IN PVOID ApcContext OPTIONAL,OUT PIO_STATUS_BLOCK IoStatusBlock,IN ULONG CompletionFilter,IN BOOLEAN WatchTree,OUT PVOID Buffer,IN ULONG Length,IN BOOLEAN Asynchronous)1290 NtNotifyChangeKey(IN HANDLE KeyHandle,
1291                   IN HANDLE Event,
1292                   IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1293                   IN PVOID ApcContext OPTIONAL,
1294                   OUT PIO_STATUS_BLOCK IoStatusBlock,
1295                   IN ULONG CompletionFilter,
1296                   IN BOOLEAN WatchTree,
1297                   OUT PVOID Buffer,
1298                   IN ULONG Length,
1299                   IN BOOLEAN Asynchronous)
1300 {
1301     /* Call the newer API */
1302     return NtNotifyChangeMultipleKeys(KeyHandle,
1303                                       0,
1304                                       NULL,
1305                                       Event,
1306                                       ApcRoutine,
1307                                       ApcContext,
1308                                       IoStatusBlock,
1309                                       CompletionFilter,
1310                                       WatchTree,
1311                                       Buffer,
1312                                       Length,
1313                                       Asynchronous);
1314 }
1315 
1316 NTSTATUS
1317 NTAPI
NtInitializeRegistry(IN USHORT Flag)1318 NtInitializeRegistry(IN USHORT Flag)
1319 {
1320     BOOLEAN SetupBoot;
1321     NTSTATUS Status = STATUS_SUCCESS;
1322     PAGED_CODE();
1323 
1324     /* Always do this as kernel mode */
1325     if (KeGetPreviousMode() == UserMode)
1326         return ZwInitializeRegistry(Flag);
1327 
1328     /* Enough of the system has booted by now */
1329     Ki386PerfEnd();
1330 
1331     /* Validate flag */
1332     if (Flag > CM_BOOT_FLAG_MAX) return STATUS_INVALID_PARAMETER;
1333 
1334     /* Check if boot was accepted */
1335     if ((Flag >= CM_BOOT_FLAG_ACCEPTED) && (Flag <= CM_BOOT_FLAG_MAX))
1336     {
1337         /* Only allow once */
1338         if (!CmBootAcceptFirstTime) return STATUS_ACCESS_DENIED;
1339         CmBootAcceptFirstTime = FALSE;
1340 
1341         /* Get the control set accepted */
1342         Flag -= CM_BOOT_FLAG_ACCEPTED;
1343         if (Flag)
1344         {
1345             /* Save the last known good boot */
1346             Status = CmpSaveBootControlSet(Flag);
1347 
1348             /* Notify HAL */
1349             HalEndOfBoot();
1350 
1351             /* Enable lazy flush */
1352             CmpHoldLazyFlush = FALSE;
1353             CmpLazyFlush();
1354             return Status;
1355         }
1356 
1357         /* Otherwise, invalid boot */
1358         return STATUS_INVALID_PARAMETER;
1359     }
1360 
1361     /* Check if this was a setup boot */
1362     SetupBoot = (Flag == CM_BOOT_FLAG_SETUP ? TRUE : FALSE);
1363 
1364     /* Make sure we're only called once */
1365     if (!CmFirstTime) return STATUS_ACCESS_DENIED;
1366     CmFirstTime = FALSE;
1367 
1368     /* Lock the registry exclusively */
1369     CmpLockRegistryExclusive();
1370 
1371     /* Initialize the hives and lazy flusher */
1372     CmpCmdInit(SetupBoot);
1373 
1374     /* Save version data */
1375     CmpSetVersionData();
1376 
1377     /* Release the registry lock */
1378     CmpUnlockRegistry();
1379     return STATUS_SUCCESS;
1380 }
1381 
1382 NTSTATUS
1383 NTAPI
NtCompactKeys(IN ULONG Count,IN PHANDLE KeyArray)1384 NtCompactKeys(IN ULONG Count,
1385               IN PHANDLE KeyArray)
1386 {
1387     UNIMPLEMENTED;
1388     return STATUS_NOT_IMPLEMENTED;
1389 }
1390 
1391 NTSTATUS
1392 NTAPI
NtCompressKey(IN HANDLE Key)1393 NtCompressKey(IN HANDLE Key)
1394 {
1395     UNIMPLEMENTED;
1396     return STATUS_NOT_IMPLEMENTED;
1397 }
1398 
1399 // FIXME: different for different windows versions!
1400 #define PRODUCT_ACTIVATION_VERSION 7749
1401 
1402 NTSTATUS
1403 NTAPI
NtLockProductActivationKeys(IN PULONG pPrivateVer,IN PULONG pSafeMode)1404 NtLockProductActivationKeys(IN PULONG pPrivateVer,
1405                             IN PULONG pSafeMode)
1406 {
1407     KPROCESSOR_MODE PreviousMode;
1408 
1409     PreviousMode = ExGetPreviousMode();
1410     _SEH2_TRY
1411     {
1412         /* Check if the caller asked for the version */
1413         if (pPrivateVer != NULL)
1414         {
1415             /* For user mode, probe it */
1416             if (PreviousMode != KernelMode)
1417             {
1418                 ProbeForWriteUlong(pPrivateVer);
1419             }
1420 
1421             /* Return the expected version */
1422             *pPrivateVer = PRODUCT_ACTIVATION_VERSION;
1423         }
1424 
1425         /* Check if the caller asked for safe mode mode state */
1426         if (pSafeMode != NULL)
1427         {
1428             /* For user mode, probe it */
1429             if (PreviousMode != KernelMode)
1430             {
1431                 ProbeForWriteUlong(pSafeMode);
1432             }
1433 
1434             /* Return the safe boot mode state */
1435             *pSafeMode = InitSafeBootMode;
1436         }
1437     }
1438     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1439     {
1440         _SEH2_YIELD(return _SEH2_GetExceptionCode());
1441     }
1442     _SEH2_END;
1443 
1444     return STATUS_SUCCESS;
1445 }
1446 
1447 NTSTATUS
1448 NTAPI
NtLockRegistryKey(IN HANDLE KeyHandle)1449 NtLockRegistryKey(IN HANDLE KeyHandle)
1450 {
1451     UNIMPLEMENTED;
1452     return STATUS_NOT_IMPLEMENTED;
1453 }
1454 
1455 NTSTATUS
1456 NTAPI
NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle,IN ULONG Count,IN POBJECT_ATTRIBUTES SlaveObjects,IN HANDLE Event,IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,IN PVOID ApcContext OPTIONAL,OUT PIO_STATUS_BLOCK IoStatusBlock,IN ULONG CompletionFilter,IN BOOLEAN WatchTree,OUT PVOID Buffer,IN ULONG Length,IN BOOLEAN Asynchronous)1457 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle,
1458                            IN ULONG Count,
1459                            IN POBJECT_ATTRIBUTES SlaveObjects,
1460                            IN HANDLE Event,
1461                            IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1462                            IN PVOID ApcContext OPTIONAL,
1463                            OUT PIO_STATUS_BLOCK IoStatusBlock,
1464                            IN ULONG CompletionFilter,
1465                            IN BOOLEAN WatchTree,
1466                            OUT PVOID Buffer,
1467                            IN ULONG Length,
1468                            IN BOOLEAN Asynchronous)
1469 {
1470     UNIMPLEMENTED_ONCE;
1471     return STATUS_NOT_IMPLEMENTED;
1472 }
1473 
1474 NTSTATUS
1475 NTAPI
NtQueryMultipleValueKey(IN HANDLE KeyHandle,IN OUT PKEY_VALUE_ENTRY ValueList,IN ULONG NumberOfValues,OUT PVOID Buffer,IN OUT PULONG Length,OUT PULONG ReturnLength)1476 NtQueryMultipleValueKey(IN HANDLE KeyHandle,
1477                         IN OUT PKEY_VALUE_ENTRY ValueList,
1478                         IN ULONG NumberOfValues,
1479                         OUT PVOID Buffer,
1480                         IN OUT PULONG Length,
1481                         OUT PULONG ReturnLength)
1482 {
1483     UNIMPLEMENTED;
1484     return STATUS_NOT_IMPLEMENTED;
1485 }
1486 
1487 NTSTATUS
1488 NTAPI
NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey,OUT PULONG HandleCount)1489 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey,
1490                    OUT PULONG HandleCount)
1491 {
1492     KPROCESSOR_MODE PreviousMode;
1493     PCM_KEY_BODY KeyBody = NULL;
1494     HANDLE KeyHandle;
1495     NTSTATUS Status;
1496     ULONG SubKeys;
1497 
1498     DPRINT("NtQueryOpenSubKeys()\n");
1499 
1500     PAGED_CODE();
1501 
1502     /* Get the processor mode */
1503     PreviousMode = KeGetPreviousMode();
1504 
1505     /* Check for user-mode caller */
1506     if (PreviousMode != KernelMode)
1507     {
1508         /* Prepare to probe parameters */
1509         _SEH2_TRY
1510         {
1511             /* Probe target key */
1512             ProbeForRead(TargetKey,
1513                          sizeof(OBJECT_ATTRIBUTES),
1514                          sizeof(ULONG));
1515 
1516             /* Probe handle count */
1517             ProbeForWriteUlong(HandleCount);
1518         }
1519         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1520         {
1521             /* Return the exception code */
1522             _SEH2_YIELD(return _SEH2_GetExceptionCode());
1523         }
1524         _SEH2_END;
1525     }
1526 
1527     /* Open a handle to the key */
1528     Status = ObOpenObjectByName(TargetKey,
1529                                 CmpKeyObjectType,
1530                                 PreviousMode,
1531                                 NULL,
1532                                 KEY_READ,
1533                                 NULL,
1534                                 &KeyHandle);
1535     if (NT_SUCCESS(Status))
1536     {
1537         /* Reference the key object */
1538         Status = ObReferenceObjectByHandle(KeyHandle,
1539                                            KEY_READ,
1540                                            CmpKeyObjectType,
1541                                            PreviousMode,
1542                                            (PVOID*)&KeyBody,
1543                                            NULL);
1544 
1545         /* Close the handle */
1546         NtClose(KeyHandle);
1547     }
1548 
1549     /* Fail, if the key object could not be referenced */
1550     if (!NT_SUCCESS(Status))
1551         return Status;
1552 
1553     /* Lock the registry exclusively */
1554     CmpLockRegistryExclusive();
1555 
1556     /* Fail, if we did not open a hive root key */
1557     if (KeyBody->KeyControlBlock->KeyCell !=
1558         KeyBody->KeyControlBlock->KeyHive->BaseBlock->RootCell)
1559     {
1560         DPRINT("Error: Key is not a hive root key!\n");
1561         CmpUnlockRegistry();
1562         ObDereferenceObject(KeyBody);
1563         return STATUS_INVALID_PARAMETER;
1564     }
1565 
1566     /* Call the internal API */
1567     SubKeys = CmpEnumerateOpenSubKeys(KeyBody->KeyControlBlock,
1568                                       FALSE, FALSE);
1569 
1570     /* Unlock the registry */
1571     CmpUnlockRegistry();
1572 
1573     /* Dereference the key object */
1574     ObDereferenceObject(KeyBody);
1575 
1576     /* Write back the result */
1577     _SEH2_TRY
1578     {
1579         *HandleCount = SubKeys;
1580     }
1581     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1582     {
1583         Status = _SEH2_GetExceptionCode();
1584     }
1585     _SEH2_END;
1586 
1587     DPRINT("Done.\n");
1588 
1589     return Status;
1590 }
1591 
1592 NTSTATUS
1593 NTAPI
NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey,IN ULONG BufferLength,IN PVOID Buffer,IN PULONG RequiredSize)1594 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey,
1595                      IN ULONG BufferLength,
1596                      IN PVOID Buffer,
1597                      IN PULONG RequiredSize)
1598 {
1599     UNIMPLEMENTED;
1600     return STATUS_NOT_IMPLEMENTED;
1601 }
1602 
1603 NTSTATUS
1604 NTAPI
NtRenameKey(IN HANDLE KeyHandle,IN PUNICODE_STRING ReplacementName)1605 NtRenameKey(IN HANDLE KeyHandle,
1606             IN PUNICODE_STRING ReplacementName)
1607 {
1608     UNIMPLEMENTED;
1609     return STATUS_NOT_IMPLEMENTED;
1610 }
1611 
1612 NTSTATUS
1613 NTAPI
NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes,IN HANDLE Key,IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)1614 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes,
1615              IN HANDLE Key,
1616              IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
1617 {
1618     UNIMPLEMENTED;
1619     return STATUS_NOT_IMPLEMENTED;
1620 }
1621 
1622 NTSTATUS
1623 NTAPI
NtRestoreKey(IN HANDLE KeyHandle,IN HANDLE FileHandle,IN ULONG RestoreFlags)1624 NtRestoreKey(IN HANDLE KeyHandle,
1625              IN HANDLE FileHandle,
1626              IN ULONG RestoreFlags)
1627 {
1628     UNIMPLEMENTED;
1629     return STATUS_NOT_IMPLEMENTED;
1630 }
1631 
1632 NTSTATUS
1633 NTAPI
NtSaveKey(IN HANDLE KeyHandle,IN HANDLE FileHandle)1634 NtSaveKey(IN HANDLE KeyHandle,
1635           IN HANDLE FileHandle)
1636 {
1637     /* Call the extended API */
1638     return NtSaveKeyEx(KeyHandle, FileHandle, REG_STANDARD_FORMAT);
1639 }
1640 
1641 NTSTATUS
1642 NTAPI
NtSaveKeyEx(IN HANDLE KeyHandle,IN HANDLE FileHandle,IN ULONG Flags)1643 NtSaveKeyEx(IN HANDLE KeyHandle,
1644             IN HANDLE FileHandle,
1645             IN ULONG Flags)
1646 {
1647     NTSTATUS Status;
1648     HANDLE KmFileHandle = NULL;
1649     PCM_KEY_BODY KeyObject;
1650     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1651 
1652     PAGED_CODE();
1653 
1654     DPRINT("NtSaveKeyEx(0x%p, 0x%p, %lu)\n", KeyHandle, FileHandle, Flags);
1655 
1656     /* Verify the flags */
1657     if ((Flags != REG_STANDARD_FORMAT)
1658         && (Flags != REG_LATEST_FORMAT)
1659         && (Flags != REG_NO_COMPRESSION))
1660     {
1661         /* Only one of these values can be specified */
1662         return STATUS_INVALID_PARAMETER;
1663     }
1664 
1665     /* Validate privilege */
1666     if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode))
1667     {
1668         return STATUS_PRIVILEGE_NOT_HELD;
1669     }
1670 
1671     /* Make sure the target file handle is a kernel handle */
1672     Status = CmpConvertHandleToKernelHandle(FileHandle,
1673                                             IoFileObjectType,
1674                                             FILE_WRITE_DATA,
1675                                             PreviousMode,
1676                                             &KmFileHandle);
1677     if (!NT_SUCCESS(Status))
1678         goto Quit;
1679 
1680     /* Verify that the handle is valid and is a registry key */
1681     Status = ObReferenceObjectByHandle(KeyHandle,
1682                                        KEY_READ,
1683                                        CmpKeyObjectType,
1684                                        PreviousMode,
1685                                        (PVOID*)&KeyObject,
1686                                        NULL);
1687     if (!NT_SUCCESS(Status))
1688         goto Quit;
1689 
1690     /* Call the internal API */
1691     Status = CmSaveKey(KeyObject->KeyControlBlock, KmFileHandle, Flags);
1692 
1693     /* Dereference the registry key */
1694     ObDereferenceObject(KeyObject);
1695 
1696 Quit:
1697     /* Close the local kernel handle */
1698     if (KmFileHandle)
1699         ObCloseHandle(KmFileHandle, KernelMode);
1700 
1701     return Status;
1702 }
1703 
1704 NTSTATUS
1705 NTAPI
NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle,IN HANDLE LowPrecedenceKeyHandle,IN HANDLE FileHandle)1706 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle,
1707                  IN HANDLE LowPrecedenceKeyHandle,
1708                  IN HANDLE FileHandle)
1709 {
1710     NTSTATUS Status;
1711     KPROCESSOR_MODE PreviousMode;
1712     HANDLE KmFileHandle = NULL;
1713     PCM_KEY_BODY HighPrecedenceKeyObject = NULL;
1714     PCM_KEY_BODY LowPrecedenceKeyObject = NULL;
1715 
1716     PAGED_CODE();
1717 
1718     DPRINT("NtSaveMergedKeys(0x%p, 0x%p, 0x%p)\n",
1719            HighPrecedenceKeyHandle, LowPrecedenceKeyHandle, FileHandle);
1720 
1721     PreviousMode = ExGetPreviousMode();
1722 
1723     /* Validate privilege */
1724     if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode))
1725     {
1726         return STATUS_PRIVILEGE_NOT_HELD;
1727     }
1728 
1729     /* Make sure the target file handle is a kernel handle */
1730     Status = CmpConvertHandleToKernelHandle(FileHandle,
1731                                             IoFileObjectType,
1732                                             FILE_WRITE_DATA,
1733                                             PreviousMode,
1734                                             &KmFileHandle);
1735     if (!NT_SUCCESS(Status))
1736         goto Quit;
1737 
1738     /* Verify that the handles are valid and are registry keys */
1739     Status = ObReferenceObjectByHandle(HighPrecedenceKeyHandle,
1740                                        KEY_READ,
1741                                        CmpKeyObjectType,
1742                                        PreviousMode,
1743                                        (PVOID*)&HighPrecedenceKeyObject,
1744                                        NULL);
1745     if (!NT_SUCCESS(Status))
1746         goto Quit;
1747 
1748     Status = ObReferenceObjectByHandle(LowPrecedenceKeyHandle,
1749                                        KEY_READ,
1750                                        CmpKeyObjectType,
1751                                        PreviousMode,
1752                                        (PVOID*)&LowPrecedenceKeyObject,
1753                                        NULL);
1754     if (!NT_SUCCESS(Status))
1755         goto Quit;
1756 
1757     /* Call the internal API */
1758     Status = CmSaveMergedKeys(HighPrecedenceKeyObject->KeyControlBlock,
1759                               LowPrecedenceKeyObject->KeyControlBlock,
1760                               KmFileHandle);
1761 
1762 Quit:
1763     /* Dereference the opened key objects */
1764     if (LowPrecedenceKeyObject)
1765         ObDereferenceObject(LowPrecedenceKeyObject);
1766     if (HighPrecedenceKeyObject)
1767         ObDereferenceObject(HighPrecedenceKeyObject);
1768 
1769     /* Close the local kernel handle */
1770     if (KmFileHandle)
1771         ObCloseHandle(KmFileHandle, KernelMode);
1772 
1773     return Status;
1774 }
1775 
1776 NTSTATUS
1777 NTAPI
NtSetInformationKey(IN HANDLE KeyHandle,IN KEY_SET_INFORMATION_CLASS KeyInformationClass,IN PVOID KeyInformation,IN ULONG KeyInformationLength)1778 NtSetInformationKey(IN HANDLE KeyHandle,
1779                     IN KEY_SET_INFORMATION_CLASS KeyInformationClass,
1780                     IN PVOID KeyInformation,
1781                     IN ULONG KeyInformationLength)
1782 {
1783     UNIMPLEMENTED;
1784     return STATUS_NOT_IMPLEMENTED;
1785 }
1786 
1787 NTSTATUS
1788 NTAPI
NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes)1789 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes)
1790 {
1791     return NtUnloadKey2(KeyObjectAttributes, 0);
1792 }
1793 
1794 NTSTATUS
1795 NTAPI
NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,IN ULONG Flags)1796 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
1797              IN ULONG Flags)
1798 {
1799     NTSTATUS Status;
1800     OBJECT_ATTRIBUTES CapturedTargetKey;
1801     UNICODE_STRING ObjectName;
1802     HANDLE KmTargetKeyRootDir = NULL;
1803     CM_PARSE_CONTEXT ParseContext = {0};
1804     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1805     PCM_KEY_BODY KeyBody = NULL;
1806     HANDLE Handle;
1807 
1808     PAGED_CODE();
1809 
1810     /* Validate privilege */
1811     if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode))
1812     {
1813         DPRINT1("Restore Privilege missing!\n");
1814         return STATUS_PRIVILEGE_NOT_HELD;
1815     }
1816 
1817     /* Check for user-mode caller */
1818     if (PreviousMode != KernelMode)
1819     {
1820         /* Prepare to probe parameters */
1821         _SEH2_TRY
1822         {
1823             /* Probe object attributes */
1824             ProbeForRead(TargetKey,
1825                          sizeof(OBJECT_ATTRIBUTES),
1826                          sizeof(ULONG));
1827 
1828             CapturedTargetKey = *TargetKey;
1829 
1830             /* Probe the string */
1831             ObjectName = ProbeForReadUnicodeString(CapturedTargetKey.ObjectName);
1832             ProbeForRead(ObjectName.Buffer,
1833                          ObjectName.Length,
1834                          sizeof(WCHAR));
1835 
1836             CapturedTargetKey.ObjectName = &ObjectName;
1837         }
1838         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1839         {
1840             /* Return the exception code */
1841             _SEH2_YIELD(return _SEH2_GetExceptionCode());
1842         }
1843         _SEH2_END;
1844     }
1845     else
1846     {
1847         /* Save the target attributes directly */
1848         CapturedTargetKey = *TargetKey;
1849     }
1850 
1851     /* Make sure the target key root directory handle is a kernel handle */
1852     Status = CmpConvertHandleToKernelHandle(CapturedTargetKey.RootDirectory,
1853                                             CmpKeyObjectType,
1854                                             KEY_WRITE,
1855                                             PreviousMode,
1856                                             &KmTargetKeyRootDir);
1857     if (!NT_SUCCESS(Status))
1858         return Status;
1859     CapturedTargetKey.RootDirectory = KmTargetKeyRootDir;
1860     CapturedTargetKey.Attributes |= OBJ_KERNEL_HANDLE;
1861 
1862     /* Setup the parse context */
1863     ParseContext.CreateOperation = TRUE;
1864     ParseContext.CreateOptions = REG_OPTION_BACKUP_RESTORE;
1865 
1866     /* Do the create */
1867     /* Open a local handle to the key */
1868     Status = ObOpenObjectByName(&CapturedTargetKey,
1869                                 CmpKeyObjectType,
1870                                 KernelMode,
1871                                 NULL,
1872                                 KEY_WRITE,
1873                                 &ParseContext,
1874                                 &Handle);
1875     if (NT_SUCCESS(Status))
1876     {
1877         /* Reference the key object */
1878         Status = ObReferenceObjectByHandle(Handle,
1879                                            KEY_WRITE,
1880                                            CmpKeyObjectType,
1881                                            KernelMode,
1882                                            (PVOID*)&KeyBody,
1883                                            NULL);
1884 
1885         /* Close the handle */
1886         ObCloseHandle(Handle, KernelMode);
1887     }
1888 
1889     /* Close the local kernel handle */
1890     if (KmTargetKeyRootDir)
1891         ObCloseHandle(KmTargetKeyRootDir, KernelMode);
1892 
1893     /* Return if a failure was encountered */
1894     if (!NT_SUCCESS(Status))
1895         return Status;
1896 
1897     /*
1898      * Lock down the entire registry when we unload a hive.
1899      *
1900      * NOTE: We might block other threads of other processes that do
1901      * operations with unrelated keys of other hives when we lock
1902      * the registry for exclusive use by the calling thread that does
1903      * the unloading. If this turns out to cause a major overhead we
1904      * have to rethink the locking mechanism here (prior commit - f1d2a44).
1905      */
1906     CmpLockRegistryExclusive();
1907     ExAcquirePushLockExclusive(&CmpLoadHiveLock);
1908 
1909     /* Check if it's being deleted already */
1910     if (KeyBody->KeyControlBlock->Delete)
1911     {
1912         /* Return appropriate status */
1913         Status = STATUS_KEY_DELETED;
1914         goto Quit;
1915     }
1916 
1917     /* Check if it's a read-only key */
1918     if (KeyBody->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
1919     {
1920         /* Return appropriate status */
1921         Status = STATUS_ACCESS_DENIED;
1922         goto Quit;
1923     }
1924 
1925     /* Call the internal API. Note that CmUnloadKey() unlocks the registry only on success. */
1926     Status = CmUnloadKey(KeyBody->KeyControlBlock, Flags);
1927 
1928 Quit:
1929     /* If CmUnloadKey() failed we need to unlock registry ourselves */
1930     if (!NT_SUCCESS(Status))
1931     {
1932         /* Unlock the hive loading and registry locks */
1933         ExReleasePushLockExclusive(&CmpLoadHiveLock);
1934         CmpUnlockRegistry();
1935     }
1936 
1937     /* Dereference the key */
1938     ObDereferenceObject(KeyBody);
1939 
1940     /* Return status */
1941     return Status;
1942 }
1943 
1944 NTSTATUS
1945 NTAPI
NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,IN HANDLE Event)1946 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
1947               IN HANDLE Event)
1948 {
1949     UNIMPLEMENTED;
1950     return STATUS_NOT_IMPLEMENTED;
1951 }
1952 
1953 /* EOF */
1954