[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / se / priv.c
index f1341ed..6031942 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id$
- *
+/*
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/se/priv.c
@@ -8,18 +7,17 @@
  * PROGRAMMERS:     No programmer listed.
  */
 
-/* INCLUDES *****************************************************************/
+/* INCLUDES ******************************************************************/
 
 #include <ntoskrnl.h>
 #define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
 
 #if defined (ALLOC_PRAGMA)
 #pragma alloc_text(INIT, SepInitPrivileges)
 #endif
 
-
-/* GLOBALS *******************************************************************/
+/* GLOBALS ********************************************************************/
 
 LUID SeCreateTokenPrivilege;
 LUID SeAssignPrimaryTokenPrivilege;
@@ -48,141 +46,139 @@ LUID SeUndockPrivilege;
 LUID SeSyncAgentPrivilege;
 LUID SeEnableDelegationPrivilege;
 
-
-/* FUNCTIONS ***************************************************************/
+/* PRIVATE FUNCTIONS **********************************************************/
 
 VOID
 INIT_FUNCTION
 NTAPI
-SepInitPrivileges (VOID)
+SepInitPrivileges(VOID)
 {
-  SeCreateTokenPrivilege.LowPart = SE_CREATE_TOKEN_PRIVILEGE;
-  SeCreateTokenPrivilege.HighPart = 0;
-  SeAssignPrimaryTokenPrivilege.LowPart = SE_ASSIGNPRIMARYTOKEN_PRIVILEGE;
-  SeAssignPrimaryTokenPrivilege.HighPart = 0;
-  SeLockMemoryPrivilege.LowPart = SE_LOCK_MEMORY_PRIVILEGE;
-  SeLockMemoryPrivilege.HighPart = 0;
-  SeIncreaseQuotaPrivilege.LowPart = SE_INCREASE_QUOTA_PRIVILEGE;
-  SeIncreaseQuotaPrivilege.HighPart = 0;
-  SeUnsolicitedInputPrivilege.LowPart = SE_UNSOLICITED_INPUT_PRIVILEGE;
-  SeUnsolicitedInputPrivilege.HighPart = 0;
-  SeTcbPrivilege.LowPart = SE_TCB_PRIVILEGE;
-  SeTcbPrivilege.HighPart = 0;
-  SeSecurityPrivilege.LowPart = SE_SECURITY_PRIVILEGE;
-  SeSecurityPrivilege.HighPart = 0;
-  SeTakeOwnershipPrivilege.LowPart = SE_TAKE_OWNERSHIP_PRIVILEGE;
-  SeTakeOwnershipPrivilege.HighPart = 0;
-  SeLoadDriverPrivilege.LowPart = SE_LOAD_DRIVER_PRIVILEGE;
-  SeLoadDriverPrivilege.HighPart = 0;
-  SeSystemProfilePrivilege.LowPart = SE_SYSTEM_PROFILE_PRIVILEGE;
-  SeSystemProfilePrivilege.HighPart = 0;
-  SeSystemtimePrivilege.LowPart = SE_SYSTEMTIME_PRIVILEGE;
-  SeSystemtimePrivilege.HighPart = 0;
-  SeProfileSingleProcessPrivilege.LowPart = SE_PROF_SINGLE_PROCESS_PRIVILEGE;
-  SeProfileSingleProcessPrivilege.HighPart = 0;
-  SeIncreaseBasePriorityPrivilege.LowPart = SE_INC_BASE_PRIORITY_PRIVILEGE;
-  SeIncreaseBasePriorityPrivilege.HighPart = 0;
-  SeCreatePagefilePrivilege.LowPart = SE_CREATE_PAGEFILE_PRIVILEGE;
-  SeCreatePagefilePrivilege.HighPart = 0;
-  SeCreatePermanentPrivilege.LowPart = SE_CREATE_PERMANENT_PRIVILEGE;
-  SeCreatePermanentPrivilege.HighPart = 0;
-  SeBackupPrivilege.LowPart = SE_BACKUP_PRIVILEGE;
-  SeBackupPrivilege.HighPart = 0;
-  SeRestorePrivilege.LowPart = SE_RESTORE_PRIVILEGE;
-  SeRestorePrivilege.HighPart = 0;
-  SeShutdownPrivilege.LowPart = SE_SHUTDOWN_PRIVILEGE;
-  SeShutdownPrivilege.HighPart = 0;
-  SeDebugPrivilege.LowPart = SE_DEBUG_PRIVILEGE;
-  SeDebugPrivilege.HighPart = 0;
-  SeAuditPrivilege.LowPart = SE_AUDIT_PRIVILEGE;
-  SeAuditPrivilege.HighPart = 0;
-  SeSystemEnvironmentPrivilege.LowPart = SE_SYSTEM_ENVIRONMENT_PRIVILEGE;
-  SeSystemEnvironmentPrivilege.HighPart = 0;
-  SeChangeNotifyPrivilege.LowPart = SE_CHANGE_NOTIFY_PRIVILEGE;
-  SeChangeNotifyPrivilege.HighPart = 0;
-  SeRemoteShutdownPrivilege.LowPart = SE_REMOTE_SHUTDOWN_PRIVILEGE;
-  SeRemoteShutdownPrivilege.HighPart = 0;
-  SeUndockPrivilege.LowPart = SE_UNDOCK_PRIVILEGE;
-  SeUndockPrivilege.HighPart = 0;
-  SeSyncAgentPrivilege.LowPart = SE_SYNC_AGENT_PRIVILEGE;
-  SeSyncAgentPrivilege.HighPart = 0;
-  SeEnableDelegationPrivilege.LowPart = SE_ENABLE_DELEGATION_PRIVILEGE;
-  SeEnableDelegationPrivilege.HighPart = 0;
+    SeCreateTokenPrivilege.LowPart = SE_CREATE_TOKEN_PRIVILEGE;
+    SeCreateTokenPrivilege.HighPart = 0;
+    SeAssignPrimaryTokenPrivilege.LowPart = SE_ASSIGNPRIMARYTOKEN_PRIVILEGE;
+    SeAssignPrimaryTokenPrivilege.HighPart = 0;
+    SeLockMemoryPrivilege.LowPart = SE_LOCK_MEMORY_PRIVILEGE;
+    SeLockMemoryPrivilege.HighPart = 0;
+    SeIncreaseQuotaPrivilege.LowPart = SE_INCREASE_QUOTA_PRIVILEGE;
+    SeIncreaseQuotaPrivilege.HighPart = 0;
+    SeUnsolicitedInputPrivilege.LowPart = SE_UNSOLICITED_INPUT_PRIVILEGE;
+    SeUnsolicitedInputPrivilege.HighPart = 0;
+    SeTcbPrivilege.LowPart = SE_TCB_PRIVILEGE;
+    SeTcbPrivilege.HighPart = 0;
+    SeSecurityPrivilege.LowPart = SE_SECURITY_PRIVILEGE;
+    SeSecurityPrivilege.HighPart = 0;
+    SeTakeOwnershipPrivilege.LowPart = SE_TAKE_OWNERSHIP_PRIVILEGE;
+    SeTakeOwnershipPrivilege.HighPart = 0;
+    SeLoadDriverPrivilege.LowPart = SE_LOAD_DRIVER_PRIVILEGE;
+    SeLoadDriverPrivilege.HighPart = 0;
+    SeSystemProfilePrivilege.LowPart = SE_SYSTEM_PROFILE_PRIVILEGE;
+    SeSystemProfilePrivilege.HighPart = 0;
+    SeSystemtimePrivilege.LowPart = SE_SYSTEMTIME_PRIVILEGE;
+    SeSystemtimePrivilege.HighPart = 0;
+    SeProfileSingleProcessPrivilege.LowPart = SE_PROF_SINGLE_PROCESS_PRIVILEGE;
+    SeProfileSingleProcessPrivilege.HighPart = 0;
+    SeIncreaseBasePriorityPrivilege.LowPart = SE_INC_BASE_PRIORITY_PRIVILEGE;
+    SeIncreaseBasePriorityPrivilege.HighPart = 0;
+    SeCreatePagefilePrivilege.LowPart = SE_CREATE_PAGEFILE_PRIVILEGE;
+    SeCreatePagefilePrivilege.HighPart = 0;
+    SeCreatePermanentPrivilege.LowPart = SE_CREATE_PERMANENT_PRIVILEGE;
+    SeCreatePermanentPrivilege.HighPart = 0;
+    SeBackupPrivilege.LowPart = SE_BACKUP_PRIVILEGE;
+    SeBackupPrivilege.HighPart = 0;
+    SeRestorePrivilege.LowPart = SE_RESTORE_PRIVILEGE;
+    SeRestorePrivilege.HighPart = 0;
+    SeShutdownPrivilege.LowPart = SE_SHUTDOWN_PRIVILEGE;
+    SeShutdownPrivilege.HighPart = 0;
+    SeDebugPrivilege.LowPart = SE_DEBUG_PRIVILEGE;
+    SeDebugPrivilege.HighPart = 0;
+    SeAuditPrivilege.LowPart = SE_AUDIT_PRIVILEGE;
+    SeAuditPrivilege.HighPart = 0;
+    SeSystemEnvironmentPrivilege.LowPart = SE_SYSTEM_ENVIRONMENT_PRIVILEGE;
+    SeSystemEnvironmentPrivilege.HighPart = 0;
+    SeChangeNotifyPrivilege.LowPart = SE_CHANGE_NOTIFY_PRIVILEGE;
+    SeChangeNotifyPrivilege.HighPart = 0;
+    SeRemoteShutdownPrivilege.LowPart = SE_REMOTE_SHUTDOWN_PRIVILEGE;
+    SeRemoteShutdownPrivilege.HighPart = 0;
+    SeUndockPrivilege.LowPart = SE_UNDOCK_PRIVILEGE;
+    SeUndockPrivilege.HighPart = 0;
+    SeSyncAgentPrivilege.LowPart = SE_SYNC_AGENT_PRIVILEGE;
+    SeSyncAgentPrivilege.HighPart = 0;
+    SeEnableDelegationPrivilege.LowPart = SE_ENABLE_DELEGATION_PRIVILEGE;
+    SeEnableDelegationPrivilege.HighPart = 0;
 }
 
 
 BOOLEAN
 NTAPI
-SepPrivilegeCheck (PTOKEN Token,
-                  PLUID_AND_ATTRIBUTES Privileges,
-                  ULONG PrivilegeCount,
-                  ULONG PrivilegeControl,
-                  KPROCESSOR_MODE PreviousMode)
+SepPrivilegeCheck(PTOKEN Token,
+                  PLUID_AND_ATTRIBUTES Privileges,
+                  ULONG PrivilegeCount,
+                  ULONG PrivilegeControl,
+                  KPROCESSOR_MODE PreviousMode)
 {
-  ULONG i;
-  ULONG j;
-  ULONG k;
+    ULONG i;
+    ULONG j;
+    ULONG k;
 
-  DPRINT ("SepPrivilegeCheck() called\n");
+    DPRINT("SepPrivilegeCheck() called\n");
 
-  PAGED_CODE();
+    PAGED_CODE();
 
-  if (PreviousMode == KernelMode)
+    if (PreviousMode == KernelMode)
     {
-      return TRUE;
+        return TRUE;
     }
 
-  k = 0;
-  if (PrivilegeCount > 0)
+    k = 0;
+    if (PrivilegeCount > 0)
     {
-      for (i = 0; i < Token->PrivilegeCount; i++)
-       {
-         for (j = 0; j < PrivilegeCount; j++)
-           {
-             if (Token->Privileges[i].Luid.LowPart == Privileges[j].Luid.LowPart &&
-                 Token->Privileges[i].Luid.HighPart == Privileges[j].Luid.HighPart)
-               {
-                 DPRINT ("Found privilege\n");
-                 DPRINT ("Privilege attributes %lx\n",
-                         Token->Privileges[i].Attributes);
-
-                 if (Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED)
-                   {
-                     Privileges[j].Attributes |= SE_PRIVILEGE_USED_FOR_ACCESS;
-                     k++;
-                   }
-               }
-           }
-       }
+        for (i = 0; i < Token->PrivilegeCount; i++)
+        {
+            for (j = 0; j < PrivilegeCount; j++)
+            {
+                if (Token->Privileges[i].Luid.LowPart == Privileges[j].Luid.LowPart &&
+                    Token->Privileges[i].Luid.HighPart == Privileges[j].Luid.HighPart)
+                {
+                    DPRINT("Found privilege\n");
+                    DPRINT("Privilege attributes %lx\n",
+                           Token->Privileges[i].Attributes);
+
+                    if (Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED)
+                    {
+                        Privileges[j].Attributes |= SE_PRIVILEGE_USED_FOR_ACCESS;
+                        k++;
+                    }
+                }
+            }
+        }
     }
 
-  if ((PrivilegeControl & PRIVILEGE_SET_ALL_NECESSARY) &&
-      PrivilegeCount == k)
+    if ((PrivilegeControl & PRIVILEGE_SET_ALL_NECESSARY) &&
+        PrivilegeCount == k)
     {
-      return TRUE;
+        return TRUE;
     }
 
-  if (k > 0 &&
-      !(PrivilegeControl & PRIVILEGE_SET_ALL_NECESSARY))
+    if (k > 0 &&
+        !(PrivilegeControl & PRIVILEGE_SET_ALL_NECESSARY))
     {
-      return TRUE;
+        return TRUE;
     }
 
-  return FALSE;
+    return FALSE;
 }
 
-
 NTSTATUS
 NTAPI
-SeCaptureLuidAndAttributesArray (PLUID_AND_ATTRIBUTES Src,
-                                ULONG PrivilegeCount,
-                                KPROCESSOR_MODE PreviousMode,
-                                PLUID_AND_ATTRIBUTES AllocatedMem,
-                                ULONG AllocatedLength,
-                                POOL_TYPE PoolType,
-                                BOOLEAN CaptureIfKernel,
-                                PLUID_AND_ATTRIBUTESDest,
-                                PULONG Length)
+SeCaptureLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Src,
+                                ULONG PrivilegeCount,
+                                KPROCESSOR_MODE PreviousMode,
+                                PLUID_AND_ATTRIBUTES AllocatedMem,
+                                ULONG AllocatedLength,
+                                POOL_TYPE PoolType,
+                                BOOLEAN CaptureIfKernel,
+                                PLUID_AND_ATTRIBUTES *Dest,
+                                PULONG Length)
 {
     ULONG BufferSize;
     NTSTATUS Status = STATUS_SUCCESS;
@@ -203,7 +199,7 @@ SeCaptureLuidAndAttributesArray (PLUID_AND_ATTRIBUTES Src,
     }
 
     /* FIXME - check PrivilegeCount for a valid number so we don't
-               cause an integer overflow or exhaust system resources! */
+     cause an integer overflow or exhaust system resources! */
 
     BufferSize = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
     *Length = ROUND_UP(BufferSize, 4); /* round up to a 4 byte alignment */
@@ -211,26 +207,22 @@ SeCaptureLuidAndAttributesArray (PLUID_AND_ATTRIBUTES Src,
     /* probe the buffer */
     if (PreviousMode != KernelMode)
     {
-        _SEH_TRY
+        _SEH2_TRY
         {
             ProbeForRead(Src,
                          BufferSize,
                          sizeof(ULONG));
         }
-        _SEH_HANDLE
-        {
-            Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-
-        if (!NT_SUCCESS(Status))
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            return Status;
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
         }
+        _SEH2_END;
     }
 
     /* allocate enough memory or check if the provided buffer is
-       large enough to hold the array */
+     large enough to hold the array */
     if (AllocatedMem != NULL)
     {
         if (AllocatedLength < BufferSize)
@@ -244,25 +236,24 @@ SeCaptureLuidAndAttributesArray (PLUID_AND_ATTRIBUTES Src,
     {
         *Dest = ExAllocatePool(PoolType,
                                BufferSize);
-
-        if (&Dest == NULL)
+        if (*Dest == NULL)
         {
             return STATUS_INSUFFICIENT_RESOURCES;
         }
     }
-
+    
     /* copy the array to the buffer */
-    _SEH_TRY
+    _SEH2_TRY
     {
         RtlCopyMemory(*Dest,
                       Src,
                       BufferSize);
     }
-    _SEH_HANDLE
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-        Status = _SEH_GetExceptionCode();
+        Status = _SEH2_GetExceptionCode();
     }
-    _SEH_END;
+    _SEH2_END;
 
     if (!NT_SUCCESS(Status) && AllocatedMem == NULL)
     {
@@ -272,12 +263,11 @@ SeCaptureLuidAndAttributesArray (PLUID_AND_ATTRIBUTES Src,
     return Status;
 }
 
-
 VOID
 NTAPI
-SeReleaseLuidAndAttributesArray (PLUID_AND_ATTRIBUTES Privilege,
-                                KPROCESSOR_MODE PreviousMode,
-                                BOOLEAN CaptureIfKernel)
+SeReleaseLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Privilege,
+                                KPROCESSOR_MODE PreviousMode,
+                                BOOLEAN CaptureIfKernel)
 {
     PAGED_CODE();
 
@@ -288,208 +278,289 @@ SeReleaseLuidAndAttributesArray (PLUID_AND_ATTRIBUTES Privilege,
     }
 }
 
+/* PUBLIC FUNCTIONS ***********************************************************/
 
-NTSTATUS STDCALL
-NtPrivilegeCheck (IN HANDLE ClientToken,
-                 IN PPRIVILEGE_SET RequiredPrivileges,
-                 OUT PBOOLEAN Result)
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+SeAppendPrivileges(IN OUT PACCESS_STATE AccessState,
+                   IN PPRIVILEGE_SET Privileges)
 {
-  PLUID_AND_ATTRIBUTES Privileges;
-  PTOKEN Token;
-  ULONG PrivilegeCount = 0;
-  ULONG PrivilegeControl = 0;
-  ULONG Length;
-  BOOLEAN CheckResult;
-  KPROCESSOR_MODE PreviousMode;
-  NTSTATUS Status = STATUS_SUCCESS;
-
-  PAGED_CODE();
-
-  PreviousMode = KeGetPreviousMode();
-
-  /* probe the buffers */
-  if (PreviousMode != KernelMode)
-  {
-    _SEH_TRY
-    {
-      ProbeForWrite(RequiredPrivileges,
-                    FIELD_OFFSET(PRIVILEGE_SET,
-                                 Privilege),
-                    sizeof(ULONG));
-
-      PrivilegeCount = RequiredPrivileges->PrivilegeCount;
-      PrivilegeControl = RequiredPrivileges->Control;
-
-      /* Check PrivilegeCount to avoid an integer overflow! */
-      if (FIELD_OFFSET(PRIVILEGE_SET,
-                       Privilege[PrivilegeCount]) /
-          sizeof(RequiredPrivileges->Privilege[0]) != PrivilegeCount)
-      {
-          Status = STATUS_INVALID_PARAMETER;
-          _SEH_LEAVE;
-      }
-
-      /* probe all of the array */
-      ProbeForWrite(RequiredPrivileges,
-                    FIELD_OFFSET(PRIVILEGE_SET,
-                                 Privilege[PrivilegeCount]),
-                    sizeof(ULONG));
-
-      ProbeForWriteBoolean(Result);
-    }
-    _SEH_HANDLE
-    {
-      Status = _SEH_GetExceptionCode();
-    }
-    _SEH_END;
+    PAUX_ACCESS_DATA AuxData;
+    ULONG OldPrivilegeSetSize;
+    ULONG NewPrivilegeSetSize;
+    PPRIVILEGE_SET PrivilegeSet;
 
-    if (!NT_SUCCESS(Status))
-    {
-      return Status;
-    }
-  }
-  else
-  {
-    PrivilegeCount = RequiredPrivileges->PrivilegeCount;
-    PrivilegeControl = RequiredPrivileges->Control;
-  }
-
-  /* reference the token and make sure we're
-     not doing an anonymous impersonation */
-  Status = ObReferenceObjectByHandle (ClientToken,
-                                     TOKEN_QUERY,
-                                     SepTokenObjectType,
-                                     PreviousMode,
-                                     (PVOID*)&Token,
-                                     NULL);
-  if (!NT_SUCCESS(Status))
-    {
-      return Status;
-    }
+    PAGED_CODE();
 
-  if (Token->TokenType == TokenImpersonation &&
-      Token->ImpersonationLevel < SecurityIdentification)
+    /* Get the Auxiliary Data */
+    AuxData = AccessState->AuxData;
+
+    /* Calculate the size of the old privilege set */
+    OldPrivilegeSetSize = sizeof(PRIVILEGE_SET) +
+                          (AuxData->PrivilegeSet->PrivilegeCount - 1) * sizeof(LUID_AND_ATTRIBUTES);
+
+    if (AuxData->PrivilegeSet->PrivilegeCount +
+        Privileges->PrivilegeCount > INITIAL_PRIVILEGE_COUNT)
     {
-      ObDereferenceObject (Token);
-      return STATUS_BAD_IMPERSONATION_LEVEL;
-    }
+        /* Calculate the size of the new privilege set */
+        NewPrivilegeSetSize = OldPrivilegeSetSize +
+                              Privileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
+
+        /* Allocate a new privilege set */
+        PrivilegeSet = ExAllocatePool(PagedPool, NewPrivilegeSetSize);
+        if (PrivilegeSet == NULL)
+            return STATUS_INSUFFICIENT_RESOURCES;
+
+        /* Copy original privileges from the acess state */
+        RtlCopyMemory(PrivilegeSet,
+                      AuxData->PrivilegeSet,
+                      OldPrivilegeSetSize);
+
+        /* Append privileges from the privilege set*/
+        RtlCopyMemory((PVOID)((ULONG_PTR)PrivilegeSet + OldPrivilegeSetSize),
+                      (PVOID)((ULONG_PTR)Privileges + sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES)),
+                      Privileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
+
+        /* Adjust the number of privileges in the new privilege set */
+        PrivilegeSet->PrivilegeCount += Privileges->PrivilegeCount;
+
+        /* Free the old privilege set if it was allocated */
+        if (AccessState->PrivilegesAllocated == TRUE)
+            ExFreePool(AuxData->PrivilegeSet);
 
-  /* capture the privileges */
-  Status = SeCaptureLuidAndAttributesArray (RequiredPrivileges->Privilege,
-                                           PrivilegeCount,
-                                           PreviousMode,
-                                           NULL,
-                                           0,
-                                           PagedPool,
-                                           TRUE,
-                                           &Privileges,
-                                           &Length);
-  if (!NT_SUCCESS(Status))
+        /* Now we are using an allocated privilege set */
+        AccessState->PrivilegesAllocated = TRUE;
+
+        /* Assign the new privileges to the access state */
+        AuxData->PrivilegeSet = PrivilegeSet;
+    }
+    else
     {
-      ObDereferenceObject (Token);
-      return Status;
+        /* Append privileges */
+        RtlCopyMemory((PVOID)((ULONG_PTR)AuxData->PrivilegeSet + OldPrivilegeSetSize),
+                      (PVOID)((ULONG_PTR)Privileges + sizeof(PRIVILEGE_SET) - sizeof(LUID_AND_ATTRIBUTES)),
+                      Privileges->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
+
+        /* Adjust the number of privileges in the target privilege set */
+        AuxData->PrivilegeSet->PrivilegeCount += Privileges->PrivilegeCount;
     }
 
-  CheckResult = SepPrivilegeCheck (Token,
-                                  Privileges,
-                                  PrivilegeCount,
-                                  PrivilegeControl,
-                                  PreviousMode);
-
-  ObDereferenceObject (Token);
-
-  /* return the array */
-  _SEH_TRY
-  {
-      RtlCopyMemory(RequiredPrivileges->Privilege,
-                    Privileges,
-                    PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
-      *Result = CheckResult;
-      Status = STATUS_SUCCESS;
-  }
-  _SEH_HANDLE
-  {
-      Status = _SEH_GetExceptionCode();
-  }
-  _SEH_END;
-
-  SeReleaseLuidAndAttributesArray (Privileges,
-                                  PreviousMode,
-                                  TRUE);
-
-  return Status;
+    return STATUS_SUCCESS;
 }
 
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+SeFreePrivileges(IN PPRIVILEGE_SET Privileges)
+{
+    PAGED_CODE();
+    ExFreePool(Privileges);
+}
 
 /*
  * @implemented
  */
-BOOLEAN STDCALL
-SePrivilegeCheck (PPRIVILEGE_SET Privileges,
-                 PSECURITY_SUBJECT_CONTEXT SubjectContext,
-                 KPROCESSOR_MODE PreviousMode)
+BOOLEAN
+NTAPI
+SePrivilegeCheck(PPRIVILEGE_SET Privileges,
+                 PSECURITY_SUBJECT_CONTEXT SubjectContext,
+                 KPROCESSOR_MODE PreviousMode)
 {
-  PACCESS_TOKEN Token = NULL;
+    PACCESS_TOKEN Token = NULL;
 
-  PAGED_CODE();
+    PAGED_CODE();
 
-  if (SubjectContext->ClientToken == NULL)
+    if (SubjectContext->ClientToken == NULL)
     {
-      Token = SubjectContext->PrimaryToken;
+        Token = SubjectContext->PrimaryToken;
     }
-  else
+    else
     {
-      Token = SubjectContext->ClientToken;
-      if (SubjectContext->ImpersonationLevel < 2)
-       {
-         return FALSE;
-       }
+        Token = SubjectContext->ClientToken;
+        if (SubjectContext->ImpersonationLevel < 2)
+        {
+            return FALSE;
+        }
     }
 
-  return SepPrivilegeCheck (Token,
-                           Privileges->Privilege,
-                           Privileges->PrivilegeCount,
-                           Privileges->Control,
-                           PreviousMode);
+    return SepPrivilegeCheck(Token,
+                             Privileges->Privilege,
+                             Privileges->PrivilegeCount,
+                             Privileges->Control,
+                             PreviousMode);
 }
 
-
 /*
  * @implemented
  */
-BOOLEAN STDCALL
-SeSinglePrivilegeCheck (IN LUID PrivilegeValue,
-                       IN KPROCESSOR_MODE PreviousMode)
+BOOLEAN
+NTAPI
+SeSinglePrivilegeCheck(IN LUID PrivilegeValue,
+                       IN KPROCESSOR_MODE PreviousMode)
 {
-  SECURITY_SUBJECT_CONTEXT SubjectContext;
-  PRIVILEGE_SET Priv;
-  BOOLEAN Result;
+    SECURITY_SUBJECT_CONTEXT SubjectContext;
+    PRIVILEGE_SET Priv;
+    BOOLEAN Result;
 
-  PAGED_CODE();
+    PAGED_CODE();
 
-  SeCaptureSubjectContext (&SubjectContext);
+    SeCaptureSubjectContext(&SubjectContext);
 
-  Priv.PrivilegeCount = 1;
-  Priv.Control = PRIVILEGE_SET_ALL_NECESSARY;
-  Priv.Privilege[0].Luid = PrivilegeValue;
-  Priv.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
+    Priv.PrivilegeCount = 1;
+    Priv.Control = PRIVILEGE_SET_ALL_NECESSARY;
+    Priv.Privilege[0].Luid = PrivilegeValue;
+    Priv.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
 
-  Result = SePrivilegeCheck (&Priv,
-                            &SubjectContext,
-                            PreviousMode);
+    Result = SePrivilegeCheck(&Priv,
+                              &SubjectContext,
+                              PreviousMode);
 
-  if (PreviousMode != KernelMode)
+    if (PreviousMode != KernelMode)
     {
 #if 0
-      SePrivilegedServiceAuditAlarm (0,
-                                    &SubjectContext,
-                                    &PrivilegeValue);
+        SePrivilegedServiceAuditAlarm(0,
+                                      &SubjectContext,
+                                      &PrivilegeValue);
 #endif
     }
 
-  SeReleaseSubjectContext (&SubjectContext);
+    SeReleaseSubjectContext(&SubjectContext);
+
+    return Result;
+}
+
+/* SYSTEM CALLS ***************************************************************/
+
+NTSTATUS
+NTAPI
+NtPrivilegeCheck(IN HANDLE ClientToken,
+                 IN PPRIVILEGE_SET RequiredPrivileges,
+                 OUT PBOOLEAN Result)
+{
+    PLUID_AND_ATTRIBUTES Privileges;
+    PTOKEN Token;
+    ULONG PrivilegeCount = 0;
+    ULONG PrivilegeControl = 0;
+    ULONG Length;
+    BOOLEAN CheckResult;
+    KPROCESSOR_MODE PreviousMode;
+    NTSTATUS Status;
+
+    PAGED_CODE();
+
+    PreviousMode = KeGetPreviousMode();
+
+    /* probe the buffers */
+    if (PreviousMode != KernelMode)
+    {
+        _SEH2_TRY
+        {
+            ProbeForWrite(RequiredPrivileges,
+                          FIELD_OFFSET(PRIVILEGE_SET,
+                                       Privilege),
+                          sizeof(ULONG));
+
+            PrivilegeCount = RequiredPrivileges->PrivilegeCount;
+            PrivilegeControl = RequiredPrivileges->Control;
+
+            /* Check PrivilegeCount to avoid an integer overflow! */
+            if (FIELD_OFFSET(PRIVILEGE_SET,
+                             Privilege[PrivilegeCount]) /
+                sizeof(RequiredPrivileges->Privilege[0]) != PrivilegeCount)
+            {
+                _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
+            }
+
+            /* probe all of the array */
+            ProbeForWrite(RequiredPrivileges,
+                          FIELD_OFFSET(PRIVILEGE_SET,
+                                       Privilege[PrivilegeCount]),
+                          sizeof(ULONG));
+
+            ProbeForWriteBoolean(Result);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+    else
+    {
+        PrivilegeCount = RequiredPrivileges->PrivilegeCount;
+        PrivilegeControl = RequiredPrivileges->Control;
+    }
+
+    /* reference the token and make sure we're
+     not doing an anonymous impersonation */
+    Status = ObReferenceObjectByHandle(ClientToken,
+                                       TOKEN_QUERY,
+                                       SepTokenObjectType,
+                                       PreviousMode,
+                                       (PVOID*)&Token,
+                                       NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    if (Token->TokenType == TokenImpersonation &&
+        Token->ImpersonationLevel < SecurityIdentification)
+    {
+        ObDereferenceObject(Token);
+        return STATUS_BAD_IMPERSONATION_LEVEL;
+    }
+
+    /* capture the privileges */
+    Status = SeCaptureLuidAndAttributesArray(RequiredPrivileges->Privilege,
+                                             PrivilegeCount,
+                                             PreviousMode,
+                                             NULL,
+                                             0,
+                                             PagedPool,
+                                             TRUE,
+                                             &Privileges,
+                                             &Length);
+    if (!NT_SUCCESS(Status))
+    {
+        ObDereferenceObject (Token);
+        return Status;
+    }
 
-  return Result;
+    CheckResult = SepPrivilegeCheck(Token,
+                                    Privileges,
+                                    PrivilegeCount,
+                                    PrivilegeControl,
+                                    PreviousMode);
+
+    ObDereferenceObject(Token);
+
+    /* return the array */
+    _SEH2_TRY
+    {
+        RtlCopyMemory(RequiredPrivileges->Privilege,
+                      Privileges,
+                      PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
+        *Result = CheckResult;
+        Status = STATUS_SUCCESS;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
+
+    SeReleaseLuidAndAttributesArray(Privileges,
+                                    PreviousMode,
+                                    TRUE);
+
+    return Status;
 }
 
 /* EOF */