[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / se / priv.c
index 403888b..0766492 100644 (file)
@@ -1,23 +1,23 @@
-/* $Id: priv.c,v 1.4 2002/09/07 15:13:06 chorns Exp $
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS kernel
+ * FILE:            ntoskrnl/se/priv.c
+ * PURPOSE:         Security manager
  *
- * COPYRIGHT:         See COPYING in the top level directory
- * PROJECT:           ReactOS kernel
- * PURPOSE:           Security manager
- * FILE:              kernel/se/priv.c
- * PROGRAMER:         ?
- * REVISION HISTORY:
- *                 26/07/98: Added stubs for security functions
+ * 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;
@@ -42,265 +42,465 @@ LUID SeAuditPrivilege;
 LUID SeSystemEnvironmentPrivilege;
 LUID SeChangeNotifyPrivilege;
 LUID SeRemoteShutdownPrivilege;
+LUID SeUndockPrivilege;
+LUID SeSyncAgentPrivilege;
+LUID SeEnableDelegationPrivilege;
 
-
-/* FUNCTIONS ***************************************************************/
+/* PRIVATE FUNCTIONS **********************************************************/
 
 VOID
-SepInitPrivileges(VOID)
+INIT_FUNCTION
+NTAPI
+SepInitPrivileges (VOID)
 {
-  SeCreateTokenPrivilege.QuadPart = SE_CREATE_TOKEN_PRIVILEGE;
-  SeAssignPrimaryTokenPrivilege.QuadPart = SE_ASSIGNPRIMARYTOKEN_PRIVILEGE;
-  SeLockMemoryPrivilege.QuadPart = SE_LOCK_MEMORY_PRIVILEGE;
-  SeIncreaseQuotaPrivilege.QuadPart = SE_INCREASE_QUOTA_PRIVILEGE;
-  SeUnsolicitedInputPrivilege.QuadPart = SE_UNSOLICITED_INPUT_PRIVILEGE;
-  SeTcbPrivilege.QuadPart = SE_TCB_PRIVILEGE;
-  SeSecurityPrivilege.QuadPart = SE_SECURITY_PRIVILEGE;
-  SeTakeOwnershipPrivilege.QuadPart = SE_TAKE_OWNERSHIP_PRIVILEGE;
-  SeLoadDriverPrivilege.QuadPart = SE_LOAD_DRIVER_PRIVILEGE;
-  SeSystemProfilePrivilege.QuadPart = SE_SYSTEM_PROFILE_PRIVILEGE;
-  SeSystemtimePrivilege.QuadPart = SE_SYSTEMTIME_PRIVILEGE;
-  SeProfileSingleProcessPrivilege.QuadPart = SE_PROF_SINGLE_PROCESS_PRIVILEGE;
-  SeIncreaseBasePriorityPrivilege.QuadPart = SE_INC_BASE_PRIORITY_PRIVILEGE;
-  SeCreatePagefilePrivilege.QuadPart = SE_CREATE_PAGEFILE_PRIVILEGE;
-  SeCreatePermanentPrivilege.QuadPart = SE_CREATE_PERMANENT_PRIVILEGE;
-  SeBackupPrivilege.QuadPart = SE_BACKUP_PRIVILEGE;
-  SeRestorePrivilege.QuadPart = SE_RESTORE_PRIVILEGE;
-  SeShutdownPrivilege.QuadPart = SE_SHUTDOWN_PRIVILEGE;
-  SeDebugPrivilege.QuadPart = SE_DEBUG_PRIVILEGE;
-  SeAuditPrivilege.QuadPart = SE_AUDIT_PRIVILEGE;
-  SeSystemEnvironmentPrivilege.QuadPart = SE_SYSTEM_ENVIRONMENT_PRIVILEGE;
-  SeChangeNotifyPrivilege.QuadPart = SE_CHANGE_NOTIFY_PRIVILEGE;
-  SeRemoteShutdownPrivilege.QuadPart = SE_REMOTE_SHUTDOWN_PRIVILEGE;
+    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 SepPrivilegeCheck(PIACCESS_TOKEN Token,
-                         PLUID_AND_ATTRIBUTES Privileges,
-                         ULONG PrivilegeCount,
-                         ULONG PrivilegeControl,
-                         KPROCESSOR_MODE PreviousMode)
+BOOLEAN
+NTAPI
+SepPrivilegeCheck (PTOKEN Token,
+                   PLUID_AND_ATTRIBUTES Privileges,
+                   ULONG PrivilegeCount,
+                   ULONG PrivilegeControl,
+                   KPROCESSOR_MODE PreviousMode)
 {
-   ULONG i;
-   PLUID_AND_ATTRIBUTES_ARRAY Current;
-   ULONG j;
-   ULONG k;
-   
-   if (PreviousMode == KernelMode)
-     {
-       return(TRUE);
-     }
-   
-   j = 0;
-   if (PrivilegeCount != 0)
-     {
-       k = PrivilegeCount;
-       do
-         {
-            i = Token->PrivilegeCount;
-            Current = Token->Privileges;
-            for (i = 0; i < Token->PrivilegeCount; i++)
-              {
-                 if (!(Current[i]->Attributes & SE_PRIVILEGE_ENABLED) &&
-                     Privileges[i].Luid.u.LowPart == 
-                     Current[i]->Luid.u.LowPart &&
-                     Privileges[i].Luid.u.HighPart == 
-                     Current[i]->Luid.u.HighPart)
-                   {
-                      Privileges[i].Attributes = 
-                        Privileges[i].Attributes | 
-                        SE_PRIVILEGE_USED_FOR_ACCESS;
-                      j++;
-                      break;
-                   }
-              }
-            k--;
-         } while (k > 0);
-     }
-   
-   if ((PrivilegeControl & PRIVILEGE_SET_ALL_NECESSARY) && 
-       PrivilegeCount == j)       
-     {
-       return(TRUE);
-     }
-       
-   if (j > 0 && 
-       !(PrivilegeControl & PRIVILEGE_SET_ALL_NECESSARY))
-     {
-       return(TRUE);
-     }
-
-   return(FALSE);
+    ULONG i;
+    ULONG j;
+    ULONG k;
+    
+    DPRINT ("SepPrivilegeCheck() called\n");
+    
+    PAGED_CODE();
+    
+    if (PreviousMode == KernelMode)
+    {
+        return TRUE;
+    }
+    
+    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++;
+                    }
+                }
+            }
+        }
+    }
+    
+    if ((PrivilegeControl & PRIVILEGE_SET_ALL_NECESSARY) &&
+        PrivilegeCount == k)
+    {
+        return TRUE;
+    }
+    
+    if (k > 0 &&
+        !(PrivilegeControl & PRIVILEGE_SET_ALL_NECESSARY))
+    {
+        return TRUE;
+    }
+    
+    return FALSE;
 }
 
-
-NTSTATUS SeCaptureLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Src,
-                                        ULONG PrivilegeCount,
-                                        KPROCESSOR_MODE PreviousMode,
-                                        PLUID_AND_ATTRIBUTES AllocatedMem,
-                                        ULONG AllocatedLength,
-                                        POOL_TYPE PoolType,
-                                        ULONG d,
-                                        PLUID_AND_ATTRIBUTES* Dest,
-                                        PULONG Length)
+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_ATTRIBUTES* Dest,
+                                 PULONG Length)
 {
-   PLUID_AND_ATTRIBUTES* NewMem;
-   ULONG SrcLength;
-   
-   if (PrivilegeCount == 0)
-     {
-       *Dest = 0;
-       *Length = 0;
-       return(STATUS_SUCCESS);
-     }
-   if (PreviousMode == 0 && d == 0)
-     {
-       *Dest = Src;
-       return(STATUS_SUCCESS);
-     }
-   SrcLength = ((PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)) + 3) & 0xfc;
-   *Length = SrcLength;
-   if (AllocatedMem == NULL)
-     {
-       NewMem = ExAllocatePool(PoolType, SrcLength);
-       *Dest =  (PLUID_AND_ATTRIBUTES)NewMem;
-       if (NewMem == NULL)
-         {
-            return(STATUS_UNSUCCESSFUL);
-         }
-     }
-   else
-     {
-       if (SrcLength > AllocatedLength)
-         {
-            return(STATUS_UNSUCCESSFUL);
-         }
-       *Dest = AllocatedMem;
-     }
-   memmove(*Dest, Src, SrcLength);
-   return(STATUS_SUCCESS);
+    ULONG BufferSize;
+    NTSTATUS Status = STATUS_SUCCESS;
+    
+    PAGED_CODE();
+    
+    if (PrivilegeCount == 0)
+    {
+        *Dest = 0;
+        *Length = 0;
+        return STATUS_SUCCESS;
+    }
+    
+    if (PreviousMode == KernelMode && !CaptureIfKernel)
+    {
+        *Dest = Src;
+        return STATUS_SUCCESS;
+    }
+    
+    /* FIXME - check PrivilegeCount for a valid number so we don't
+     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 */
+    
+    /* probe the buffer */
+    if (PreviousMode != KernelMode)
+    {
+        _SEH2_TRY
+        {
+            ProbeForRead(Src,
+                         BufferSize,
+                         sizeof(ULONG));
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* 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 */
+    if (AllocatedMem != NULL)
+    {
+        if (AllocatedLength < BufferSize)
+        {
+            return STATUS_BUFFER_TOO_SMALL;
+        }
+        
+        *Dest = AllocatedMem;
+    }
+    else
+    {
+        *Dest = ExAllocatePool(PoolType,
+                               BufferSize);
+        
+        if (*Dest == NULL)
+        {
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+    }
+    
+    /* copy the array to the buffer */
+    _SEH2_TRY
+    {
+        RtlCopyMemory(*Dest,
+                      Src,
+                      BufferSize);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
+    
+    if (!NT_SUCCESS(Status) && AllocatedMem == NULL)
+    {
+        ExFreePool(*Dest);
+    }
+    
+    return Status;
 }
 
 VOID
-SeReleaseLuidAndAttributesArray(PLUID_AND_ATTRIBUTES Privilege,
-                               KPROCESSOR_MODE PreviousMode,
-                               ULONG a)
+NTAPI
+SeReleaseLuidAndAttributesArray (PLUID_AND_ATTRIBUTES Privilege,
+                                 KPROCESSOR_MODE PreviousMode,
+                                 BOOLEAN CaptureIfKernel)
 {
-   ExFreePool(Privilege);
+    PAGED_CODE();
+    
+    if (Privilege != NULL &&
+        (PreviousMode != KernelMode || CaptureIfKernel))
+    {
+        ExFreePool(Privilege);
+    }
 }
 
-NTSTATUS STDCALL
-NtPrivilegeCheck(IN HANDLE ClientToken,
-                IN PPRIVILEGE_SET RequiredPrivileges,
-                IN PBOOLEAN Result)
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+SeAppendPrivileges(PACCESS_STATE AccessState,
+                   PPRIVILEGE_SET Privileges)
 {
-   NTSTATUS Status;
-   PIACCESS_TOKEN iToken;
-   ULONG PrivilegeCount;
-   BOOLEAN TResult;
-   ULONG PrivilegeControl;
-   PLUID_AND_ATTRIBUTES Privilege;
-   ULONG Length;
-   
-   Status = ObReferenceObjectByHandle(ClientToken,
-                                     0,
-                                     SepTokenObjectType,
-                                     UserMode,
-                                     (PVOID*)&iToken,
-                                     NULL);
-   if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
-   if (iToken->TokenType == TokenImpersonation &&
-       iToken->ImpersonationLevel < SecurityAnonymous)
-     {
-       ObDereferenceObject(iToken);
-       return(STATUS_UNSUCCESSFUL);
-     }
-   PrivilegeCount = RequiredPrivileges->PrivilegeCount;
-   PrivilegeControl = RequiredPrivileges->Control;
-   Privilege = 0;
-   Status = SeCaptureLuidAndAttributesArray(RequiredPrivileges->Privilege,
-                                           PrivilegeCount,
-                                           1,
-                                           0,
-                                           0,
-                                           1,
-                                           1,
-                                           &Privilege,
-                                           &Length);
-   if (!NT_SUCCESS(Status))
-     {
-       ObDereferenceObject(iToken);
-       return(STATUS_UNSUCCESSFUL);
-     }
-   TResult = SepPrivilegeCheck(iToken,
-                              Privilege,
-                              PrivilegeCount,
-                              PrivilegeControl,
-                              UserMode);
-   memmove(RequiredPrivileges->Privilege, Privilege, Length);
-   *Result = TResult;
-   SeReleaseLuidAndAttributesArray(Privilege, UserMode, 1);
-   return(STATUS_SUCCESS);
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
 }
 
-BOOLEAN STDCALL
-SePrivilegeCheck(PPRIVILEGE_SET Privileges,
-                PSECURITY_SUBJECT_CONTEXT SubjectContext,
-                KPROCESSOR_MODE PreviousMode)
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+SeFreePrivileges(IN PPRIVILEGE_SET Privileges)
 {
-   PIACCESS_TOKEN iToken = NULL;
-   
-   if (SubjectContext->ClientToken == NULL)
-     {
-       iToken = SubjectContext->PrimaryToken;
-     }
-   else
-     {
-       iToken = SubjectContext->ClientToken;
-       if (SubjectContext->ImpersonationLevel < 2)
-         {
-            return(FALSE);
-         }
-     }
-   
-   return(SepPrivilegeCheck(iToken,
-                           Privileges->Privilege,
-                           Privileges->PrivilegeCount,
-                           Privileges->Control,
-                           PreviousMode));
+    PAGED_CODE();
+    ExFreePool(Privileges);
 }
 
-BOOLEAN STDCALL
-SeSinglePrivilegeCheck(IN LUID PrivilegeValue,
-                      IN KPROCESSOR_MODE PreviousMode)
+/*
+ * @implemented
+ */
+BOOLEAN NTAPI
+SePrivilegeCheck (PPRIVILEGE_SET Privileges,
+                  PSECURITY_SUBJECT_CONTEXT SubjectContext,
+                  KPROCESSOR_MODE PreviousMode)
 {
-   SECURITY_SUBJECT_CONTEXT SubjectContext;
-   BOOLEAN r;
-   PRIVILEGE_SET Priv;
-   
-   SeCaptureSubjectContext(&SubjectContext);
-   
-   Priv.PrivilegeCount = 1;
-   Priv.Control = 1;
-   Priv.Privilege[0].Luid = PrivilegeValue;
-   Priv.Privilege[0].Attributes = 0;
-   
-   r = SePrivilegeCheck(&Priv,
-                       &SubjectContext,
-                       PreviousMode);
-      
-   if (PreviousMode != KernelMode)
-     {
+    PACCESS_TOKEN Token = NULL;
+    
+    PAGED_CODE();
+    
+    if (SubjectContext->ClientToken == NULL)
+    {
+        Token = SubjectContext->PrimaryToken;
+    }
+    else
+    {
+        Token = SubjectContext->ClientToken;
+        if (SubjectContext->ImpersonationLevel < 2)
+        {
+            return FALSE;
+        }
+    }
+    
+    return SepPrivilegeCheck (Token,
+                              Privileges->Privilege,
+                              Privileges->PrivilegeCount,
+                              Privileges->Control,
+                              PreviousMode);
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN NTAPI
+SeSinglePrivilegeCheck (IN LUID PrivilegeValue,
+                        IN KPROCESSOR_MODE PreviousMode)
+{
+    SECURITY_SUBJECT_CONTEXT SubjectContext;
+    PRIVILEGE_SET Priv;
+    BOOLEAN Result;
+    
+    PAGED_CODE();
+    
+    SeCaptureSubjectContext (&SubjectContext);
+    
+    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);
+    
+    if (PreviousMode != KernelMode)
+    {
 #if 0
-       SePrivilegeServiceAuditAlarm(0,
-                                    &SubjectContext,
-                                    &PrivilegeValue);
+        SePrivilegedServiceAuditAlarm (0,
+                                       &SubjectContext,
+                                       &PrivilegeValue);
 #endif
-     }
-   SeReleaseSubjectContext(&SubjectContext);
-   return(r);
+    }
+    
+    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;
+    }
+    
+    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 */