SeCaptureSubjectContext() must not crash if no current thread exists.
[reactos.git] / reactos / ntoskrnl / se / semgr.c
index 7dce4db..a8fe6f5 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* $Id: semgr.c,v 1.35 2004/07/19 12:45:56 ekohl Exp $
+ *
  * COPYRIGHT:         See COPYING in the top level directory
  * PROJECT:           ReactOS kernel
  * PURPOSE:           Security manager
 /* INCLUDES *****************************************************************/
 
 #include <ddk/ntddk.h>
+#include <internal/ps.h>
+#include <internal/se.h>
 
+#define NDEBUG
 #include <internal/debug.h>
 
-/* FUNCTIONS ***************************************************************/
+#define TAG_SXPT   TAG('S', 'X', 'P', 'T')
 
-NTSTATUS STDCALL ZwQueryInformationToken(IN HANDLE TokenHandle,     
-       IN TOKEN_INFORMATION_CLASS TokenInformationClass,
-       OUT PVOID TokenInformation,  
-       IN ULONG TokenInformationLength,
-       OUT PULONG ReturnLength)
-{
-   UNIMPLEMENTED;
-}
 
-NTSTATUS STDCALL NtQueryInformationToken(IN HANDLE TokenHandle,     
-       IN TOKEN_INFORMATION_CLASS TokenInformationClass,
-       OUT PVOID TokenInformation,  
-       IN ULONG TokenInformationLength,
-       OUT PULONG ReturnLength)
-{
-   return(ZwQueryInformationToken(TokenHandle,
-                                 TokenInformationClass,
-                                 TokenInformation,
-                                 TokenInformationLength,
-                                 ReturnLength));
-}
+/* GLOBALS ******************************************************************/
 
-NTSTATUS STDCALL ZwQuerySecurityObject(IN HANDLE Object,
-                                      IN CINT SecurityObjectInformationClass,
-                                      OUT PVOID SecurityObjectInformation,
-                                      IN ULONG Length,
-                                      OUT PULONG ReturnLength)
-{
-   UNIMPLEMENTED;
-}
+PSE_EXPORTS EXPORTED SeExports = NULL;
 
-NTSTATUS STDCALL NtQuerySecurityObject(IN HANDLE Object,
-                                      IN CINT SecurityObjectInformationClass,
-                                      OUT PVOID SecurityObjectInformation,
-                                      IN ULONG Length,
-                                      OUT PULONG ReturnLength)
-{
-   return(ZwQuerySecurityObject(Object,
-                               SecurityObjectInformationClass,
-                               SecurityObjectInformation,
-                               Length,
-                               ReturnLength));
-}
 
-NTSTATUS
-STDCALL
-NtSetSecurityObject(
-       IN HANDLE Handle, 
-       IN SECURITY_INFORMATION SecurityInformation, 
-       IN PSECURITY_DESCRIPTOR SecurityDescriptor 
-       )
-{
-}
+/* PROTOTYPES ***************************************************************/
 
-NTSTATUS
-STDCALL
-NtSetInformationToken(
-       IN HANDLE TokenHandle,            
-       IN TOKEN_INFORMATION_CLASS TokenInformationClass,
-       OUT PVOID TokenInformation,       
-       IN ULONG TokenInformationLength   
-       )
-{
-}
+static BOOLEAN SepInitExports(VOID);
 
-NTSTATUS
-STDCALL
-NtPrivilegeCheck(
-       IN HANDLE ClientToken,             
-       IN PPRIVILEGE_SET RequiredPrivileges,  
-       IN PBOOLEAN Result                    
-       )
-{
-}
+/* FUNCTIONS ****************************************************************/
 
-NTSTATUS
-STDCALL
-NtPrivilegedServiceAuditAlarm(
-       IN PUNICODE_STRING SubsystemName,       
-       IN PUNICODE_STRING ServiceName, 
-       IN HANDLE ClientToken,
-       IN PPRIVILEGE_SET Privileges,   
-       IN BOOLEAN AccessGranted        
-       )
-{
-}
 
-NTSTATUS
-STDCALL
-NtPrivilegeObjectAuditAlarm(
-       IN PUNICODE_STRING SubsystemName,
-       IN PVOID HandleId,      
-       IN HANDLE ClientToken,
-       IN ULONG DesiredAccess,
-       IN PPRIVILEGE_SET Privileges,
-       IN BOOLEAN AccessGranted 
-       )
+BOOLEAN INIT_FUNCTION
+SeInit1(VOID)
 {
-}
+  SepInitLuid();
 
-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    
-       )
-{
-}
+  if (!SepInitSecurityIDs())
+    return FALSE;
 
-NTSTATUS
-STDCALL
-NtOpenProcessToken(  
-       IN HANDLE ProcessHandle, 
-       IN ACCESS_MASK DesiredAccess,  
-       OUT PHANDLE TokenHandle  
-       )
-{
-}
+  if (!SepInitDACLs())
+    return FALSE;
 
-NTSTATUS
-STDCALL
-NtOpenThreadToken(  
-       IN HANDLE ThreadHandle,  
-       IN ACCESS_MASK DesiredAccess,  
-       IN BOOLEAN OpenAsSelf,     
-       OUT PHANDLE TokenHandle  
-       )
-{
-}
+  if (!SepInitSDs())
+    return FALSE;
 
-NTSTATUS
-STDCALL
-NtDuplicateToken(  
-       IN HANDLE ExistingToken, 
-       IN ACCESS_MASK DesiredAccess, 
-       IN POBJECT_ATTRIBUTES ObjectAttributes,
-       IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
-       IN TOKEN_TYPE TokenType,  
-       OUT PHANDLE NewToken     
-       )
-{
-}
+  SepInitPrivileges();
 
+  if (!SepInitExports())
+    return FALSE;
 
-NTSTATUS STDCALL NtImpersonateClientOfPort(VOID)
-{
+  return TRUE;
 }
 
-NTSTATUS
-STDCALL 
-NtImpersonateThread(
-       IN HANDLE ThreadHandle,
-       IN HANDLE ThreadToImpersonate,
-       IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService
-       )
-{
-}
 
-NTSTATUS STDCALL NtCreateToken(VOID)
+BOOLEAN INIT_FUNCTION
+SeInit2(VOID)
 {
-}
+  SepInitializeTokenImplementation();
 
-NTSTATUS
-STDCALL
-NtDeleteObjectAuditAlarm ( 
-       IN PUNICODE_STRING SubsystemName, 
-       IN PVOID HandleId, 
-       IN BOOLEAN GenerateOnClose 
-       )
-{
+  return TRUE;
 }
 
 
-NTSTATUS
-STDCALL
-NtAllocateLocallyUniqueId(
-       OUT LUID *LocallyUniqueId
-       )
+BOOLEAN
+SeInitSRM(VOID)
 {
-}
+  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 = NtCreateDirectoryObject(&DirectoryHandle,
+                                  DIRECTORY_ALL_ACCESS,
+                                  &ObjectAttributes);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("Failed to create 'Security' directory!\n");
+      return FALSE;
+    }
 
-NTSTATUS
-STDCALL
-ZwAllocateLocallyUniqueId(
-       OUT LUID *LocallyUniqueId
-       )
-{
-}
+  /* Create 'LSA_AUTHENTICATION_INITALIZED' event */
+  RtlInitUnicodeString(&Name,
+                      L"\\LSA_AUTHENTICATION_INITALIZED");
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &Name,
+                            OBJ_PERMANENT,
+                            DirectoryHandle,
+                            SePublicDefaultSd);
+  Status = NtCreateEvent(&EventHandle,
+                        EVENT_ALL_ACCESS,
+                        &ObjectAttributes,
+                        FALSE,
+                        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    
-       )
-{
-}
+  NtClose(EventHandle);
+  NtClose(DirectoryHandle);
 
-NTSTATUS 
-STDCALL 
-NtAdjustGroupsToken(
-       IN HANDLE TokenHandle,
-       IN BOOLEAN  ResetToDefault,     
-       IN PTOKEN_GROUPS  NewState, 
-       IN ULONG  BufferLength, 
-       OUT PTOKEN_GROUPS  PreviousState OPTIONAL,      
-       OUT PULONG  ReturnLength        
-       )
-{
+  /* FIXME: Create SRM port and listener thread */
+
+  return TRUE;
 }
 
-NTSTATUS 
-STDCALL 
-NtAdjustPrivilegesToken(
-       IN HANDLE  TokenHandle, 
-       IN BOOLEAN  DisableAllPrivileges,
-       IN PTOKEN_PRIVILEGES  NewState, 
-       IN ULONG  BufferLength, 
-       OUT PTOKEN_PRIVILEGES  PreviousState,   
-       OUT PULONG ReturnLength         
-       )
+
+static BOOLEAN INIT_FUNCTION
+SepInitExports(VOID)
 {
-}
-NTSTATUS 
-STDCALL 
-ZwAdjustPrivilegesToken(
-       IN HANDLE  TokenHandle, 
-       IN BOOLEAN  DisableAllPrivileges,
-       IN PTOKEN_PRIVILEGES  NewState, 
-       IN ULONG  BufferLength, 
-       OUT PTOKEN_PRIVILEGES  PreviousState,   
-       OUT PULONG ReturnLength         
-       )
+  SeExports = ExAllocatePoolWithTag(NonPagedPool,
+                                   sizeof(SE_EXPORTS),
+                                   TAG_SXPT);
+  if (SeExports == NULL)
+    return FALSE;
+
+  SeExports->SeCreateTokenPrivilege = SeCreateTokenPrivilege;
+  SeExports->SeAssignPrimaryTokenPrivilege = SeAssignPrimaryTokenPrivilege;
+  SeExports->SeLockMemoryPrivilege = SeLockMemoryPrivilege;
+  SeExports->SeIncreaseQuotaPrivilege = SeIncreaseQuotaPrivilege;
+  SeExports->SeUnsolicitedInputPrivilege = SeUnsolicitedInputPrivilege;
+  SeExports->SeTcbPrivilege = SeTcbPrivilege;
+  SeExports->SeSecurityPrivilege = SeSecurityPrivilege;
+  SeExports->SeTakeOwnershipPrivilege = SeTakeOwnershipPrivilege;
+  SeExports->SeLoadDriverPrivilege = SeLoadDriverPrivilege;
+  SeExports->SeCreatePagefilePrivilege = SeCreatePagefilePrivilege;
+  SeExports->SeIncreaseBasePriorityPrivilege = SeIncreaseBasePriorityPrivilege;
+  SeExports->SeSystemProfilePrivilege = SeSystemProfilePrivilege;
+  SeExports->SeSystemtimePrivilege = SeSystemtimePrivilege;
+  SeExports->SeProfileSingleProcessPrivilege = SeProfileSingleProcessPrivilege;
+  SeExports->SeCreatePermanentPrivilege = SeCreatePermanentPrivilege;
+  SeExports->SeBackupPrivilege = SeBackupPrivilege;
+  SeExports->SeRestorePrivilege = SeRestorePrivilege;
+  SeExports->SeShutdownPrivilege = SeShutdownPrivilege;
+  SeExports->SeDebugPrivilege = SeDebugPrivilege;
+  SeExports->SeAuditPrivilege = SeAuditPrivilege;
+  SeExports->SeSystemEnvironmentPrivilege = SeSystemEnvironmentPrivilege;
+  SeExports->SeChangeNotifyPrivilege = SeChangeNotifyPrivilege;
+  SeExports->SeRemoteShutdownPrivilege = SeRemoteShutdownPrivilege;
+
+  SeExports->SeNullSid = SeNullSid;
+  SeExports->SeWorldSid = SeWorldSid;
+  SeExports->SeLocalSid = SeLocalSid;
+  SeExports->SeCreatorOwnerSid = SeCreatorOwnerSid;
+  SeExports->SeCreatorGroupSid = SeCreatorGroupSid;
+  SeExports->SeNtAuthoritySid = SeNtAuthoritySid;
+  SeExports->SeDialupSid = SeDialupSid;
+  SeExports->SeNetworkSid = SeNetworkSid;
+  SeExports->SeBatchSid = SeBatchSid;
+  SeExports->SeInteractiveSid = SeInteractiveSid;
+  SeExports->SeLocalSystemSid = SeLocalSystemSid;
+  SeExports->SeAliasAdminsSid = SeAliasAdminsSid;
+  SeExports->SeAliasUsersSid = SeAliasUsersSid;
+  SeExports->SeAliasGuestsSid = SeAliasGuestsSid;
+  SeExports->SeAliasPowerUsersSid = SeAliasPowerUsersSid;
+  SeExports->SeAliasAccountOpsSid = SeAliasAccountOpsSid;
+  SeExports->SeAliasSystemOpsSid = SeAliasSystemOpsSid;
+  SeExports->SeAliasPrintOpsSid = SeAliasPrintOpsSid;
+  SeExports->SeAliasBackupOpsSid = SeAliasBackupOpsSid;
+
+  return TRUE;
+}
+
+
+VOID SepReferenceLogonSession(PLUID AuthenticationId)
 {
+   UNIMPLEMENTED;
 }
 
-NTSTATUS 
-STDCALL 
-NtAllocateUuids(
-       PLARGE_INTEGER Time,
-       PULONG Version, // ???
-       PULONG ClockCycle
-       )
+VOID SepDeReferenceLogonSession(PLUID AuthenticationId)
 {
+   UNIMPLEMENTED;
 }
 
-NTSTATUS 
-STDCALL 
-ZwAllocateUuids(
-       PLARGE_INTEGER Time,
-       PULONG Version, // ???
-       PULONG ClockCycle
-       )
-{
-}
 
-NTSTATUS
-STDCALL
-NtCloseObjectAuditAlarm(
-       IN PUNICODE_STRING SubsystemName,       
-       IN PVOID HandleId,      
-       IN BOOLEAN GenerateOnClose      
-       )
-{
-}
 
-NTSTATUS
-STDCALL
-NtAccessCheck(
-       IN PSECURITY_DESCRIPTOR SecurityDescriptor,
-       IN HANDLE ClientToken,
-       IN ACCESS_MASK DesiredAcces,
-       IN PGENERIC_MAPPING GenericMapping,
-       OUT PRIVILEGE_SET PrivilegeSet,
-       OUT PULONG ReturnLength,
-       OUT PULONG GrantedAccess,
-       OUT PBOOLEAN AccessStatus
-       )
+/*
+ * @unimplemented
+ */
+NTSTATUS STDCALL
+NtAllocateUuids(PULARGE_INTEGER Time,
+               PULONG Range,
+               PULONG Sequence)
 {
+  UNIMPLEMENTED;
+  return(STATUS_NOT_IMPLEMENTED);
 }
 
-NTSTATUS
-STDCALL
-ZwAccessCheck(
-       IN PSECURITY_DESCRIPTOR SecurityDescriptor,
-       IN HANDLE ClientToken,
-       IN ACCESS_MASK DesiredAcces,
-       IN PGENERIC_MAPPING GenericMapping,
-       OUT PRIVILEGE_SET PrivilegeSet,
-       OUT PULONG ReturnLength,
-       OUT PULONG GrantedAccess,
-       OUT PBOOLEAN AccessStatus
-       )
-{
+
+/*
+ * @implemented
+ */
+VOID STDCALL
+SeCaptureSubjectContext(OUT PSECURITY_SUBJECT_CONTEXT SubjectContext)
+{
+  PETHREAD Thread;
+  BOOLEAN CopyOnOpen;
+  BOOLEAN EffectiveOnly;
+
+  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);
+    }
 }
 
-NTSTATUS RtlCreateSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
-                                    ULONG Revision)
+
+/*
+ * @unimplemented
+ */
+VOID STDCALL
+SeLockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
 {
-   UNIMPLEMENTED;
+  UNIMPLEMENTED;
 }
 
-ULONG RtlLengthSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor)
+
+/*
+ * @implemented
+ */
+VOID STDCALL
+SeReleaseSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
 {
-   UNIMPLEMENTED;
+  if (SubjectContext->PrimaryToken != NULL)
+    {
+      ObDereferenceObject(SubjectContext->PrimaryToken);
+    }
+
+  if (SubjectContext->ClientToken != NULL)
+    {
+      ObDereferenceObject(SubjectContext->ClientToken);
+    }
 }
 
-NTSTATUS RtlSetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor,
-                                     BOOLEAN DaclPresent,
-                                     PACL Dacl,
-                                     BOOLEAN DaclDefaulted)
+
+/*
+ * @unimplemented
+ */
+VOID STDCALL
+SeUnlockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
 {
-   UNIMPLEMENTED;
+  UNIMPLEMENTED;
 }
 
-BOOLEAN RtlValidSecurityDescriptor(PSECURITY_DESCRIPTOR SecurityDescriptor)
+
+/*
+ * @implemented
+ */
+NTSTATUS STDCALL
+SeDeassignSecurity(PSECURITY_DESCRIPTOR *SecurityDescriptor)
 {
-   UNIMPLEMENTED;
+  if (*SecurityDescriptor != NULL)
+    {
+      ExFreePool(*SecurityDescriptor);
+      *SecurityDescriptor = NULL;
+    }
+
+  return STATUS_SUCCESS;
 }
 
-BOOLEAN SeSinglePrivilegeCheck(LUID PrivilegeValue,
-                              KPROCESSOR_MODE PreviousMode)
+
+#if 0
+VOID
+SepGetDefaultsSubjectContext(PSECURITY_SUBJECT_CONTEXT SubjectContext,
+                            PSID* Owner,
+                            PSID* PrimaryGroup,
+                            PSID* ProcessOwner,
+                            PSID* ProcessPrimaryGroup,
+                            PACL* DefaultDacl)
 {
-   UNIMPLEMENTED;
+  PACCESS_TOKEN Token;
+
+  if (SubjectContext->ClientToken != NULL)
+    {
+       Token = SubjectContext->ClientToken;
+    }
+  else
+    {
+       Token = SubjectContext->PrimaryToken;
+    }
+  *Owner = Token->UserAndGroups[Token->DefaultOwnerIndex].Sid;
+  *PrimaryGroup = Token->PrimaryGroup;
+  *DefaultDacl = Token->DefaultDacl;
+  *ProcessOwner = SubjectContext->PrimaryToken->
+    UserAndGroups[Token->DefaultOwnerIndex].Sid;
+  *ProcessPrimaryGroup = SubjectContext->PrimaryToken->PrimaryGroup;
 }
 
-NTSTATUS SeDeassignSecurity(PSECURITY_DESCRIPTOR* SecurityDescriptor)
+
+NTSTATUS
+SepInheritAcl(PACL Acl,
+             BOOLEAN IsDirectoryObject,
+             PSID Owner,
+             PSID PrimaryGroup,
+             PACL DefaultAcl,
+             PSID ProcessOwner,
+             PSID ProcessGroup,
+             PGENERIC_MAPPING GenericMapping)
 {
-   UNIMPLEMENTED;
+  if (Acl == NULL)
+    {
+       return(STATUS_UNSUCCESSFUL);
+    }
+
+  if (Acl->AclRevision != 2 &&
+      Acl->AclRevision != 3 )
+    {
+       return(STATUS_UNSUCCESSFUL);
+    }
+
 }
+#endif
 
-NTSTATUS SeAssignSecurity(PSECURITY_DESCRIPTOR ParentDescriptor,
-                         PSECURITY_DESCRIPTOR ExplicitDescriptor,
-                         BOOLEAN IsDirectoryObject,
-                         PSECURITY_SUBJECT_CONTEXT SubjectContext,
-                         PGENERIC_MAPPING GenericMapping,
-                         POOL_TYPE PoolType)
-{
-   UNIMPLEMENTED;
+
+/*
+ * @unimplemented
+ */
+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)
+{
+  PSECURITY_DESCRIPTOR Descriptor;
+  ULONG Length;
+  NTSTATUS Status;
+
+  if (ExplicitDescriptor != NULL)
+    {
+      Length = RtlLengthSecurityDescriptor(ExplicitDescriptor);
+    }
+  else
+    {
+      DPRINT("No explicit security descriptor\n");
+      return STATUS_UNSUCCESSFUL;
+    }
+
+  Descriptor = ExAllocatePool(NonPagedPool,
+                             Length);
+  if (Descriptor == NULL)
+    {
+      DPRINT1("ExAlloctePool() failed\n");
+      return STATUS_UNSUCCESSFUL;
+    }
+
+  Status = RtlMakeSelfRelativeSD(ExplicitDescriptor,
+                                Descriptor,
+                                &Length);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("RtlMakeSelfRelativeSD() failed (Status %lx)\n", Status);
+      return Status;
+    }
+
+  *NewDescriptor = Descriptor;
+
+  return STATUS_SUCCESS;
+
+#if 0
+   PSID Owner;
+   PSID PrimaryGroup;
+   PACL DefaultDacl;
+   PSID ProcessOwner;
+   PSID ProcessPrimaryGroup;
+   PACL Sacl;
+
+   if (ExplicitDescriptor == NULL)
+     {
+       RtlCreateSecurityDescriptor(&Descriptor, 1);
+     }
+   else
+     {
+       Descriptor = ExplicitDescriptor;
+     }
+
+   SeLockSubjectContext(SubjectContext);
+
+   SepGetDefaultsSubjectContext(SubjectContext,
+                               &Owner,
+                               &PrimaryGroup,
+                               &DefaultDacl,
+                               &ProcessOwner,
+                               &ProcessPrimaryGroup);
+
+   if (Descriptor->Control & SE_SACL_PRESENT ||
+       Descriptor->Control & SE_SACL_DEFAULTED)
+     {
+       if (ParentDescriptor == NULL)
+         {
+         }
+
+       if (Descriptor->Control & SE_SACL_PRESENT ||
+           Descriptor->Sacl == NULL ||)
+         {
+            Sacl = NULL;
+         }
+       else
+         {
+            Sacl = Descriptor->Sacl;
+            if (Descriptor->Control & SE_SELF_RELATIVE)
+              {
+                 Sacl = (PACL)(((ULONG_PTR)Sacl) + (ULONG_PTR)Descriptor);
+              }
+         }
+
+       SepInheritAcl(Sacl,
+                     IsDirectoryObject,
+                     Owner,
+                     PrimaryGroup,
+                     DefaultDacl,
+                     ProcessOwner,
+                     GenericMapping);
+     }
+#endif
+}
+
+
+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 (Token->UserAndGroups[i].Attributes & SE_GROUP_ENABLED)
+      {
+        return TRUE;
+      }
+
+      return FALSE;
+    }
+  }
+
+  return FALSE;
 }
 
-BOOLEAN SeAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
-                     IN PSECURITY_DESCRIPTOR_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
  * ARGUMENTS:
- *      SecurityDescriptor = Security descriptor protected the object
+ *      SecurityDescriptor = Security descriptor protecting the object
  *      SubjectSecurityContext = Subject's captured security context
  *      SubjectContextLocked = Indicates the user's subject context is locked
  *      DesiredAccess = Access rights the caller is trying to acquire
  *      PreviouslyGrantedAccess = Specified the access rights already granted
- *      Priveleges = ?
+ *      Privileges = ?
  *      GenericMapping = Generic mapping associated with the object
  *      AccessMode = Access mode used for the check
  *      GrantedAccess (OUT) = On return specifies the access granted
  *      AccessStatus (OUT) = Status indicating why access was denied
  * RETURNS: If access was granted, returns TRUE
+ *
+ * @implemented
  */
-{
-   UNIMPLEMENTED;
-}
-
-
+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)
+{
+  LUID_AND_ATTRIBUTES Privilege;
+  ACCESS_MASK CurrentAccess;
+  PACCESS_TOKEN Token;
+  ULONG i;
+  PACL Dacl;
+  BOOLEAN Present;
+  BOOLEAN Defaulted;
+  PACE CurrentAce;
+  PSID Sid;
+  NTSTATUS Status;
+
+  CurrentAccess = PreviouslyGrantedAccess;
+
+  Token = SubjectSecurityContext->ClientToken ?
+           SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
+
+  /* Get the DACL */
+  Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
+                                       &Present,
+                                       &Dacl,
+                                       &Defaulted);
+  if (!NT_SUCCESS(Status))
+    {
+      *AccessStatus = Status;
+      return FALSE;
+    }
+
+  /* RULE 1: Grant desired access if the object is unprotected */
+  if (Dacl == NULL)
+    {
+      *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)
+       {
+         *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))
+    {
+      DPRINT1("RtlGetOwnerSecurityDescriptor() failed (Status %lx)\n", Status);
+      *AccessStatus = Status;
+      return FALSE;
+   }
+
+  if (SepSidInToken(Token, Sid))
+    {
+      CurrentAccess |= (READ_CONTROL | WRITE_DAC);
+      if (DesiredAccess == CurrentAccess)
+       {
+         *GrantedAccess = CurrentAccess;
+         *AccessStatus = STATUS_SUCCESS;
+         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))
+           {
+             *GrantedAccess = 0;
+             *AccessStatus = STATUS_ACCESS_DENIED;
+             return TRUE;
+           }
+       }
+
+      if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
+       {
+         if (SepSidInToken(Token, Sid))
+           {
+             CurrentAccess |= CurrentAce->AccessMask;
+           }
+       }
+    }
+
+  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;
+  KPROCESSOR_MODE PreviousMode;
+  PACCESS_TOKEN Token;
+  NTSTATUS Status;
+
+  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;
+    }
+
+  RtlZeroMemory(&SubjectSecurityContext,
+               sizeof(SECURITY_SUBJECT_CONTEXT));
+  SubjectSecurityContext.ClientToken = Token;
+  SubjectSecurityContext.ImpersonationLevel = Token->ImpersonationLevel;
+
+  /* FIXME: Lock subject context */
+
+  if (!SeAccessCheck(SecurityDescriptor,
+                    &SubjectSecurityContext,
+                    TRUE,
+                    DesiredAccess,
+                    0,
+                    &PrivilegeSet,
+                    GenericMapping,
+                    PreviousMode,
+                    GrantedAccess,
+                    AccessStatus))
+    {
+      Status = *AccessStatus;
+    }
+  else
+    {
+      Status = STATUS_SUCCESS;
+    }
+
+  /* FIXME: Unlock subject context */
+
+  ObDereferenceObject(Token);
+
+  DPRINT("NtAccessCheck() done\n");
+
+  return Status;
+}
+
+/* EOF */