[NTOSKRNL]
authorTimo Kreuzer <timo.kreuzer@reactos.org>
Sat, 8 Feb 2014 20:01:09 +0000 (20:01 +0000)
committerTimo Kreuzer <timo.kreuzer@reactos.org>
Sat, 8 Feb 2014 20:01:09 +0000 (20:01 +0000)
- Lock the token in SepPrivilegeCheck
- Make use of RtlEqualLuid instead of manual comparison of fields
- Implement SepSinglePrivilegeCheck and SePrivilegePolicyCheck and use the latter in SepAccessCheck

svn path=/trunk/; revision=62058

reactos/ntoskrnl/include/internal/se.h
reactos/ntoskrnl/se/accesschk.c
reactos/ntoskrnl/se/priv.c

index 88cbfa1..ec516eb 100644 (file)
@@ -380,6 +380,16 @@ SepPrivilegeCheck(
     KPROCESSOR_MODE PreviousMode
 );
 
+NTSTATUS
+NTAPI
+SePrivilegePolicyCheck(
+    _Inout_ PACCESS_MASK DesiredAccess,
+    _Inout_ PACCESS_MASK GrantedAccess,
+    _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
+    _In_ PTOKEN Token,
+    _Out_opt_ PPRIVILEGE_SET *OutPrivilegeSet,
+    _In_ KPROCESSOR_MODE PreviousMode);
+
 BOOLEAN
 NTAPI
 SeCheckPrivilegedObject(
index 06bb550..69c5969 100644 (file)
@@ -31,7 +31,6 @@ SepAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
                OUT PACCESS_MASK GrantedAccess,
                OUT PNTSTATUS AccessStatus)
 {
-    LUID_AND_ATTRIBUTES Privilege;
 #ifdef OLD_ACCESS_CHECK
     ACCESS_MASK CurrentAccess, AccessMask;
 #endif
@@ -72,43 +71,31 @@ 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)
+        SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
+
+    /* Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access */
+    Status = SePrivilegePolicyCheck(&RemainingAccess,
+                                    &PreviouslyGrantedAccess,
+                                    NULL,
+                                    Token,
+                                    NULL,
+                                    UserMode);
+    if (!NT_SUCCESS(Status))
     {
-        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;
+        *AccessStatus = Status;
+        return FALSE;
+    }
 
-        /* Succeed if there are no more rights to grant */
-        if (RemainingAccess == 0)
-        {
-            *GrantedAccess = PreviouslyGrantedAccess;
-            *AccessStatus = STATUS_SUCCESS;
-            return TRUE;
-        }
+    /* Succeed if there are no more rights to grant */
+    if (RemainingAccess == 0)
+    {
+        *GrantedAccess = PreviouslyGrantedAccess;
+        *AccessStatus = STATUS_SUCCESS;
+        return TRUE;
     }
 
     /* Get the DACL */
@@ -143,35 +130,6 @@ SepAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
     CurrentAccess = PreviouslyGrantedAccess;
 #endif
 
-    /* RULE 2: Check token for 'take ownership' privilege */
-    if (DesiredAccess & WRITE_OWNER)
-    {
-        Privilege.Luid = SeTakeOwnershipPrivilege;
-        Privilege.Attributes = SE_PRIVILEGE_ENABLED;
-
-        if (SepPrivilegeCheck(Token,
-                              &Privilege,
-                              1,
-                              PRIVILEGE_SET_ALL_NECESSARY,
-                              AccessMode))
-        {
-            /* 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;
-            }
-        }
-    }
-
     /* Deny access if the DACL is empty */
     if (Dacl->AceCount == 0)
     {
index a89077a..292da12 100644 (file)
@@ -89,6 +89,9 @@ SepPrivilegeCheck(PTOKEN Token,
     /* Get the number of privileges that are required to match */
     Required = (PrivilegeControl & PRIVILEGE_SET_ALL_NECESSARY) ? PrivilegeCount : 1;
 
+    /* Acquire a shared token lock */
+    SepAcquireTokenLockShared(Token);
+
     /* Loop all requested privileges until we found the required ones */
     for (i = 0; i < PrivilegeCount; i++)
     {
@@ -96,8 +99,7 @@ SepPrivilegeCheck(PTOKEN Token,
         for (j = 0; j < Token->PrivilegeCount; j++)
         {
             /* Check if the LUIDs match */
-            if (Token->Privileges[j].Luid.LowPart == Privileges[i].Luid.LowPart &&
-                Token->Privileges[j].Luid.HighPart == Privileges[i].Luid.HighPart)
+            if (RtlEqualLuid(&Token->Privileges[j].Luid, &Privileges[i].Luid))
             {
                 DPRINT("Found privilege. Attributes: %lx\n",
                        Token->Privileges[j].Attributes);
@@ -112,6 +114,7 @@ SepPrivilegeCheck(PTOKEN Token,
                     if (Required == 0)
                     {
                         /* We're done! */
+                        SepReleaseTokenLock(Token);
                         return TRUE;
                     }
                 }
@@ -122,11 +125,133 @@ SepPrivilegeCheck(PTOKEN Token,
         }
     }
 
+    /* Release the token lock */
+    SepReleaseTokenLock(Token);
+
     /* When we reached this point, we did not find all privileges */
     NT_ASSERT(Required > 0);
     return FALSE;
 }
 
+NTSTATUS
+NTAPI
+SepSinglePrivilegeCheck(
+    LUID PrivilegeValue,
+    PTOKEN Token,
+    KPROCESSOR_MODE PreviousMode)
+{
+    LUID_AND_ATTRIBUTES Privilege;
+    PAGED_CODE();
+    ASSERT(!RtlEqualLuid(&PrivilegeValue, &SeTcbPrivilege));
+
+    Privilege.Luid = PrivilegeValue;
+    Privilege.Attributes = SE_PRIVILEGE_ENABLED;
+    return SepPrivilegeCheck(Token,
+                             &Privilege,
+                             1,
+                             PRIVILEGE_SET_ALL_NECESSARY,
+                             PreviousMode);
+}
+
+NTSTATUS
+NTAPI
+SePrivilegePolicyCheck(
+    _Inout_ PACCESS_MASK DesiredAccess,
+    _Inout_ PACCESS_MASK GrantedAccess,
+    _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
+    _In_ PTOKEN Token,
+    _Out_opt_ PPRIVILEGE_SET *OutPrivilegeSet,
+    _In_ KPROCESSOR_MODE PreviousMode)
+{
+    SIZE_T PrivilegeSize;
+    PPRIVILEGE_SET PrivilegeSet;
+    ULONG PrivilegeCount = 0, Index = 0;
+    ACCESS_MASK AccessMask = 0;
+    PAGED_CODE();
+
+    /* Check if we have a security subject context */
+    if (SubjectContext != NULL)
+    {
+        /* Check if there is a client impersonation token */
+        if (SubjectContext->ClientToken != NULL)
+            Token = SubjectContext->ClientToken;
+        else
+            Token = SubjectContext->PrimaryToken;
+    }
+
+    /* Check if the caller wants ACCESS_SYSTEM_SECURITY access */
+    if (*DesiredAccess & ACCESS_SYSTEM_SECURITY)
+    {
+        /* Do the privilege check */
+        if (SepSinglePrivilegeCheck(SeSecurityPrivilege, Token, PreviousMode))
+        {
+            /* Remember this access flag */
+            AccessMask |= ACCESS_SYSTEM_SECURITY;
+            PrivilegeCount++;
+        }
+        else
+        {
+            return STATUS_PRIVILEGE_NOT_HELD;
+        }
+    }
+
+    /* Check if the caller wants WRITE_OWNER access */
+    if (*DesiredAccess & WRITE_OWNER)
+    {
+        /* Do the privilege check */
+        if (SepSinglePrivilegeCheck(SeTakeOwnershipPrivilege, Token, PreviousMode))
+        {
+            /* Remember this access flag */
+            AccessMask |= WRITE_OWNER;
+            PrivilegeCount++;
+        }
+    }
+
+    /* Update the access masks */
+    *GrantedAccess |= AccessMask;
+    *DesiredAccess &= ~AccessMask;
+
+    /* Does the caller want a privilege set? */
+    if (OutPrivilegeSet != NULL)
+    {
+        /* Do we have any privileges to report? */
+        if (PrivilegeCount > 0)
+        {
+            /* Calculate size and allocate the structure */
+            PrivilegeSize = FIELD_OFFSET(PRIVILEGE_SET, Privilege[PrivilegeCount]);
+            PrivilegeSet = ExAllocatePoolWithTag(PagedPool, PrivilegeSize, 'rPeS');
+            *OutPrivilegeSet = PrivilegeSet;
+            if (PrivilegeSet == NULL)
+            {
+                return STATUS_INSUFFICIENT_RESOURCES;
+            }
+
+            PrivilegeSet->PrivilegeCount = PrivilegeCount;
+            PrivilegeSet->Control = 0;
+
+            if (AccessMask & WRITE_OWNER)
+            {
+                PrivilegeSet->Privilege[Index].Luid = SeTakeOwnershipPrivilege;
+                PrivilegeSet->Privilege[Index].Attributes = SE_PRIVILEGE_USED_FOR_ACCESS;
+                Index++;
+            }
+
+            if (AccessMask & ACCESS_SYSTEM_SECURITY)
+            {
+                PrivilegeSet->Privilege[Index].Luid = SeSecurityPrivilege;
+                PrivilegeSet->Privilege[Index].Attributes = SE_PRIVILEGE_USED_FOR_ACCESS;
+            }
+        }
+        else
+        {
+            /* No privileges, no structure */
+            *OutPrivilegeSet = NULL;
+        }
+    }
+
+    return STATUS_SUCCESS;
+}
+
 NTSTATUS
 NTAPI
 SeCaptureLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Src,