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