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