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