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