[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / se / access.c
index 1e49fce..b4ebe9f 100644 (file)
-/* $Id$
- *
+/*
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/se/access.c
- * PURPOSE:         Access rights handling functions
- * 
- * PROGRAMMERS:     Eric Kohl <eric.kohl@t-online.de>
+ * PURPOSE:         Access state functions
+ *
+ * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net) - 
+ *                               Based on patch by Javier M. Mellid
  */
 
-/* INCLUDES *****************************************************************/
+/* INCLUDES *******************************************************************/
 
 #include <ntoskrnl.h>
 #define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
 
-/* FUNCTIONS ***************************************************************/
+/* GLOBALS ********************************************************************/
+
+ERESOURCE SepSubjectContextLock;
+
+/* FUNCTIONS ******************************************************************/
 
 /*
  * @implemented
  */
-BOOLEAN
-STDCALL
-RtlAreAllAccessesGranted (
-       ACCESS_MASK     GrantedAccess,
-       ACCESS_MASK     DesiredAccess
-       )
+VOID
+NTAPI
+SeCaptureSubjectContextEx(IN PETHREAD Thread,
+                          IN PEPROCESS Process,
+                          OUT PSECURITY_SUBJECT_CONTEXT SubjectContext)
 {
-       PAGED_CODE_RTL();
+    BOOLEAN CopyOnOpen, EffectiveOnly;
 
-       return ((GrantedAccess & DesiredAccess) == DesiredAccess);
+    PAGED_CODE();
+
+    /* Save the unique ID */
+    SubjectContext->ProcessAuditId = Process->UniqueProcessId;
+
+    /* Check if we have a thread */
+    if (!Thread)
+    {
+        /* We don't, so no token */
+        SubjectContext->ClientToken = NULL;
+    }
+    else
+    {
+        /* Get the impersonation token */
+        SubjectContext->ClientToken = PsReferenceImpersonationToken(Thread,
+                                                                    &CopyOnOpen,
+                                                                    &EffectiveOnly,
+                                                                    &SubjectContext->ImpersonationLevel);
+    }
+
+    /* Get the primary token */
+    SubjectContext->PrimaryToken = PsReferencePrimaryToken(Process);
 }
 
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+SeCaptureSubjectContext(OUT PSECURITY_SUBJECT_CONTEXT SubjectContext)
+{
+    /* Call the extended API */
+    SeCaptureSubjectContextEx(PsGetCurrentThread(),
+                              PsGetCurrentProcess(),
+                              SubjectContext);
+}
 
 /*
  * @implemented
  */
-BOOLEAN
-STDCALL
-RtlAreAnyAccessesGranted (
-       ACCESS_MASK     GrantedAccess,
-       ACCESS_MASK     DesiredAccess
-       )
+VOID
+NTAPI
+SeLockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
 {
-       PAGED_CODE_RTL();
+    PAGED_CODE();
 
-       return ((GrantedAccess & DesiredAccess) != 0);
+    KeEnterCriticalRegion();
+    ExAcquireResourceExclusiveLite(&SepSubjectContextLock, TRUE);
 }
 
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+SeUnlockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
+{
+    PAGED_CODE();
+
+    ExReleaseResourceLite(&SepSubjectContextLock);
+    KeLeaveCriticalRegion();
+}
 
 /*
  * @implemented
  */
 VOID
-STDCALL
-RtlMapGenericMask (
-       PACCESS_MASK            AccessMask,
-       PGENERIC_MAPPING        GenericMapping
-       )
+NTAPI
+SeReleaseSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
 {
-       PAGED_CODE_RTL();
+    PAGED_CODE();
+
+    if (SubjectContext->PrimaryToken != NULL)
+    {
+        ObFastDereferenceObject(&PsGetCurrentProcess()->Token, SubjectContext->PrimaryToken);
+    }
+
+    if (SubjectContext->ClientToken != NULL)
+    {
+        ObDereferenceObject(SubjectContext->ClientToken);
+    }
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+SeCreateAccessStateEx(IN PETHREAD Thread,
+                      IN PEPROCESS Process,
+                      IN OUT PACCESS_STATE AccessState,
+                      IN PAUX_ACCESS_DATA AuxData,
+                      IN ACCESS_MASK Access,
+                      IN PGENERIC_MAPPING GenericMapping)
+{
+    ACCESS_MASK AccessMask = Access;
+    PTOKEN Token;
+
+    PAGED_CODE();
 
-       if (*AccessMask & GENERIC_READ)
-               *AccessMask |= GenericMapping->GenericRead;
+    /* Map the Generic Acess to Specific Access if we have a Mapping */
+    if ((Access & GENERIC_ACCESS) && (GenericMapping))
+    {
+        RtlMapGenericMask(&AccessMask, GenericMapping);
+    }
 
-       if (*AccessMask & GENERIC_WRITE)
-               *AccessMask |= GenericMapping->GenericWrite;
+    /* Initialize the Access State */
+    RtlZeroMemory(AccessState, sizeof(ACCESS_STATE));
 
-       if (*AccessMask & GENERIC_EXECUTE)
-               *AccessMask |= GenericMapping->GenericExecute;
+    /* Capture the Subject Context */
+    SeCaptureSubjectContextEx(Thread,
+                              Process,
+                              &AccessState->SubjectSecurityContext);
 
-       if (*AccessMask & GENERIC_ALL)
-               *AccessMask |= GenericMapping->GenericAll;
+    /* Set Access State Data */
+    AccessState->AuxData = AuxData;
+    AccessState->RemainingDesiredAccess  = AccessMask;
+    AccessState->OriginalDesiredAccess = AccessMask;
+    ExpAllocateLocallyUniqueId(&AccessState->OperationID);
 
-       *AccessMask &= 0x0FFFFFFF;
+    /* Get the Token to use */
+    Token = AccessState->SubjectSecurityContext.ClientToken ?
+            (PTOKEN)&AccessState->SubjectSecurityContext.ClientToken :
+            (PTOKEN)&AccessState->SubjectSecurityContext.PrimaryToken;
+
+    /* Check for Travers Privilege */
+    if (Token->TokenFlags & TOKEN_HAS_TRAVERSE_PRIVILEGE)
+    {
+        /* Preserve the Traverse Privilege */
+        AccessState->Flags = TOKEN_HAS_TRAVERSE_PRIVILEGE;
+    }
+
+    /* Set the Auxiliary Data */
+    AuxData->PrivilegeSet = (PPRIVILEGE_SET)((ULONG_PTR)AccessState +
+                                             FIELD_OFFSET(ACCESS_STATE,
+                                                          Privileges));
+    if (GenericMapping) AuxData->GenericMapping = *GenericMapping;
+
+    /* Return Sucess */
+    return STATUS_SUCCESS;
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS
-STDCALL
-SeCreateAccessState(
-       PACCESS_STATE AccessState,
-       PVOID AuxData,
-       ACCESS_MASK Access,
-       PGENERIC_MAPPING GenericMapping
-       )
+NTAPI
+SeCreateAccessState(IN OUT PACCESS_STATE AccessState,
+                    IN PAUX_ACCESS_DATA AuxData,
+                    IN ACCESS_MASK Access,
+                    IN PGENERIC_MAPPING GenericMapping)
 {
-       UNIMPLEMENTED;
-       return STATUS_NOT_IMPLEMENTED;
+    PAGED_CODE();
+
+    /* Call the extended API */
+    return SeCreateAccessStateEx(PsGetCurrentThread(),
+                                 PsGetCurrentProcess(),
+                                 AccessState,
+                                 AuxData,
+                                 Access,
+                                 GenericMapping);
 }
 
 /*
- * @unimplemented
+ * @implemented
+ */
+VOID
+NTAPI
+SeDeleteAccessState(IN PACCESS_STATE AccessState)
+{
+    PAUX_ACCESS_DATA AuxData;
+
+    PAGED_CODE();
+
+    /* Get the Auxiliary Data */
+    AuxData = AccessState->AuxData;
+
+    /* Deallocate Privileges */
+    if (AccessState->PrivilegesAllocated) ExFreePool(AuxData->PrivilegeSet);
+
+    /* Deallocate Name and Type Name */
+    if (AccessState->ObjectName.Buffer)
+    {
+        ExFreePool(AccessState->ObjectName.Buffer);
+    }
+
+    if (AccessState->ObjectTypeName.Buffer)
+    {
+        ExFreePool(AccessState->ObjectTypeName.Buffer);
+    }
+
+    /* Release the Subject Context */
+    SeReleaseSubjectContext(&AccessState->SubjectSecurityContext);
+}
+
+/*
+ * @implemented
  */
 VOID
-STDCALL
-SeDeleteAccessState(
-       IN PACCESS_STATE AccessState
-       )
+NTAPI
+SeSetAccessStateGenericMapping(IN PACCESS_STATE AccessState,
+                               IN PGENERIC_MAPPING GenericMapping)
+{
+    PAGED_CODE();
+
+    /* Set the Generic Mapping */
+    ((PAUX_ACCESS_DATA)AccessState->AuxData)->GenericMapping = *GenericMapping;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+SeCreateClientSecurity(IN PETHREAD Thread,
+                       IN PSECURITY_QUALITY_OF_SERVICE Qos,
+                       IN BOOLEAN RemoteClient,
+                       OUT PSECURITY_CLIENT_CONTEXT ClientContext)
 {
-       UNIMPLEMENTED;
+    TOKEN_TYPE TokenType;
+    BOOLEAN ThreadEffectiveOnly;
+    SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
+    PACCESS_TOKEN Token;
+    NTSTATUS Status;
+    PACCESS_TOKEN NewToken;
+
+    PAGED_CODE();
+
+    Token = PsReferenceEffectiveToken(Thread,
+                                      &TokenType,
+                                      &ThreadEffectiveOnly,
+                                      &ImpersonationLevel);
+    if (TokenType != TokenImpersonation)
+    {
+        ClientContext->DirectAccessEffectiveOnly = Qos->EffectiveOnly;
+    }
+    else
+    {
+        if (Qos->ImpersonationLevel > ImpersonationLevel)
+        {
+            if (Token) ObDereferenceObject(Token);
+            return STATUS_BAD_IMPERSONATION_LEVEL;
+        }
+
+        if ((ImpersonationLevel == SecurityAnonymous) ||
+            (ImpersonationLevel == SecurityIdentification) ||
+            ((RemoteClient) && (ImpersonationLevel != SecurityDelegation)))
+        {
+            if (Token) ObDereferenceObject(Token);
+            return STATUS_BAD_IMPERSONATION_LEVEL;
+        }
+
+        ClientContext->DirectAccessEffectiveOnly = ((ThreadEffectiveOnly) ||
+                                                    (Qos->EffectiveOnly)) ? TRUE : FALSE;
+    }
+
+    if (Qos->ContextTrackingMode == SECURITY_STATIC_TRACKING)
+    {
+        ClientContext->DirectlyAccessClientToken = FALSE;
+        Status = SeCopyClientToken(Token, ImpersonationLevel, 0, &NewToken);
+        if (!NT_SUCCESS(Status)) return Status;
+    }
+    else
+    {
+        ClientContext->DirectlyAccessClientToken = TRUE;
+        if (RemoteClient != FALSE)
+        {
+#if 0
+            SeGetTokenControlInformation(Token,
+                                         &ClientContext->ClientTokenControl);
+#endif
+        }
+
+        NewToken = Token;
+    }
+
+    ClientContext->SecurityQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
+    ClientContext->SecurityQos.ImpersonationLevel = Qos->ImpersonationLevel;
+    ClientContext->SecurityQos.ContextTrackingMode = Qos->ContextTrackingMode;
+    ClientContext->SecurityQos.EffectiveOnly = Qos->EffectiveOnly;
+    ClientContext->ServerIsRemote = RemoteClient;
+    ClientContext->ClientToken = NewToken;
+    return STATUS_SUCCESS;
 }
 
 /*
  * @unimplemented
  */
+NTSTATUS
+NTAPI
+SeCreateClientSecurityFromSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext,
+                                         IN PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos,
+                                         IN BOOLEAN ServerIsRemote,
+                                         OUT PSECURITY_CLIENT_CONTEXT ClientContext)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+SeImpersonateClientEx(IN PSECURITY_CLIENT_CONTEXT ClientContext,
+                      IN PETHREAD ServerThread OPTIONAL)
+{
+    BOOLEAN EffectiveOnly;
+
+    PAGED_CODE();
+
+    if (ClientContext->DirectlyAccessClientToken == FALSE)
+    {
+        EffectiveOnly = ClientContext->SecurityQos.EffectiveOnly;
+    }
+    else
+    {
+        EffectiveOnly = ClientContext->DirectAccessEffectiveOnly;
+    }
+
+    if (ServerThread == NULL)
+    {
+        ServerThread = PsGetCurrentThread();
+    }
+
+    return PsImpersonateClient(ServerThread,
+                               ClientContext->ClientToken,
+                               TRUE,
+                               EffectiveOnly,
+                               ClientContext->SecurityQos.ImpersonationLevel);
+}
+
+/*
+ * @implemented
+ */
 VOID
-STDCALL
-SeSetAccessStateGenericMapping(
-       PACCESS_STATE AccessState,
-       PGENERIC_MAPPING GenericMapping
-       )
+NTAPI
+SeImpersonateClient(IN PSECURITY_CLIENT_CONTEXT ClientContext,
+                    IN PETHREAD ServerThread OPTIONAL)
 {
-       UNIMPLEMENTED;
+    PAGED_CODE();
+
+    SeImpersonateClientEx(ClientContext,
+                          ServerThread);
 }
 
 /* EOF */