/*++

Copyright (c) Microsoft Corporation. All rights reserved. 

You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.


Module Name:

    tokenp.h

Abstract:

    This module contains the internal (private) declarations needed by the
    TOKEN object routines.

    It also contains global variables needed by the TOKEN object routines.

--*/

#ifndef _TOKENP_
#define _TOKENP_

#include "ntos.h"
#include "sep.h"
#include "seopaque.h"



/////////////////////////////////////////////////////////////////////////
//                                                                     //
//                Token Diagnostics                                    //
//                                                                     //
/////////////////////////////////////////////////////////////////////////



#if DBG
#define TOKEN_DIAGNOSTICS_ENABLED 1
#endif // DBG


//
// These definitions are useful diagnostics aids
//

#if TOKEN_DIAGNOSTICS_ENABLED

//
// Test for enabled diagnostic
//

#define IF_TOKEN_GLOBAL( FlagName ) \
    if (TokenGlobalFlag & (TOKEN_DIAG_##FlagName))

//
// Diagnostics print statement
//

#define TokenDiagPrint( FlagName, _Text_ )                               \
    IF_TOKEN_GLOBAL( FlagName )                                          \
        DbgPrint _Text_



#else  // !TOKEN_DIAGNOSTICS_ENABLED

//
// No diagnostics included in build
//


//
// Test for diagnostics enabled
//

#define IF_TOKEN_GLOBAL( FlagName ) if (FALSE)

//
// Diagnostics print statement (expands to no-op)
//

#define TokenDiagPrint( FlagName, _Text_ )     ;

#endif // TOKEN_DIAGNOSTICS_ENABLED


//
// The following flags enable or disable various diagnostic
// capabilities within token code.  These flags are set in
// TokenGlobalFlag (only available within a DBG system).
//
//
//      TOKEN_LOCKS - Display information about acquisition and freeing
//          of token locks.
//

#define TOKEN_DIAG_TOKEN_LOCKS          ((ULONG) 0x00000001L)


/////////////////////////////////////////////////////////////////////////
//                                                                     //
//                Token Related Constants                              //
//                                                                     //
/////////////////////////////////////////////////////////////////////////

//
// By default, a token is charged the following for its dynamic component.
// The dynamic component houses the default ACL and primary group ID.
// If the size of these parameters passed upon token creation are larger
// than this default, then the larger value will be charged.
//

#define TOKEN_DEFAULT_DYNAMIC_CHARGE 500

//
// AuditPolicy bit array is arranged with 4 bits for each audit category.
// The bit ordering for each category is:
//     Success Include, Success Exclude, Failure Include, Failure Exclude
// The number of tokens that have audit policies
// are tracked in SepTokenPolicyCounter.  This is done so that when all tokens
// with policies are gone (ie SepTokenPolicyCounter == 0) the routines that
// decide if an audit should be generated can execute faster.
//
    
typedef struct _SEP_AUDIT_POLICY_CATEGORIES {
    ULONG System : 4;
    ULONG Logon : 4;
    ULONG ObjectAccess : 4;
    ULONG PrivilegeUse : 4;
    ULONG DetailedTracking : 4;
    ULONG PolicyChange : 4;
    ULONG AccountManagement : 4;
    ULONG DirectoryServiceAccess : 4;
    ULONG AccountLogon : 4;
} SEP_AUDIT_POLICY_CATEGORIES, *PSEP_AUDIT_POLICY_CATEGORIES;

typedef struct _SEP_AUDIT_POLICY_OVERLAY {
    ULONGLONG PolicyBits : 36;
    ULONGLONG SetBit : 1;
} SEP_AUDIT_POLICY_OVERLAY, *PSEP_AUDIT_POLICY_OVERLAY;

typedef struct _SEP_AUDIT_POLICY {
    union {
        SEP_AUDIT_POLICY_CATEGORIES PolicyElements;
        SEP_AUDIT_POLICY_OVERLAY PolicyOverlay;
        ULONGLONG Overlay;
    };
} SEP_AUDIT_POLICY, *PSEP_AUDIT_POLICY;



/////////////////////////////////////////////////////////////////////////
//                                                                     //
//                Token Object Body                                    //
//                                                                     //
/////////////////////////////////////////////////////////////////////////

//          
// Tokens have three parts:
//
//               Fixed part of body,
//               Variable part of body,
//               Dynamic part (not in body).
//
// The fixed and variable parts are allocated in a single block of memory.
// The dynamic part is a separately allocated block of memory.
//
// The fixed part of the body contains the fixed length fields.  These
// are defined in the TOKEN data type.
//
// The variable part of the body is variable in length and contains
// privileges and user/group SIDs.  This part is variable in length
// between different token objects, but does not change once established
// for an individual token.
//
// The dynamic part is used to house default discretionary ACL information
// and the primary group ID.
//
// Pictorially, a token looks like:
//
//    ==============      +---------------+
//          ^             |               |
//          |             |               |
//          |             |               |
//          |             | DynamicPart   o-----------+
//          |             |- - - - - - - -|           |
//                  +-----o Privileges    |           |
//        Token     |     |- - - - - - - -|           |
//        Body      |  +--o UserAndGroups |           |
//          |       |  |  |- - - - - - - -|           |
//          |       |  +--o RestrictedSids|          \|/
//          |       |  |  |- - - - - - - -|        +---------------------+
//          |       |  |  | PrimaryGroup  o------->| [Primary Group SID] |
//          |       |  |  |- - - - - - - -|        |         o           |
//          |       |  |  | DefaultAcl    o---+    |         o           |
//          |       |  |  |- - - - - - - -|   |    |         o           |
//          |       |  |  |      o        |   |    |- - - - - - - - - - -|
//          |       |  |  |      o        |   +--->| [  Default Acl  ]   |
//          v       |  |  |      o        |        |         o           |
//    ==============|  |  |===============|        |         o           |
//          ^       |  +->| SIDs  Array   |        |         o           |
//          |       |     | [User  SID ]  |        +---------------------+
//          |       |     | [Group SID ]  |
//                  |     | [Group SID ]  |
//        Variable  |     | [Rest. Sid ]  |
//         Part     |     |     o         |
//                  |     |- - - - - - - -|
//          |       +---->| Privileges    |
//          |             | Array         |
//          v             |               |
//    ==============      +---------------+
//
//     WARNING: The positions of fields illustrated in this picture are not
//              intented to reflect their actual or even relative positions
//              within the real data structures.  The exception to this is
//              that THE USER SID IS THE FIRST SID IN THE UserAndGroups
//              ARRAY.
//


//
//             ! ! ! !     IMPORTANT     ! ! ! !
//
//      The access validation routines assume the SIDs are arranged
//      in a particular order within the variable part of the token.
//      Any changes to the order of the SIDs must be coordinated with
//      corresponding changes to the access validation routines.
//
//                   ! ! ! ! ! ! ! ! ! ! !



typedef struct _TOKEN {

    //
    // Fields arranged by size to preserve alignment.
    // Large fields before small fields.
    //


    //
    //  The following fields are either ReadOnly or ReadWrite.
    //  ReadOnly fields may be referenced any time a pointer to the
    //  token is still valid.  ReadWrite fields may only be referenced
    //  when the TokenLock is held.

    //  The dynamic part of the token (pointed to by the DynamicPart field)
    //  is also protected by the token lock.
    //
    //  ReadOnly  fields are marked Ro: in their comment.
    //  ReadWrite fields are marked Wr: in their comment.
    //

    TOKEN_SOURCE TokenSource;                           // Ro: 16-Bytes

    LUID TokenId;                                       // Ro: 8-Bytes
    LUID AuthenticationId;                              // Ro: 8-Bytes
    LUID ParentTokenId;                                 // Ro: 8-Bytes
    LARGE_INTEGER ExpirationTime;                       // Ro: 8-Bytes
    PERESOURCE TokenLock;                               // Ro:

    SEP_AUDIT_POLICY AuditPolicy;                       // RW: 8 bytes

    //
    // Each time the security information in a token is changed, the
    // following ID is changed.  Fields that cause this field to be
    // updated are marked as (Mod) in their comment field.
    //

    LUID ModifiedId;                                    // Wr: 8-Bytes

    ULONG SessionId;                                    // Wr: 4-bytes
    ULONG UserAndGroupCount;                            // Ro: 4-Bytes
    ULONG RestrictedSidCount;                           // Ro: 4-Bytes
    ULONG PrivilegeCount;                               // Ro: 4-Bytes
    ULONG VariableLength;                               // Ro: 4-Bytes
    ULONG DynamicCharged;                               // Ro: 4-Bytes

    ULONG DynamicAvailable;                             // Wr: 4-Bytes (Mod)
    ULONG DefaultOwnerIndex;                            // Wr: 4-Bytes (Mod)
    PSID_AND_ATTRIBUTES UserAndGroups;                  // Wr: 4-Bytes (Mod)
    PSID_AND_ATTRIBUTES RestrictedSids;                 // Ro: 4-Bytes
    PSID PrimaryGroup;                                  // Wr: 4-Bytes (Mod)
    PLUID_AND_ATTRIBUTES Privileges;                    // Wr: 4-Bytes (Mod)
    PULONG DynamicPart;                                 // Wr: 4-Bytes (Mod)
    PACL DefaultDacl;                                   // Wr: 4-Bytes (Mod)

    TOKEN_TYPE TokenType;                               // Ro: 1-Byte
    SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;    // Ro: 1-Byte

    UCHAR TokenFlags;                                   // Rw: 4-Bytes
    BOOLEAN TokenInUse;                                 // Wr: 1-Byte

    PSECURITY_TOKEN_PROXY_DATA ProxyData;               // Ro: 4-Bytes
    PSECURITY_TOKEN_AUDIT_DATA AuditData;               // Ro: 4-Bytes

    //
    // Pointer to the referenced logon session. Protected by the token
    // lock and only valid when TOKEN_SESSION_NOT_REFERENCED is clear.
    //
    PSEP_LOGON_SESSION_REFERENCES LogonSession;         // Rw: Ptr

    //
    // Originating information for allowing certain impersonation operations
    // later
    //
    LUID OriginatingLogonSession ;                      // Rw: 8 bytes (set by LSA)



#if DBG || TOKEN_LEAK_MONITOR
#define TRACE_SIZE 30

    //
    // This code is for tracking token leaks, in conjunction with !obtrace.
    //

    HANDLE ProcessCid;                          // Cid of creator process
    HANDLE ThreadCid;                           // Cid of creator thread
    UCHAR  ImageFileName[16];                   // Image name of creator process
    ULONG  CreateMethod;                        // Either 0xC (SepCreateToken) 0xD (SepDuplicateToken) or 0xF (SepFilterToken)
    ULONG_PTR CreateTrace[TRACE_SIZE];          // Stack backtrace that created this token (usermode part is first 20 nonzero stack entries)
    LONG Count;                                 // This is the nth token created with watch method
    LONG CaptureCount;                          // This is the # of SeCaptureSubjectContext - SeReleaseSubjectContext

#endif
    
    //
    // This marks the beginning of the variable part of the token.
    // It must follow all other fields in the token.
    //

    ULONG VariablePart;                                 // Wr: 4-Bytes (Mod)

} TOKEN, * PTOKEN;

//
// Where:
//
//    TokenSource - Information provided by the executive component that
//                  requested the logon that the token represents.
//
//
//    TokenId - Is an LUID value.  Each token object has a uniquely
//        assigned LUID.
//
//
//    AuthenticationId - Is the LUID assigned by the domain controller for
//        the logon session.
//
//
//    ExpirationTime - Not yet supported in NT.
//
//
//    ModifiedId - Is an LUID which is changed each time a modification is
//        made to this token which changes the security semantics of the
//        token.  This includes enabling/disabling privileges and groups
//        and changing default ACLs, et cetera.  Any token which is a
//        duplicate of this token will have the same ModifiedId (until
//        one or the other is changed).  This does not cover changes to
//        non-security semantics fields, like TokenInUse.
//
//
//    UserAndGroupCount - Indicates the number of user/group IDs in this token.
//        This value must be at least 1.  A value of 1 indicates a user
//        ID with no supplemental group IDs.  A value of 5 indicates a
//        user ID and 4 supplemental group IDs.
//
//    PrivilegeCount - Indicates how many privileges are included in
//        this token.  May be zero or larger.
//
//    TokenType - Indicates which type of token this token object is.
//
//    ImpersonationLevel - For TokenImpersonation type tokens, this field
//        indicates the impersonation level.  For TokenPrimary type tokens,
//        this field is ignored.
//
//    DynamicCharged - Indicates how much pool quota has been charged
//        for the dynamic portion of this token.
//
//    DynamicAvailable - Indicates how much of the charged quota is still
//        available for use.  This is modified when  pool associated
//        with the dynamic portion of the token is allocated or freed,
//        such as when the default DACL or primary group is replaced.
//
//
//    DefaultOwnerIndex - If non-zero, identifies an ID that has explicitly
//        been established as the default owner for this token.  If it is zero,
//        the standard default (user ID) is used as the default owner.
//
//    UserAndGroups - Points to an array of SID_AND_ATTRIBUTES.  The first
//        element in this array is the token's user ID.  Any additional
//        elements are those of groups.  The number of entries in this
//        array is one greater than
//
//    PrimaryGroup - Points to an SID that is to be used as the primary
//        group of the token.  There are no value restrictions
//        placed upon what can be used as a primary group.  This
//        SID is not one of user or group IDs (although it may have the
//        same value as one of those IDs).
//
//    Privileges - Points to an array of privileges represented as
//        LUID_AND_ATTRIBUTES.  The number of elements in this array
//        is contained in the PrivilegesCount field.
//
//    TokenInUse - Is a boolean that indicates whether a primary token
//        is already in use by a process.  This field value is only
//        valid for primary tokens.
//
//    ProxyData - Optionally points to a Proxy data structure, containing
//        the information to be passed to AVR routines by file systems.
//        This field being non-null identifies the token as a proxy token.
//
//    AuditData - Optionally points to an Audit data structure, containing
//         global auditing data for this subject.
//
//        NOTE:  Access to this field is guarded by the global
//               PROCESS SECURITY FIELDS LOCK.
//    VariablePart - Is the beginning of the variable part of the token.
//


////////////////////////////////////////////////////////////////////////
//
// Internal version of Object Type list
//
////////////////////////////////////////////////////////////////////////

typedef struct _IOBJECT_TYPE_LIST {
    USHORT Level;
    USHORT Flags;
#define OBJECT_SUCCESS_AUDIT 0x1
#define OBJECT_FAILURE_AUDIT 0x2
    GUID ObjectType;
    LONG ParentIndex;
    ULONG Remaining;
    ULONG CurrentGranted;
    ULONG CurrentDenied;
} IOBJECT_TYPE_LIST, *PIOBJECT_TYPE_LIST;

NTSTATUS
SeCaptureObjectTypeList (
    IN POBJECT_TYPE_LIST ObjectTypeList OPTIONAL,
    IN ULONG ObjectTypeListLength,
    IN KPROCESSOR_MODE RequestorMode,
    OUT PIOBJECT_TYPE_LIST *CapturedObjectTypeList
    );

VOID
SeFreeCapturedObjectTypeList(
    IN PVOID ObjectTypeList
    );


/////////////////////////////////////////////////////////////////////////
//                                                                     //
//                Token Specific Macros                                //
//                                                                     //
/////////////////////////////////////////////////////////////////////////







#ifndef TOKEN_DIAGNOSTICS_ENABLED

#define SepAcquireTokenReadLock(T)  KeEnterCriticalRegion();          \
                                    ExAcquireResourceSharedLite((T)->TokenLock, TRUE)

#define SepAcquireTokenWriteLock(T) KeEnterCriticalRegion();          \
                                    ExAcquireResourceExclusiveLite((T)->TokenLock, TRUE)

#define SepReleaseTokenReadLock(T)  ExReleaseResourceLite((T)->TokenLock);  \
                                    KeLeaveCriticalRegion()

#else  // TOKEN_DIAGNOSTICS_ENABLED

#define SepAcquireTokenReadLock(T)  if (TokenGlobalFlag & TOKEN_DIAG_TOKEN_LOCKS) { \
                                        DbgPrint("SE (Token):  Acquiring Token READ Lock for access to token 0x%lx\n", (T)); \
                                    }                                 \
                                    KeEnterCriticalRegion();          \
                                    ExAcquireResourceSharedLite((T)->TokenLock, TRUE)

#define SepAcquireTokenWriteLock(T) if (TokenGlobalFlag & TOKEN_DIAG_TOKEN_LOCKS) { \
                                        DbgPrint("SE (Token):  Acquiring Token WRITE Lock for access to token 0x%lx    ********************* EXCLUSIVE *****\n", (T)); \
                                    }                                 \
                                    KeEnterCriticalRegion();          \
                                    ExAcquireResourceExclusiveLite((T)->TokenLock, TRUE)

#define SepReleaseTokenReadLock(T)  if (TokenGlobalFlag & TOKEN_DIAG_TOKEN_LOCKS) { \
                                        DbgPrint("SE (Token):  Releasing Token Lock for access to token 0x%lx\n", (T)); \
                                    }                                 \
                                    ExReleaseResourceLite((T)->TokenLock); \
                                    KeLeaveCriticalRegion()

#endif // TOKEN_DIAGNOSTICS_ENABLED

#define SepReleaseTokenWriteLock(T,M)                                    \
    {                                                                    \
      if ((M)) {                                                         \
          ExAllocateLocallyUniqueId( &((PTOKEN)(T))->ModifiedId  );      \
      }                                                                  \
      SepReleaseTokenReadLock( T );                                      \
    }

//
// Reference individual privilege attribute flags of any privilege array
//
//  P - is a pointer to an array of privileges (PLUID_AND_ATTRIBUTES)
//  I - is the index of the privilege
//  A - is the name of the attribute desired (e.g., Enabled, EnabledByDefault, etc. )
//

#define SepArrayPrivilegeAttributes(P,I) ( (P)[I].Attributes )

//
// Reference individual privilege attribute flags of token privileges
//
//  T - is a pointer to a token
//  I - is the index of the privilege
//  A - is the name of the attribute desired (e.g., Enabled, EnabledByDefault, etc. )
//

#define SepTokenPrivilegeAttributes(T,I) ( (T)->Privileges[I].Attributes )

//
// Reference individual group attribute flags of any group array
//
//  G - is a pointer to the array of groups  (SID_AND_ATTRIBUTES[])
//  I - is the index of the group
//

#define SepArrayGroupAttributes(G,I)   ( (G)[I].Attributes )


//
// Reference individual group attribute flags of token groups
//
//  T - is a pointer to a token
//  I - is the index of the group
//

#define SepTokenGroupAttributes(T,I) ( (T)->UserAndGroups[I].Attributes )




////////////////////////////////////////////////////////////////////////
//                                                                    //
//           Private Routine Declarations                             //
//                                                                    //
////////////////////////////////////////////////////////////////////////

NTSTATUS
SepAdjustGroups(
    IN PTOKEN Token,
    IN BOOLEAN MakeChanges,
    IN BOOLEAN ResetToDefault,
    IN ULONG GroupCount OPTIONAL,
    IN PSID_AND_ATTRIBUTES NewState OPTIONAL,
    OUT PTOKEN_GROUPS PreviousState OPTIONAL,
    OUT PSID SidBuffer OPTIONAL,
    OUT PULONG ReturnLength,
    OUT PULONG ChangeCount,
    OUT PBOOLEAN ChangesMade
    );

NTSTATUS
SepAdjustPrivileges(
    IN PTOKEN Token,
    IN BOOLEAN MakeChanges,
    IN BOOLEAN DisableAllPrivileges,
    IN ULONG PrivilegeCount OPTIONAL,
    IN PLUID_AND_ATTRIBUTES NewState OPTIONAL,
    OUT PTOKEN_PRIVILEGES PreviousState OPTIONAL,
    OUT PULONG ReturnLength,
    OUT PULONG ChangeCount,
    OUT PBOOLEAN ChangesMade
    );

VOID
SepAppendDefaultDacl(
    IN PTOKEN Token,
    IN PACL PAcl
    );

VOID
SepAppendPrimaryGroup(
    IN PTOKEN Token,
    IN PSID PSid
    );

NTSTATUS
SepDuplicateToken(
    IN PTOKEN ExistingToken,
    IN POBJECT_ATTRIBUTES ObjectAttributes,
    IN BOOLEAN EffectiveOnly,
    IN TOKEN_TYPE TokenType,
    IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel OPTIONAL,
    IN KPROCESSOR_MODE RequestorMode,
    OUT PTOKEN *DuplicateToken
    );

NTSTATUS
SepFilterToken(
    IN PTOKEN ExistingToken,
    IN KPROCESSOR_MODE RequestorMode,
    IN ULONG Flags,
    IN ULONG GroupCount,
    IN PSID_AND_ATTRIBUTES GroupsToDisable OPTIONAL,
    IN ULONG PrivilegeCount,
    IN PLUID_AND_ATTRIBUTES PrivilegesToDelete OPTIONAL,
    IN ULONG SidCount,
    IN PSID_AND_ATTRIBUTES RestrictedSids OPTIONAL,
    IN ULONG SidLength,
    OUT PTOKEN * FilteredToken
    );

BOOLEAN
SepSidInSidAndAttributes (
    IN PSID_AND_ATTRIBUTES SidAndAttributes,
    IN ULONG SidCount,
    IN PSID PrincipalSelfSid,
    IN PSID Sid
    );

VOID
SepRemoveDisabledGroupsAndPrivileges(
    IN PTOKEN Token,
    IN ULONG Flags,
    IN ULONG GroupCount,
    IN PSID_AND_ATTRIBUTES GroupsToDisable,
    IN ULONG PrivilegeCount,
    IN PLUID_AND_ATTRIBUTES PrivilegesToDelete
    );


VOID
SepFreeDefaultDacl(
    IN PTOKEN Token
    );

VOID
SepFreePrimaryGroup(
    IN PTOKEN Token
    );

NTSTATUS
SepExpandDynamic(
    IN PTOKEN Token,
    IN ULONG NewLength
    );

BOOLEAN
SepIdAssignableAsOwner(
    IN PTOKEN Token,
    IN ULONG Index
    );

VOID
SepMakeTokenEffectiveOnly(
    IN PTOKEN Token
    );

BOOLEAN
SepTokenInitialization( VOID );


VOID
SepTokenDeleteMethod (
    IN  PVOID   Token
    );

//
// These are here because if they are placed in sep.h, we don't
// have the PTOKEN datatype available.
//

BOOLEAN
SepPrivilegeCheck(
    IN PTOKEN Token,
    IN OUT PLUID_AND_ATTRIBUTES RequiredPrivileges,
    IN ULONG RequiredPrivilegeCount,
    IN ULONG PrivilegeSetControl,
    IN KPROCESSOR_MODE PreviousMode
    );

BOOLEAN
SepAccessCheck (
    IN PSECURITY_DESCRIPTOR SecurityDescriptor,
    IN PSID PrincipalSelfSid,
    IN PTOKEN PrimaryToken,
    IN PTOKEN ClientToken OPTIONAL,
    IN ACCESS_MASK DesiredAccess,
    IN PIOBJECT_TYPE_LIST ObjectTypeList OPTIONAL,
    IN ULONG ObjectTypeListLength,
    IN PGENERIC_MAPPING GenericMapping,
    IN ACCESS_MASK PreviouslyGrantedAccess,
    IN KPROCESSOR_MODE PreviousMode,
    OUT PACCESS_MASK GrantedAccess,
    OUT PPRIVILEGE_SET *Privileges OPTIONAL,
    OUT PNTSTATUS AccessStatus,
    IN BOOLEAN ReturnResultList,
    OUT PBOOLEAN ReturnSomeAccessGranted,
    OUT PBOOLEAN ReturnSomeAccessDenied
    );

BOOLEAN
SepObjectInTypeList (
    IN GUID *ObjectType,
    IN PIOBJECT_TYPE_LIST ObjectTypeList,
    IN ULONG ObjectTypeListLength,
    OUT PULONG ReturnedIndex
    );

VOID
SepModifyTokenPolicyCounter(
    PSEP_AUDIT_POLICY TokenPolicy,
    BOOLEAN bIncrement
    );

NTSTATUS
FORCEINLINE
SepDuplicateLogonSessionReference(
    IN PTOKEN NewToken,
    IN PTOKEN ExistingToken
    )
{
    PSEP_LOGON_SESSION_REFERENCES LogonSession;
    LONG NewRef;
    NTSTATUS Status;

    //
    // Obtain the logon session reference. If the existing token
    // has a reference then use that to obtain a new one. Otherwise
    // Look up the session the slow way.
    //
    if ((ExistingToken->TokenFlags & TOKEN_SESSION_NOT_REFERENCED) == 0) {
        LogonSession = ExistingToken->LogonSession;
        NewToken->LogonSession = LogonSession;
        NewRef = InterlockedIncrement (&LogonSession->ReferenceCount);
        ASSERT (NewRef > 1);
        return STATUS_SUCCESS;
    } else {
        Status = SepReferenceLogonSession (&ExistingToken->AuthenticationId,
                                           &NewToken->LogonSession);
        if (!NT_SUCCESS (Status)) {
            NewToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
            NewToken->LogonSession = NULL;
        }
        return Status;
    }
}

VOID
FORCEINLINE
SepDeReferenceLogonSessionDirect(
    IN PSEP_LOGON_SESSION_REFERENCES LogonSession
    )
{
    LONG OldValue;
    LUID LogonId;

    while (1) {
        OldValue = LogonSession->ReferenceCount;
        ASSERT (OldValue > 0);
        if (OldValue == 1) {
            LogonId = LogonSession->LogonId;
            SepDeReferenceLogonSession (&LogonId);
            break;
        }

        if (InterlockedCompareExchange (&LogonSession->ReferenceCount, OldValue-1, OldValue) == OldValue) {
            break;
        }
    }
}


////////////////////////////////////////////////////////////////////////
//                                                                    //
//           Global Variables                                         //
//                                                                    //
////////////////////////////////////////////////////////////////////////


extern const GENERIC_MAPPING  SepTokenMapping;
extern POBJECT_TYPE     SeTokenObjectType;

//extern ERESOURCE        SepTokenLock;


#ifdef    TOKEN_DIAGNOSTICS_ENABLED
extern ULONG            TokenGlobalFlag;
#endif // TOKEN_DIAGNOSTICS_ENABLED

#endif // _TOKENP_

