Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

818 lines
27 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
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.
Author:
Jim Kelly (JimK) 18-May-1990
Revision History:
v10: robertre
Added SepAccessCheck and SepPrivilegeCheck prototypes
v11: robertre
Added parameter to SepAccessCheck
--*/
#ifndef _TOKENP_
#define _TOKENP_
//#define TOKEN_DEBUG
#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;
}
}
}
#ifdef TOKEN_DEBUG
VOID
SepDumpToken(
IN PTOKEN T
);
#endif //TOKEN_DEBUG
////////////////////////////////////////////////////////////////////////
// //
// 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_