- Use _SEH2_YIELD when returning from an exception instead of returning outside the...
[reactos.git] / reactos / ntoskrnl / config / ntapi.c
index f177ece..0d62269 100644 (file)
@@ -23,11 +23,11 @@ NtCreateKey(OUT PHANDLE KeyHandle,
             IN ACCESS_MASK DesiredAccess,
             IN POBJECT_ATTRIBUTES ObjectAttributes,
             IN ULONG TitleIndex,
-            IN PUNICODE_STRING Class,
+            IN PUNICODE_STRING Class OPTIONAL,
             IN ULONG CreateOptions,
-            OUT PULONG Disposition)
+            OUT PULONG Disposition OPTIONAL)
 {
-    NTSTATUS Status = STATUS_SUCCESS;
+    NTSTATUS Status;
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     CM_PARSE_CONTEXT ParseContext = {0};
     HANDLE Handle;
@@ -35,20 +35,19 @@ NtCreateKey(OUT PHANDLE KeyHandle,
     DPRINT("NtCreateKey(OB name %wZ)\n", ObjectAttributes->ObjectName);
 
     /* Check for user-mode caller */
-    if (PreviousMode == UserMode)
+    if (PreviousMode != KernelMode)
     {
         /* Prepare to probe parameters */
-        _SEH_TRY
+        _SEH2_TRY
         {
             /* Check if we have a class */
             if (Class)
             {
                 /* Probe it */
-                ProbeForReadUnicodeString(Class);
+                ParseContext.Class = ProbeForReadUnicodeString(Class);
                 ProbeForRead(ParseContext.Class.Buffer,
                              ParseContext.Class.Length,
                              sizeof(WCHAR));
-                ParseContext.Class = *Class;
             }
 
             /* Probe the key handle */
@@ -56,15 +55,18 @@ NtCreateKey(OUT PHANDLE KeyHandle,
             *KeyHandle = NULL;
 
             /* Probe object attributes */
-            ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), 4);
+            ProbeForRead(ObjectAttributes,
+                         sizeof(OBJECT_ATTRIBUTES),
+                         sizeof(ULONG));
+
+            if (Disposition) ProbeForWriteUlong(Disposition);
         }
-        _SEH_HANDLE
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            /* Get the error code */
-            Status = _SEH_GetExceptionCode();
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
         }
-        _SEH_END;
-        if(!NT_SUCCESS(Status)) return Status;
+        _SEH2_END;
     }
     else
     {
@@ -85,19 +87,18 @@ NtCreateKey(OUT PHANDLE KeyHandle,
                                 &ParseContext,
                                 &Handle);
 
-    _SEH_TRY
+    _SEH2_TRY
     {
-        if (NT_SUCCESS(Status)) *KeyHandle = Handle;
-
         /* Return data to user */
+        if (NT_SUCCESS(Status)) *KeyHandle = Handle;
         if (Disposition) *Disposition = ParseContext.Disposition;
     }
-    _SEH_HANDLE
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
         /* Get the status */
-        Status = _SEH_GetExceptionCode();
+        Status = _SEH2_GetExceptionCode();
     }
-    _SEH_END;
+    _SEH2_END;
 
     /* Return status */
     return Status;
@@ -111,31 +112,32 @@ NtOpenKey(OUT PHANDLE KeyHandle,
 {
     CM_PARSE_CONTEXT ParseContext = {0};
     HANDLE Handle;
-    NTSTATUS Status = STATUS_SUCCESS;
+    NTSTATUS Status;
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     PAGED_CODE();
     DPRINT("NtOpenKey(OB 0x%wZ)\n", ObjectAttributes->ObjectName);
 
     /* Check for user-mode caller */
-    if (PreviousMode == UserMode)
+    if (PreviousMode != KernelMode)
     {
         /* Prepare to probe parameters */
-        _SEH_TRY
+        _SEH2_TRY
         {
             /* Probe the key handle */
             ProbeForWriteHandle(KeyHandle);
             *KeyHandle = NULL;
 
             /* Probe object attributes */
-            ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), 4);
+            ProbeForRead(ObjectAttributes,
+                         sizeof(OBJECT_ATTRIBUTES),
+                         sizeof(ULONG));
         }
-        _SEH_HANDLE
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            /* Get the status */
-            Status = _SEH_GetExceptionCode();
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
         }
-        _SEH_END;
-        if(!NT_SUCCESS(Status)) return Status;
+        _SEH2_END;
     }
 
     /* Just let the object manager handle this */
@@ -147,18 +149,20 @@ NtOpenKey(OUT PHANDLE KeyHandle,
                                 &ParseContext,
                                 &Handle);
 
+    /* Only do this if we succeeded */
     if (NT_SUCCESS(Status))
     {
-        _SEH_TRY
+        _SEH2_TRY
         {
+            /* Return the handle to caller */
             *KeyHandle = Handle;
         }
-        _SEH_HANDLE
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
             /* Get the status */
-            Status = _SEH_GetExceptionCode();
+            Status = _SEH2_GetExceptionCode();
         }
-        _SEH_END;
+        _SEH2_END;
     }
 
     /* Return status */
@@ -202,7 +206,7 @@ NtDeleteKey(IN HANDLE KeyHandle)
         else
         {
             /* Call the internal API */
-            Status = CmDeleteKey(KeyObject);            
+            Status = CmDeleteKey(KeyObject);
         }
 
         /* Do post callback */
@@ -224,6 +228,7 @@ NtEnumerateKey(IN HANDLE KeyHandle,
                IN ULONG Length,
                OUT PULONG ResultLength)
 {
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     NTSTATUS Status;
     PCM_KEY_BODY KeyObject;
     REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo;
@@ -250,6 +255,24 @@ NtEnumerateKey(IN HANDLE KeyHandle,
                                        NULL);
     if (!NT_SUCCESS(Status)) return Status;
 
+    if (PreviousMode != KernelMode)
+    {
+        _SEH2_TRY
+        {
+            ProbeForWriteUlong(ResultLength);
+            ProbeForWrite(KeyInformation,
+                          Length,
+                          sizeof(ULONG));
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Dereference and return status */
+            ObDereferenceObject(KeyObject);
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+
     /* Setup the callback */
     PostOperationInfo.Object = (PVOID)KeyObject;
     EnumerateKeyInfo.Object = (PVOID)KeyObject;
@@ -289,6 +312,7 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
                     IN ULONG Length,
                     OUT PULONG ResultLength)
 {
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     NTSTATUS Status;
     PCM_KEY_BODY KeyObject;
     REG_ENUMERATE_VALUE_KEY_INFORMATION EnumerateValueKeyInfo;
@@ -315,6 +339,24 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
                                        NULL);
     if (!NT_SUCCESS(Status)) return Status;
 
+    if (PreviousMode != KernelMode)
+    {
+        _SEH2_TRY
+        {
+            ProbeForWriteUlong(ResultLength);
+            ProbeForWrite(KeyValueInformation,
+                          Length,
+                          sizeof(ULONG));
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Dereference and return status */
+            ObDereferenceObject(KeyObject);
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+
     /* Setup the callback */
     PostOperationInfo.Object = (PVOID)KeyObject;
     EnumerateValueKeyInfo.Object = (PVOID)KeyObject;
@@ -354,6 +396,7 @@ NtQueryKey(IN HANDLE KeyHandle,
            IN ULONG Length,
            OUT PULONG ResultLength)
 {
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     NTSTATUS Status;
     PCM_KEY_BODY KeyObject;
     REG_QUERY_KEY_INFORMATION QueryKeyInfo;
@@ -374,7 +417,7 @@ NtQueryKey(IN HANDLE KeyHandle,
         /* Fail */
         return STATUS_INVALID_PARAMETER;
     }
-    
+
     /* Check if just the name is required */
     if (KeyInformationClass == KeyNameInformation)
     {
@@ -406,10 +449,28 @@ NtQueryKey(IN HANDLE KeyHandle,
                                            (PVOID*)&KeyObject,
                                            NULL);
     }
-    
+
     /* Quit on failure */
     if (!NT_SUCCESS(Status)) return Status;
 
+    if (PreviousMode != KernelMode)
+    {
+        _SEH2_TRY
+        {
+            ProbeForWriteUlong(ResultLength);
+            ProbeForWrite(KeyInformation,
+                          Length,
+                          sizeof(ULONG));
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Dereference and return status */
+            ObDereferenceObject(KeyObject);
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+
     /* Setup the callback */
     PostOperationInfo.Object = (PVOID)KeyObject;
     QueryKeyInfo.Object = (PVOID)KeyObject;
@@ -448,6 +509,7 @@ NtQueryValueKey(IN HANDLE KeyHandle,
                 IN ULONG Length,
                 OUT PULONG ResultLength)
 {
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     NTSTATUS Status;
     PCM_KEY_BODY KeyObject;
     REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo;
@@ -466,6 +528,24 @@ NtQueryValueKey(IN HANDLE KeyHandle,
                                        NULL);
     if (!NT_SUCCESS(Status)) return Status;
 
+    if (PreviousMode != KernelMode)
+    {
+        _SEH2_TRY
+        {
+            ProbeForWriteUlong(ResultLength);
+            ProbeForWrite(KeyValueInformation,
+                          Length,
+                          sizeof(ULONG));
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Dereference and return status */
+            ObDereferenceObject(KeyObject);
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+
     /* Make sure the name is aligned properly */
     if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1)))
     {
@@ -558,7 +638,7 @@ NtSetValueKey(IN HANDLE KeyHandle,
         /* Skip it */
         ValueNameCopy.Length -= sizeof(WCHAR);
     }
-    
+
     /* Don't touch read-only keys */
     if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
     {
@@ -579,7 +659,7 @@ NtSetValueKey(IN HANDLE KeyHandle,
     /* Do the callback */
     Status = CmiCallRegisteredCallbacks(RegNtPreSetValueKey, &SetValueKeyInfo);
     if (NT_SUCCESS(Status))
-    {        
+    {
         /* Call the internal API */
         Status = CmSetValueKey(KeyObject->KeyControlBlock,
                                &ValueNameCopy,
@@ -626,7 +706,7 @@ NtDeleteValueKey(IN HANDLE KeyHandle,
         ObDereferenceObject(KeyObject);
         return STATUS_ACCESS_DENIED;
     }
-    
+
     /* Make sure the name is aligned properly */
     if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1)))
     {
@@ -664,7 +744,7 @@ NtFlushKey(IN HANDLE KeyHandle)
     NTSTATUS Status;
     PCM_KEY_BODY KeyObject;
     PAGED_CODE();
-    
+
     /* Get the key object */
     Status = ObReferenceObjectByHandle(KeyHandle,
                                        0,
@@ -673,13 +753,13 @@ NtFlushKey(IN HANDLE KeyHandle)
                                        (PVOID*)&KeyObject,
                                        NULL);
     if (!NT_SUCCESS(Status)) return Status;
-    
+
     /* Lock the registry */
     CmpLockRegistry();
-    
+
     /* Lock the KCB */
     CmpAcquireKcbLockShared(KeyObject->KeyControlBlock);
-    
+
     /* Make sure KCB isn't deleted */
     if (KeyObject->KeyControlBlock->Delete)
     {
@@ -691,11 +771,11 @@ NtFlushKey(IN HANDLE KeyHandle)
         /* Call the internal API */
         Status = CmFlushKey(KeyObject->KeyControlBlock, FALSE);
     }
-    
+
     /* Release the locks */
     CmpReleaseKcbLock(KeyObject->KeyControlBlock);
     CmpUnlockRegistry();
-    
+
     /* Dereference the object and return status */
     ObDereferenceObject(KeyObject);
     return Status;
@@ -707,7 +787,7 @@ NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
           IN POBJECT_ATTRIBUTES FileObjectAttributes)
 {
     /* Call the newer API */
-    return NtLoadKey2(KeyObjectAttributes, FileObjectAttributes, 0);
+    return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, 0, NULL);
 }
 
 NTSTATUS
@@ -734,7 +814,7 @@ NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
 
     /* Validate flags */
     if (Flags & ~REG_NO_LAZY_FLUSH) return STATUS_INVALID_PARAMETER;
-    
+
     /* Validate privilege */
     if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode))
     {
@@ -742,10 +822,10 @@ NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
         DPRINT1("Restore Privilege missing!\n");
         return STATUS_PRIVILEGE_NOT_HELD;
     }
-    
+
     /* Block APCs */
     KeEnterCriticalRegion();
-    
+
     /* Check if we have a trust class */
     if (TrustClassKey)
     {
@@ -757,16 +837,16 @@ NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
                                            (PVOID *)&KeyBody,
                                            NULL);
     }
-    
+
     /* Call the internal API */
     Status = CmLoadKey(TargetKey, SourceFile, Flags, KeyBody);
-    
+
     /* Dereference the trust key, if any */
     if (KeyBody) ObDereferenceObject(KeyBody);
-    
+
     /* Bring back APCs */
     KeLeaveCriticalRegion();
-    
+
     /* Return status */
     return Status;
 }
@@ -809,7 +889,7 @@ NtInitializeRegistry(IN USHORT Flag)
 
     /* Always do this as kernel mode */
     if (KeGetPreviousMode() == UserMode) return ZwInitializeRegistry(Flag);
-    
+
     /* Validate flag */
     if (Flag > CM_BOOT_FLAG_MAX) return STATUS_INVALID_PARAMETER;
 
@@ -819,14 +899,14 @@ NtInitializeRegistry(IN USHORT Flag)
         /* Only allow once */
         if (!CmBootAcceptFirstTime) return STATUS_ACCESS_DENIED;
         CmBootAcceptFirstTime = FALSE;
-        
+
         /* Get the control set accepted */
         Flag -= CM_BOOT_FLAG_ACCEPTED;
         if (Flag)
         {
             /* FIXME: Save the last known good boot */
             //Status = CmpSaveBootControlSet(Flag);
-            
+
             /* Notify HAL */
             HalEndOfBoot();
 
@@ -839,14 +919,14 @@ NtInitializeRegistry(IN USHORT Flag)
         /* Otherwise, invalid boot */
         return STATUS_INVALID_PARAMETER;
     }
-    
+
     /* Check if this was a setup boot */
     SetupBoot = (Flag == CM_BOOT_FLAG_SETUP ? TRUE : FALSE);
 
     /* Make sure we're only called once */
     if (!CmFirstTime) return STATUS_ACCESS_DENIED;
     CmFirstTime = FALSE;
-    
+
     /* Acquire registry lock */
     //CmpLockRegistryExclusive();
 
@@ -930,7 +1010,7 @@ NtQueryMultipleValueKey(IN HANDLE KeyHandle,
 NTSTATUS
 NTAPI
 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey,
-                   IN ULONG HandleCount)
+                   OUT PULONG HandleCount)
 {
     UNIMPLEMENTED;
     return STATUS_NOT_IMPLEMENTED;
@@ -1020,8 +1100,7 @@ NTSTATUS
 NTAPI
 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    return NtUnloadKey2(KeyObjectAttributes, 0);
 }
 
 NTSTATUS
@@ -1029,8 +1108,170 @@ NTAPI
 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
              IN ULONG Flags)
 {
+#if 0
+    NTSTATUS Status;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    UNICODE_STRING ObjectName;
+    CM_PARSE_CONTEXT ParseContext = {0};
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    PCM_KEY_BODY KeyBody = NULL;
+    ULONG ParentConv = 0, ChildConv = 0;
+    HANDLE Handle;
+    PAGED_CODE();
+
+    /* Validate privilege */
+    if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode))
+    {
+        /* Fail */
+        DPRINT1("Restore Privilege missing!\n");
+        return STATUS_PRIVILEGE_NOT_HELD;
+    }
+
+    /* Check for user-mode caller */
+    if (PreviousMode != KernelMode)
+    {
+        /* Prepare to probe parameters */
+        _SEH2_TRY
+        {
+            /* Probe object attributes */
+            ProbeForRead(TargetKey,
+                         sizeof(OBJECT_ATTRIBUTES),
+                         sizeof(ULONG));
+
+            ObjectAttributes = *TargetKey;
+
+            /* Probe the string */
+            ProbeForReadUnicodeString(&TargetKey->ObjectName);
+
+            ObjectName = *TargetKey->ObjectName;
+
+            ProbeForRead(ObjectName.Buffer,
+                         ObjectName.Length,
+                         sizeof(WCHAR));
+
+            ObjectAttributes.ObjectName = &ObjectName;
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+    else
+    {
+        /* Save the target attributes directly */
+        ObjectAttributes = *TargetKey;
+    }
+
+    /* Setup the parse context */
+    ParseContext.CreateOperation = TRUE;
+    ParseContext.CreateOptions = REG_OPTION_BACKUP_RESTORE;
+
+    /* Do the create */
+    Status = ObOpenObjectByName(&ObjectAttributes,
+                                CmpKeyObjectType,
+                                KernelMode,
+                                NULL,
+                                KEY_WRITE,
+                                &ParseContext,
+                                &Handle);
+
+    /* Return if failure encountered */
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Reference it */
+    Status = ObReferenceObjectByHandle(Handle,
+                                       KEY_WRITE,
+                                       CmpKeyObjectType,
+                                       KernelMode,
+                                       (PVOID *)&KeyBody,
+                                       NULL);
+
+    /* Close the handle */
+    ZwClose(Handle);
+
+    /* Return if failure encountered */
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Acquire the lock depending on flags */
+    if (Flags == REG_FORCE_UNLOAD)
+    {
+        /* Lock registry exclusively */
+        CmpLockRegistryExclusive();
+    }
+    else
+    {
+        /* Lock registry */
+        CmpLockRegistry();
+
+        /* Acquire the hive loading lock */
+        ExAcquirePushLockExclusive(&CmpLoadHiveLock);
+
+        /* Lock parent and child */
+        if (KeyBody->KeyControlBlock->ParentKcb)
+            ParentConv = KeyBody->KeyControlBlock->ParentKcb->ConvKey;
+        else
+            ParentConv = KeyBody->KeyControlBlock->ConvKey;
+
+        ChildConv = KeyBody->KeyControlBlock->ConvKey;
+
+        CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv, ParentConv);
+    }
+
+    /* Check if it's being deleted already */
+    if (KeyBody->KeyControlBlock->Delete)
+    {
+        /* Return appropriate status */
+        Status = STATUS_KEY_DELETED;
+        goto Quickie;
+    }
+
+    /* Check if it's a readonly key */
+    if (KeyBody->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
+    {
+        /* Return appropriate status */
+        Status = STATUS_ACCESS_DENIED;
+        goto Quickie;
+    }
+
+    /* Call the internal API */
+    Status = CmUnloadKey(KeyBody->KeyControlBlock,
+                         Flags);
+
+    /* Check if we failed, but really need to succeed */
+    if ((Status == STATUS_CANNOT_DELETE) && (Flags == REG_FORCE_UNLOAD))
+    {
+        /* TODO: We should perform another attempt here */
+        ASSERT(FALSE);
+    }
+
+    /* If CmUnloadKey failed we need to unlock registry ourselves */
+    if (!NT_SUCCESS(Status))
+    {
+        if (Flags != REG_FORCE_UNLOAD)
+        {
+            /* Release the hive loading lock */
+            ExReleasePushLockExclusive(&CmpLoadHiveLock);
+
+            /* Release two KCBs lock */
+            CmpReleaseTwoKcbLockByKey(ChildConv, ParentConv);
+        }
+
+        /* Unlock the registry */
+        CmpUnlockRegistry();
+    }
+
+Quickie:
+    /* Dereference the key */
+    ObDereferenceObject(KeyBody);
+
+    /* Return status */
+    return Status;
+#else
     UNIMPLEMENTED;
     return STATUS_NOT_IMPLEMENTED;
+#endif
 }
 
 NTSTATUS