Enable old access check code until the bug that keeps the device installer from worki...
[reactos.git] / reactos / ntoskrnl / se / semgr.c
index 6885cb7..de37447 100644 (file)
@@ -314,6 +314,31 @@ SepSidInToken(PACCESS_TOKEN _Token,
     return FALSE;
 }
 
+static BOOLEAN
+SepTokenIsOwner(PACCESS_TOKEN Token,
+                PSECURITY_DESCRIPTOR SecurityDescriptor)
+{
+    NTSTATUS Status;
+    PSID Sid = NULL;
+    BOOLEAN Defaulted;
+
+    Status = RtlGetOwnerSecurityDescriptor(SecurityDescriptor,
+                                           &Sid,
+                                           &Defaulted);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("RtlGetOwnerSecurityDescriptor() failed (Status %lx)\n", Status);
+        return FALSE;
+    }
+
+    if (Sid == NULL)
+    {
+        DPRINT1("Owner Sid is NULL\n");
+        return FALSE;
+    }
+
+    return SepSidInToken(Token, Sid);
+}
 
 VOID NTAPI
 SeQuerySecurityAccessMask(IN SECURITY_INFORMATION SecurityInformation,
@@ -352,6 +377,9 @@ SeSetSecurityAccessMask(IN SECURITY_INFORMATION SecurityInformation,
     }
 }
 
+
+#define OLD_ACCESS_CHECK
+
 BOOLEAN NTAPI
 SepAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
                IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
@@ -364,7 +392,13 @@ SepAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
                OUT PNTSTATUS AccessStatus)
 {
     LUID_AND_ATTRIBUTES Privilege;
+#ifdef OLD_ACCESS_CHECK
     ACCESS_MASK CurrentAccess, AccessMask;
+#endif
+    ACCESS_MASK RemainingAccess;
+    ACCESS_MASK TempAccess;
+    ACCESS_MASK TempGrantedAccess = 0;
+    ACCESS_MASK TempDeniedAccess = 0;
     PACCESS_TOKEN Token;
     ULONG i;
     PACL Dacl;
@@ -398,15 +432,45 @@ SepAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
     if (PreviouslyGrantedAccess)
         RtlMapGenericMask(&PreviouslyGrantedAccess, GenericMapping);
 
-
-
+#ifdef OLD_ACCESS_CHECK
     CurrentAccess = PreviouslyGrantedAccess;
-
-
+#endif
+    /* Initialize remaining access rights */
+    RemainingAccess = DesiredAccess;
 
     Token = SubjectSecurityContext->ClientToken ?
     SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
 
+    /* Check for system security access */
+    if (RemainingAccess & ACCESS_SYSTEM_SECURITY)
+    {
+        Privilege.Luid = SeSecurityPrivilege;
+        Privilege.Attributes = SE_PRIVILEGE_ENABLED;
+
+        /* Fail if we do not the SeSecurityPrivilege */
+        if (!SepPrivilegeCheck(Token,
+                               &Privilege,
+                               1,
+                               PRIVILEGE_SET_ALL_NECESSARY,
+                               AccessMode))
+        {
+            *AccessStatus = STATUS_PRIVILEGE_NOT_HELD;
+            return FALSE;
+        }
+
+        /* Adjust access rights */
+        RemainingAccess &= ~ACCESS_SYSTEM_SECURITY;
+        PreviouslyGrantedAccess |= ACCESS_SYSTEM_SECURITY;
+
+        /* Succeed if there are no more rights to grant */
+        if (RemainingAccess == 0)
+        {
+            *GrantedAccess = PreviouslyGrantedAccess;
+            *AccessStatus = STATUS_SUCCESS;
+            return TRUE;
+        }
+    }
+
     /* Get the DACL */
     Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
                                           &Present,
@@ -435,49 +499,54 @@ SepAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
         return TRUE;
     }
 
+#ifdef OLD_ACCESS_CHECK
     CurrentAccess = PreviouslyGrantedAccess;
+#endif
 
     /* RULE 2: Check token for 'take ownership' privilege */
-    Privilege.Luid = SeTakeOwnershipPrivilege;
-    Privilege.Attributes = SE_PRIVILEGE_ENABLED;
-
-    if (SepPrivilegeCheck(Token,
-                          &Privilege,
-                          1,
-                          PRIVILEGE_SET_ALL_NECESSARY,
-                          AccessMode))
-    {
-        CurrentAccess |= WRITE_OWNER;
-        if ((DesiredAccess & ~VALID_INHERIT_FLAGS) == 
-            (CurrentAccess & ~VALID_INHERIT_FLAGS))
+    if (DesiredAccess & WRITE_OWNER)
+    {
+        Privilege.Luid = SeTakeOwnershipPrivilege;
+        Privilege.Attributes = SE_PRIVILEGE_ENABLED;
+
+        if (SepPrivilegeCheck(Token,
+                              &Privilege,
+                              1,
+                              PRIVILEGE_SET_ALL_NECESSARY,
+                              AccessMode))
         {
-            *GrantedAccess = CurrentAccess;
-            *AccessStatus = STATUS_SUCCESS;
-            return TRUE;
+            /* Adjust access rights */
+            RemainingAccess &= ~WRITE_OWNER;
+            PreviouslyGrantedAccess |= WRITE_OWNER;
+#ifdef OLD_ACCESS_CHECK
+            CurrentAccess |= WRITE_OWNER;
+#endif
+
+            /* Succeed if there are no more rights to grant */
+            if (RemainingAccess == 0)
+            {
+                *GrantedAccess = PreviouslyGrantedAccess;
+                *AccessStatus = STATUS_SUCCESS;
+                return TRUE;
+            }
         }
     }
 
-    /* RULE 3: Check whether the token is the owner */
-    Status = RtlGetOwnerSecurityDescriptor(SecurityDescriptor,
-                                           &Sid,
-                                           &Defaulted);
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("RtlGetOwnerSecurityDescriptor() failed (Status %lx)\n", Status);
-        *AccessStatus = Status;
-        return FALSE;
-    }
-
-    if (Sid && SepSidInToken(Token, Sid))
+    /* Deny access if the DACL is empty */
+    if (Dacl->AceCount == 0)
     {
-        CurrentAccess |= (READ_CONTROL | WRITE_DAC);
-        if ((DesiredAccess & ~VALID_INHERIT_FLAGS) == 
-            (CurrentAccess & ~VALID_INHERIT_FLAGS))
+        if (RemainingAccess == MAXIMUM_ALLOWED && PreviouslyGrantedAccess != 0)
         {
-            *GrantedAccess = CurrentAccess;
+            *GrantedAccess = PreviouslyGrantedAccess;
             *AccessStatus = STATUS_SUCCESS;
             return TRUE;
         }
+        else
+        {
+            *GrantedAccess = 0;
+            *AccessStatus = STATUS_ACCESS_DENIED;
+            return FALSE;
+        }
     }
 
     /* Fail if DACL is absent */
@@ -488,50 +557,134 @@ SepAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
         return FALSE;
     }
 
-    /* RULE 4: Grant rights according to the DACL */
-    CurrentAce = (PACE)(Dacl + 1);
-    for (i = 0; i < Dacl->AceCount; i++)
+    /* Determine the MAXIMUM_ALLOWED access rights according to the DACL */
+    if (DesiredAccess & MAXIMUM_ALLOWED)
     {
-        Sid = (PSID)(CurrentAce + 1);
-        if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE)
+        CurrentAce = (PACE)(Dacl + 1);
+        for (i = 0; i < Dacl->AceCount; i++)
         {
-            if (SepSidInToken(Token, Sid))
+            if (!(CurrentAce->Header.AceFlags & INHERIT_ONLY_ACE))
             {
-                *GrantedAccess = 0;
-                *AccessStatus = STATUS_ACCESS_DENIED;
-                return FALSE;
+                Sid = (PSID)(CurrentAce + 1);
+                if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE)
+                {
+                    if (SepSidInToken(Token, Sid))
+                    {
+                        /* Map access rights from the ACE */
+                        TempAccess = CurrentAce->AccessMask;
+                        RtlMapGenericMask(&TempAccess, GenericMapping);
+
+                        /* Deny access rights that have not been granted yet */
+                        TempDeniedAccess |= (TempAccess & ~TempGrantedAccess);
+                    }
+                }
+                else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
+                {
+                    if (SepSidInToken(Token, Sid))
+                    {
+                        /* Map access rights from the ACE */
+                        TempAccess = CurrentAce->AccessMask;
+                        RtlMapGenericMask(&TempAccess, GenericMapping);
+
+                        /* Grant access rights that have not been denied yet */
+                        TempGrantedAccess |= (TempAccess & ~TempDeniedAccess);
+                    }
+                }
+                else
+                {
+                    DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType);
+                }
             }
+
+            /* Get the next ACE */
+            CurrentAce = (PACE)((ULONG_PTR)CurrentAce + CurrentAce->Header.AceSize);
         }
 
-        else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
+        /* Fail if some rights have not been granted */
+        RemainingAccess &= ~(MAXIMUM_ALLOWED | TempGrantedAccess);
+        if (RemainingAccess != 0)
         {
-            if (SepSidInToken(Token, Sid))
-            {
-                AccessMask = CurrentAce->AccessMask;
-                RtlMapGenericMask(&AccessMask, GenericMapping);
-                CurrentAccess |= AccessMask;
-            }
+            *GrantedAccess = 0;
+            *AccessStatus = STATUS_ACCESS_DENIED;
+            return FALSE;
+        }
+
+        /* Set granted access right and access status */
+        *GrantedAccess = TempGrantedAccess | PreviouslyGrantedAccess;
+        if (*GrantedAccess != 0)
+        {
+            *AccessStatus = STATUS_SUCCESS;
+            return TRUE;
         }
         else
         {
-            DPRINT1("Unknown Ace type 0x%lx\n", CurrentAce->Header.AceType);
+            *AccessStatus = STATUS_ACCESS_DENIED;
+            return FALSE;
+        }
+    }
+
+    /* RULE 4: Grant rights according to the DACL */
+    CurrentAce = (PACE)(Dacl + 1);
+    for (i = 0; i < Dacl->AceCount; i++)
+    {
+        if (!(CurrentAce->Header.AceFlags & INHERIT_ONLY_ACE))
+        {
+            Sid = (PSID)(CurrentAce + 1);
+            if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE)
+            {
+                if (SepSidInToken(Token, Sid))
+                {
+#ifdef OLD_ACCESS_CHECK
+                    *GrantedAccess = 0;
+                    *AccessStatus = STATUS_ACCESS_DENIED;
+                    return FALSE;
+#else
+                    /* Map access rights from the ACE */
+                    TempAccess = CurrentAce->AccessMask;
+                    RtlMapGenericMask(&TempAccess, GenericMapping);
+
+                    /* Leave if a remaining right must be denied */
+                    if (RemainingAccess & TempAccess)
+                        break;
+#endif
+                }
+            }
+            else if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
+            {
+                if (SepSidInToken(Token, Sid))
+                {
+#ifdef OLD_ACCESS_CHECK
+                    AccessMask = CurrentAce->AccessMask;
+                    RtlMapGenericMask(&AccessMask, GenericMapping);
+                    CurrentAccess |= AccessMask;
+#else
+                    /* Map access rights from the ACE */
+                    TempAccess = CurrentAce->AccessMask;
+                    RtlMapGenericMask(&TempAccess, GenericMapping);
+
+                    /* Remove granted rights */
+                    RemainingAccess &= ~TempAccess;
+#endif
+                }
+            }
+            else
+            {
+                DPRINT1("Unsupported ACE type 0x%lx\n", CurrentAce->Header.AceType);
+            }
         }
+
+        /* Get the next ACE */
         CurrentAce = (PACE)((ULONG_PTR)CurrentAce + CurrentAce->Header.AceSize);
     }
 
+#ifdef OLD_ACCESS_CHECK
     DPRINT("CurrentAccess %08lx\n DesiredAccess %08lx\n",
            CurrentAccess, DesiredAccess);
 
     *GrantedAccess = CurrentAccess & DesiredAccess;
 
-    if (DesiredAccess & MAXIMUM_ALLOWED)
-    {
-        *GrantedAccess = CurrentAccess;
-        *AccessStatus = STATUS_SUCCESS;
-        return TRUE;
-    }
-    else if ((*GrantedAccess & ~VALID_INHERIT_FLAGS) == 
-             (DesiredAccess & ~VALID_INHERIT_FLAGS))
+    if ((*GrantedAccess & ~VALID_INHERIT_FLAGS) == 
+        (DesiredAccess & ~VALID_INHERIT_FLAGS))
     {
         *AccessStatus = STATUS_SUCCESS;
         return TRUE;
@@ -545,6 +698,33 @@ SepAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
         *AccessStatus = STATUS_SUCCESS;
         return TRUE;
     }
+#else
+    DPRINT("DesiredAccess %08lx\nPreviouslyGrantedAccess %08lx\nRemainingAccess %08lx\n",
+           DesiredAccess, PreviouslyGrantedAccess, RemainingAccess);
+
+    /* Fail if some rights have not been granted */
+    if (RemainingAccess != 0)
+    {
+        *GrantedAccess = 0;
+        *AccessStatus = STATUS_ACCESS_DENIED;
+        return FALSE;
+    }
+
+    /* Set granted access rights */
+    *GrantedAccess = DesiredAccess | PreviouslyGrantedAccess;
+
+    DPRINT("GrantedAccess %08lx\n", *GrantedAccess);
+
+    /* Fail if no rights have been granted */
+    if (*GrantedAccess == 0)
+    {
+        *AccessStatus = STATUS_ACCESS_DENIED;
+        return FALSE;
+    }
+
+    *AccessStatus = STATUS_SUCCESS;
+    return TRUE;
+#endif
 }
 
 static PSID
@@ -641,16 +821,43 @@ SeAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
     if (!SubjectContextLocked)
         SeLockSubjectContext(SubjectSecurityContext);
 
-    /* Call the internal function */
-    ret = SepAccessCheck(SecurityDescriptor,
-                         SubjectSecurityContext,
-                         DesiredAccess,
-                         PreviouslyGrantedAccess,
-                         Privileges,
-                         GenericMapping,
-                         AccessMode,
-                         GrantedAccess,
-                         AccessStatus);
+    /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
+    if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED))
+    {
+         PACCESS_TOKEN Token = SubjectSecurityContext->ClientToken ?
+             SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
+
+        if (SepTokenIsOwner(Token,
+                            SecurityDescriptor))
+        {
+            if (DesiredAccess & MAXIMUM_ALLOWED)
+                PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL);
+            else
+                PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL));
+
+            DesiredAccess &= ~(WRITE_DAC | READ_CONTROL);
+        }
+    }
+
+    if (DesiredAccess == 0)
+    {
+        *GrantedAccess = PreviouslyGrantedAccess;
+        *AccessStatus = STATUS_SUCCESS;
+        ret = TRUE;
+    }
+    else
+    {
+        /* Call the internal function */
+        ret = SepAccessCheck(SecurityDescriptor,
+                             SubjectSecurityContext,
+                             DesiredAccess,
+                             PreviouslyGrantedAccess,
+                             Privileges,
+                             GenericMapping,
+                             AccessMode,
+                             GrantedAccess,
+                             AccessStatus);
+    }
 
     /* Release the lock if needed */
     if (!SubjectContextLocked)
@@ -678,6 +885,7 @@ NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
     PSECURITY_DESCRIPTOR CapturedSecurityDescriptor = NULL;
     SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    ACCESS_MASK PreviouslyGrantedAccess = 0;
     PTOKEN Token;
     NTSTATUS Status;
     PAGED_CODE();
@@ -793,16 +1001,38 @@ NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
     SubjectSecurityContext.ProcessAuditId = NULL;
     SeLockSubjectContext(&SubjectSecurityContext);
 
-    /* Now perform the access check */
-    SepAccessCheck(SecurityDescriptor, // FIXME: use CapturedSecurityDescriptor
-                   &SubjectSecurityContext,
-                   DesiredAccess,
-                   0,
-                   &PrivilegeSet, //FIXME
-                   GenericMapping,
-                   PreviousMode,
-                   GrantedAccess,
-                   AccessStatus);
+    /* Check if the token is the owner and grant WRITE_DAC and READ_CONTROL rights */
+    if (DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED))
+    {
+        if (SepTokenIsOwner(Token, SecurityDescriptor)) // FIXME: use CapturedSecurityDescriptor
+        {
+            if (DesiredAccess & MAXIMUM_ALLOWED)
+                PreviouslyGrantedAccess |= (WRITE_DAC | READ_CONTROL);
+            else
+                PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL));
+
+            DesiredAccess &= ~(WRITE_DAC | READ_CONTROL);
+        }
+    }
+
+    if (DesiredAccess == 0)
+    {
+        *GrantedAccess = PreviouslyGrantedAccess;
+        *AccessStatus = STATUS_SUCCESS;
+    }
+    else
+    {
+        /* Now perform the access check */
+        SepAccessCheck(SecurityDescriptor, // FIXME: use CapturedSecurityDescriptor
+                       &SubjectSecurityContext,
+                       DesiredAccess,
+                       PreviouslyGrantedAccess,
+                       &PrivilegeSet, //FIXME
+                       GenericMapping,
+                       PreviousMode,
+                       GrantedAccess,
+                       AccessStatus);
+    }
 
     /* Unlock subject context */
     SeUnlockSubjectContext(&SubjectSecurityContext);