Sync with trunk r43000
[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 /* Validate flag */
894 if (Flag > CM_BOOT_FLAG_MAX) return STATUS_INVALID_PARAMETER;
895
896 /* Check if boot was accepted */
897 if ((Flag >= CM_BOOT_FLAG_ACCEPTED) && (Flag <= CM_BOOT_FLAG_MAX))
898 {
899 /* Only allow once */
900 if (!CmBootAcceptFirstTime) return STATUS_ACCESS_DENIED;
901 CmBootAcceptFirstTime = FALSE;
902
903 /* Get the control set accepted */
904 Flag -= CM_BOOT_FLAG_ACCEPTED;
905 if (Flag)
906 {
907 /* FIXME: Save the last known good boot */
908 //Status = CmpSaveBootControlSet(Flag);
909
910 /* Notify HAL */
911 HalEndOfBoot();
912
913 /* Enable lazy flush */
914 CmpHoldLazyFlush = FALSE;
915 CmpLazyFlush();
916 return Status;
917 }
918
919 /* Otherwise, invalid boot */
920 return STATUS_INVALID_PARAMETER;
921 }
922
923 /* Check if this was a setup boot */
924 SetupBoot = (Flag == CM_BOOT_FLAG_SETUP ? TRUE : FALSE);
925
926 /* Make sure we're only called once */
927 if (!CmFirstTime) return STATUS_ACCESS_DENIED;
928 CmFirstTime = FALSE;
929
930 /* Acquire registry lock */
931 //CmpLockRegistryExclusive();
932
933 /* Initialize the hives and lazy flusher */
934 CmpCmdInit(SetupBoot);
935
936 /* FIXME: Save version data */
937 //CmpSetVersionData();
938
939 /* Release the registry lock */
940 //CmpUnlockRegistry();
941 return STATUS_SUCCESS;
942 }
943
944 NTSTATUS
945 NTAPI
946 NtCompactKeys(IN ULONG Count,
947 IN PHANDLE KeyArray)
948 {
949 UNIMPLEMENTED;
950 return STATUS_NOT_IMPLEMENTED;
951 }
952
953 NTSTATUS
954 NTAPI
955 NtCompressKey(IN HANDLE Key)
956 {
957 UNIMPLEMENTED;
958 return STATUS_NOT_IMPLEMENTED;
959 }
960
961 NTSTATUS
962 NTAPI
963 NtLockProductActivationKeys(IN PULONG pPrivateVer,
964 IN PULONG pSafeMode)
965 {
966 UNIMPLEMENTED;
967 return STATUS_NOT_IMPLEMENTED;
968 }
969
970 NTSTATUS
971 NTAPI
972 NtLockRegistryKey(IN HANDLE KeyHandle)
973 {
974 UNIMPLEMENTED;
975 return STATUS_NOT_IMPLEMENTED;
976 }
977
978 NTSTATUS
979 NTAPI
980 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle,
981 IN ULONG Count,
982 IN POBJECT_ATTRIBUTES SlaveObjects,
983 IN HANDLE Event,
984 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
985 IN PVOID ApcContext OPTIONAL,
986 OUT PIO_STATUS_BLOCK IoStatusBlock,
987 IN ULONG CompletionFilter,
988 IN BOOLEAN WatchTree,
989 OUT PVOID Buffer,
990 IN ULONG Length,
991 IN BOOLEAN Asynchronous)
992 {
993 UNIMPLEMENTED;
994 return STATUS_NOT_IMPLEMENTED;
995 }
996
997 NTSTATUS
998 NTAPI
999 NtQueryMultipleValueKey(IN HANDLE KeyHandle,
1000 IN OUT PKEY_VALUE_ENTRY ValueList,
1001 IN ULONG NumberOfValues,
1002 OUT PVOID Buffer,
1003 IN OUT PULONG Length,
1004 OUT PULONG ReturnLength)
1005 {
1006 UNIMPLEMENTED;
1007 return STATUS_NOT_IMPLEMENTED;
1008 }
1009
1010 NTSTATUS
1011 NTAPI
1012 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey,
1013 OUT PULONG HandleCount)
1014 {
1015 UNIMPLEMENTED;
1016 return STATUS_NOT_IMPLEMENTED;
1017 }
1018
1019 NTSTATUS
1020 NTAPI
1021 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey,
1022 IN ULONG BufferLength,
1023 IN PVOID Buffer,
1024 IN PULONG RequiredSize)
1025 {
1026 UNIMPLEMENTED;
1027 return STATUS_NOT_IMPLEMENTED;
1028 }
1029
1030 NTSTATUS
1031 NTAPI
1032 NtRenameKey(IN HANDLE KeyHandle,
1033 IN PUNICODE_STRING ReplacementName)
1034 {
1035 UNIMPLEMENTED;
1036 return STATUS_NOT_IMPLEMENTED;
1037 }
1038
1039 NTSTATUS
1040 NTAPI
1041 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes,
1042 IN HANDLE Key,
1043 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
1044 {
1045 UNIMPLEMENTED;
1046 return STATUS_NOT_IMPLEMENTED;
1047 }
1048
1049 NTSTATUS
1050 NTAPI
1051 NtRestoreKey(IN HANDLE KeyHandle,
1052 IN HANDLE FileHandle,
1053 IN ULONG RestoreFlags)
1054 {
1055 UNIMPLEMENTED;
1056 return STATUS_NOT_IMPLEMENTED;
1057 }
1058
1059 NTSTATUS
1060 NTAPI
1061 NtSaveKey(IN HANDLE KeyHandle,
1062 IN HANDLE FileHandle)
1063 {
1064 UNIMPLEMENTED;
1065 return STATUS_NOT_IMPLEMENTED;
1066 }
1067
1068 NTSTATUS
1069 NTAPI
1070 NtSaveKeyEx(IN HANDLE KeyHandle,
1071 IN HANDLE FileHandle,
1072 IN ULONG Flags)
1073 {
1074 UNIMPLEMENTED;
1075 return STATUS_NOT_IMPLEMENTED;
1076 }
1077
1078 NTSTATUS
1079 NTAPI
1080 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle,
1081 IN HANDLE LowPrecedenceKeyHandle,
1082 IN HANDLE FileHandle)
1083 {
1084 UNIMPLEMENTED;
1085 return STATUS_NOT_IMPLEMENTED;
1086 }
1087
1088 NTSTATUS
1089 NTAPI
1090 NtSetInformationKey(IN HANDLE KeyHandle,
1091 IN KEY_SET_INFORMATION_CLASS KeyInformationClass,
1092 IN PVOID KeyInformation,
1093 IN ULONG KeyInformationLength)
1094 {
1095 UNIMPLEMENTED;
1096 return STATUS_NOT_IMPLEMENTED;
1097 }
1098
1099 NTSTATUS
1100 NTAPI
1101 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes)
1102 {
1103 return NtUnloadKey2(KeyObjectAttributes, 0);
1104 }
1105
1106 NTSTATUS
1107 NTAPI
1108 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
1109 IN ULONG Flags)
1110 {
1111 #if 0
1112 NTSTATUS Status;
1113 OBJECT_ATTRIBUTES ObjectAttributes;
1114 UNICODE_STRING ObjectName;
1115 CM_PARSE_CONTEXT ParseContext = {0};
1116 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1117 PCM_KEY_BODY KeyBody = NULL;
1118 ULONG ParentConv = 0, ChildConv = 0;
1119 HANDLE Handle;
1120 PAGED_CODE();
1121
1122 /* Validate privilege */
1123 if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode))
1124 {
1125 /* Fail */
1126 DPRINT1("Restore Privilege missing!\n");
1127 return STATUS_PRIVILEGE_NOT_HELD;
1128 }
1129
1130 /* Check for user-mode caller */
1131 if (PreviousMode != KernelMode)
1132 {
1133 /* Prepare to probe parameters */
1134 _SEH2_TRY
1135 {
1136 /* Probe object attributes */
1137 ProbeForRead(TargetKey,
1138 sizeof(OBJECT_ATTRIBUTES),
1139 sizeof(ULONG));
1140
1141 ObjectAttributes = *TargetKey;
1142
1143 /* Probe the string */
1144 ProbeForReadUnicodeString(&TargetKey->ObjectName);
1145
1146 ObjectName = *TargetKey->ObjectName;
1147
1148 ProbeForRead(ObjectName.Buffer,
1149 ObjectName.Length,
1150 sizeof(WCHAR));
1151
1152 ObjectAttributes.ObjectName = &ObjectName;
1153 }
1154 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1155 {
1156 /* Return the exception code */
1157 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1158 }
1159 _SEH2_END;
1160 }
1161 else
1162 {
1163 /* Save the target attributes directly */
1164 ObjectAttributes = *TargetKey;
1165 }
1166
1167 /* Setup the parse context */
1168 ParseContext.CreateOperation = TRUE;
1169 ParseContext.CreateOptions = REG_OPTION_BACKUP_RESTORE;
1170
1171 /* Do the create */
1172 Status = ObOpenObjectByName(&ObjectAttributes,
1173 CmpKeyObjectType,
1174 KernelMode,
1175 NULL,
1176 KEY_WRITE,
1177 &ParseContext,
1178 &Handle);
1179
1180 /* Return if failure encountered */
1181 if (!NT_SUCCESS(Status)) return Status;
1182
1183 /* Reference it */
1184 Status = ObReferenceObjectByHandle(Handle,
1185 KEY_WRITE,
1186 CmpKeyObjectType,
1187 KernelMode,
1188 (PVOID *)&KeyBody,
1189 NULL);
1190
1191 /* Close the handle */
1192 ZwClose(Handle);
1193
1194 /* Return if failure encountered */
1195 if (!NT_SUCCESS(Status)) return Status;
1196
1197 /* Acquire the lock depending on flags */
1198 if (Flags == REG_FORCE_UNLOAD)
1199 {
1200 /* Lock registry exclusively */
1201 CmpLockRegistryExclusive();
1202 }
1203 else
1204 {
1205 /* Lock registry */
1206 CmpLockRegistry();
1207
1208 /* Acquire the hive loading lock */
1209 ExAcquirePushLockExclusive(&CmpLoadHiveLock);
1210
1211 /* Lock parent and child */
1212 if (KeyBody->KeyControlBlock->ParentKcb)
1213 ParentConv = KeyBody->KeyControlBlock->ParentKcb->ConvKey;
1214 else
1215 ParentConv = KeyBody->KeyControlBlock->ConvKey;
1216
1217 ChildConv = KeyBody->KeyControlBlock->ConvKey;
1218
1219 CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv, ParentConv);
1220 }
1221
1222 /* Check if it's being deleted already */
1223 if (KeyBody->KeyControlBlock->Delete)
1224 {
1225 /* Return appropriate status */
1226 Status = STATUS_KEY_DELETED;
1227 goto Quickie;
1228 }
1229
1230 /* Check if it's a readonly key */
1231 if (KeyBody->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
1232 {
1233 /* Return appropriate status */
1234 Status = STATUS_ACCESS_DENIED;
1235 goto Quickie;
1236 }
1237
1238 /* Call the internal API */
1239 Status = CmUnloadKey(KeyBody->KeyControlBlock,
1240 Flags);
1241
1242 /* Check if we failed, but really need to succeed */
1243 if ((Status == STATUS_CANNOT_DELETE) && (Flags == REG_FORCE_UNLOAD))
1244 {
1245 /* TODO: We should perform another attempt here */
1246 ASSERT(FALSE);
1247 }
1248
1249 /* If CmUnloadKey failed we need to unlock registry ourselves */
1250 if (!NT_SUCCESS(Status))
1251 {
1252 if (Flags != REG_FORCE_UNLOAD)
1253 {
1254 /* Release the hive loading lock */
1255 ExReleasePushLockExclusive(&CmpLoadHiveLock);
1256
1257 /* Release two KCBs lock */
1258 CmpReleaseTwoKcbLockByKey(ChildConv, ParentConv);
1259 }
1260
1261 /* Unlock the registry */
1262 CmpUnlockRegistry();
1263 }
1264
1265 Quickie:
1266 /* Dereference the key */
1267 ObDereferenceObject(KeyBody);
1268
1269 /* Return status */
1270 return Status;
1271 #else
1272 UNIMPLEMENTED;
1273 return STATUS_NOT_IMPLEMENTED;
1274 #endif
1275 }
1276
1277 NTSTATUS
1278 NTAPI
1279 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
1280 IN HANDLE Event)
1281 {
1282 UNIMPLEMENTED;
1283 return STATUS_NOT_IMPLEMENTED;
1284 }
1285
1286 /* EOF */