|
|
/*++
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_
|