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