[NTOSKRNL]
authorEric Kohl <eric.kohl@reactos.org>
Tue, 13 Jun 2017 20:58:10 +0000 (20:58 +0000)
committerEric Kohl <eric.kohl@reactos.org>
Tue, 13 Jun 2017 20:58:10 +0000 (20:58 +0000)
NtAccessCheck: Call SePrivilegePolicyCheck to get the list of required privileges and return it to the caller.
This fixes the ERROR_INSUFFICIENT_BUFFER failures in the advapi32 security winetest.

svn path=/trunk/; revision=75028

reactos/ntoskrnl/se/accesschk.c

index 9b84b46..a7784b1 100644 (file)
@@ -316,6 +316,19 @@ SepGetSDGroup(IN PSECURITY_DESCRIPTOR _SecurityDescriptor)
     return Group;
 }
 
+static
+ULONG
+SepGetPrivilegeSetLength(IN PPRIVILEGE_SET PrivilegeSet)
+{
+    if (PrivilegeSet == NULL)
+        return 0;
+
+    if (PrivilegeSet->PrivilegeCount == 0)
+        return (ULONG)(sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES));
+
+    return (ULONG)(sizeof(PRIVILEGE_SET) +
+                   (PrivilegeSet->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES));
+}
 
 /* PUBLIC FUNCTIONS ***********************************************************/
 
@@ -526,6 +539,8 @@ NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
     SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     ACCESS_MASK PreviouslyGrantedAccess = 0;
+    PPRIVILEGE_SET Privileges = NULL;
+    ULONG CapturedPrivilegeSetLength, RequiredPrivilegeSetLength;
     PTOKEN Token;
     NTSTATUS Status;
     PAGED_CODE();
@@ -561,8 +576,8 @@ NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
         ProbeForWrite(GrantedAccess, sizeof(ACCESS_MASK), sizeof(ULONG));
         ProbeForWrite(AccessStatus, sizeof(NTSTATUS), sizeof(ULONG));
 
-        /* Initialize the privilege set */
-        PrivilegeSet->PrivilegeCount = 0;
+        /* Capture the privilege set length and the mapping */
+        CapturedPrivilegeSetLength = *PrivilegeSetLength;
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
@@ -604,6 +619,64 @@ NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
         return STATUS_BAD_IMPERSONATION_LEVEL;
     }
 
+    /* Check for ACCESS_SYSTEM_SECURITY and WRITE_OWNER access */
+    Status = SePrivilegePolicyCheck(&DesiredAccess,
+                                    &PreviouslyGrantedAccess,
+                                    NULL,
+                                    Token,
+                                    &Privileges,
+                                    PreviousMode);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT("SePrivilegePolicyCheck failed (Status 0x%08lx)\n", Status);
+        ObDereferenceObject(Token);
+        *AccessStatus = Status;
+        *GrantedAccess = 0;
+        return STATUS_SUCCESS;
+    }
+
+    /* Check the size of the privilege set and return the privileges */
+    if (Privileges != NULL)
+    {
+        DPRINT("Privileges != NULL\n");
+
+        /* Calculate the required privilege set buffer size */
+        RequiredPrivilegeSetLength = SepGetPrivilegeSetLength(Privileges);
+
+        /* Fail if the privilege set buffer is too small */
+        if (CapturedPrivilegeSetLength < RequiredPrivilegeSetLength)
+        {
+            ObDereferenceObject(Token);
+            SeFreePrivileges(Privileges);
+            *PrivilegeSetLength = RequiredPrivilegeSetLength;
+            return STATUS_BUFFER_TOO_SMALL;
+        }
+
+        /* Copy the privilege set to the caller */
+        RtlCopyMemory(PrivilegeSet,
+                      Privileges,
+                      RequiredPrivilegeSetLength);
+
+        /* Free the local privilege set */
+        SeFreePrivileges(Privileges);
+    }
+    else
+    {
+        DPRINT("Privileges == NULL\n");
+
+        /* Fail if the privilege set buffer is too small */
+        if (CapturedPrivilegeSetLength < sizeof(PRIVILEGE_SET))
+        {
+            ObDereferenceObject(Token);
+            *PrivilegeSetLength = sizeof(PRIVILEGE_SET);
+            return STATUS_BUFFER_TOO_SMALL;
+        }
+
+        /* Initialize the privilege set */
+        PrivilegeSet->PrivilegeCount = 0;
+        PrivilegeSet->Control = 0;
+    }
+
     /* Capture the security descriptor */
     Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
                                          PreviousMode,