Merge freeldr from amd64 branch:
[reactos.git] / reactos / ntoskrnl / config / ntapi.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmapi.c
5 * PURPOSE: Configuration Manager - Internal Registry APIs
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "ntoskrnl.h"
12 #define NDEBUG
13 #include "debug.h"
14
15 BOOLEAN CmBootAcceptFirstTime = TRUE;
16 BOOLEAN CmFirstTime = TRUE;
17
18 /* FUNCTIONS *****************************************************************/
19
20 NTSTATUS
21 NTAPI
22 NtCreateKey(OUT PHANDLE KeyHandle,
23 IN ACCESS_MASK DesiredAccess,
24 IN POBJECT_ATTRIBUTES ObjectAttributes,
25 IN ULONG TitleIndex,
26 IN PUNICODE_STRING Class,
27 IN ULONG CreateOptions,
28 OUT PULONG Disposition)
29 {
30 NTSTATUS Status = STATUS_SUCCESS;
31 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
32 CM_PARSE_CONTEXT ParseContext = {0};
33 HANDLE Handle;
34 PAGED_CODE();
35 DPRINT("NtCreateKey(OB name %wZ)\n", ObjectAttributes->ObjectName);
36
37 /* Check for user-mode caller */
38 if (PreviousMode != KernelMode)
39 {
40 /* Prepare to probe parameters */
41 _SEH2_TRY
42 {
43 /* Check if we have a class */
44 if (Class)
45 {
46 /* Probe it */
47 ParseContext.Class = ProbeForReadUnicodeString(Class);
48 ProbeForRead(ParseContext.Class.Buffer,
49 ParseContext.Class.Length,
50 sizeof(WCHAR));
51 }
52
53 /* Probe the key handle */
54 ProbeForWriteHandle(KeyHandle);
55 *KeyHandle = NULL;
56
57 /* Probe object attributes */
58 ProbeForRead(ObjectAttributes,
59 sizeof(OBJECT_ATTRIBUTES),
60 sizeof(ULONG));
61 }
62 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
63 {
64 /* Get the error code */
65 Status = _SEH2_GetExceptionCode();
66 }
67 _SEH2_END;
68 if(!NT_SUCCESS(Status)) return Status;
69 }
70 else
71 {
72 /* Save the class directly */
73 if (Class) ParseContext.Class = *Class;
74 }
75
76 /* Setup the parse context */
77 ParseContext.CreateOperation = TRUE;
78 ParseContext.CreateOptions = CreateOptions;
79
80 /* Do the create */
81 Status = ObOpenObjectByName(ObjectAttributes,
82 CmpKeyObjectType,
83 PreviousMode,
84 NULL,
85 DesiredAccess,
86 &ParseContext,
87 &Handle);
88
89 _SEH2_TRY
90 {
91 /* Return data to user */
92 if (NT_SUCCESS(Status)) *KeyHandle = Handle;
93 if (Disposition) *Disposition = ParseContext.Disposition;
94 }
95 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
96 {
97 /* Get the status */
98 Status = _SEH2_GetExceptionCode();
99 }
100 _SEH2_END;
101
102 /* Return status */
103 return Status;
104 }
105
106 NTSTATUS
107 NTAPI
108 NtOpenKey(OUT PHANDLE KeyHandle,
109 IN ACCESS_MASK DesiredAccess,
110 IN POBJECT_ATTRIBUTES ObjectAttributes)
111 {
112 CM_PARSE_CONTEXT ParseContext = {0};
113 HANDLE Handle;
114 NTSTATUS Status = STATUS_SUCCESS;
115 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
116 PAGED_CODE();
117 DPRINT("NtOpenKey(OB 0x%wZ)\n", ObjectAttributes->ObjectName);
118
119 /* Check for user-mode caller */
120 if (PreviousMode != KernelMode)
121 {
122 /* Prepare to probe parameters */
123 _SEH2_TRY
124 {
125 /* Probe the key handle */
126 ProbeForWriteHandle(KeyHandle);
127 *KeyHandle = NULL;
128
129 /* Probe object attributes */
130 ProbeForRead(ObjectAttributes,
131 sizeof(OBJECT_ATTRIBUTES),
132 sizeof(ULONG));
133 }
134 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
135 {
136 /* Get the status */
137 Status = _SEH2_GetExceptionCode();
138 }
139 _SEH2_END;
140 if(!NT_SUCCESS(Status)) return Status;
141 }
142
143 /* Just let the object manager handle this */
144 Status = ObOpenObjectByName(ObjectAttributes,
145 CmpKeyObjectType,
146 ExGetPreviousMode(),
147 NULL,
148 DesiredAccess,
149 &ParseContext,
150 &Handle);
151
152 /* Only do this if we succeeded */
153 if (NT_SUCCESS(Status))
154 {
155 _SEH2_TRY
156 {
157 /* Return the handle to caller */
158 *KeyHandle = Handle;
159 }
160 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
161 {
162 /* Get the status */
163 Status = _SEH2_GetExceptionCode();
164 }
165 _SEH2_END;
166 }
167
168 /* Return status */
169 return Status;
170 }
171
172
173 NTSTATUS
174 NTAPI
175 NtDeleteKey(IN HANDLE KeyHandle)
176 {
177 PCM_KEY_BODY KeyObject;
178 NTSTATUS Status;
179 REG_DELETE_KEY_INFORMATION DeleteKeyInfo;
180 REG_POST_OPERATION_INFORMATION PostOperationInfo;
181 PAGED_CODE();
182 DPRINT("NtDeleteKey(KH 0x%p)\n", KeyHandle);
183
184 /* Verify that the handle is valid and is a registry key */
185 Status = ObReferenceObjectByHandle(KeyHandle,
186 DELETE,
187 CmpKeyObjectType,
188 ExGetPreviousMode(),
189 (PVOID*)&KeyObject,
190 NULL);
191 if (!NT_SUCCESS(Status)) return Status;
192
193 /* Setup the callback */
194 PostOperationInfo.Object = (PVOID)KeyObject;
195 DeleteKeyInfo.Object = (PVOID)KeyObject;
196 Status = CmiCallRegisteredCallbacks(RegNtPreDeleteKey, &DeleteKeyInfo);
197 if (NT_SUCCESS(Status))
198 {
199 /* Check if we are read-only */
200 if ((KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) ||
201 (KeyObject->KeyControlBlock->ParentKcb->ExtFlags & CM_KCB_READ_ONLY_KEY))
202 {
203 /* Fail */
204 Status = STATUS_ACCESS_DENIED;
205 }
206 else
207 {
208 /* Call the internal API */
209 Status = CmDeleteKey(KeyObject);
210 }
211
212 /* Do post callback */
213 PostOperationInfo.Status = Status;
214 CmiCallRegisteredCallbacks(RegNtPostDeleteKey, &PostOperationInfo);
215 }
216
217 /* Dereference the object */
218 ObDereferenceObject(KeyObject);
219 return Status;
220 }
221
222 NTSTATUS
223 NTAPI
224 NtEnumerateKey(IN HANDLE KeyHandle,
225 IN ULONG Index,
226 IN KEY_INFORMATION_CLASS KeyInformationClass,
227 OUT PVOID KeyInformation,
228 IN ULONG Length,
229 OUT PULONG ResultLength)
230 {
231 NTSTATUS Status;
232 PCM_KEY_BODY KeyObject;
233 REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo;
234 REG_POST_OPERATION_INFORMATION PostOperationInfo;
235 PAGED_CODE();
236 DPRINT("NtEnumerateKey() KH 0x%x, Index 0x%x, KIC %d, Length %d\n",
237 KeyHandle, Index, KeyInformationClass, Length);
238
239 /* Reject classes we don't know about */
240 if ((KeyInformationClass != KeyBasicInformation) &&
241 (KeyInformationClass != KeyNodeInformation) &&
242 (KeyInformationClass != KeyFullInformation))
243 {
244 /* Fail */
245 return STATUS_INVALID_PARAMETER;
246 }
247
248 /* Verify that the handle is valid and is a registry key */
249 Status = ObReferenceObjectByHandle(KeyHandle,
250 KEY_ENUMERATE_SUB_KEYS,
251 CmpKeyObjectType,
252 ExGetPreviousMode(),
253 (PVOID*)&KeyObject,
254 NULL);
255 if (!NT_SUCCESS(Status)) return Status;
256
257 /* Setup the callback */
258 PostOperationInfo.Object = (PVOID)KeyObject;
259 EnumerateKeyInfo.Object = (PVOID)KeyObject;
260 EnumerateKeyInfo.Index = Index;
261 EnumerateKeyInfo.KeyInformationClass = KeyInformationClass;
262 EnumerateKeyInfo.Length = Length;
263 EnumerateKeyInfo.ResultLength = ResultLength;
264
265 /* Do the callback */
266 Status = CmiCallRegisteredCallbacks(RegNtPreEnumerateKey, &EnumerateKeyInfo);
267 if (NT_SUCCESS(Status))
268 {
269 /* Call the internal API */
270 Status = CmEnumerateKey(KeyObject->KeyControlBlock,
271 Index,
272 KeyInformationClass,
273 KeyInformation,
274 Length,
275 ResultLength);
276
277 /* Do the post callback */
278 PostOperationInfo.Status = Status;
279 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey, &PostOperationInfo);
280 }
281
282 /* Dereference and return status */
283 ObDereferenceObject(KeyObject);
284 return Status;
285 }
286
287 NTSTATUS
288 NTAPI
289 NtEnumerateValueKey(IN HANDLE KeyHandle,
290 IN ULONG Index,
291 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
292 OUT PVOID KeyValueInformation,
293 IN ULONG Length,
294 OUT PULONG ResultLength)
295 {
296 NTSTATUS Status;
297 PCM_KEY_BODY KeyObject;
298 REG_ENUMERATE_VALUE_KEY_INFORMATION EnumerateValueKeyInfo;
299 REG_POST_OPERATION_INFORMATION PostOperationInfo;
300 PAGED_CODE();
301 DPRINT("NtEnumerateValueKey() KH 0x%x, Index 0x%x, KVIC %d, Length %d\n",
302 KeyHandle, Index, KeyValueInformationClass, Length);
303
304 /* Reject classes we don't know about */
305 if ((KeyValueInformationClass != KeyValueBasicInformation) &&
306 (KeyValueInformationClass != KeyValueFullInformation) &&
307 (KeyValueInformationClass != KeyValuePartialInformation))
308 {
309 /* Fail */
310 return STATUS_INVALID_PARAMETER;
311 }
312
313 /* Verify that the handle is valid and is a registry key */
314 Status = ObReferenceObjectByHandle(KeyHandle,
315 KEY_QUERY_VALUE,
316 CmpKeyObjectType,
317 ExGetPreviousMode(),
318 (PVOID*)&KeyObject,
319 NULL);
320 if (!NT_SUCCESS(Status)) return Status;
321
322 /* Setup the callback */
323 PostOperationInfo.Object = (PVOID)KeyObject;
324 EnumerateValueKeyInfo.Object = (PVOID)KeyObject;
325 EnumerateValueKeyInfo.Index = Index;
326 EnumerateValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass;
327 EnumerateValueKeyInfo.KeyValueInformation = KeyValueInformation;
328 EnumerateValueKeyInfo.Length = Length;
329 EnumerateValueKeyInfo.ResultLength = ResultLength;
330
331 /* Do the callback */
332 Status = CmiCallRegisteredCallbacks(RegNtPreEnumerateValueKey,
333 &EnumerateValueKeyInfo);
334 if (NT_SUCCESS(Status))
335 {
336 /* Call the internal API */
337 Status = CmEnumerateValueKey(KeyObject->KeyControlBlock,
338 Index,
339 KeyValueInformationClass,
340 KeyValueInformation,
341 Length,
342 ResultLength);
343
344 /* Do the post callback */
345 PostOperationInfo.Status = Status;
346 CmiCallRegisteredCallbacks(RegNtPostEnumerateValueKey, &PostOperationInfo);
347 }
348
349 ObDereferenceObject(KeyObject);
350 return Status;
351 }
352
353 NTSTATUS
354 NTAPI
355 NtQueryKey(IN HANDLE KeyHandle,
356 IN KEY_INFORMATION_CLASS KeyInformationClass,
357 OUT PVOID KeyInformation,
358 IN ULONG Length,
359 OUT PULONG ResultLength)
360 {
361 NTSTATUS Status;
362 PCM_KEY_BODY KeyObject;
363 REG_QUERY_KEY_INFORMATION QueryKeyInfo;
364 REG_POST_OPERATION_INFORMATION PostOperationInfo;
365 OBJECT_HANDLE_INFORMATION HandleInfo;
366 PAGED_CODE();
367 DPRINT("NtQueryKey() KH 0x%x, KIC %d, Length %d\n",
368 KeyHandle, KeyInformationClass, Length);
369
370 /* Reject invalid classes */
371 if ((KeyInformationClass != KeyBasicInformation) &&
372 (KeyInformationClass != KeyNodeInformation) &&
373 (KeyInformationClass != KeyFullInformation) &&
374 (KeyInformationClass != KeyNameInformation) &&
375 (KeyInformationClass != KeyCachedInformation) &&
376 (KeyInformationClass != KeyFlagsInformation))
377 {
378 /* Fail */
379 return STATUS_INVALID_PARAMETER;
380 }
381
382 /* Check if just the name is required */
383 if (KeyInformationClass == KeyNameInformation)
384 {
385 /* Ignore access level */
386 Status = ObReferenceObjectByHandle(KeyHandle,
387 0,
388 CmpKeyObjectType,
389 ExGetPreviousMode(),
390 (PVOID*)&KeyObject,
391 &HandleInfo);
392 if (NT_SUCCESS(Status))
393 {
394 /* At least a single bit of access is required */
395 if (!HandleInfo.GrantedAccess)
396 {
397 /* No such luck */
398 ObDereferenceObject(KeyObject);
399 Status = STATUS_ACCESS_DENIED;
400 }
401 }
402 }
403 else
404 {
405 /* Get a reference */
406 Status = ObReferenceObjectByHandle(KeyHandle,
407 KEY_QUERY_VALUE,
408 CmpKeyObjectType,
409 ExGetPreviousMode(),
410 (PVOID*)&KeyObject,
411 NULL);
412 }
413
414 /* Quit on failure */
415 if (!NT_SUCCESS(Status)) return Status;
416
417 /* Setup the callback */
418 PostOperationInfo.Object = (PVOID)KeyObject;
419 QueryKeyInfo.Object = (PVOID)KeyObject;
420 QueryKeyInfo.KeyInformationClass = KeyInformationClass;
421 QueryKeyInfo.KeyInformation = KeyInformation;
422 QueryKeyInfo.Length = Length;
423 QueryKeyInfo.ResultLength = ResultLength;
424
425 /* Do the callback */
426 Status = CmiCallRegisteredCallbacks(RegNtPreQueryKey, &QueryKeyInfo);
427 if (NT_SUCCESS(Status))
428 {
429 /* Call the internal API */
430 Status = CmQueryKey(KeyObject->KeyControlBlock,
431 KeyInformationClass,
432 KeyInformation,
433 Length,
434 ResultLength);
435
436 /* Do the post callback */
437 PostOperationInfo.Status = Status;
438 CmiCallRegisteredCallbacks(RegNtPostQueryKey, &PostOperationInfo);
439 }
440
441 /* Dereference and return status */
442 ObDereferenceObject(KeyObject);
443 return Status;
444 }
445
446 NTSTATUS
447 NTAPI
448 NtQueryValueKey(IN HANDLE KeyHandle,
449 IN PUNICODE_STRING ValueName,
450 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
451 OUT PVOID KeyValueInformation,
452 IN ULONG Length,
453 OUT PULONG ResultLength)
454 {
455 NTSTATUS Status;
456 PCM_KEY_BODY KeyObject;
457 REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo;
458 REG_POST_OPERATION_INFORMATION PostOperationInfo;
459 UNICODE_STRING ValueNameCopy = *ValueName;
460 PAGED_CODE();
461 DPRINT("NtQueryValueKey() KH 0x%x, VN '%wZ', KVIC %d, Length %d\n",
462 KeyHandle, ValueName, KeyValueInformationClass, Length);
463
464 /* Verify that the handle is valid and is a registry key */
465 Status = ObReferenceObjectByHandle(KeyHandle,
466 KEY_QUERY_VALUE,
467 CmpKeyObjectType,
468 ExGetPreviousMode(),
469 (PVOID*)&KeyObject,
470 NULL);
471 if (!NT_SUCCESS(Status)) return Status;
472
473 /* Make sure the name is aligned properly */
474 if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1)))
475 {
476 /* It isn't, so we'll fail */
477 ObDereferenceObject(KeyObject);
478 return STATUS_INVALID_PARAMETER;
479 }
480 else
481 {
482 /* Ignore any null characters at the end */
483 while ((ValueNameCopy.Length) &&
484 !(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1]))
485 {
486 /* Skip it */
487 ValueNameCopy.Length -= sizeof(WCHAR);
488 }
489 }
490
491 /* Setup the callback */
492 PostOperationInfo.Object = (PVOID)KeyObject;
493 QueryValueKeyInfo.Object = (PVOID)KeyObject;
494 QueryValueKeyInfo.ValueName = &ValueNameCopy;
495 QueryValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass;
496 QueryValueKeyInfo.Length = Length;
497 QueryValueKeyInfo.ResultLength = ResultLength;
498
499 /* Do the callback */
500 Status = CmiCallRegisteredCallbacks(RegNtPreQueryValueKey, &QueryValueKeyInfo);
501 if (NT_SUCCESS(Status))
502 {
503 /* Call the internal API */
504 Status = CmQueryValueKey(KeyObject->KeyControlBlock,
505 ValueNameCopy,
506 KeyValueInformationClass,
507 KeyValueInformation,
508 Length,
509 ResultLength);
510
511 /* Do the post callback */
512 PostOperationInfo.Status = Status;
513 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey, &PostOperationInfo);
514 }
515
516 /* Dereference and return status */
517 ObDereferenceObject(KeyObject);
518 return Status;
519 }
520
521 NTSTATUS
522 NTAPI
523 NtSetValueKey(IN HANDLE KeyHandle,
524 IN PUNICODE_STRING ValueName,
525 IN ULONG TitleIndex,
526 IN ULONG Type,
527 IN PVOID Data,
528 IN ULONG DataSize)
529 {
530 NTSTATUS Status;
531 PCM_KEY_BODY KeyObject;
532 REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo;
533 REG_POST_OPERATION_INFORMATION PostOperationInfo;
534 UNICODE_STRING ValueNameCopy = *ValueName;
535 PAGED_CODE();
536 DPRINT("NtSetValueKey() KH 0x%x, VN '%wZ', TI %x, T %d, DS %d\n",
537 KeyHandle, ValueName, TitleIndex, Type, DataSize);
538
539 /* Verify that the handle is valid and is a registry key */
540 Status = ObReferenceObjectByHandle(KeyHandle,
541 KEY_SET_VALUE,
542 CmpKeyObjectType,
543 ExGetPreviousMode(),
544 (PVOID*)&KeyObject,
545 NULL);
546 if (!NT_SUCCESS(Status)) return Status;
547
548 /* Make sure the name is aligned, not too long, and the data under 4GB */
549 if ( (ValueNameCopy.Length > 32767) ||
550 ((ValueNameCopy.Length & (sizeof(WCHAR) - 1))) ||
551 (DataSize > 0x80000000))
552 {
553 /* Fail */
554 ObDereferenceObject(KeyObject);
555 return STATUS_INVALID_PARAMETER;
556 }
557
558 /* Ignore any null characters at the end */
559 while ((ValueNameCopy.Length) &&
560 !(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1]))
561 {
562 /* Skip it */
563 ValueNameCopy.Length -= sizeof(WCHAR);
564 }
565
566 /* Don't touch read-only keys */
567 if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
568 {
569 /* Fail */
570 ObDereferenceObject(KeyObject);
571 return STATUS_ACCESS_DENIED;
572 }
573
574 /* Setup callback */
575 PostOperationInfo.Object = (PVOID)KeyObject;
576 SetValueKeyInfo.Object = (PVOID)KeyObject;
577 SetValueKeyInfo.ValueName = ValueName;
578 SetValueKeyInfo.TitleIndex = TitleIndex;
579 SetValueKeyInfo.Type = Type;
580 SetValueKeyInfo.Data = Data;
581 SetValueKeyInfo.DataSize = DataSize;
582
583 /* Do the callback */
584 Status = CmiCallRegisteredCallbacks(RegNtPreSetValueKey, &SetValueKeyInfo);
585 if (NT_SUCCESS(Status))
586 {
587 /* Call the internal API */
588 Status = CmSetValueKey(KeyObject->KeyControlBlock,
589 &ValueNameCopy,
590 Type,
591 Data,
592 DataSize);
593 }
594
595 /* Do the post-callback */
596 PostOperationInfo.Status = Status;
597 CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
598
599 /* Dereference and return status */
600 ObDereferenceObject(KeyObject);
601 return Status;
602 }
603
604 NTSTATUS
605 NTAPI
606 NtDeleteValueKey(IN HANDLE KeyHandle,
607 IN PUNICODE_STRING ValueName)
608 {
609 PCM_KEY_BODY KeyObject;
610 NTSTATUS Status;
611 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo;
612 REG_POST_OPERATION_INFORMATION PostOperationInfo;
613 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
614 UNICODE_STRING ValueNameCopy = *ValueName;
615 PAGED_CODE();
616
617 /* Verify that the handle is valid and is a registry key */
618 Status = ObReferenceObjectByHandle(KeyHandle,
619 KEY_SET_VALUE,
620 CmpKeyObjectType,
621 PreviousMode,
622 (PVOID *)&KeyObject,
623 NULL);
624 if (!NT_SUCCESS(Status)) return Status;
625
626 /* Don't touch read-only keys */
627 if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
628 {
629 /* Fail */
630 ObDereferenceObject(KeyObject);
631 return STATUS_ACCESS_DENIED;
632 }
633
634 /* Make sure the name is aligned properly */
635 if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1)))
636 {
637 /* It isn't, so we'll fail */
638 ObDereferenceObject(KeyObject);
639 return STATUS_INVALID_PARAMETER;
640 }
641
642 /* Do the callback */
643 DeleteValueKeyInfo.Object = (PVOID)KeyObject;
644 DeleteValueKeyInfo.ValueName = ValueName;
645 Status = CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey,
646 &DeleteValueKeyInfo);
647 if (NT_SUCCESS(Status))
648 {
649 /* Call the internal API */
650 Status = CmDeleteValueKey(KeyObject->KeyControlBlock, ValueNameCopy);
651
652 /* Do the post callback */
653 PostOperationInfo.Object = (PVOID)KeyObject;
654 PostOperationInfo.Status = Status;
655 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey,
656 &PostOperationInfo);
657 }
658
659 /* Dereference the key body */
660 ObDereferenceObject(KeyObject);
661 return Status;
662 }
663
664 NTSTATUS
665 NTAPI
666 NtFlushKey(IN HANDLE KeyHandle)
667 {
668 NTSTATUS Status;
669 PCM_KEY_BODY KeyObject;
670 PAGED_CODE();
671
672 /* Get the key object */
673 Status = ObReferenceObjectByHandle(KeyHandle,
674 0,
675 CmpKeyObjectType,
676 ExGetPreviousMode(),
677 (PVOID*)&KeyObject,
678 NULL);
679 if (!NT_SUCCESS(Status)) return Status;
680
681 /* Lock the registry */
682 CmpLockRegistry();
683
684 /* Lock the KCB */
685 CmpAcquireKcbLockShared(KeyObject->KeyControlBlock);
686
687 /* Make sure KCB isn't deleted */
688 if (KeyObject->KeyControlBlock->Delete)
689 {
690 /* Fail */
691 Status = STATUS_KEY_DELETED;
692 }
693 else
694 {
695 /* Call the internal API */
696 Status = CmFlushKey(KeyObject->KeyControlBlock, FALSE);
697 }
698
699 /* Release the locks */
700 CmpReleaseKcbLock(KeyObject->KeyControlBlock);
701 CmpUnlockRegistry();
702
703 /* Dereference the object and return status */
704 ObDereferenceObject(KeyObject);
705 return Status;
706 }
707
708 NTSTATUS
709 NTAPI
710 NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
711 IN POBJECT_ATTRIBUTES FileObjectAttributes)
712 {
713 /* Call the newer API */
714 return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, 0, NULL);
715 }
716
717 NTSTATUS
718 NTAPI
719 NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
720 IN POBJECT_ATTRIBUTES FileObjectAttributes,
721 IN ULONG Flags)
722 {
723 /* Call the newer API */
724 return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, Flags, NULL);
725 }
726
727 NTSTATUS
728 NTAPI
729 NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
730 IN POBJECT_ATTRIBUTES SourceFile,
731 IN ULONG Flags,
732 IN HANDLE TrustClassKey)
733 {
734 NTSTATUS Status;
735 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
736 PCM_KEY_BODY KeyBody = NULL;
737 PAGED_CODE();
738
739 /* Validate flags */
740 if (Flags & ~REG_NO_LAZY_FLUSH) return STATUS_INVALID_PARAMETER;
741
742 /* Validate privilege */
743 if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode))
744 {
745 /* Fail */
746 DPRINT1("Restore Privilege missing!\n");
747 return STATUS_PRIVILEGE_NOT_HELD;
748 }
749
750 /* Block APCs */
751 KeEnterCriticalRegion();
752
753 /* Check if we have a trust class */
754 if (TrustClassKey)
755 {
756 /* Reference it */
757 Status = ObReferenceObjectByHandle(TrustClassKey,
758 0,
759 CmpKeyObjectType,
760 PreviousMode,
761 (PVOID *)&KeyBody,
762 NULL);
763 }
764
765 /* Call the internal API */
766 Status = CmLoadKey(TargetKey, SourceFile, Flags, KeyBody);
767
768 /* Dereference the trust key, if any */
769 if (KeyBody) ObDereferenceObject(KeyBody);
770
771 /* Bring back APCs */
772 KeLeaveCriticalRegion();
773
774 /* Return status */
775 return Status;
776 }
777
778 NTSTATUS
779 NTAPI
780 NtNotifyChangeKey(IN HANDLE KeyHandle,
781 IN HANDLE Event,
782 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
783 IN PVOID ApcContext OPTIONAL,
784 OUT PIO_STATUS_BLOCK IoStatusBlock,
785 IN ULONG CompletionFilter,
786 IN BOOLEAN WatchTree,
787 OUT PVOID Buffer,
788 IN ULONG Length,
789 IN BOOLEAN Asynchronous)
790 {
791 /* Call the newer API */
792 return NtNotifyChangeMultipleKeys(KeyHandle,
793 0,
794 NULL,
795 Event,
796 ApcRoutine,
797 ApcContext,
798 IoStatusBlock,
799 CompletionFilter,
800 WatchTree,
801 Buffer,
802 Length,
803 Asynchronous);
804 }
805
806 NTSTATUS
807 NTAPI
808 NtInitializeRegistry(IN USHORT Flag)
809 {
810 BOOLEAN SetupBoot;
811 NTSTATUS Status = STATUS_SUCCESS;
812 PAGED_CODE();
813
814 /* Always do this as kernel mode */
815 if (KeGetPreviousMode() == UserMode) return ZwInitializeRegistry(Flag);
816
817 /* Validate flag */
818 if (Flag > CM_BOOT_FLAG_MAX) return STATUS_INVALID_PARAMETER;
819
820 /* Check if boot was accepted */
821 if ((Flag >= CM_BOOT_FLAG_ACCEPTED) && (Flag <= CM_BOOT_FLAG_MAX))
822 {
823 /* Only allow once */
824 if (!CmBootAcceptFirstTime) return STATUS_ACCESS_DENIED;
825 CmBootAcceptFirstTime = FALSE;
826
827 /* Get the control set accepted */
828 Flag -= CM_BOOT_FLAG_ACCEPTED;
829 if (Flag)
830 {
831 /* FIXME: Save the last known good boot */
832 //Status = CmpSaveBootControlSet(Flag);
833
834 /* Notify HAL */
835 HalEndOfBoot();
836
837 /* Enable lazy flush */
838 CmpHoldLazyFlush = FALSE;
839 CmpLazyFlush();
840 return Status;
841 }
842
843 /* Otherwise, invalid boot */
844 return STATUS_INVALID_PARAMETER;
845 }
846
847 /* Check if this was a setup boot */
848 SetupBoot = (Flag == CM_BOOT_FLAG_SETUP ? TRUE : FALSE);
849
850 /* Make sure we're only called once */
851 if (!CmFirstTime) return STATUS_ACCESS_DENIED;
852 CmFirstTime = FALSE;
853
854 /* Acquire registry lock */
855 //CmpLockRegistryExclusive();
856
857 /* Initialize the hives and lazy flusher */
858 CmpCmdInit(SetupBoot);
859
860 /* FIXME: Save version data */
861 //CmpSetVersionData();
862
863 /* Release the registry lock */
864 //CmpUnlockRegistry();
865 return STATUS_SUCCESS;
866 }
867
868 NTSTATUS
869 NTAPI
870 NtCompactKeys(IN ULONG Count,
871 IN PHANDLE KeyArray)
872 {
873 UNIMPLEMENTED;
874 return STATUS_NOT_IMPLEMENTED;
875 }
876
877 NTSTATUS
878 NTAPI
879 NtCompressKey(IN HANDLE Key)
880 {
881 UNIMPLEMENTED;
882 return STATUS_NOT_IMPLEMENTED;
883 }
884
885 NTSTATUS
886 NTAPI
887 NtLockProductActivationKeys(IN PULONG pPrivateVer,
888 IN PULONG pSafeMode)
889 {
890 UNIMPLEMENTED;
891 return STATUS_NOT_IMPLEMENTED;
892 }
893
894 NTSTATUS
895 NTAPI
896 NtLockRegistryKey(IN HANDLE KeyHandle)
897 {
898 UNIMPLEMENTED;
899 return STATUS_NOT_IMPLEMENTED;
900 }
901
902 NTSTATUS
903 NTAPI
904 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle,
905 IN ULONG Count,
906 IN POBJECT_ATTRIBUTES SlaveObjects,
907 IN HANDLE Event,
908 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
909 IN PVOID ApcContext OPTIONAL,
910 OUT PIO_STATUS_BLOCK IoStatusBlock,
911 IN ULONG CompletionFilter,
912 IN BOOLEAN WatchTree,
913 OUT PVOID Buffer,
914 IN ULONG Length,
915 IN BOOLEAN Asynchronous)
916 {
917 UNIMPLEMENTED;
918 return STATUS_NOT_IMPLEMENTED;
919 }
920
921 NTSTATUS
922 NTAPI
923 NtQueryMultipleValueKey(IN HANDLE KeyHandle,
924 IN OUT PKEY_VALUE_ENTRY ValueList,
925 IN ULONG NumberOfValues,
926 OUT PVOID Buffer,
927 IN OUT PULONG Length,
928 OUT PULONG ReturnLength)
929 {
930 UNIMPLEMENTED;
931 return STATUS_NOT_IMPLEMENTED;
932 }
933
934 NTSTATUS
935 NTAPI
936 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey,
937 OUT PULONG HandleCount)
938 {
939 UNIMPLEMENTED;
940 return STATUS_NOT_IMPLEMENTED;
941 }
942
943 NTSTATUS
944 NTAPI
945 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey,
946 IN ULONG BufferLength,
947 IN PVOID Buffer,
948 IN PULONG RequiredSize)
949 {
950 UNIMPLEMENTED;
951 return STATUS_NOT_IMPLEMENTED;
952 }
953
954 NTSTATUS
955 NTAPI
956 NtRenameKey(IN HANDLE KeyHandle,
957 IN PUNICODE_STRING ReplacementName)
958 {
959 UNIMPLEMENTED;
960 return STATUS_NOT_IMPLEMENTED;
961 }
962
963 NTSTATUS
964 NTAPI
965 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes,
966 IN HANDLE Key,
967 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
968 {
969 UNIMPLEMENTED;
970 return STATUS_NOT_IMPLEMENTED;
971 }
972
973 NTSTATUS
974 NTAPI
975 NtRestoreKey(IN HANDLE KeyHandle,
976 IN HANDLE FileHandle,
977 IN ULONG RestoreFlags)
978 {
979 UNIMPLEMENTED;
980 return STATUS_NOT_IMPLEMENTED;
981 }
982
983 NTSTATUS
984 NTAPI
985 NtSaveKey(IN HANDLE KeyHandle,
986 IN HANDLE FileHandle)
987 {
988 UNIMPLEMENTED;
989 return STATUS_NOT_IMPLEMENTED;
990 }
991
992 NTSTATUS
993 NTAPI
994 NtSaveKeyEx(IN HANDLE KeyHandle,
995 IN HANDLE FileHandle,
996 IN ULONG Flags)
997 {
998 UNIMPLEMENTED;
999 return STATUS_NOT_IMPLEMENTED;
1000 }
1001
1002 NTSTATUS
1003 NTAPI
1004 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle,
1005 IN HANDLE LowPrecedenceKeyHandle,
1006 IN HANDLE FileHandle)
1007 {
1008 UNIMPLEMENTED;
1009 return STATUS_NOT_IMPLEMENTED;
1010 }
1011
1012 NTSTATUS
1013 NTAPI
1014 NtSetInformationKey(IN HANDLE KeyHandle,
1015 IN KEY_SET_INFORMATION_CLASS KeyInformationClass,
1016 IN PVOID KeyInformation,
1017 IN ULONG KeyInformationLength)
1018 {
1019 UNIMPLEMENTED;
1020 return STATUS_NOT_IMPLEMENTED;
1021 }
1022
1023 NTSTATUS
1024 NTAPI
1025 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes)
1026 {
1027 UNIMPLEMENTED;
1028 return STATUS_NOT_IMPLEMENTED;
1029 }
1030
1031 NTSTATUS
1032 NTAPI
1033 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
1034 IN ULONG Flags)
1035 {
1036 UNIMPLEMENTED;
1037 return STATUS_NOT_IMPLEMENTED;
1038 }
1039
1040 NTSTATUS
1041 NTAPI
1042 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
1043 IN HANDLE Event)
1044 {
1045 UNIMPLEMENTED;
1046 return STATUS_NOT_IMPLEMENTED;
1047 }
1048
1049 /* EOF */