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