Add missing processor architecture cases
[reactos.git] / reactos / ntoskrnl / se / semgr.c
index 06c00a0..1f52a26 100644 (file)
-/* $Id: semgr.c,v 1.14 2000/01/05 21:57:00 dwelch Exp $
+/* $Id$
  *
- * COPYRIGHT:         See COPYING in the top level directory
- * PROJECT:           ReactOS kernel
- * PURPOSE:           Security manager
- * FILE:              kernel/se/semgr.c
- * PROGRAMER:         ?
- * REVISION HISTORY:
- *                 26/07/98: Added stubs for security functions
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS kernel
+ * FILE:            ntoskrnl/se/semgr.c
+ * PURPOSE:         Security manager
+ *
+ * PROGRAMMERS:     No programmer listed.
  */
 
 /* INCLUDES *****************************************************************/
 
-#include <ddk/ntddk.h>
-
+#include <ntoskrnl.h>
+#define NDEBUG
 #include <internal/debug.h>
 
-/* FUNCTIONS ***************************************************************/
+/* GLOBALS ******************************************************************/
 
-VOID SepReferenceLogonSession(PLUID AuthenticationId)
-{
-   UNIMPLEMENTED;
-}
+PSE_EXPORTS SeExports = NULL;
+SE_EXPORTS SepExports;
 
-VOID SepDeReferenceLogonSession(PLUID AuthenticationId)
-{
-   UNIMPLEMENTED;
-}
+static ERESOURCE SepSubjectContextLock;
 
-VOID SepFreeProxyData(PVOID ProxyData)
-{
-   UNIMPLEMENTED;
-}
 
-NTSTATUS SepCopyProxyData(PVOID* Dest, PVOID Src)
-{
-   UNIMPLEMENTED;
-}
+/* PROTOTYPES ***************************************************************/
 
-NTSTATUS SepDuplicationToken(PACCESS_TOKEN Token,
-                            PULONG a,
-                            ULONG b,
-                            TOKEN_TYPE TokenType,
-                            SECURITY_IMPERSONATION_LEVEL Level,
-                            ULONG d,
-                            PACCESS_TOKEN* e)
-{
-#if 0
-   PVOID mem1;
-   PVOID mem2;
-   PVOID f;
-   PACCESS_TOKEN g;
-   NTSTATUS Status;
-   
-   if (TokenType == 2 && 
-       (Level > 3 || Level < 0))
-     {
-       return(STATUS_UNSUCCESSFUL);
-     }
-   
-   SepReferenceLogonSession(&Token->AuthenticationId);
-   
-   mem1 = ExAllocatePool(NonPagedPool, Token->DynamicCharged);
-   if (mem1 == NULL)
-     {
-       SepDeReferenceLogonSession(&Token->AuthenticationId);
-       return(STATUS_UNSUCCESSFUL);
-     }
-   if (Token->ProxyData != NULL)
-     {
-       Status = SepCopyProxyData(&f, Token->ProxyData);
-       if (!NT_SUCCESS(Status))
-         {
-            SepDeReferenceLogonSession(&Token->AuthenticationId);
-            ExFreePool(mem1);
-            return(Status);
-         }
-     }
-   else
-     {
-       f = 0;
-     }
-   if (Token->AuditData != NULL)
-     {
-       mem2 = ExAllocatePool(NonPagedPool, 0xc);
-       if (mem2 == NULL)
-         {
-            SepFreeProxyData(f);
-            SepDeReferenceLogonSession(&Token->AuthenticationId);
-            ExFreePool(mem1);
-            return(STATUS_UNSUCCESSFUL);
-         }
-       memcpy(mem2, Token->AuditData, 0xc);
-     }
-   else
-     {
-       mem2 = NULL;
-     }
-   
-   Status = ObCreateObject(d,
-                          SeTokenType,
-                          b,
-                          d,
-                          0,
-                          Token->VariableLength + 0x78,
-                          Token->DynamicCharged,
-                          Token->VariableLength + 0x78,
-                          &g);
-   if (!NT_SUCCESS(Status))
-     {
-       SepDeReferenceLogonSession(Token->AuthenticationId);
-       ExFreePool(mem1);
-       SepFreeProxyData(f);
-       if (mem2 != NULL)
-         {
-            ExFreePool(mem2);
-         }
-       return(Status);
-     }
-   
-   g->TokenId = Token->TokenId;
-   g->ModifiedId = Token->ModifiedId;
-   g->ExpirationTime = Token->ExpirationTime;
-   memcpy(&g->TokenSource, &Token->TokenSource, sizeof(TOKEN_SOURCE));
-   g->DynamicCharged = Token->DynamicCharged;
-   g->DynamicAvailable = Token->DynamicAvailable;
-   g->DefaultOwnerIndex = Token->DefaultOwnerIndex;
-   g->UserAndGroupCount = Token->UserAndGroupCount;
-   g->PrivilegeCount = Token->PrivilegeCount;
-   g->VariableLength = Token->VariableLength;
-   g->TokenFlags = Token->TokenFlags;
-   g->ProxyData = f;
-   g->AuditData = mem2;
-   //g->TokenId = ExInterlockedExchangeAdd();
-   g->TokenInUse = 0;
-   g->TokenType = TokenType;
-   g->ImpersonationLevel = Level;
-   memmove(g->VariablePart, Token->VariablePart, Token->VariableLength);
-   /* ... */
-   *e = g;
-   return(STATUS_SUCCESS);
+static BOOLEAN SepInitExports(VOID);
+
+#if defined (ALLOC_PRAGMA)
+#pragma alloc_text(INIT, SeInit1)
+#pragma alloc_text(INIT, SeInit2)
+#pragma alloc_text(INIT, SepInitExports)
 #endif
-   UNIMPLEMENTED;   
-}
 
-NTSTATUS SeCopyClientToken(PACCESS_TOKEN Token,
-                          SECURITY_IMPERSONATION_LEVEL Level,
-                          ULONG a,
-                          PACCESS_TOKEN* b)
-{
-   ULONG c;
-   PACCESS_TOKEN d;
-   NTSTATUS Status;
-   
-   c = 18;
-   Status = SepDuplicationToken(Token,
-                               &c,
-                               0,
-                               TokenImpersonation,
-                               Level,
-                               a,
-                               &d);
-   *b = d;
-   return(Status);
-}
+/* FUNCTIONS ****************************************************************/
 
-NTSTATUS SeCreateClientSecurity(PETHREAD Thread,
-                               PSECURITY_QUALITY_OF_SERVICE Qos,
-                               ULONG e,
-                               PSE_SOME_STRUCT2 f)
+BOOLEAN 
+INIT_FUNCTION
+NTAPI
+SeInit1(VOID)
 {
-   TOKEN_TYPE TokenType;
-   UCHAR b;
-   SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
-   PACCESS_TOKEN Token;
-   ULONG g;   
-   PACCESS_TOKEN NewToken;
-   
-   Token = PsReferenceEffectiveToken(Thread,
-                                    &TokenType,
-                                    &b,
-                                    &ImpersonationLevel);
-   if (TokenType != 2)
-     {
-       f->Unknown9 = Qos->EffectiveOnly;
-     }
-   else
-     {
-       if (Qos->ImpersonationLevel > ImpersonationLevel)
-         {
-            if (Token != NULL)
-              {
-                 ObDereferenceObject(Token);
-              }
-            return(STATUS_UNSUCCESSFUL);
-         }
-       if (ImpersonationLevel == 0 ||
-           ImpersonationLevel == 1 ||
-           (e != 0 && ImpersonationLevel != 3))
-         {
-            if (Token != NULL)
-              {
-                 ObDereferenceObject(Token);
-              }
-            return(STATUS_UNSUCCESSFUL);
-         }
-       if (b != 0 ||
-           Qos->EffectiveOnly != 0)
-         {
-            f->Unknown9 = 1;
-         }
-       else
-         {
-            f->Unknown9 = 0;
-         }       
-     }
-   
-   if (Qos->ContextTrackingMode == 0)
-     {
-       f->Unknown8 = 0;
-       g = SeCopyClientToken(Token, ImpersonationLevel, 0, &NewToken);
-       if (g >= 0)
-         {
-//          ObDeleteCapturedInsertInfo(NewToken);
-         }
-       if (TokenType == TokenPrimary || Token != NULL)          
-         {
-            ObDereferenceObject(Token);
-         }
-       if (g < 0)
-         {
-            return(g);
-         }
-     }
-   else
-     {
-       f->Unknown8 = 1;
-       if (e != 0)
-         {
-//          SeGetTokenControlInformation(Token, &f->Unknown11);
-         }
-       NewToken = Token;
-     }
-   f->Unknown1 = 0xc;
-   f->Level = Qos->ImpersonationLevel;
-   f->ContextTrackingMode = Qos->ContextTrackingMode;
-   f->EffectiveOnly = Qos->EffectiveOnly;
-   f->Unknown10 = e;
-   f->Token = NewToken;
-   
-   return(STATUS_SUCCESS);
-}
+  SepInitLuid();
 
+  if (!SepInitSecurityIDs())
+    return FALSE;
 
-VOID SeImpersonateClient(PSE_SOME_STRUCT2 a,
-                        PETHREAD Thread)
-{
-   UCHAR b;
-   
-   if (a->Unknown8 == 0)
-     {
-       b = a->EffectiveOnly;
-     }
-   else
-     {
-       b = a->Unknown9;
-     }
-   if (Thread == NULL)
-     {
-       Thread = PsGetCurrentThread();
-     }
-   PsImpersonateClient(Thread, 
-                      a->Token, 
-                      1, 
-                      (ULONG)b, 
-                      a->Level);
-}
+  if (!SepInitDACLs())
+    return FALSE;
 
+  if (!SepInitSDs())
+    return FALSE;
 
+  SepInitPrivileges();
 
+  if (!SepInitExports())
+    return FALSE;
 
-NTSTATUS STDCALL NtPrivilegeCheck (IN  HANDLE          ClientToken,
-                                  IN   PPRIVILEGE_SET  RequiredPrivileges,  
-                                  IN   PBOOLEAN        Result)
-{
-   UNIMPLEMENTED;
+  /* Initialize the subject context lock */
+  ExInitializeResource(&SepSubjectContextLock);
+
+  return TRUE;
 }
 
 
-NTSTATUS STDCALL NtPrivilegedServiceAuditAlarm(
-                                            IN PUNICODE_STRING SubsystemName, 
-                                            IN PUNICODE_STRING ServiceName,   
-                                            IN HANDLE          ClientToken,
-                                            IN PPRIVILEGE_SET  Privileges,    
-                                            IN BOOLEAN         AccessGranted)
+BOOLEAN
+INIT_FUNCTION
+NTAPI
+SeInit2(VOID)
 {
-   UNIMPLEMENTED;
+  SepInitializeTokenImplementation();
+
+  return TRUE;
 }
 
 
-NTSTATUS
-STDCALL
-NtPrivilegeObjectAuditAlarm (
-       IN      PUNICODE_STRING SubsystemName,
-       IN      PVOID           HandleId,       
-       IN      HANDLE          ClientToken,
-       IN      ULONG           DesiredAccess,
-       IN      PPRIVILEGE_SET  Privileges,
-       IN      BOOLEAN         AccessGranted 
-       )
+BOOLEAN
+NTAPI
+SeInitSRM(VOID)
 {
-       UNIMPLEMENTED;
-}
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  UNICODE_STRING Name;
+  HANDLE DirectoryHandle;
+  HANDLE EventHandle;
+  NTSTATUS Status;
 
+  /* Create '\Security' directory */
+  RtlInitUnicodeString(&Name,
+                      L"\\Security");
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &Name,
+                            OBJ_PERMANENT,
+                            0,
+                            NULL);
+  Status = ZwCreateDirectoryObject(&DirectoryHandle,
+                                  DIRECTORY_ALL_ACCESS,
+                                  &ObjectAttributes);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("Failed to create 'Security' directory!\n");
+      return FALSE;
+    }
 
-NTSTATUS
-STDCALL
-NtOpenObjectAuditAlarm (
-       IN      PUNICODE_STRING         SubsystemName,  
-       IN      PVOID                   HandleId,       
-       IN      POBJECT_ATTRIBUTES      ObjectAttributes,
-       IN      HANDLE                  ClientToken,    
-       IN      ULONG                   DesiredAccess,  
-       IN      ULONG                   GrantedAccess,  
-       IN      PPRIVILEGE_SET          Privileges,
-       IN      BOOLEAN                 ObjectCreation, 
-       IN      BOOLEAN                 AccessGranted,  
-       OUT     PBOOLEAN                GenerateOnClose         
-       )
-{
-       UNIMPLEMENTED;
-}
+  /* Create 'LSA_AUTHENTICATION_INITALIZED' event */
+  RtlInitUnicodeString(&Name,
+                      L"\\LSA_AUTHENTICATION_INITALIZED");
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &Name,
+                            OBJ_PERMANENT,
+                            DirectoryHandle,
+                            SePublicDefaultSd);
+  Status = ZwCreateEvent(&EventHandle,
+                        EVENT_ALL_ACCESS,
+                        &ObjectAttributes,
+                        SynchronizationEvent,
+                        FALSE);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("Failed to create 'LSA_AUTHENTICATION_INITALIZED' event!\n");
+      NtClose(DirectoryHandle);
+      return FALSE;
+    }
 
-NTSTATUS
-STDCALL
-NtAccessCheckAndAuditAlarm (
-       IN PUNICODE_STRING SubsystemName,
-       IN PHANDLE ObjectHandle,        
-       IN POBJECT_ATTRIBUTES ObjectAttributes,
-       IN ACCESS_MASK DesiredAccess,   
-       IN PGENERIC_MAPPING GenericMapping,     
-       IN BOOLEAN ObjectCreation,      
-       OUT PULONG GrantedAccess,       
-       OUT PBOOLEAN AccessStatus,      
-       OUT PBOOLEAN GenerateOnClose
-       )
-{
-   UNIMPLEMENTED;
+  ZwClose(EventHandle);
+  ZwClose(DirectoryHandle);
+
+  /* FIXME: Create SRM port and listener thread */
+
+  return TRUE;
 }
 
 
-NTSTATUS
-STDCALL
-NtAllocateUuids (
-       PLARGE_INTEGER  Time,
-       PULONG          Version, // ???
-       PULONG          ClockCycle
-       )
+static BOOLEAN INIT_FUNCTION
+SepInitExports(VOID)
 {
-   UNIMPLEMENTED;
+  SepExports.SeCreateTokenPrivilege = SeCreateTokenPrivilege;
+  SepExports.SeAssignPrimaryTokenPrivilege = SeAssignPrimaryTokenPrivilege;
+  SepExports.SeLockMemoryPrivilege = SeLockMemoryPrivilege;
+  SepExports.SeIncreaseQuotaPrivilege = SeIncreaseQuotaPrivilege;
+  SepExports.SeUnsolicitedInputPrivilege = SeUnsolicitedInputPrivilege;
+  SepExports.SeTcbPrivilege = SeTcbPrivilege;
+  SepExports.SeSecurityPrivilege = SeSecurityPrivilege;
+  SepExports.SeTakeOwnershipPrivilege = SeTakeOwnershipPrivilege;
+  SepExports.SeLoadDriverPrivilege = SeLoadDriverPrivilege;
+  SepExports.SeCreatePagefilePrivilege = SeCreatePagefilePrivilege;
+  SepExports.SeIncreaseBasePriorityPrivilege = SeIncreaseBasePriorityPrivilege;
+  SepExports.SeSystemProfilePrivilege = SeSystemProfilePrivilege;
+  SepExports.SeSystemtimePrivilege = SeSystemtimePrivilege;
+  SepExports.SeProfileSingleProcessPrivilege = SeProfileSingleProcessPrivilege;
+  SepExports.SeCreatePermanentPrivilege = SeCreatePermanentPrivilege;
+  SepExports.SeBackupPrivilege = SeBackupPrivilege;
+  SepExports.SeRestorePrivilege = SeRestorePrivilege;
+  SepExports.SeShutdownPrivilege = SeShutdownPrivilege;
+  SepExports.SeDebugPrivilege = SeDebugPrivilege;
+  SepExports.SeAuditPrivilege = SeAuditPrivilege;
+  SepExports.SeSystemEnvironmentPrivilege = SeSystemEnvironmentPrivilege;
+  SepExports.SeChangeNotifyPrivilege = SeChangeNotifyPrivilege;
+  SepExports.SeRemoteShutdownPrivilege = SeRemoteShutdownPrivilege;
+
+  SepExports.SeNullSid = SeNullSid;
+  SepExports.SeWorldSid = SeWorldSid;
+  SepExports.SeLocalSid = SeLocalSid;
+  SepExports.SeCreatorOwnerSid = SeCreatorOwnerSid;
+  SepExports.SeCreatorGroupSid = SeCreatorGroupSid;
+  SepExports.SeNtAuthoritySid = SeNtAuthoritySid;
+  SepExports.SeDialupSid = SeDialupSid;
+  SepExports.SeNetworkSid = SeNetworkSid;
+  SepExports.SeBatchSid = SeBatchSid;
+  SepExports.SeInteractiveSid = SeInteractiveSid;
+  SepExports.SeLocalSystemSid = SeLocalSystemSid;
+  SepExports.SeAliasAdminsSid = SeAliasAdminsSid;
+  SepExports.SeAliasUsersSid = SeAliasUsersSid;
+  SepExports.SeAliasGuestsSid = SeAliasGuestsSid;
+  SepExports.SeAliasPowerUsersSid = SeAliasPowerUsersSid;
+  SepExports.SeAliasAccountOpsSid = SeAliasAccountOpsSid;
+  SepExports.SeAliasSystemOpsSid = SeAliasSystemOpsSid;
+  SepExports.SeAliasPrintOpsSid = SeAliasPrintOpsSid;
+  SepExports.SeAliasBackupOpsSid = SeAliasBackupOpsSid;
+  SepExports.SeAuthenticatedUsersSid = SeAuthenticatedUsersSid;
+  SepExports.SeRestrictedSid = SeRestrictedSid;
+  SepExports.SeAnonymousLogonSid = SeAnonymousLogonSid;
+
+  SepExports.SeUndockPrivilege = SeUndockPrivilege;
+  SepExports.SeSyncAgentPrivilege = SeSyncAgentPrivilege;
+  SepExports.SeEnableDelegationPrivilege = SeEnableDelegationPrivilege;
+  
+  SeExports = &SepExports;
+  return TRUE;
 }
 
 
-NTSTATUS STDCALL NtCloseObjectAuditAlarm(IN PUNICODE_STRING SubsystemName,     
-                                        IN PVOID HandleId,     
-                                        IN BOOLEAN GenerateOnClose)
+VOID SepReferenceLogonSession(PLUID AuthenticationId)
 {
    UNIMPLEMENTED;
 }
 
-NTSTATUS STDCALL NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
-                              IN HANDLE ClientToken,
-                              IN ACCESS_MASK DesiredAccess,
-                              IN PGENERIC_MAPPING GenericMapping,
-                               OUT PPRIVILEGE_SET PrivilegeSet,
-                              OUT PULONG ReturnLength,
-                              OUT PULONG GrantedAccess,
-                              OUT PBOOLEAN AccessStatus)
+VOID SepDeReferenceLogonSession(PLUID AuthenticationId)
 {
    UNIMPLEMENTED;
 }
 
-
 NTSTATUS
 STDCALL
-NtDeleteObjectAuditAlarm ( 
-       IN PUNICODE_STRING SubsystemName, 
-       IN PVOID HandleId, 
-       IN BOOLEAN GenerateOnClose 
-       )
+SeDefaultObjectMethod(PVOID Object,
+                      SECURITY_OPERATION_CODE OperationType,
+                      SECURITY_INFORMATION SecurityInformation,
+                      PSECURITY_DESCRIPTOR _SecurityDescriptor,
+                      PULONG ReturnLength,
+                      PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
+                      POOL_TYPE PoolType,
+                      PGENERIC_MAPPING GenericMapping)
 {
- UNIMPLEMENTED;
+  PISECURITY_DESCRIPTOR ObjectSd;
+  PISECURITY_DESCRIPTOR NewSd;
+  PISECURITY_DESCRIPTOR SecurityDescriptor = _SecurityDescriptor;
+  POBJECT_HEADER Header = BODY_TO_HEADER(Object);
+  PSID Owner = 0;
+  PSID Group = 0;
+  PACL Dacl = 0;
+  PACL Sacl = 0;
+  ULONG OwnerLength = 0;
+  ULONG GroupLength = 0;
+  ULONG DaclLength = 0;
+  ULONG SaclLength = 0;
+  ULONG Control = 0;
+  ULONG_PTR Current;
+  NTSTATUS Status;
+
+    if (OperationType == SetSecurityDescriptor)
+    {
+        ObjectSd = Header->SecurityDescriptor;
+
+      /* Get owner and owner size */
+      if (SecurityInformation & OWNER_SECURITY_INFORMATION)
+       {
+         if (SecurityDescriptor->Owner != NULL)
+           {
+               if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
+                   Owner = (PSID)((ULONG_PTR)SecurityDescriptor->Owner +
+                                  (ULONG_PTR)SecurityDescriptor);
+               else
+                   Owner = (PSID)SecurityDescriptor->Owner;
+               OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4);
+           }
+         Control |= (SecurityDescriptor->Control & SE_OWNER_DEFAULTED);
+       }
+      else
+       {
+         if (ObjectSd->Owner != NULL)
+         {
+             Owner = (PSID)((ULONG_PTR)ObjectSd->Owner + (ULONG_PTR)ObjectSd);
+             OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4);
+         }
+         Control |= (ObjectSd->Control & SE_OWNER_DEFAULTED);
+       }
+
+      /* Get group and group size */
+      if (SecurityInformation & GROUP_SECURITY_INFORMATION)
+       {
+         if (SecurityDescriptor->Group != NULL)
+           {
+               if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
+                   Group = (PSID)((ULONG_PTR)SecurityDescriptor->Group +
+                                  (ULONG_PTR)SecurityDescriptor);
+               else
+                   Group = (PSID)SecurityDescriptor->Group;
+               GroupLength = ROUND_UP(RtlLengthSid(Group), 4);
+           }
+         Control |= (SecurityDescriptor->Control & SE_GROUP_DEFAULTED);
+       }
+      else
+       {
+         if (ObjectSd->Group != NULL)
+           {
+             Group = (PSID)((ULONG_PTR)ObjectSd->Group + (ULONG_PTR)ObjectSd);
+             GroupLength = ROUND_UP(RtlLengthSid(Group), 4);
+           }
+         Control |= (ObjectSd->Control & SE_GROUP_DEFAULTED);
+       }
+
+      /* Get DACL and DACL size */
+      if (SecurityInformation & DACL_SECURITY_INFORMATION)
+       {
+         if ((SecurityDescriptor->Control & SE_DACL_PRESENT) &&
+             (SecurityDescriptor->Dacl != NULL))
+           {
+               if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
+                   Dacl = (PACL)((ULONG_PTR)SecurityDescriptor->Dacl +
+                                 (ULONG_PTR)SecurityDescriptor);
+               else
+                   Dacl = (PACL)SecurityDescriptor->Dacl;
+
+             DaclLength = ROUND_UP((ULONG)Dacl->AclSize, 4);
+           }
+         Control |= (SecurityDescriptor->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT));
+       }
+      else
+       {
+         if ((ObjectSd->Control & SE_DACL_PRESENT) &&
+             (ObjectSd->Dacl != NULL))
+           {
+             Dacl = (PACL)((ULONG_PTR)ObjectSd->Dacl + (ULONG_PTR)ObjectSd);
+             DaclLength = ROUND_UP((ULONG)Dacl->AclSize, 4);
+           }
+         Control |= (ObjectSd->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT));
+       }
+
+      /* Get SACL and SACL size */
+      if (SecurityInformation & SACL_SECURITY_INFORMATION)
+       {
+         if ((SecurityDescriptor->Control & SE_SACL_PRESENT) &&
+             (SecurityDescriptor->Sacl != NULL))
+           {
+               if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
+                   Sacl = (PACL)((ULONG_PTR)SecurityDescriptor->Sacl +
+                                 (ULONG_PTR)SecurityDescriptor);
+               else
+                   Sacl = (PACL)SecurityDescriptor->Sacl;
+               SaclLength = ROUND_UP((ULONG)Sacl->AclSize, 4);
+           }
+         Control |= (SecurityDescriptor->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT));
+       }
+      else
+       {
+         if ((ObjectSd->Control & SE_SACL_PRESENT) &&
+             (ObjectSd->Sacl != NULL))
+           {
+             Sacl = (PACL)((ULONG_PTR)ObjectSd->Sacl + (ULONG_PTR)ObjectSd);
+             SaclLength = ROUND_UP((ULONG)Sacl->AclSize, 4);
+           }
+         Control |= (ObjectSd->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT));
+       }
+
+      NewSd = ExAllocatePool(NonPagedPool,
+                            sizeof(SECURITY_DESCRIPTOR) + OwnerLength + GroupLength +
+                            DaclLength + SaclLength);
+      if (NewSd == NULL)
+       {
+         ObDereferenceObject(Object);
+         return STATUS_INSUFFICIENT_RESOURCES;
+       }
+
+      RtlCreateSecurityDescriptor(NewSd,
+                                 SECURITY_DESCRIPTOR_REVISION1);
+      /* We always build a self-relative descriptor */
+      NewSd->Control = Control | SE_SELF_RELATIVE;
+
+      Current = (ULONG_PTR)NewSd + sizeof(SECURITY_DESCRIPTOR);
+
+      if (OwnerLength != 0)
+       {
+         RtlCopyMemory((PVOID)Current,
+                       Owner,
+                       OwnerLength);
+         NewSd->Owner = (PSID)(Current - (ULONG_PTR)NewSd);
+         Current += OwnerLength;
+       }
+
+      if (GroupLength != 0)
+       {
+         RtlCopyMemory((PVOID)Current,
+                       Group,
+                       GroupLength);
+         NewSd->Group = (PSID)(Current - (ULONG_PTR)NewSd);
+         Current += GroupLength;
+       }
+
+      if (DaclLength != 0)
+       {
+         RtlCopyMemory((PVOID)Current,
+                       Dacl,
+                       DaclLength);
+         NewSd->Dacl = (PACL)(Current - (ULONG_PTR)NewSd);
+         Current += DaclLength;
+       }
+
+      if (SaclLength != 0)
+       {
+         RtlCopyMemory((PVOID)Current,
+                       Sacl,
+                       SaclLength);
+         NewSd->Sacl = (PACL)(Current - (ULONG_PTR)NewSd);
+         Current += SaclLength;
+       }
+
+      /* Add the new SD */
+      Status = ObpAddSecurityDescriptor(NewSd,
+                                       &Header->SecurityDescriptor);
+      if (NT_SUCCESS(Status))
+       {
+         /* Remove the old security descriptor */
+         ObpRemoveSecurityDescriptor(ObjectSd);
+       }
+      else
+       {
+         /* Restore the old security descriptor */
+         Header->SecurityDescriptor = ObjectSd;
+       }
+
+      ExFreePool(NewSd);
+    }
+    else if (OperationType == QuerySecurityDescriptor)
+    {
+        Status = SeQuerySecurityDescriptorInfo(&SecurityInformation,
+                                               SecurityDescriptor,
+                                               ReturnLength,
+                                               &Header->SecurityDescriptor);
+    }
+    else if (OperationType == AssignSecurityDescriptor)
+    {
+      /* Assign the security descriptor to the object header */
+      Status = ObpAddSecurityDescriptor(SecurityDescriptor,
+                                                       &Header->SecurityDescriptor);
+    }
+
+
+    return STATUS_SUCCESS;
 }
 
-VOID STDCALL SeReleaseSubjectContext (PSECURITY_SUBJECT_CONTEXT SubjectContext)
+/*
+ * @implemented
+ */
+VOID STDCALL
+SeCaptureSubjectContext(OUT PSECURITY_SUBJECT_CONTEXT SubjectContext)
 {
-   ObDereferenceObject(SubjectContext->PrimaryToken);
-   if (SubjectContext->ClientToken != NULL)
-     {
-       ObDereferenceObject(SubjectContext->ClientToken);
-     }   
+  PETHREAD Thread;
+  BOOLEAN CopyOnOpen;
+  BOOLEAN EffectiveOnly;
+
+  PAGED_CODE();
+
+  Thread = PsGetCurrentThread();
+  if (Thread == NULL)
+    {
+      SubjectContext->ProcessAuditId = 0;
+      SubjectContext->PrimaryToken = NULL;
+      SubjectContext->ClientToken = NULL;
+      SubjectContext->ImpersonationLevel = 0;
+    }
+  else
+    {
+      SubjectContext->ProcessAuditId = Thread->ThreadsProcess;
+      SubjectContext->ClientToken =
+       PsReferenceImpersonationToken(Thread,
+                                     &CopyOnOpen,
+                                     &EffectiveOnly,
+                                     &SubjectContext->ImpersonationLevel);
+      SubjectContext->PrimaryToken = PsReferencePrimaryToken(Thread->ThreadsProcess);
+    }
 }
 
-VOID STDCALL SeCaptureSubjectContext (PSECURITY_SUBJECT_CONTEXT SubjectContext)
+
+/*
+ * @implemented
+ */
+VOID STDCALL
+SeLockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
 {
-   PEPROCESS Process;
-   ULONG a;
-   ULONG b;
-   
-   Process = PsGetCurrentThread()->ThreadsProcess;
-   
-   SubjectContext->ProcessAuditId = Process;
-   SubjectContext->ClientToken = 
-     PsReferenceImpersonationToken(PsGetCurrentThread(),
-                                  &a,
-                                  &b,
-                                  &SubjectContext->ImpersonationLevel);
-   SubjectContext->PrimaryToken = PsReferencePrimaryToken(Process);
+  PAGED_CODE();
+
+  KeEnterCriticalRegion();
+  ExAcquireResourceExclusiveLite(&SepSubjectContextLock, TRUE);
 }
 
-BOOLEAN SepPrivilegeCheck(PACCESS_TOKEN Token,
-                         PLUID_AND_ATTRIBUTES Privileges,
-                         ULONG PrivilegeCount,
-                         ULONG PrivilegeControl,
-                         KPROCESSOR_MODE PreviousMode)
+
+/*
+ * @implemented
+ */
+VOID STDCALL
+SeUnlockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
 {
-   ULONG i;
-   PLUID_AND_ATTRIBUTES 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 & 2) &&
-                     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 | 0x80;
-                      j++;
-                      break;
-                   }
-              }
-            k--;
-         } while (k > 0);
-     }
-   
-   if ((PrivilegeControl & 0x2) && PrivilegeCount == j)       
-     {
-       return(TRUE);
-     }
-       
-   if (j > 0 && !(PrivilegeControl & 0x2))
-     {
-       return(TRUE);
-     }
-
-   return(FALSE);
+  PAGED_CODE();
+
+  ExReleaseResourceLite(&SepSubjectContextLock);
+  KeLeaveCriticalRegion();
 }
-   
-BOOLEAN STDCALL SePrivilegeCheck(PPRIVILEGE_SET Privileges,
-                        PSECURITY_SUBJECT_CONTEXT SubjectContext,
-                        KPROCESSOR_MODE PreviousMode)
+
+
+/*
+ * @implemented
+ */
+VOID STDCALL
+SeReleaseSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
 {
-   PACCESS_TOKEN Token = NULL;
-   
-   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));                         
+  PAGED_CODE();
+
+  if (SubjectContext->PrimaryToken != NULL)
+    {
+      ObDereferenceObject(SubjectContext->PrimaryToken);
+    }
+
+  if (SubjectContext->ClientToken != NULL)
+    {
+      ObDereferenceObject(SubjectContext->ClientToken);
+    }
 }
 
-BOOLEAN STDCALL SeSinglePrivilegeCheck(LUID PrivilegeValue,
-                              KPROCESSOR_MODE PreviousMode)
+
+/*
+ * @implemented
+ */
+NTSTATUS STDCALL
+SeDeassignSecurity(PSECURITY_DESCRIPTOR *SecurityDescriptor)
 {
-   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)
-     {
-/*     SePrivilegeServiceAuditAlarm(0,
-                                    &SubjectContext,
-                                    &PrivilegeValue);*/
-     }
-   SeReleaseSubjectContext(&SubjectContext);
-   return(r);
+  PAGED_CODE();
+
+  if (*SecurityDescriptor != NULL)
+    {
+      ExFreePool(*SecurityDescriptor);
+      *SecurityDescriptor = NULL;
+    }
+
+  return STATUS_SUCCESS;
 }
 
-NTSTATUS STDCALL SeDeassignSecurity(PSECURITY_DESCRIPTOR* SecurityDescriptor)
+
+/*
+ * @unimplemented
+ */
+NTSTATUS STDCALL
+SeAssignSecurityEx(IN PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
+                  IN PSECURITY_DESCRIPTOR ExplicitDescriptor OPTIONAL,
+                  OUT PSECURITY_DESCRIPTOR *NewDescriptor,
+                  IN GUID *ObjectType OPTIONAL,
+                  IN BOOLEAN IsDirectoryObject,
+                  IN ULONG AutoInheritFlags,
+                  IN PSECURITY_SUBJECT_CONTEXT SubjectContext,
+                  IN PGENERIC_MAPPING GenericMapping,
+                  IN POOL_TYPE PoolType)
 {
-   UNIMPLEMENTED;
+  UNIMPLEMENTED;
+  return STATUS_NOT_IMPLEMENTED;
 }
 
-NTSTATUS STDCALL SeAssignSecurity(PSECURITY_DESCRIPTOR ParentDescriptor,
-                                 PSECURITY_DESCRIPTOR ExplicitDescriptor,
-                                 BOOLEAN IsDirectoryObject,
-                                 PSECURITY_SUBJECT_CONTEXT SubjectContext,
-                                 PGENERIC_MAPPING GenericMapping,
-                                 POOL_TYPE PoolType)
+
+/*
+ * FUNCTION: Creates a security descriptor for a new object.
+ * ARGUMENTS:
+ *         ParentDescriptor =
+ *         ExplicitDescriptor =
+ *         NewDescriptor =
+ *         IsDirectoryObject =
+ *         SubjectContext =
+ *         GeneralMapping =
+ *         PoolType =
+ * RETURNS: Status
+ *
+ * @implemented
+ */
+NTSTATUS STDCALL
+SeAssignSecurity(PSECURITY_DESCRIPTOR _ParentDescriptor OPTIONAL,
+                PSECURITY_DESCRIPTOR _ExplicitDescriptor OPTIONAL,
+                PSECURITY_DESCRIPTOR *NewDescriptor,
+                BOOLEAN IsDirectoryObject,
+                PSECURITY_SUBJECT_CONTEXT SubjectContext,
+                PGENERIC_MAPPING GenericMapping,
+                POOL_TYPE PoolType)
 {
-   UNIMPLEMENTED;
+  PISECURITY_DESCRIPTOR ParentDescriptor = _ParentDescriptor;
+  PISECURITY_DESCRIPTOR ExplicitDescriptor = _ExplicitDescriptor;
+  PISECURITY_DESCRIPTOR Descriptor;
+  PTOKEN Token;
+  ULONG OwnerLength = 0;
+  ULONG GroupLength = 0;
+  ULONG DaclLength = 0;
+  ULONG SaclLength = 0;
+  ULONG Length = 0;
+  ULONG Control = 0;
+  ULONG_PTR Current;
+  PSID Owner = NULL;
+  PSID Group = NULL;
+  PACL Dacl = NULL;
+  PACL Sacl = NULL;
+
+  PAGED_CODE();
+
+  /* Lock subject context */
+  SeLockSubjectContext(SubjectContext);
+
+  if (SubjectContext->ClientToken != NULL)
+    {
+      Token = SubjectContext->ClientToken;
+    }
+  else
+    {
+      Token = SubjectContext->PrimaryToken;
+    }
+
+
+  /* Inherit the Owner SID */
+  if (ExplicitDescriptor != NULL && ExplicitDescriptor->Owner != NULL)
+    {
+      DPRINT("Use explicit owner sid!\n");
+      Owner = ExplicitDescriptor->Owner;
+      
+      if (ExplicitDescriptor->Control & SE_SELF_RELATIVE)
+       {
+         Owner = (PSID)(((ULONG_PTR)Owner) + (ULONG_PTR)ExplicitDescriptor);
+
+       }
+    }
+  else
+    {
+      if (Token != NULL)
+       {
+         DPRINT("Use token owner sid!\n");
+         Owner = Token->UserAndGroups[Token->DefaultOwnerIndex].Sid;
+       }
+      else
+       {
+         DPRINT("Use default owner sid!\n");
+         Owner = SeLocalSystemSid;
+       }
+
+      Control |= SE_OWNER_DEFAULTED;
+    }
+
+  OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4);
+
+
+  /* Inherit the Group SID */
+  if (ExplicitDescriptor != NULL && ExplicitDescriptor->Group != NULL)
+    {
+      DPRINT("Use explicit group sid!\n");
+      Group = ExplicitDescriptor->Group;
+      if (ExplicitDescriptor->Control & SE_SELF_RELATIVE)
+       {
+         Group = (PSID)(((ULONG_PTR)Group) + (ULONG_PTR)ExplicitDescriptor);
+       }
+    }
+  else
+    {
+      if (Token != NULL)
+       {
+         DPRINT("Use token group sid!\n");
+         Group = Token->PrimaryGroup;
+       }
+      else
+       {
+         DPRINT("Use default group sid!\n");
+         Group = SeLocalSystemSid;
+       }
+
+      Control |= SE_OWNER_DEFAULTED;
+    }
+
+  GroupLength = ROUND_UP(RtlLengthSid(Group), 4);
+
+
+  /* Inherit the DACL */
+  if (ExplicitDescriptor != NULL &&
+      (ExplicitDescriptor->Control & SE_DACL_PRESENT) &&
+      !(ExplicitDescriptor->Control & SE_DACL_DEFAULTED))
+    {
+      DPRINT("Use explicit DACL!\n");
+      Dacl = ExplicitDescriptor->Dacl;
+      if (Dacl != NULL && (ExplicitDescriptor->Control & SE_SELF_RELATIVE))
+       {
+         Dacl = (PACL)(((ULONG_PTR)Dacl) + (ULONG_PTR)ExplicitDescriptor);
+       }
+
+      Control |= SE_DACL_PRESENT;
+    }
+  else if (ParentDescriptor != NULL &&
+          (ParentDescriptor->Control & SE_DACL_PRESENT))
+    {
+      DPRINT("Use parent DACL!\n");
+      /* FIXME: Inherit */
+      Dacl = ParentDescriptor->Dacl;
+      if (Dacl != NULL && (ParentDescriptor->Control & SE_SELF_RELATIVE))
+       {
+         Dacl = (PACL)(((ULONG_PTR)Dacl) + (ULONG_PTR)ParentDescriptor);
+       }
+      Control |= (SE_DACL_PRESENT | SE_DACL_DEFAULTED);
+    }
+  else if (Token != NULL && Token->DefaultDacl != NULL)
+    {
+      DPRINT("Use token default DACL!\n");
+      /* FIXME: Inherit */
+      Dacl = Token->DefaultDacl;
+      Control |= (SE_DACL_PRESENT | SE_DACL_DEFAULTED);
+    }
+  else
+    {
+      DPRINT("Use NULL DACL!\n");
+      Dacl = NULL;
+      Control |= (SE_DACL_PRESENT | SE_DACL_DEFAULTED);
+    }
+
+  DaclLength = (Dacl != NULL) ? ROUND_UP(Dacl->AclSize, 4) : 0;
+
+
+  /* Inherit the SACL */
+  if (ExplicitDescriptor != NULL &&
+      (ExplicitDescriptor->Control & SE_SACL_PRESENT) &&
+      !(ExplicitDescriptor->Control & SE_SACL_DEFAULTED))
+    {
+      DPRINT("Use explicit SACL!\n");
+      Sacl = ExplicitDescriptor->Sacl;
+      if (Sacl != NULL && (ExplicitDescriptor->Control & SE_SELF_RELATIVE))
+       {
+         Sacl = (PACL)(((ULONG_PTR)Sacl) + (ULONG_PTR)ExplicitDescriptor);
+       }
+
+      Control |= SE_SACL_PRESENT;
+    }
+  else if (ParentDescriptor != NULL &&
+          (ParentDescriptor->Control & SE_SACL_PRESENT))
+    {
+      DPRINT("Use parent SACL!\n");
+      /* FIXME: Inherit */
+      Sacl = ParentDescriptor->Sacl;
+      if (Sacl != NULL && (ParentDescriptor->Control & SE_SELF_RELATIVE))
+       {
+         Sacl = (PACL)(((ULONG_PTR)Sacl) + (ULONG_PTR)ParentDescriptor);
+       }
+      Control |= (SE_SACL_PRESENT | SE_SACL_DEFAULTED);
+    }
+
+  SaclLength = (Sacl != NULL) ? ROUND_UP(Sacl->AclSize, 4) : 0;
+
+
+  /* Allocate and initialize the new security descriptor */
+  Length = sizeof(SECURITY_DESCRIPTOR) +
+      OwnerLength + GroupLength + DaclLength + SaclLength;
+
+  DPRINT("L: sizeof(SECURITY_DESCRIPTOR) %d OwnerLength %d GroupLength %d DaclLength %d SaclLength %d\n",
+        sizeof(SECURITY_DESCRIPTOR),
+        OwnerLength,
+        GroupLength,
+        DaclLength,
+        SaclLength);
+
+  Descriptor = ExAllocatePool(PagedPool,
+                             Length);
+  if (Descriptor == NULL)
+    {
+      DPRINT1("ExAlloctePool() failed\n");
+      /* FIXME: Unlock subject context */
+      return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+  RtlZeroMemory( Descriptor, Length );
+  RtlCreateSecurityDescriptor(Descriptor,
+                             SECURITY_DESCRIPTOR_REVISION);
+
+  Descriptor->Control = Control | SE_SELF_RELATIVE;
+
+  Current = (ULONG_PTR)Descriptor + sizeof(SECURITY_DESCRIPTOR);
+
+  if (SaclLength != 0)
+    {
+      RtlCopyMemory((PVOID)Current,
+                   Sacl,
+                   SaclLength);
+      Descriptor->Sacl = (PACL)((ULONG_PTR)Current - (ULONG_PTR)Descriptor);
+      Current += SaclLength;
+    }
+
+  if (DaclLength != 0)
+    {
+      RtlCopyMemory((PVOID)Current,
+                   Dacl,
+                   DaclLength);
+      Descriptor->Dacl = (PACL)((ULONG_PTR)Current - (ULONG_PTR)Descriptor);
+      Current += DaclLength;
+    }
+
+  if (OwnerLength != 0)
+    {
+      RtlCopyMemory((PVOID)Current,
+                   Owner,
+                   OwnerLength);
+      Descriptor->Owner = (PSID)((ULONG_PTR)Current - (ULONG_PTR)Descriptor);
+      Current += OwnerLength;
+      DPRINT("Owner of %x at %x\n", Descriptor, Descriptor->Owner);
+    }
+  else
+      DPRINT("Owner of %x is zero length\n", Descriptor);
+
+  if (GroupLength != 0)
+    {
+      memmove((PVOID)Current,
+              Group,
+              GroupLength);
+      Descriptor->Group = (PSID)((ULONG_PTR)Current - (ULONG_PTR)Descriptor);
+    }
+
+  /* Unlock subject context */
+  SeUnlockSubjectContext(SubjectContext);
+
+  *NewDescriptor = Descriptor;
+
+  DPRINT("Descrptor %x\n", Descriptor);
+  ASSERT(RtlLengthSecurityDescriptor(Descriptor));
+
+  return STATUS_SUCCESS;
 }
 
-BOOLEAN SepSidInToken(PACCESS_TOKEN Token,
-                     PSID Sid)
+
+static BOOLEAN
+SepSidInToken(PACCESS_TOKEN _Token,
+             PSID Sid)
 {
-   ULONG i;
-   
-   if (Token->UserAndGroupCount == 0)
-     {
-       return(FALSE);
-     }
-   
-   for (i=0; i<Token->UserAndGroupCount; i++)
-     {
-       if (RtlEqualSid(Sid, Token->UserAndGroups[i].Sid))
-         {
-            if (i == 0 ||
-                (!(Token->UserAndGroups[i].Attributes & 0x4)))
-              {
-                 return(TRUE);
-              }
-            return(FALSE);
-         }
-     }
-   return(FALSE);
+  ULONG i;
+  PTOKEN Token = (PTOKEN)_Token;
+
+  PAGED_CODE();
+
+  if (Token->UserAndGroupCount == 0)
+  {
+    return FALSE;
+  }
+
+  for (i=0; i<Token->UserAndGroupCount; i++)
+  {
+    if (RtlEqualSid(Sid, Token->UserAndGroups[i].Sid))
+    {
+      if (Token->UserAndGroups[i].Attributes & SE_GROUP_ENABLED)
+      {
+        return TRUE;
+      }
+
+      return FALSE;
+    }
+  }
+
+  return FALSE;
 }
 
-BOOLEAN STDCALL SeAccessCheck (IN PSECURITY_DESCRIPTOR SecurityDescriptor,
-                     IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
-                     IN BOOLEAN SubjectContextLocked,
-                     IN ACCESS_MASK DesiredAccess,
-                     IN ACCESS_MASK PreviouslyGrantedAccess,
-                     OUT PPRIVILEGE_SET* Privileges,
-                     IN PGENERIC_MAPPING GenericMapping,
-                     IN KPROCESSOR_MODE AccessMode,
-                     OUT PACCESS_MODE GrantedAccess,
-                     OUT PNTSTATUS AccessStatus)
+
 /*
  * FUNCTION: Determines whether the requested access rights can be granted
  * to an object protected by a security descriptor and an object owner
@@ -592,70 +843,310 @@ BOOLEAN STDCALL SeAccessCheck (IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  *      GrantedAccess (OUT) = On return specifies the access granted
  *      AccessStatus (OUT) = Status indicating why access was denied
  * RETURNS: If access was granted, returns TRUE
+ *
+ * @implemented
  */
+BOOLEAN STDCALL
+SeAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+             IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
+             IN BOOLEAN SubjectContextLocked,
+             IN ACCESS_MASK DesiredAccess,
+             IN ACCESS_MASK PreviouslyGrantedAccess,
+             OUT PPRIVILEGE_SET* Privileges,
+             IN PGENERIC_MAPPING GenericMapping,
+             IN KPROCESSOR_MODE AccessMode,
+             OUT PACCESS_MASK GrantedAccess,
+             OUT PNTSTATUS AccessStatus)
 {
-   ULONG i;
-   PACL Dacl;
-   BOOLEAN Present;
-   BOOLEAN Defaulted;
-   NTSTATUS Status;
-   PACE CurrentAce;
-   PSID Sid;
-   ACCESS_MASK CurrentAccess;
-   
-   CurrentAccess = PreviouslyGrantedAccess;
-   
-   /*    
-    * Ignore the SACL for now
-    */
-   
-   /*
-    * Check the DACL
-    */
-   Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
-                                        &Present,
-                                        &Dacl,
+  LUID_AND_ATTRIBUTES Privilege;
+  ACCESS_MASK CurrentAccess;
+  PACCESS_TOKEN Token;
+  ULONG i;
+  PACL Dacl;
+  BOOLEAN Present;
+  BOOLEAN Defaulted;
+  PACE CurrentAce;
+  PSID Sid;
+  NTSTATUS Status;
+
+  PAGED_CODE();
+
+  CurrentAccess = PreviouslyGrantedAccess;
+
+  if (SubjectContextLocked == FALSE)
+    {
+      SeLockSubjectContext(SubjectSecurityContext);
+    }
+
+  Token = SubjectSecurityContext->ClientToken ?
+           SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
+
+  /* Get the DACL */
+  Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
+                                       &Present,
+                                       &Dacl,
+                                       &Defaulted);
+  if (!NT_SUCCESS(Status))
+    {
+      if (SubjectContextLocked == FALSE)
+       {
+         SeUnlockSubjectContext(SubjectSecurityContext);
+       }
+
+      *AccessStatus = Status;
+      return FALSE;
+    }
+
+  /* RULE 1: Grant desired access if the object is unprotected */
+  if (Present == TRUE && Dacl == NULL)
+    {
+      if (SubjectContextLocked == FALSE)
+       {
+         SeUnlockSubjectContext(SubjectSecurityContext);
+       }
+
+      *GrantedAccess = DesiredAccess;
+      *AccessStatus = STATUS_SUCCESS;
+      return TRUE;
+    }
+
+  CurrentAccess = PreviouslyGrantedAccess;
+
+  /* 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 == CurrentAccess)
+       {
+         if (SubjectContextLocked == FALSE)
+           {
+             SeUnlockSubjectContext(SubjectSecurityContext);
+           }
+
+         *GrantedAccess = CurrentAccess;
+         *AccessStatus = STATUS_SUCCESS;
+         return TRUE;
+       }
+    }
+
+  /* RULE 3: Check whether the token is the owner */
+  Status = RtlGetOwnerSecurityDescriptor(SecurityDescriptor,
+                                        &Sid,
                                         &Defaulted);
-   if (!NT_SUCCESS(Status))
-     {
-       return(Status);
-     }
-   
-   CurrentAce = (PACE)(Dacl + 1);
-   for (i = 0; i < Dacl->AceCount; i++)
-     {
-       Sid = (PSID)(CurrentAce + 1);
-       if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE)
-         {
-            if (SepSidInToken(SubjectSecurityContext->ClientToken, Sid))
-              {
-                 *AccessStatus = STATUS_ACCESS_DENIED;
-                 *GrantedAccess = 0;
-                 return(STATUS_SUCCESS);
-              }
-         }
-       if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
-         {
-            if (SepSidInToken(SubjectSecurityContext->ClientToken, Sid))
-              {
-                 CurrentAccess = CurrentAccess | 
-                   CurrentAce->Header.AccessMask;                
-              }
-         }
-     }
-   if (!(CurrentAccess & DesiredAccess) &&
-       !((~CurrentAccess) & DesiredAccess))
-     {
-       *AccessStatus = STATUS_ACCESS_DENIED;   
-     }
-   else
-     {
-       *AccessStatus = STATUS_SUCCESS;
-     }
-   *GrantedAccess = CurrentAccess;
-   
-   return(STATUS_SUCCESS);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("RtlGetOwnerSecurityDescriptor() failed (Status %lx)\n", Status);
+      if (SubjectContextLocked == FALSE)
+       {
+         SeUnlockSubjectContext(SubjectSecurityContext);
+       }
+
+      *AccessStatus = Status;
+      return FALSE;
+   }
+
+  if (SepSidInToken(Token, Sid))
+    {
+      CurrentAccess |= (READ_CONTROL | WRITE_DAC);
+      if (DesiredAccess == CurrentAccess)
+       {
+         if (SubjectContextLocked == FALSE)
+           {
+             SeUnlockSubjectContext(SubjectSecurityContext);
+           }
+
+         *GrantedAccess = CurrentAccess;
+         *AccessStatus = STATUS_SUCCESS;
+         return TRUE;
+       }
+    }
+
+  /* Fail if DACL is absent */
+  if (Present == FALSE)
+    {
+      if (SubjectContextLocked == FALSE)
+       {
+         SeUnlockSubjectContext(SubjectSecurityContext);
+       }
+
+      *GrantedAccess = 0;
+      *AccessStatus = STATUS_ACCESS_DENIED;
+      return TRUE;
+    }
+
+  /* RULE 4: Grant rights according to the DACL */
+  CurrentAce = (PACE)(Dacl + 1);
+  for (i = 0; i < Dacl->AceCount; i++)
+    {
+      Sid = (PSID)(CurrentAce + 1);
+      if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE)
+       {
+         if (SepSidInToken(Token, Sid))
+           {
+             if (SubjectContextLocked == FALSE)
+               {
+                 SeUnlockSubjectContext(SubjectSecurityContext);
+               }
+
+             *GrantedAccess = 0;
+             *AccessStatus = STATUS_ACCESS_DENIED;
+             return TRUE;
+           }
+       }
+
+      if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
+       {
+         if (SepSidInToken(Token, Sid))
+           {
+             CurrentAccess |= CurrentAce->AccessMask;
+           }
+       }
+    }
+
+  if (SubjectContextLocked == FALSE)
+    {
+      SeUnlockSubjectContext(SubjectSecurityContext);
+    }
+
+  DPRINT("CurrentAccess %08lx\n DesiredAccess %08lx\n",
+         CurrentAccess, DesiredAccess);
+
+  *GrantedAccess = CurrentAccess & DesiredAccess;
+
+  *AccessStatus =
+    (*GrantedAccess == DesiredAccess) ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
+
+  return TRUE;
+}
+
+
+NTSTATUS STDCALL
+NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+             IN HANDLE TokenHandle,
+             IN ACCESS_MASK DesiredAccess,
+             IN PGENERIC_MAPPING GenericMapping,
+             OUT PPRIVILEGE_SET PrivilegeSet,
+             OUT PULONG ReturnLength,
+             OUT PACCESS_MASK GrantedAccess,
+             OUT PNTSTATUS AccessStatus)
+{
+  SECURITY_SUBJECT_CONTEXT SubjectSecurityContext = {0};
+  KPROCESSOR_MODE PreviousMode;
+  PTOKEN Token;
+  NTSTATUS Status;
+
+  PAGED_CODE();
+
+  DPRINT("NtAccessCheck() called\n");
+
+  PreviousMode = KeGetPreviousMode();
+  if (PreviousMode == KernelMode)
+    {
+      *GrantedAccess = DesiredAccess;
+      *AccessStatus = STATUS_SUCCESS;
+      return STATUS_SUCCESS;
+    }
+
+  Status = ObReferenceObjectByHandle(TokenHandle,
+                                    TOKEN_QUERY,
+                                    SepTokenObjectType,
+                                    PreviousMode,
+                                    (PVOID*)&Token,
+                                    NULL);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("Failed to reference token (Status %lx)\n", Status);
+      return Status;
+    }
+
+  /* Check token type */
+  if (Token->TokenType != TokenImpersonation)
+    {
+      DPRINT1("No impersonation token\n");
+      ObDereferenceObject(Token);
+      return STATUS_ACCESS_VIOLATION;
+    }
+
+  /* Check impersonation level */
+  if (Token->ImpersonationLevel < SecurityAnonymous)
+    {
+      DPRINT1("Invalid impersonation level\n");
+      ObDereferenceObject(Token);
+      return STATUS_ACCESS_VIOLATION;
+    }
+
+  SubjectSecurityContext.ClientToken = Token;
+  SubjectSecurityContext.ImpersonationLevel = Token->ImpersonationLevel;
+
+  /* Lock subject context */
+  SeLockSubjectContext(&SubjectSecurityContext);
+
+  if (SeAccessCheck(SecurityDescriptor,
+                   &SubjectSecurityContext,
+                   TRUE,
+                   DesiredAccess,
+                   0,
+                   &PrivilegeSet,
+                   GenericMapping,
+                   PreviousMode,
+                   GrantedAccess,
+                   AccessStatus))
+    {
+      Status = *AccessStatus;
+    }
+  else
+    {
+      Status = STATUS_ACCESS_DENIED;
+    }
+
+  /* Unlock subject context */
+  SeUnlockSubjectContext(&SubjectSecurityContext);
+
+  ObDereferenceObject(Token);
+
+  DPRINT("NtAccessCheck() done\n");
+
+  return Status;
 }
 
+VOID STDCALL
+SeQuerySecurityAccessMask(IN SECURITY_INFORMATION SecurityInformation,
+                          OUT PACCESS_MASK DesiredAccess)
+{
+    if (SecurityInformation & (OWNER_SECURITY_INFORMATION |
+                               GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION))
+    {
+        *DesiredAccess |= READ_CONTROL;
+    }
+    if (SecurityInformation & SACL_SECURITY_INFORMATION)
+    {
+        *DesiredAccess |= ACCESS_SYSTEM_SECURITY;
+    }
+}
+
+VOID STDCALL
+SeSetSecurityAccessMask(IN SECURITY_INFORMATION SecurityInformation,
+                        OUT PACCESS_MASK DesiredAccess)
+{
+    if (SecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
+    {
+        *DesiredAccess |= WRITE_OWNER;
+    }
+    if (SecurityInformation & DACL_SECURITY_INFORMATION)
+    {
+        *DesiredAccess |= WRITE_DAC;
+    }
+    if (SecurityInformation & SACL_SECURITY_INFORMATION)
+    {
+        *DesiredAccess |= ACCESS_SYSTEM_SECURITY;
+    }
+}
 
 /* EOF */