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