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