SeCaptureSubjectContext() must not crash if no current thread exists.
[reactos.git] / reactos / ntoskrnl / se / semgr.c
index fc08889..a8fe6f5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: semgr.c,v 1.30 2004/05/20 12:42:11 ekohl Exp $
+/* $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
@@ -15,6 +15,7 @@
 #include <internal/ps.h>
 #include <internal/se.h>
 
+#define NDEBUG
 #include <internal/debug.h>
 
 #define TAG_SXPT   TAG('S', 'X', 'P', 'T')
@@ -201,40 +202,34 @@ NtAllocateUuids(PULARGE_INTEGER Time,
 }
 
 
-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)
-{
-  UNIMPLEMENTED;
-  return(STATUS_NOT_IMPLEMENTED);
-}
-
-
 /*
  * @implemented
  */
 VOID STDCALL
 SeCaptureSubjectContext(OUT PSECURITY_SUBJECT_CONTEXT SubjectContext)
 {
-  PEPROCESS Process;
+  PETHREAD Thread;
   BOOLEAN CopyOnOpen;
   BOOLEAN EffectiveOnly;
 
-  Process = PsGetCurrentThread ()->ThreadsProcess;
-
-  SubjectContext->ProcessAuditId = Process;
-  SubjectContext->ClientToken = 
-    PsReferenceImpersonationToken (PsGetCurrentThread(),
-                                  &CopyOnOpen,
-                                  &EffectiveOnly,
-                                  &SubjectContext->ImpersonationLevel);
-  SubjectContext->PrimaryToken = PsReferencePrimaryToken (Process);
+  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);
+    }
 }
 
 
@@ -254,10 +249,14 @@ SeLockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
 VOID STDCALL
 SeReleaseSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
 {
-  ObDereferenceObject (SubjectContext->PrimaryToken);
+  if (SubjectContext->PrimaryToken != NULL)
+    {
+      ObDereferenceObject(SubjectContext->PrimaryToken);
+    }
+
   if (SubjectContext->ClientToken != NULL)
     {
-      ObDereferenceObject (SubjectContext->ClientToken);
+      ObDereferenceObject(SubjectContext->ClientToken);
     }
 }
 
@@ -276,86 +275,126 @@ SeUnlockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
  * @implemented
  */
 NTSTATUS STDCALL
-SeDeassignSecurity(PSECURITY_DESCRIPTORSecurityDescriptor)
+SeDeassignSecurity(PSECURITY_DESCRIPTOR *SecurityDescriptor)
 {
-  if ((*SecurityDescriptor) != NULL)
+  if (*SecurityDescriptor != NULL)
     {
       ExFreePool(*SecurityDescriptor);
-      (*SecurityDescriptor) = NULL;
+      *SecurityDescriptor = NULL;
     }
-  return(STATUS_SUCCESS);
+
+  return STATUS_SUCCESS;
 }
 
 
 #if 0
-VOID SepGetDefaultsSubjectContext(PSECURITY_SUBJECT_CONTEXT SubjectContext,
-                                 PSID* Owner,
-                                 PSID* PrimaryGroup,
-                                 PSID* ProcessOwner,
-                                 PSID* ProcessPrimaryGroup,
-                                 PACL* DefaultDacl)
+VOID
+SepGetDefaultsSubjectContext(PSECURITY_SUBJECT_CONTEXT SubjectContext,
+                            PSID* Owner,
+                            PSID* PrimaryGroup,
+                            PSID* ProcessOwner,
+                            PSID* ProcessPrimaryGroup,
+                            PACL* DefaultDacl)
 {
-   PACCESS_TOKEN Token;
-   
-   if (SubjectContext->ClientToken != NULL)
-     {
+  PACCESS_TOKEN Token;
+
+  if (SubjectContext->ClientToken != NULL)
+    {
        Token = SubjectContext->ClientToken;
-     }
-   else
-     {
+    }
+  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;
+    }
+  *Owner = Token->UserAndGroups[Token->DefaultOwnerIndex].Sid;
+  *PrimaryGroup = Token->PrimaryGroup;
+  *DefaultDacl = Token->DefaultDacl;
+  *ProcessOwner = SubjectContext->PrimaryToken->
+    UserAndGroups[Token->DefaultOwnerIndex].Sid;
+  *ProcessPrimaryGroup = SubjectContext->PrimaryToken->PrimaryGroup;
 }
 
-NTSTATUS SepInheritAcl(PACL Acl,
-                      BOOLEAN IsDirectoryObject,
-                      PSID Owner,
-                      PSID PrimaryGroup,
-                      PACL DefaultAcl,
-                      PSID ProcessOwner,
-                      PSID ProcessGroup,
-                      PGENERIC_MAPPING GenericMapping)
+
+NTSTATUS
+SepInheritAcl(PACL Acl,
+             BOOLEAN IsDirectoryObject,
+             PSID Owner,
+             PSID PrimaryGroup,
+             PACL DefaultAcl,
+             PSID ProcessOwner,
+             PSID ProcessGroup,
+             PGENERIC_MAPPING GenericMapping)
 {
-   if (Acl == NULL)
-     {
+  if (Acl == NULL)
+    {
        return(STATUS_UNSUCCESSFUL);
-     }
-   if (Acl->AclRevision != 2 &&
-       Acl->AclRevision != 3 )
-     {
+    }
+
+  if (Acl->AclRevision != 2 &&
+      Acl->AclRevision != 3 )
+    {
        return(STATUS_UNSUCCESSFUL);
-     }
-   
+    }
+
 }
 #endif
 
+
 /*
  * @unimplemented
  */
 NTSTATUS STDCALL
-SeAssignSecurity(PSECURITY_DESCRIPTOR ParentDescriptor,
-                PSECURITY_DESCRIPTOR ExplicitDescriptor,
-                PSECURITY_DESCRIPTORNewDescriptor,
+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
-   PSECURITY_DESCRIPTOR Descriptor;
    PSID Owner;
    PSID PrimaryGroup;
    PACL DefaultDacl;
    PSID ProcessOwner;
    PSID ProcessPrimaryGroup;
    PACL Sacl;
-   
+
    if (ExplicitDescriptor == NULL)
      {
        RtlCreateSecurityDescriptor(&Descriptor, 1);
@@ -364,19 +403,23 @@ SeAssignSecurity(PSECURITY_DESCRIPTOR ParentDescriptor,
      {
        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 ||)
          {
@@ -387,9 +430,10 @@ SeAssignSecurity(PSECURITY_DESCRIPTOR ParentDescriptor,
             Sacl = Descriptor->Sacl;
             if (Descriptor->Control & SE_SELF_RELATIVE)
               {
-                 Sacl = (PACL)(((PVOID)Sacl) + (PVOID)Descriptor);
+                 Sacl = (PACL)(((ULONG_PTR)Sacl) + (ULONG_PTR)Descriptor);
               }
          }
+
        SepInheritAcl(Sacl,
                      IsDirectoryObject,
                      Owner,
@@ -398,52 +442,38 @@ SeAssignSecurity(PSECURITY_DESCRIPTOR ParentDescriptor,
                      ProcessOwner,
                      GenericMapping);
      }
-#else
-  UNIMPLEMENTED;
-  return(STATUS_NOT_IMPLEMENTED);
 #endif
 }
 
-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 & SE_GROUP_ENABLED)))
-              {
-                 return(TRUE);
-              }
-            return(FALSE);
-         }
-     }
-   return(FALSE);
+  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;
 }
 
 
-/*
- * @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_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
@@ -459,69 +489,220 @@ 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;
+
+  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))
-     {
-       return(Status);
-     }
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("RtlGetOwnerSecurityDescriptor() failed (Status %lx)\n", Status);
+      *AccessStatus = Status;
+      return FALSE;
+   }
 
-   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->AccessMask;
-              }
-         }
-     }
-   if (!(CurrentAccess & DesiredAccess) &&
-       !((~CurrentAccess) & DesiredAccess))
-     {
-       *AccessStatus = STATUS_ACCESS_DENIED;
-     }
-   else
-     {
-       *AccessStatus = STATUS_SUCCESS;
-     }
-   *GrantedAccess = CurrentAccess;
+  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_SUCCESS);
+  return Status;
 }
 
 /* EOF */