20176b3012589cfdf4faabb257383e2ec488f27a
[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 OPTIONAL,
27 IN ULONG CreateOptions,
28 OUT PULONG Disposition OPTIONAL)
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 if (Disposition) ProbeForWriteUlong(Disposition);
63 }
64 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
65 {
66 /* Get the error code */
67 Status = _SEH2_GetExceptionCode();
68 }
69 _SEH2_END;
70 if(!NT_SUCCESS(Status)) return Status;
71 }
72 else
73 {
74 /* Save the class directly */
75 if (Class) ParseContext.Class = *Class;
76 }
77
78 /* Setup the parse context */
79 ParseContext.CreateOperation = TRUE;
80 ParseContext.CreateOptions = CreateOptions;
81
82 /* Do the create */
83 Status = ObOpenObjectByName(ObjectAttributes,
84 CmpKeyObjectType,
85 PreviousMode,
86 NULL,
87 DesiredAccess,
88 &ParseContext,
89 &Handle);
90
91 _SEH2_TRY
92 {
93 /* Return data to user */
94 if (NT_SUCCESS(Status)) *KeyHandle = Handle;
95 if (Disposition) *Disposition = ParseContext.Disposition;
96 }
97 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
98 {
99 /* Get the status */
100 Status = _SEH2_GetExceptionCode();
101 }
102 _SEH2_END;
103
104 /* Return status */
105 return Status;
106 }
107
108 NTSTATUS
109 NTAPI
110 NtOpenKey(OUT PHANDLE KeyHandle,
111 IN ACCESS_MASK DesiredAccess,
112 IN POBJECT_ATTRIBUTES ObjectAttributes)
113 {
114 CM_PARSE_CONTEXT ParseContext = {0};
115 HANDLE Handle;
116 NTSTATUS Status = STATUS_SUCCESS;
117 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
118 PAGED_CODE();
119 DPRINT("NtOpenKey(OB 0x%wZ)\n", ObjectAttributes->ObjectName);
120
121 /* Check for user-mode caller */
122 if (PreviousMode != KernelMode)
123 {
124 /* Prepare to probe parameters */
125 _SEH2_TRY
126 {
127 /* Probe the key handle */
128 ProbeForWriteHandle(KeyHandle);
129 *KeyHandle = NULL;
130
131 /* Probe object attributes */
132 ProbeForRead(ObjectAttributes,
133 sizeof(OBJECT_ATTRIBUTES),
134 sizeof(ULONG));
135 }
136 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
137 {
138 /* Get the status */
139 Status = _SEH2_GetExceptionCode();
140 }
141 _SEH2_END;
142 if(!NT_SUCCESS(Status)) return Status;
143 }
144
145 /* Just let the object manager handle this */
146 Status = ObOpenObjectByName(ObjectAttributes,
147 CmpKeyObjectType,
148 ExGetPreviousMode(),
149 NULL,
150 DesiredAccess,
151 &ParseContext,
152 &Handle);
153
154 /* Only do this if we succeeded */
155 if (NT_SUCCESS(Status))
156 {
157 _SEH2_TRY
158 {
159 /* Return the handle to caller */
160 *KeyHandle = Handle;
161 }
162 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
163 {
164 /* Get the status */
165 Status = _SEH2_GetExceptionCode();
166 }
167 _SEH2_END;
168 }
169
170 /* Return status */
171 return Status;
172 }
173
174
175 NTSTATUS
176 NTAPI
177 NtDeleteKey(IN HANDLE KeyHandle)
178 {
179 PCM_KEY_BODY KeyObject;
180 NTSTATUS Status;
181 REG_DELETE_KEY_INFORMATION DeleteKeyInfo;
182 REG_POST_OPERATION_INFORMATION PostOperationInfo;
183 PAGED_CODE();
184 DPRINT("NtDeleteKey(KH 0x%p)\n", KeyHandle);
185
186 /* Verify that the handle is valid and is a registry key */
187 Status = ObReferenceObjectByHandle(KeyHandle,
188 DELETE,
189 CmpKeyObjectType,
190 ExGetPreviousMode(),
191 (PVOID*)&KeyObject,
192 NULL);
193 if (!NT_SUCCESS(Status)) return Status;
194
195 /* Setup the callback */
196 PostOperationInfo.Object = (PVOID)KeyObject;
197 DeleteKeyInfo.Object = (PVOID)KeyObject;
198 Status = CmiCallRegisteredCallbacks(RegNtPreDeleteKey, &DeleteKeyInfo);
199 if (NT_SUCCESS(Status))
200 {
201 /* Check if we are read-only */
202 if ((KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) ||
203 (KeyObject->KeyControlBlock->ParentKcb->ExtFlags & CM_KCB_READ_ONLY_KEY))
204 {
205 /* Fail */
206 Status = STATUS_ACCESS_DENIED;
207 }
208 else
209 {
210 /* Call the internal API */
211 Status = CmDeleteKey(KeyObject);
212 }
213
214 /* Do post callback */
215 PostOperationInfo.Status = Status;
216 CmiCallRegisteredCallbacks(RegNtPostDeleteKey, &PostOperationInfo);
217 }
218
219 /* Dereference the object */
220 ObDereferenceObject(KeyObject);
221 return Status;
222 }
223
224 NTSTATUS
225 NTAPI
226 NtEnumerateKey(IN HANDLE KeyHandle,
227 IN ULONG Index,
228 IN KEY_INFORMATION_CLASS KeyInformationClass,
229 OUT PVOID KeyInformation,
230 IN ULONG Length,
231 OUT PULONG ResultLength)
232 {
233 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
234 NTSTATUS Status;
235 PCM_KEY_BODY KeyObject;
236 REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo;
237 REG_POST_OPERATION_INFORMATION PostOperationInfo;
238 PAGED_CODE();
239 DPRINT("NtEnumerateKey() KH 0x%x, Index 0x%x, KIC %d, Length %d\n",
240 KeyHandle, Index, KeyInformationClass, Length);
241
242 /* Reject classes we don't know about */
243 if ((KeyInformationClass != KeyBasicInformation) &&
244 (KeyInformationClass != KeyNodeInformation) &&
245 (KeyInformationClass != KeyFullInformation))
246 {
247 /* Fail */
248 return STATUS_INVALID_PARAMETER;
249 }
250
251 /* Verify that the handle is valid and is a registry key */
252 Status = ObReferenceObjectByHandle(KeyHandle,
253 KEY_ENUMERATE_SUB_KEYS,
254 CmpKeyObjectType,
255 ExGetPreviousMode(),
256 (PVOID*)&KeyObject,
257 NULL);
258 if (!NT_SUCCESS(Status)) return Status;
259
260 if (PreviousMode != KernelMode)
261 {
262 _SEH2_TRY
263 {
264 ProbeForWriteUlong(ResultLength);
265 ProbeForWrite(KeyInformation,
266 Length,
267 sizeof(ULONG));
268 }
269 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
270 {
271 Status = _SEH2_GetExceptionCode();
272 }
273 _SEH2_END;
274
275 if (!NT_SUCCESS(Status))
276 {
277 /* Dereference and return status */
278 ObDereferenceObject(KeyObject);
279 return Status;
280 }
281 }
282
283 /* Setup the callback */
284 PostOperationInfo.Object = (PVOID)KeyObject;
285 EnumerateKeyInfo.Object = (PVOID)KeyObject;
286 EnumerateKeyInfo.Index = Index;
287 EnumerateKeyInfo.KeyInformationClass = KeyInformationClass;
288 EnumerateKeyInfo.Length = Length;
289 EnumerateKeyInfo.ResultLength = ResultLength;
290
291 /* Do the callback */
292 Status = CmiCallRegisteredCallbacks(RegNtPreEnumerateKey, &EnumerateKeyInfo);
293 if (NT_SUCCESS(Status))
294 {
295 /* Call the internal API */
296 Status = CmEnumerateKey(KeyObject->KeyControlBlock,
297 Index,
298 KeyInformationClass,
299 KeyInformation,
300 Length,
301 ResultLength);
302
303 /* Do the post callback */
304 PostOperationInfo.Status = Status;
305 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey, &PostOperationInfo);
306 }
307
308 /* Dereference and return status */
309 ObDereferenceObject(KeyObject);
310 return Status;
311 }
312
313 NTSTATUS
314 NTAPI
315 NtEnumerateValueKey(IN HANDLE KeyHandle,
316 IN ULONG Index,
317 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
318 OUT PVOID KeyValueInformation,
319 IN ULONG Length,
320 OUT PULONG ResultLength)
321 {
322 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
323 NTSTATUS Status;
324 PCM_KEY_BODY KeyObject;
325 REG_ENUMERATE_VALUE_KEY_INFORMATION EnumerateValueKeyInfo;
326 REG_POST_OPERATION_INFORMATION PostOperationInfo;
327 PAGED_CODE();
328 DPRINT("NtEnumerateValueKey() KH 0x%x, Index 0x%x, KVIC %d, Length %d\n",
329 KeyHandle, Index, KeyValueInformationClass, Length);
330
331 /* Reject classes we don't know about */
332 if ((KeyValueInformationClass != KeyValueBasicInformation) &&
333 (KeyValueInformationClass != KeyValueFullInformation) &&
334 (KeyValueInformationClass != KeyValuePartialInformation))
335 {
336 /* Fail */
337 return STATUS_INVALID_PARAMETER;
338 }
339
340 /* Verify that the handle is valid and is a registry key */
341 Status = ObReferenceObjectByHandle(KeyHandle,
342 KEY_QUERY_VALUE,
343 CmpKeyObjectType,
344 ExGetPreviousMode(),
345 (PVOID*)&KeyObject,
346 NULL);
347 if (!NT_SUCCESS(Status)) return Status;
348
349 if (PreviousMode != KernelMode)
350 {
351 _SEH2_TRY
352 {
353 ProbeForWriteUlong(ResultLength);
354 ProbeForWrite(KeyValueInformation,
355 Length,
356 sizeof(ULONG));
357 }
358 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
359 {
360 Status = _SEH2_GetExceptionCode();
361 }
362 _SEH2_END;
363
364 if (!NT_SUCCESS(Status))
365 {
366 /* Dereference and return status */
367 ObDereferenceObject(KeyObject);
368 return Status;
369 }
370 }
371
372 /* Setup the callback */
373 PostOperationInfo.Object = (PVOID)KeyObject;
374 EnumerateValueKeyInfo.Object = (PVOID)KeyObject;
375 EnumerateValueKeyInfo.Index = Index;
376 EnumerateValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass;
377 EnumerateValueKeyInfo.KeyValueInformation = KeyValueInformation;
378 EnumerateValueKeyInfo.Length = Length;
379 EnumerateValueKeyInfo.ResultLength = ResultLength;
380
381 /* Do the callback */
382 Status = CmiCallRegisteredCallbacks(RegNtPreEnumerateValueKey,
383 &EnumerateValueKeyInfo);
384 if (NT_SUCCESS(Status))
385 {
386 /* Call the internal API */
387 Status = CmEnumerateValueKey(KeyObject->KeyControlBlock,
388 Index,
389 KeyValueInformationClass,
390 KeyValueInformation,
391 Length,
392 ResultLength);
393
394 /* Do the post callback */
395 PostOperationInfo.Status = Status;
396 CmiCallRegisteredCallbacks(RegNtPostEnumerateValueKey, &PostOperationInfo);
397 }
398
399 ObDereferenceObject(KeyObject);
400 return Status;
401 }
402
403 NTSTATUS
404 NTAPI
405 NtQueryKey(IN HANDLE KeyHandle,
406 IN KEY_INFORMATION_CLASS KeyInformationClass,
407 OUT PVOID KeyInformation,
408 IN ULONG Length,
409 OUT PULONG ResultLength)
410 {
411 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
412 NTSTATUS Status;
413 PCM_KEY_BODY KeyObject;
414 REG_QUERY_KEY_INFORMATION QueryKeyInfo;
415 REG_POST_OPERATION_INFORMATION PostOperationInfo;
416 OBJECT_HANDLE_INFORMATION HandleInfo;
417 PAGED_CODE();
418 DPRINT("NtQueryKey() KH 0x%x, KIC %d, Length %d\n",
419 KeyHandle, KeyInformationClass, Length);
420
421 /* Reject invalid classes */
422 if ((KeyInformationClass != KeyBasicInformation) &&
423 (KeyInformationClass != KeyNodeInformation) &&
424 (KeyInformationClass != KeyFullInformation) &&
425 (KeyInformationClass != KeyNameInformation) &&
426 (KeyInformationClass != KeyCachedInformation) &&
427 (KeyInformationClass != KeyFlagsInformation))
428 {
429 /* Fail */
430 return STATUS_INVALID_PARAMETER;
431 }
432
433 /* Check if just the name is required */
434 if (KeyInformationClass == KeyNameInformation)
435 {
436 /* Ignore access level */
437 Status = ObReferenceObjectByHandle(KeyHandle,
438 0,
439 CmpKeyObjectType,
440 ExGetPreviousMode(),
441 (PVOID*)&KeyObject,
442 &HandleInfo);
443 if (NT_SUCCESS(Status))
444 {
445 /* At least a single bit of access is required */
446 if (!HandleInfo.GrantedAccess)
447 {
448 /* No such luck */
449 ObDereferenceObject(KeyObject);
450 Status = STATUS_ACCESS_DENIED;
451 }
452 }
453 }
454 else
455 {
456 /* Get a reference */
457 Status = ObReferenceObjectByHandle(KeyHandle,
458 KEY_QUERY_VALUE,
459 CmpKeyObjectType,
460 ExGetPreviousMode(),
461 (PVOID*)&KeyObject,
462 NULL);
463 }
464
465 /* Quit on failure */
466 if (!NT_SUCCESS(Status)) return Status;
467
468 if (PreviousMode != KernelMode)
469 {
470 _SEH2_TRY
471 {
472 ProbeForWriteUlong(ResultLength);
473 ProbeForWrite(KeyInformation,
474 Length,
475 sizeof(ULONG));
476 }
477 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
478 {
479 Status = _SEH2_GetExceptionCode();
480 }
481 _SEH2_END;
482
483 if (!NT_SUCCESS(Status))
484 {
485 /* Dereference and return status */
486 ObDereferenceObject(KeyObject);
487 return Status;
488 }
489 }
490
491 /* Setup the callback */
492 PostOperationInfo.Object = (PVOID)KeyObject;
493 QueryKeyInfo.Object = (PVOID)KeyObject;
494 QueryKeyInfo.KeyInformationClass = KeyInformationClass;
495 QueryKeyInfo.KeyInformation = KeyInformation;
496 QueryKeyInfo.Length = Length;
497 QueryKeyInfo.ResultLength = ResultLength;
498
499 /* Do the callback */
500 Status = CmiCallRegisteredCallbacks(RegNtPreQueryKey, &QueryKeyInfo);
501 if (NT_SUCCESS(Status))
502 {
503 /* Call the internal API */
504 Status = CmQueryKey(KeyObject->KeyControlBlock,
505 KeyInformationClass,
506 KeyInformation,
507 Length,
508 ResultLength);
509
510 /* Do the post callback */
511 PostOperationInfo.Status = Status;
512 CmiCallRegisteredCallbacks(RegNtPostQueryKey, &PostOperationInfo);
513 }
514
515 /* Dereference and return status */
516 ObDereferenceObject(KeyObject);
517 return Status;
518 }
519
520 NTSTATUS
521 NTAPI
522 NtQueryValueKey(IN HANDLE KeyHandle,
523 IN PUNICODE_STRING ValueName,
524 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
525 OUT PVOID KeyValueInformation,
526 IN ULONG Length,
527 OUT PULONG ResultLength)
528 {
529 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
530 NTSTATUS Status;
531 PCM_KEY_BODY KeyObject;
532 REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo;
533 REG_POST_OPERATION_INFORMATION PostOperationInfo;
534 UNICODE_STRING ValueNameCopy = *ValueName;
535 PAGED_CODE();
536 DPRINT("NtQueryValueKey() KH 0x%x, VN '%wZ', KVIC %d, Length %d\n",
537 KeyHandle, ValueName, KeyValueInformationClass, Length);
538
539 /* Verify that the handle is valid and is a registry key */
540 Status = ObReferenceObjectByHandle(KeyHandle,
541 KEY_QUERY_VALUE,
542 CmpKeyObjectType,
543 ExGetPreviousMode(),
544 (PVOID*)&KeyObject,
545 NULL);
546 if (!NT_SUCCESS(Status)) return Status;
547
548 if (PreviousMode != KernelMode)
549 {
550 _SEH2_TRY
551 {
552 ProbeForWriteUlong(ResultLength);
553 ProbeForWrite(KeyValueInformation,
554 Length,
555 sizeof(ULONG));
556 }
557 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
558 {
559 Status = _SEH2_GetExceptionCode();
560 }
561 _SEH2_END;
562
563 if (!NT_SUCCESS(Status))
564 {
565 /* Dereference and return status */
566 ObDereferenceObject(KeyObject);
567 return Status;
568 }
569 }
570
571 /* Make sure the name is aligned properly */
572 if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1)))
573 {
574 /* It isn't, so we'll fail */
575 ObDereferenceObject(KeyObject);
576 return STATUS_INVALID_PARAMETER;
577 }
578 else
579 {
580 /* Ignore any null characters at the end */
581 while ((ValueNameCopy.Length) &&
582 !(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1]))
583 {
584 /* Skip it */
585 ValueNameCopy.Length -= sizeof(WCHAR);
586 }
587 }
588
589 /* Setup the callback */
590 PostOperationInfo.Object = (PVOID)KeyObject;
591 QueryValueKeyInfo.Object = (PVOID)KeyObject;
592 QueryValueKeyInfo.ValueName = &ValueNameCopy;
593 QueryValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass;
594 QueryValueKeyInfo.Length = Length;
595 QueryValueKeyInfo.ResultLength = ResultLength;
596
597 /* Do the callback */
598 Status = CmiCallRegisteredCallbacks(RegNtPreQueryValueKey, &QueryValueKeyInfo);
599 if (NT_SUCCESS(Status))
600 {
601 /* Call the internal API */
602 Status = CmQueryValueKey(KeyObject->KeyControlBlock,
603 ValueNameCopy,
604 KeyValueInformationClass,
605 KeyValueInformation,
606 Length,
607 ResultLength);
608
609 /* Do the post callback */
610 PostOperationInfo.Status = Status;
611 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey, &PostOperationInfo);
612 }
613
614 /* Dereference and return status */
615 ObDereferenceObject(KeyObject);
616 return Status;
617 }
618
619 NTSTATUS
620 NTAPI
621 NtSetValueKey(IN HANDLE KeyHandle,
622 IN PUNICODE_STRING ValueName,
623 IN ULONG TitleIndex,
624 IN ULONG Type,
625 IN PVOID Data,
626 IN ULONG DataSize)
627 {
628 NTSTATUS Status;
629 PCM_KEY_BODY KeyObject;
630 REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo;
631 REG_POST_OPERATION_INFORMATION PostOperationInfo;
632 UNICODE_STRING ValueNameCopy = *ValueName;
633 PAGED_CODE();
634 DPRINT("NtSetValueKey() KH 0x%x, VN '%wZ', TI %x, T %d, DS %d\n",
635 KeyHandle, ValueName, TitleIndex, Type, DataSize);
636
637 /* Verify that the handle is valid and is a registry key */
638 Status = ObReferenceObjectByHandle(KeyHandle,
639 KEY_SET_VALUE,
640 CmpKeyObjectType,
641 ExGetPreviousMode(),
642 (PVOID*)&KeyObject,
643 NULL);
644 if (!NT_SUCCESS(Status)) return Status;
645
646 /* Make sure the name is aligned, not too long, and the data under 4GB */
647 if ( (ValueNameCopy.Length > 32767) ||
648 ((ValueNameCopy.Length & (sizeof(WCHAR) - 1))) ||
649 (DataSize > 0x80000000))
650 {
651 /* Fail */
652 ObDereferenceObject(KeyObject);
653 return STATUS_INVALID_PARAMETER;
654 }
655
656 /* Ignore any null characters at the end */
657 while ((ValueNameCopy.Length) &&
658 !(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1]))
659 {
660 /* Skip it */
661 ValueNameCopy.Length -= sizeof(WCHAR);
662 }
663
664 /* Don't touch read-only keys */
665 if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
666 {
667 /* Fail */
668 ObDereferenceObject(KeyObject);
669 return STATUS_ACCESS_DENIED;
670 }
671
672 /* Setup callback */
673 PostOperationInfo.Object = (PVOID)KeyObject;
674 SetValueKeyInfo.Object = (PVOID)KeyObject;
675 SetValueKeyInfo.ValueName = ValueName;
676 SetValueKeyInfo.TitleIndex = TitleIndex;
677 SetValueKeyInfo.Type = Type;
678 SetValueKeyInfo.Data = Data;
679 SetValueKeyInfo.DataSize = DataSize;
680
681 /* Do the callback */
682 Status = CmiCallRegisteredCallbacks(RegNtPreSetValueKey, &SetValueKeyInfo);
683 if (NT_SUCCESS(Status))
684 {
685 /* Call the internal API */
686 Status = CmSetValueKey(KeyObject->KeyControlBlock,
687 &ValueNameCopy,
688 Type,
689 Data,
690 DataSize);
691 }
692
693 /* Do the post-callback */
694 PostOperationInfo.Status = Status;
695 CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
696
697 /* Dereference and return status */
698 ObDereferenceObject(KeyObject);
699 return Status;
700 }
701
702 NTSTATUS
703 NTAPI
704 NtDeleteValueKey(IN HANDLE KeyHandle,
705 IN PUNICODE_STRING ValueName)
706 {
707 PCM_KEY_BODY KeyObject;
708 NTSTATUS Status;
709 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo;
710 REG_POST_OPERATION_INFORMATION PostOperationInfo;
711 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
712 UNICODE_STRING ValueNameCopy = *ValueName;
713 PAGED_CODE();
714
715 /* Verify that the handle is valid and is a registry key */
716 Status = ObReferenceObjectByHandle(KeyHandle,
717 KEY_SET_VALUE,
718 CmpKeyObjectType,
719 PreviousMode,
720 (PVOID *)&KeyObject,
721 NULL);
722 if (!NT_SUCCESS(Status)) return Status;
723
724 /* Don't touch read-only keys */
725 if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
726 {
727 /* Fail */
728 ObDereferenceObject(KeyObject);
729 return STATUS_ACCESS_DENIED;
730 }
731
732 /* Make sure the name is aligned properly */
733 if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1)))
734 {
735 /* It isn't, so we'll fail */
736 ObDereferenceObject(KeyObject);
737 return STATUS_INVALID_PARAMETER;
738 }
739
740 /* Do the callback */
741 DeleteValueKeyInfo.Object = (PVOID)KeyObject;
742 DeleteValueKeyInfo.ValueName = ValueName;
743 Status = CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey,
744 &DeleteValueKeyInfo);
745 if (NT_SUCCESS(Status))
746 {
747 /* Call the internal API */
748 Status = CmDeleteValueKey(KeyObject->KeyControlBlock, ValueNameCopy);
749
750 /* Do the post callback */
751 PostOperationInfo.Object = (PVOID)KeyObject;
752 PostOperationInfo.Status = Status;
753 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey,
754 &PostOperationInfo);
755 }
756
757 /* Dereference the key body */
758 ObDereferenceObject(KeyObject);
759 return Status;
760 }
761
762 NTSTATUS
763 NTAPI
764 NtFlushKey(IN HANDLE KeyHandle)
765 {
766 NTSTATUS Status;
767 PCM_KEY_BODY KeyObject;
768 PAGED_CODE();
769
770 /* Get the key object */
771 Status = ObReferenceObjectByHandle(KeyHandle,
772 0,
773 CmpKeyObjectType,
774 ExGetPreviousMode(),
775 (PVOID*)&KeyObject,
776 NULL);
777 if (!NT_SUCCESS(Status)) return Status;
778
779 /* Lock the registry */
780 CmpLockRegistry();
781
782 /* Lock the KCB */
783 CmpAcquireKcbLockShared(KeyObject->KeyControlBlock);
784
785 /* Make sure KCB isn't deleted */
786 if (KeyObject->KeyControlBlock->Delete)
787 {
788 /* Fail */
789 Status = STATUS_KEY_DELETED;
790 }
791 else
792 {
793 /* Call the internal API */
794 Status = CmFlushKey(KeyObject->KeyControlBlock, FALSE);
795 }
796
797 /* Release the locks */
798 CmpReleaseKcbLock(KeyObject->KeyControlBlock);
799 CmpUnlockRegistry();
800
801 /* Dereference the object and return status */
802 ObDereferenceObject(KeyObject);
803 return Status;
804 }
805
806 NTSTATUS
807 NTAPI
808 NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
809 IN POBJECT_ATTRIBUTES FileObjectAttributes)
810 {
811 /* Call the newer API */
812 return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, 0, NULL);
813 }
814
815 NTSTATUS
816 NTAPI
817 NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
818 IN POBJECT_ATTRIBUTES FileObjectAttributes,
819 IN ULONG Flags)
820 {
821 /* Call the newer API */
822 return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, Flags, NULL);
823 }
824
825 NTSTATUS
826 NTAPI
827 NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
828 IN POBJECT_ATTRIBUTES SourceFile,
829 IN ULONG Flags,
830 IN HANDLE TrustClassKey)
831 {
832 NTSTATUS Status;
833 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
834 PCM_KEY_BODY KeyBody = NULL;
835 PAGED_CODE();
836
837 /* Validate flags */
838 if (Flags & ~REG_NO_LAZY_FLUSH) return STATUS_INVALID_PARAMETER;
839
840 /* Validate privilege */
841 if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode))
842 {
843 /* Fail */
844 DPRINT1("Restore Privilege missing!\n");
845 return STATUS_PRIVILEGE_NOT_HELD;
846 }
847
848 /* Block APCs */
849 KeEnterCriticalRegion();
850
851 /* Check if we have a trust class */
852 if (TrustClassKey)
853 {
854 /* Reference it */
855 Status = ObReferenceObjectByHandle(TrustClassKey,
856 0,
857 CmpKeyObjectType,
858 PreviousMode,
859 (PVOID *)&KeyBody,
860 NULL);
861 }
862
863 /* Call the internal API */
864 Status = CmLoadKey(TargetKey, SourceFile, Flags, KeyBody);
865
866 /* Dereference the trust key, if any */
867 if (KeyBody) ObDereferenceObject(KeyBody);
868
869 /* Bring back APCs */
870 KeLeaveCriticalRegion();
871
872 /* Return status */
873 return Status;
874 }
875
876 NTSTATUS
877 NTAPI
878 NtNotifyChangeKey(IN HANDLE KeyHandle,
879 IN HANDLE Event,
880 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
881 IN PVOID ApcContext OPTIONAL,
882 OUT PIO_STATUS_BLOCK IoStatusBlock,
883 IN ULONG CompletionFilter,
884 IN BOOLEAN WatchTree,
885 OUT PVOID Buffer,
886 IN ULONG Length,
887 IN BOOLEAN Asynchronous)
888 {
889 /* Call the newer API */
890 return NtNotifyChangeMultipleKeys(KeyHandle,
891 0,
892 NULL,
893 Event,
894 ApcRoutine,
895 ApcContext,
896 IoStatusBlock,
897 CompletionFilter,
898 WatchTree,
899 Buffer,
900 Length,
901 Asynchronous);
902 }
903
904 NTSTATUS
905 NTAPI
906 NtInitializeRegistry(IN USHORT Flag)
907 {
908 BOOLEAN SetupBoot;
909 NTSTATUS Status = STATUS_SUCCESS;
910 PAGED_CODE();
911
912 /* Always do this as kernel mode */
913 if (KeGetPreviousMode() == UserMode) return ZwInitializeRegistry(Flag);
914
915 /* Validate flag */
916 if (Flag > CM_BOOT_FLAG_MAX) return STATUS_INVALID_PARAMETER;
917
918 /* Check if boot was accepted */
919 if ((Flag >= CM_BOOT_FLAG_ACCEPTED) && (Flag <= CM_BOOT_FLAG_MAX))
920 {
921 /* Only allow once */
922 if (!CmBootAcceptFirstTime) return STATUS_ACCESS_DENIED;
923 CmBootAcceptFirstTime = FALSE;
924
925 /* Get the control set accepted */
926 Flag -= CM_BOOT_FLAG_ACCEPTED;
927 if (Flag)
928 {
929 /* FIXME: Save the last known good boot */
930 //Status = CmpSaveBootControlSet(Flag);
931
932 /* Notify HAL */
933 HalEndOfBoot();
934
935 /* Enable lazy flush */
936 CmpHoldLazyFlush = FALSE;
937 CmpLazyFlush();
938 return Status;
939 }
940
941 /* Otherwise, invalid boot */
942 return STATUS_INVALID_PARAMETER;
943 }
944
945 /* Check if this was a setup boot */
946 SetupBoot = (Flag == CM_BOOT_FLAG_SETUP ? TRUE : FALSE);
947
948 /* Make sure we're only called once */
949 if (!CmFirstTime) return STATUS_ACCESS_DENIED;
950 CmFirstTime = FALSE;
951
952 /* Acquire registry lock */
953 //CmpLockRegistryExclusive();
954
955 /* Initialize the hives and lazy flusher */
956 CmpCmdInit(SetupBoot);
957
958 /* FIXME: Save version data */
959 //CmpSetVersionData();
960
961 /* Release the registry lock */
962 //CmpUnlockRegistry();
963 return STATUS_SUCCESS;
964 }
965
966 NTSTATUS
967 NTAPI
968 NtCompactKeys(IN ULONG Count,
969 IN PHANDLE KeyArray)
970 {
971 UNIMPLEMENTED;
972 return STATUS_NOT_IMPLEMENTED;
973 }
974
975 NTSTATUS
976 NTAPI
977 NtCompressKey(IN HANDLE Key)
978 {
979 UNIMPLEMENTED;
980 return STATUS_NOT_IMPLEMENTED;
981 }
982
983 NTSTATUS
984 NTAPI
985 NtLockProductActivationKeys(IN PULONG pPrivateVer,
986 IN PULONG pSafeMode)
987 {
988 UNIMPLEMENTED;
989 return STATUS_NOT_IMPLEMENTED;
990 }
991
992 NTSTATUS
993 NTAPI
994 NtLockRegistryKey(IN HANDLE KeyHandle)
995 {
996 UNIMPLEMENTED;
997 return STATUS_NOT_IMPLEMENTED;
998 }
999
1000 NTSTATUS
1001 NTAPI
1002 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle,
1003 IN ULONG Count,
1004 IN POBJECT_ATTRIBUTES SlaveObjects,
1005 IN HANDLE Event,
1006 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1007 IN PVOID ApcContext OPTIONAL,
1008 OUT PIO_STATUS_BLOCK IoStatusBlock,
1009 IN ULONG CompletionFilter,
1010 IN BOOLEAN WatchTree,
1011 OUT PVOID Buffer,
1012 IN ULONG Length,
1013 IN BOOLEAN Asynchronous)
1014 {
1015 UNIMPLEMENTED;
1016 return STATUS_NOT_IMPLEMENTED;
1017 }
1018
1019 NTSTATUS
1020 NTAPI
1021 NtQueryMultipleValueKey(IN HANDLE KeyHandle,
1022 IN OUT PKEY_VALUE_ENTRY ValueList,
1023 IN ULONG NumberOfValues,
1024 OUT PVOID Buffer,
1025 IN OUT PULONG Length,
1026 OUT PULONG ReturnLength)
1027 {
1028 UNIMPLEMENTED;
1029 return STATUS_NOT_IMPLEMENTED;
1030 }
1031
1032 NTSTATUS
1033 NTAPI
1034 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey,
1035 OUT PULONG HandleCount)
1036 {
1037 UNIMPLEMENTED;
1038 return STATUS_NOT_IMPLEMENTED;
1039 }
1040
1041 NTSTATUS
1042 NTAPI
1043 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey,
1044 IN ULONG BufferLength,
1045 IN PVOID Buffer,
1046 IN PULONG RequiredSize)
1047 {
1048 UNIMPLEMENTED;
1049 return STATUS_NOT_IMPLEMENTED;
1050 }
1051
1052 NTSTATUS
1053 NTAPI
1054 NtRenameKey(IN HANDLE KeyHandle,
1055 IN PUNICODE_STRING ReplacementName)
1056 {
1057 UNIMPLEMENTED;
1058 return STATUS_NOT_IMPLEMENTED;
1059 }
1060
1061 NTSTATUS
1062 NTAPI
1063 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes,
1064 IN HANDLE Key,
1065 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
1066 {
1067 UNIMPLEMENTED;
1068 return STATUS_NOT_IMPLEMENTED;
1069 }
1070
1071 NTSTATUS
1072 NTAPI
1073 NtRestoreKey(IN HANDLE KeyHandle,
1074 IN HANDLE FileHandle,
1075 IN ULONG RestoreFlags)
1076 {
1077 UNIMPLEMENTED;
1078 return STATUS_NOT_IMPLEMENTED;
1079 }
1080
1081 NTSTATUS
1082 NTAPI
1083 NtSaveKey(IN HANDLE KeyHandle,
1084 IN HANDLE FileHandle)
1085 {
1086 UNIMPLEMENTED;
1087 return STATUS_NOT_IMPLEMENTED;
1088 }
1089
1090 NTSTATUS
1091 NTAPI
1092 NtSaveKeyEx(IN HANDLE KeyHandle,
1093 IN HANDLE FileHandle,
1094 IN ULONG Flags)
1095 {
1096 UNIMPLEMENTED;
1097 return STATUS_NOT_IMPLEMENTED;
1098 }
1099
1100 NTSTATUS
1101 NTAPI
1102 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle,
1103 IN HANDLE LowPrecedenceKeyHandle,
1104 IN HANDLE FileHandle)
1105 {
1106 UNIMPLEMENTED;
1107 return STATUS_NOT_IMPLEMENTED;
1108 }
1109
1110 NTSTATUS
1111 NTAPI
1112 NtSetInformationKey(IN HANDLE KeyHandle,
1113 IN KEY_SET_INFORMATION_CLASS KeyInformationClass,
1114 IN PVOID KeyInformation,
1115 IN ULONG KeyInformationLength)
1116 {
1117 UNIMPLEMENTED;
1118 return STATUS_NOT_IMPLEMENTED;
1119 }
1120
1121 NTSTATUS
1122 NTAPI
1123 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes)
1124 {
1125 return NtUnloadKey2(KeyObjectAttributes, 0);
1126 }
1127
1128 NTSTATUS
1129 NTAPI
1130 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
1131 IN ULONG Flags)
1132 {
1133 #if 0
1134 NTSTATUS Status = STATUS_SUCCESS;
1135 OBJECT_ATTRIBUTES ObjectAttributes;
1136 UNICODE_STRING ObjectName;
1137 CM_PARSE_CONTEXT ParseContext = {0};
1138 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1139 PCM_KEY_BODY KeyBody = NULL;
1140 ULONG ParentConv = 0, ChildConv = 0;
1141 HANDLE Handle;
1142 PAGED_CODE();
1143
1144 /* Validate privilege */
1145 if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode))
1146 {
1147 /* Fail */
1148 DPRINT1("Restore Privilege missing!\n");
1149 return STATUS_PRIVILEGE_NOT_HELD;
1150 }
1151
1152 /* Check for user-mode caller */
1153 if (PreviousMode != KernelMode)
1154 {
1155 /* Prepare to probe parameters */
1156 _SEH2_TRY
1157 {
1158 /* Probe object attributes */
1159 ProbeForRead(TargetKey,
1160 sizeof(OBJECT_ATTRIBUTES),
1161 sizeof(ULONG));
1162
1163 ObjectAttributes = *TargetKey;
1164
1165 /* Probe the string */
1166 ProbeForReadUnicodeString(&TargetKey->ObjectName);
1167
1168 ObjectName = *TargetKey->ObjectName;
1169
1170 ProbeForRead(ObjectName.Buffer,
1171 ObjectName.Length,
1172 sizeof(WCHAR));
1173
1174 ObjectAttributes.ObjectName = &ObjectName;
1175 }
1176 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1177 {
1178 /* Get the error code */
1179 Status = _SEH2_GetExceptionCode();
1180 }
1181 _SEH2_END;
1182 if(!NT_SUCCESS(Status)) return Status;
1183 }
1184 else
1185 {
1186 /* Save the target attributes directly */
1187 ObjectAttributes = *TargetKey;
1188 }
1189
1190 /* Setup the parse context */
1191 ParseContext.CreateOperation = TRUE;
1192 ParseContext.CreateOptions = REG_OPTION_BACKUP_RESTORE;
1193
1194 /* Do the create */
1195 Status = ObOpenObjectByName(&ObjectAttributes,
1196 CmpKeyObjectType,
1197 KernelMode,
1198 NULL,
1199 KEY_WRITE,
1200 &ParseContext,
1201 &Handle);
1202
1203 /* Return if failure encountered */
1204 if (!NT_SUCCESS(Status)) return Status;
1205
1206 /* Reference it */
1207 Status = ObReferenceObjectByHandle(Handle,
1208 KEY_WRITE,
1209 CmpKeyObjectType,
1210 KernelMode,
1211 (PVOID *)&KeyBody,
1212 NULL);
1213
1214 /* Close the handle */
1215 ZwClose(Handle);
1216
1217 /* Return if failure encountered */
1218 if (!NT_SUCCESS(Status)) return Status;
1219
1220 /* Acquire the lock depending on flags */
1221 if (Flags == REG_FORCE_UNLOAD)
1222 {
1223 /* Lock registry exclusively */
1224 CmpLockRegistryExclusive();
1225 }
1226 else
1227 {
1228 /* Lock registry */
1229 CmpLockRegistry();
1230
1231 /* Acquire the hive loading lock */
1232 ExAcquirePushLockExclusive(&CmpLoadHiveLock);
1233
1234 /* Lock parent and child */
1235 if (KeyBody->KeyControlBlock->ParentKcb)
1236 ParentConv = KeyBody->KeyControlBlock->ParentKcb->ConvKey;
1237 else
1238 ParentConv = KeyBody->KeyControlBlock->ConvKey;
1239
1240 ChildConv = KeyBody->KeyControlBlock->ConvKey;
1241
1242 CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv, ParentConv);
1243 }
1244
1245 /* Check if it's being deleted already */
1246 if (KeyBody->KeyControlBlock->Delete)
1247 {
1248 /* Return appropriate status */
1249 Status = STATUS_KEY_DELETED;
1250 goto Quickie;
1251 }
1252
1253 /* Check if it's a readonly key */
1254 if (KeyBody->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
1255 {
1256 /* Return appropriate status */
1257 Status = STATUS_ACCESS_DENIED;
1258 goto Quickie;
1259 }
1260
1261 /* Call the internal API */
1262 Status = CmUnloadKey(KeyBody->KeyControlBlock,
1263 Flags);
1264
1265 /* Check if we failed, but really need to succeed */
1266 if ((Status == STATUS_CANNOT_DELETE) && (Flags == REG_FORCE_UNLOAD))
1267 {
1268 /* TODO: We should perform another attempt here */
1269 ASSERT(FALSE);
1270 }
1271
1272 /* If CmUnloadKey failed we need to unlock registry ourselves */
1273 if (!NT_SUCCESS(Status))
1274 {
1275 if (Flags != REG_FORCE_UNLOAD)
1276 {
1277 /* Release the hive loading lock */
1278 ExReleasePushLockExclusive(&CmpLoadHiveLock);
1279
1280 /* Release two KCBs lock */
1281 CmpReleaseTwoKcbLockByKey(ChildConv, ParentConv);
1282 }
1283
1284 /* Unlock the registry */
1285 CmpUnlockRegistry();
1286 }
1287
1288 Quickie:
1289 /* Dereference the key */
1290 ObDereferenceObject(KeyBody);
1291
1292 /* Return status */
1293 return Status;
1294 #else
1295 UNIMPLEMENTED;
1296 return STATUS_NOT_IMPLEMENTED;
1297 #endif
1298 }
1299
1300 NTSTATUS
1301 NTAPI
1302 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
1303 IN HANDLE Event)
1304 {
1305 UNIMPLEMENTED;
1306 return STATUS_NOT_IMPLEMENTED;
1307 }
1308
1309 /* EOF */