diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/se/tokenqry.c | 1612 |
1 files changed, 1612 insertions, 0 deletions
diff --git a/private/ntos/se/tokenqry.c b/private/ntos/se/tokenqry.c new file mode 100644 index 000000000..04c5e3f11 --- /dev/null +++ b/private/ntos/se/tokenqry.c @@ -0,0 +1,1612 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + Tokenqry.c + +Abstract: + + This module implements the QUERY function for the executive + token object. + +Author: + + Jim Kelly (JimK) 15-June-1990 + + +Revision History: + +--*/ + +#include "sep.h" +#include "seopaque.h" +#include "tokenp.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,NtQueryInformationToken) +#pragma alloc_text(PAGE,SeQueryAuthenticationIdToken) +#pragma alloc_text(PAGE,SeQueryInformationToken) +#endif + + +NTSTATUS +NtQueryInformationToken ( + IN HANDLE TokenHandle, + IN TOKEN_INFORMATION_CLASS TokenInformationClass, + OUT PVOID TokenInformation, + IN ULONG TokenInformationLength, + OUT PULONG ReturnLength + ) + +/*++ + + +Routine Description: + + Retrieve information about a specified token. + +Arguments: + + TokenHandle - Provides a handle to the token to operate on. + + TokenInformationClass - The token information class about which + to retrieve information. + + TokenInformation - The buffer to receive the requested class of + information. The buffer must be aligned on at least a + longword boundary. The actual structures returned are + dependent upon the information class requested, as defined in + the TokenInformationClass parameter description. + + TokenInformation Format By Information Class: + + TokenUser => TOKEN_USER data structure. TOKEN_QUERY + access is needed to retrieve this information about a + token. + + TokenGroups => TOKEN_GROUPS data structure. TOKEN_QUERY + access is needed to retrieve this information about a + token. + + TokenPrivileges => TOKEN_PRIVILEGES data structure. + TOKEN_QUERY access is needed to retrieve this information + about a token. + + TokenOwner => TOKEN_OWNER data structure. TOKEN_QUERY + access is needed to retrieve this information about a + token. + + TokenPrimaryGroup => TOKEN_PRIMARY_GROUP data structure. + TOKEN_QUERY access is needed to retrieve this information + about a token. + + TokenDefaultDacl => TOKEN_DEFAULT_DACL data structure. + TOKEN_QUERY access is needed to retrieve this information + about a token. + + TokenSource => TOKEN_SOURCE data structure. + TOKEN_QUERY_SOURCE access is needed to retrieve this + information about a token. + + TokenType => TOKEN_TYPE data structure. + TOKEN_QUERY access is needed to retrieve this information + about a token. + + TokenStatistics => TOKEN_STATISTICS data structure. + TOKEN_QUERY access is needed to retrieve this + information about a token. + + TokenInformationLength - Indicates the length, in bytes, of the + TokenInformation buffer. + + ReturnLength - This OUT parameter receives the actual length of + the requested information. If this value is larger than that + provided by the TokenInformationLength parameter, then the + buffer provided to receive the requested information is not + large enough to hold that data and no data is returned. + + If the queried class is TokenDefaultDacl and there is no + default Dacl established for the token, then the return + length will be returned as zero, and no data will be returned. + +Return Value: + + STATUS_SUCCESS - Indicates the operation was successful. + + STATUS_BUFFER_TOO_SMALL - if the requested information did not + fit in the provided output buffer. In this case, the + ReturnLength OUT parameter contains the number of bytes + actually needed to store the requested information. + +--*/ +{ + + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status; + + PTOKEN Token; + + ULONG RequiredLength; + ULONG Index; + + PTOKEN_TYPE LocalType; + PTOKEN_USER LocalUser; + PTOKEN_GROUPS LocalGroups; + PTOKEN_PRIVILEGES LocalPrivileges; + PTOKEN_OWNER LocalOwner; + PTOKEN_PRIMARY_GROUP LocalPrimaryGroup; + PTOKEN_DEFAULT_DACL LocalDefaultDacl; + PTOKEN_SOURCE LocalSource; + PSECURITY_IMPERSONATION_LEVEL LocalImpersonationLevel; + PTOKEN_STATISTICS LocalStatistics; + + PSID PSid; + PACL PAcl; + + PVOID Ignore; + + PAGED_CODE(); + + // + // Get previous processor mode and probe output argument if necessary. + // + + PreviousMode = KeGetPreviousMode(); + if (PreviousMode != KernelMode) { + try { + + ProbeForWrite( + TokenInformation, + TokenInformationLength, + sizeof(ULONG) + ); + + ProbeForWriteUlong(ReturnLength); + + } except(EXCEPTION_EXECUTE_HANDLER) { + return GetExceptionCode(); + } + } + + // + // Case on information class. + // + + switch ( TokenInformationClass ) { + + case TokenUser: + + LocalUser = (PTOKEN_USER)TokenInformation; + + Status = ObReferenceObjectByHandle( + TokenHandle, // Handle + TOKEN_QUERY, // DesiredAccess + SepTokenObjectType, // ObjectType + PreviousMode, // AccessMode + (PVOID *)&Token, // Object + NULL // GrantedAccess + ); + + if ( !NT_SUCCESS(Status) ) { + return Status; + } + + // + // Gain exclusive access to the token. + // + + SepAcquireTokenReadLock( Token ); + + + + // + // Return the length required now in case not enough buffer + // was provided by the caller and we have to return an error. + // + + RequiredLength = SeLengthSid( Token->UserAndGroups[0].Sid) + + (ULONG)sizeof( TOKEN_USER ); + + try { + + *ReturnLength = RequiredLength; + + } except(EXCEPTION_EXECUTE_HANDLER) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + if ( TokenInformationLength < RequiredLength ) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return STATUS_BUFFER_TOO_SMALL; + + } + + // + // Return the user SID + // + + try { + + // + // Put SID immediately following TOKEN_USER data structure + // + PSid = (PSID)( (ULONG)LocalUser + (ULONG)sizeof(TOKEN_USER) ); + + RtlCopySidAndAttributesArray( + 1, + Token->UserAndGroups, + RequiredLength, + &(LocalUser->User), + PSid, + ((PSID *)&Ignore), + ((PULONG)&Ignore) + ); + + } except(EXCEPTION_EXECUTE_HANDLER) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return STATUS_SUCCESS; + + case TokenGroups: + + LocalGroups = (PTOKEN_GROUPS)TokenInformation; + + Status = ObReferenceObjectByHandle( + TokenHandle, // Handle + TOKEN_QUERY, // DesiredAccess + SepTokenObjectType, // ObjectType + PreviousMode, // AccessMode + (PVOID *)&Token, // Object + NULL // GrantedAccess + ); + + if ( !NT_SUCCESS(Status) ) { + return Status; + } + + // + // Gain exclusive access to the token. + // + + SepAcquireTokenReadLock( Token ); + + // + // Figure out how much space is needed to return the group SIDs. + // That's the size of TOKEN_GROUPS (without any array entries) + // plus the size of an SID_AND_ATTRIBUTES times the number of groups. + // The number of groups is Token->UserAndGroups-1 (since the count + // includes the user ID). Then the lengths of each individual group + // must be added. + // + + RequiredLength = (ULONG)sizeof(TOKEN_GROUPS) + + ((Token->UserAndGroupCount - ANYSIZE_ARRAY - 1) * + ((ULONG)sizeof(SID_AND_ATTRIBUTES)) ); + + Index = 1; + while (Index < Token->UserAndGroupCount) { + + RequiredLength += SeLengthSid( Token->UserAndGroups[Index].Sid ); + + Index += 1; + + } // endwhile + + // + // Return the length required now in case not enough buffer + // was provided by the caller and we have to return an error. + // + + try { + + *ReturnLength = RequiredLength; + + } except(EXCEPTION_EXECUTE_HANDLER) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + if ( TokenInformationLength < RequiredLength ) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return STATUS_BUFFER_TOO_SMALL; + + } + + // + // Now copy the groups. + // + + try { + + LocalGroups->GroupCount = Token->UserAndGroupCount - 1; + + PSid = (PSID)( (ULONG)LocalGroups + + (ULONG)sizeof(TOKEN_GROUPS) + + ( (Token->UserAndGroupCount - ANYSIZE_ARRAY - 1) * + (ULONG)sizeof(SID_AND_ATTRIBUTES) ) + ); + + RtlCopySidAndAttributesArray( + (ULONG)(Token->UserAndGroupCount - 1), + &(Token->UserAndGroups[1]), + RequiredLength, + LocalGroups->Groups, + PSid, + ((PSID *)&Ignore), + ((PULONG)&Ignore) + ); + + } except(EXCEPTION_EXECUTE_HANDLER) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return STATUS_SUCCESS; + + case TokenPrivileges: + + LocalPrivileges = (PTOKEN_PRIVILEGES)TokenInformation; + + Status = ObReferenceObjectByHandle( + TokenHandle, // Handle + TOKEN_QUERY, // DesiredAccess + SepTokenObjectType, // ObjectType + PreviousMode, // AccessMode + (PVOID *)&Token, // Object + NULL // GrantedAccess + ); + + if ( !NT_SUCCESS(Status) ) { + return Status; + } + + // + // Gain exclusive access to the token to prevent changes + // from occuring to the privileges. + // + + SepAcquireTokenReadLock( Token ); + + + // + // Return the length required now in case not enough buffer + // was provided by the caller and we have to return an error. + // + + RequiredLength = (ULONG)sizeof(TOKEN_PRIVILEGES) + + ((Token->PrivilegeCount - ANYSIZE_ARRAY) * + ((ULONG)sizeof(LUID_AND_ATTRIBUTES)) ); + + + try { + + *ReturnLength = RequiredLength; + + } except(EXCEPTION_EXECUTE_HANDLER) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + if ( TokenInformationLength < RequiredLength ) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return STATUS_BUFFER_TOO_SMALL; + + } + + // + // Return the token privileges. + // + + try { + + LocalPrivileges->PrivilegeCount = Token->PrivilegeCount; + + RtlCopyLuidAndAttributesArray( + Token->PrivilegeCount, + Token->Privileges, + LocalPrivileges->Privileges + ); + + } except(EXCEPTION_EXECUTE_HANDLER) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return STATUS_SUCCESS; + + case TokenOwner: + + LocalOwner = (PTOKEN_OWNER)TokenInformation; + + Status = ObReferenceObjectByHandle( + TokenHandle, // Handle + TOKEN_QUERY, // DesiredAccess + SepTokenObjectType, // ObjectType + PreviousMode, // AccessMode + (PVOID *)&Token, // Object + NULL // GrantedAccess + ); + + if ( !NT_SUCCESS(Status) ) { + return Status; + } + + // + // Gain exclusive access to the token to prevent changes + // from occuring to the owner. + // + + SepAcquireTokenReadLock( Token ); + + // + // Return the length required now in case not enough buffer + // was provided by the caller and we have to return an error. + // + + PSid = Token->UserAndGroups[Token->DefaultOwnerIndex].Sid; + RequiredLength = (ULONG)sizeof(TOKEN_OWNER) + + SeLengthSid( PSid ); + + try { + + *ReturnLength = RequiredLength; + + } except(EXCEPTION_EXECUTE_HANDLER) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + if ( TokenInformationLength < RequiredLength ) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return STATUS_BUFFER_TOO_SMALL; + + } + + // + // Return the owner SID + // + + PSid = (PSID)((ULONG)LocalOwner + + (ULONG)sizeof(TOKEN_OWNER)); + + try { + + LocalOwner->Owner = PSid; + + Status = RtlCopySid( + (RequiredLength - (ULONG)sizeof(TOKEN_OWNER)), + PSid, + Token->UserAndGroups[Token->DefaultOwnerIndex].Sid + ); + + ASSERT( NT_SUCCESS(Status) ); + + } except(EXCEPTION_EXECUTE_HANDLER) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return STATUS_SUCCESS; + + case TokenPrimaryGroup: + + LocalPrimaryGroup = (PTOKEN_PRIMARY_GROUP)TokenInformation; + + Status = ObReferenceObjectByHandle( + TokenHandle, // Handle + TOKEN_QUERY, // DesiredAccess + SepTokenObjectType, // ObjectType + PreviousMode, // AccessMode + (PVOID *)&Token, // Object + NULL // GrantedAccess + ); + + if ( !NT_SUCCESS(Status) ) { + return Status; + } + + // + // Gain exclusive access to the token to prevent changes + // from occuring to the owner. + // + + SepAcquireTokenReadLock( Token ); + + // + // Return the length required now in case not enough buffer + // was provided by the caller and we have to return an error. + // + + RequiredLength = (ULONG)sizeof(TOKEN_PRIMARY_GROUP) + + SeLengthSid( Token->PrimaryGroup ); + + try { + + *ReturnLength = RequiredLength; + + } except(EXCEPTION_EXECUTE_HANDLER) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + if ( TokenInformationLength < RequiredLength ) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return STATUS_BUFFER_TOO_SMALL; + + } + + // + // Return the primary group SID + // + + PSid = (PSID)((ULONG)LocalPrimaryGroup + + (ULONG)sizeof(TOKEN_PRIMARY_GROUP)); + + try { + + LocalPrimaryGroup->PrimaryGroup = PSid; + + Status = RtlCopySid( (RequiredLength - (ULONG)sizeof(TOKEN_PRIMARY_GROUP)), + PSid, + Token->PrimaryGroup + ); + + ASSERT( NT_SUCCESS(Status) ); + + } except(EXCEPTION_EXECUTE_HANDLER) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return STATUS_SUCCESS; + + case TokenDefaultDacl: + + LocalDefaultDacl = (PTOKEN_DEFAULT_DACL)TokenInformation; + + Status = ObReferenceObjectByHandle( + TokenHandle, // Handle + TOKEN_QUERY, // DesiredAccess + SepTokenObjectType, // ObjectType + PreviousMode, // AccessMode + (PVOID *)&Token, // Object + NULL // GrantedAccess + ); + + if ( !NT_SUCCESS(Status) ) { + return Status; + } + + // + // Gain exclusive access to the token to prevent changes + // from occuring to the owner. + // + + SepAcquireTokenReadLock( Token ); + + + // + // Return the length required now in case not enough buffer + // was provided by the caller and we have to return an error. + // + + RequiredLength = (ULONG)sizeof(TOKEN_DEFAULT_DACL); + + if (ARGUMENT_PRESENT(Token->DefaultDacl)) { + + RequiredLength += Token->DefaultDacl->AclSize; + + } + + try { + + *ReturnLength = RequiredLength; + + } except(EXCEPTION_EXECUTE_HANDLER) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + if ( TokenInformationLength < RequiredLength ) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return STATUS_BUFFER_TOO_SMALL; + + } + + // + // Return the default Dacl + // + + PAcl = (PACL)((ULONG)LocalDefaultDacl + + (ULONG)sizeof(TOKEN_DEFAULT_DACL)); + + try { + + if (ARGUMENT_PRESENT(Token->DefaultDacl)) { + + LocalDefaultDacl->DefaultDacl = PAcl; + + RtlMoveMemory( (PVOID)PAcl, + (PVOID)Token->DefaultDacl, + Token->DefaultDacl->AclSize + ); + } else { + + LocalDefaultDacl->DefaultDacl = NULL; + + } + + } except(EXCEPTION_EXECUTE_HANDLER) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return STATUS_SUCCESS; + + + + case TokenSource: + + LocalSource = (PTOKEN_SOURCE)TokenInformation; + + Status = ObReferenceObjectByHandle( + TokenHandle, // Handle + TOKEN_QUERY_SOURCE, // DesiredAccess + SepTokenObjectType, // ObjectType + PreviousMode, // AccessMode + (PVOID *)&Token, // Object + NULL // GrantedAccess + ); + + if ( !NT_SUCCESS(Status) ) { + return Status; + } + + // + // The type of a token can not be changed, so + // exclusive access to the token is not necessary. + // + + // + // Return the length required now in case not enough buffer + // was provided by the caller and we have to return an error. + // + + RequiredLength = (ULONG) sizeof(TOKEN_SOURCE); + + try { + + *ReturnLength = RequiredLength; + + } except(EXCEPTION_EXECUTE_HANDLER) { + + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + if ( TokenInformationLength < RequiredLength ) { + + ObDereferenceObject( Token ); + return STATUS_BUFFER_TOO_SMALL; + + } + + + // + // Return the token source + // + + try { + + (*LocalSource) = Token->TokenSource; + + } except(EXCEPTION_EXECUTE_HANDLER) { + + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + + ObDereferenceObject( Token ); + return STATUS_SUCCESS; + + case TokenType: + + LocalType = (PTOKEN_TYPE)TokenInformation; + + Status = ObReferenceObjectByHandle( + TokenHandle, // Handle + TOKEN_QUERY, // DesiredAccess + SepTokenObjectType, // ObjectType + PreviousMode, // AccessMode + (PVOID *)&Token, // Object + NULL // GrantedAccess + ); + + if ( !NT_SUCCESS(Status) ) { + return Status; + } + + // + // The type of a token can not be changed, so + // exclusive access to the token is not necessary. + // + + // + // Return the length required now in case not enough buffer + // was provided by the caller and we have to return an error. + // + + RequiredLength = (ULONG) sizeof(TOKEN_TYPE); + + try { + + *ReturnLength = RequiredLength; + + } except(EXCEPTION_EXECUTE_HANDLER) { + + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + if ( TokenInformationLength < RequiredLength ) { + + ObDereferenceObject( Token ); + return STATUS_BUFFER_TOO_SMALL; + + } + + + // + // Return the token type + // + + try { + + (*LocalType) = Token->TokenType; + + } except(EXCEPTION_EXECUTE_HANDLER) { + + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + + ObDereferenceObject( Token ); + return STATUS_SUCCESS; + + + case TokenImpersonationLevel: + + LocalImpersonationLevel = (PSECURITY_IMPERSONATION_LEVEL)TokenInformation; + + Status = ObReferenceObjectByHandle( + TokenHandle, // Handle + TOKEN_QUERY, // DesiredAccess + SepTokenObjectType, // ObjectType + PreviousMode, // AccessMode + (PVOID *)&Token, // Object + NULL // GrantedAccess + ); + + if ( !NT_SUCCESS(Status) ) { + return Status; + } + + // + // The impersonation level of a token can not be changed, so + // exclusive access to the token is not necessary. + // + + // + // Make sure the token is an appropriate type to be retrieving + // the impersonation level from. + // + + if (Token->TokenType != TokenImpersonation) { + + ObDereferenceObject( Token ); + return STATUS_INVALID_INFO_CLASS; + + } + + // + // Return the length required now in case not enough buffer + // was provided by the caller and we have to return an error. + // + + RequiredLength = (ULONG) sizeof(SECURITY_IMPERSONATION_LEVEL); + + try { + + *ReturnLength = RequiredLength; + + } except(EXCEPTION_EXECUTE_HANDLER) { + + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + if ( TokenInformationLength < RequiredLength ) { + + ObDereferenceObject( Token ); + return STATUS_BUFFER_TOO_SMALL; + + } + + + // + // Return the impersonation level + // + + try { + + (*LocalImpersonationLevel) = Token->ImpersonationLevel; + + } except(EXCEPTION_EXECUTE_HANDLER) { + + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + + ObDereferenceObject( Token ); + return STATUS_SUCCESS; + + + case TokenStatistics: + + LocalStatistics = (PTOKEN_STATISTICS)TokenInformation; + + Status = ObReferenceObjectByHandle( + TokenHandle, // Handle + TOKEN_QUERY, // DesiredAccess + SepTokenObjectType, // ObjectType + PreviousMode, // AccessMode + (PVOID *)&Token, // Object + NULL // GrantedAccess + ); + + if ( !NT_SUCCESS(Status) ) { + return Status; + } + + // + // Gain exclusive access to the token. + // + + SepAcquireTokenReadLock( Token ); + + + + // + // Return the length required now in case not enough buffer + // was provided by the caller and we have to return an error. + // + + RequiredLength = (ULONG)sizeof( TOKEN_STATISTICS ); + + try { + + *ReturnLength = RequiredLength; + + } except(EXCEPTION_EXECUTE_HANDLER) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + if ( TokenInformationLength < RequiredLength ) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return STATUS_BUFFER_TOO_SMALL; + + } + + // + // Return the statistics + // + + try { + + LocalStatistics->TokenId = Token->TokenId; + LocalStatistics->AuthenticationId = Token->AuthenticationId; + LocalStatistics->ExpirationTime = Token->ExpirationTime; + LocalStatistics->TokenType = Token->TokenType; + LocalStatistics->ImpersonationLevel = Token->ImpersonationLevel; + LocalStatistics->DynamicCharged = Token->DynamicCharged; + LocalStatistics->DynamicAvailable = Token->DynamicAvailable; + LocalStatistics->GroupCount = Token->UserAndGroupCount-1; + LocalStatistics->PrivilegeCount = Token->PrivilegeCount; + LocalStatistics->ModifiedId = Token->ModifiedId; + + } except(EXCEPTION_EXECUTE_HANDLER) { + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return GetExceptionCode(); + } + + + SepReleaseTokenReadLock( Token ); + ObDereferenceObject( Token ); + return STATUS_SUCCESS; + + default: + + return STATUS_INVALID_INFO_CLASS; + } +} + + +NTSTATUS +SeQueryAuthenticationIdToken( + IN PACCESS_TOKEN Token, + OUT PLUID AuthenticationId + ) + +/*++ + + +Routine Description: + + Retrieve authentication ID out of the token. + +Arguments: + + Token - Referenced pointer to a token. + + AutenticationId - Receives the token's authentication ID. + +Return Value: + + STATUS_SUCCESS - Indicates the operation was successful. + + This is the only expected status. + +--*/ +{ + PAGED_CODE(); + + SepAcquireTokenReadLock( ((PTOKEN)Token) ); + (*AuthenticationId) = ((PTOKEN)Token)->AuthenticationId; + SepReleaseTokenReadLock( ((PTOKEN)Token) ); + return(STATUS_SUCCESS); +} + + + +NTSTATUS +SeQueryInformationToken ( + IN PACCESS_TOKEN AccessToken, + IN TOKEN_INFORMATION_CLASS TokenInformationClass, + OUT PVOID *TokenInformation + ) + +/*++ + + +Routine Description: + + Retrieve information about a specified token. + +Arguments: + + TokenHandle - Provides a handle to the token to operate on. + + TokenInformationClass - The token information class about which + to retrieve information. + + TokenInformation - Receives a pointer to the requested information. + The actual structures returned are dependent upon the information + class requested, as defined in the TokenInformationClass parameter + description. + + TokenInformation Format By Information Class: + + TokenUser => TOKEN_USER data structure. TOKEN_QUERY + access is needed to retrieve this information about a + token. + + TokenGroups => TOKEN_GROUPS data structure. TOKEN_QUERY + access is needed to retrieve this information about a + token. + + TokenPrivileges => TOKEN_PRIVILEGES data structure. + TOKEN_QUERY access is needed to retrieve this information + about a token. + + TokenOwner => TOKEN_OWNER data structure. TOKEN_QUERY + access is needed to retrieve this information about a + token. + + TokenPrimaryGroup => TOKEN_PRIMARY_GROUP data structure. + TOKEN_QUERY access is needed to retrieve this information + about a token. + + TokenDefaultDacl => TOKEN_DEFAULT_DACL data structure. + TOKEN_QUERY access is needed to retrieve this information + about a token. + + TokenSource => TOKEN_SOURCE data structure. + TOKEN_QUERY_SOURCE access is needed to retrieve this + information about a token. + + TokenType => TOKEN_TYPE data structure. + TOKEN_QUERY access is needed to retrieve this information + about a token. + + TokenStatistics => TOKEN_STATISTICS data structure. + TOKEN_QUERY access is needed to retrieve this + information about a token. + +Return Value: + + STATUS_SUCCESS - Indicates the operation was successful. + +--*/ +{ + + NTSTATUS Status; + + ULONG RequiredLength; + ULONG Index; + + PSID PSid; + PACL PAcl; + + PVOID Ignore; + PTOKEN Token = (PTOKEN)AccessToken; + + PAGED_CODE(); + + // + // Case on information class. + // + + switch ( TokenInformationClass ) { + + case TokenUser: + { + PTOKEN_USER LocalUser; + + LocalUser = (PTOKEN_USER)(*TokenInformation); + + // + // Gain exclusive access to the token. + // + + SepAcquireTokenReadLock( Token ); + + // + // Return the length required now in case not enough buffer + // was provided by the caller and we have to return an error. + // + + RequiredLength = SeLengthSid( Token->UserAndGroups[0].Sid) + + (ULONG)sizeof( TOKEN_USER ); + + LocalUser = ExAllocatePool( PagedPool, RequiredLength ); + + if (LocalUser == NULL) { + SepReleaseTokenReadLock( Token ); + return( STATUS_INSUFFICIENT_RESOURCES ); + } + + // + // Return the user SID + // + // Put SID immediately following TOKEN_USER data structure + // + + PSid = (PSID)( (ULONG)LocalUser + (ULONG)sizeof(TOKEN_USER) ); + + RtlCopySidAndAttributesArray( + 1, + Token->UserAndGroups, + RequiredLength, + &(LocalUser->User), + PSid, + ((PSID *)&Ignore), + ((PULONG)&Ignore) + ); + + SepReleaseTokenReadLock( Token ); + return STATUS_SUCCESS; + } + + + case TokenGroups: + { + PTOKEN_GROUPS LocalGroups; + + LocalGroups = (PTOKEN_GROUPS)(*TokenInformation); + + // + // Gain exclusive access to the token. + // + + SepAcquireTokenReadLock( Token ); + + // + // Figure out how much space is needed to return the group SIDs. + // That's the size of TOKEN_GROUPS (without any array entries) + // plus the size of an SID_AND_ATTRIBUTES times the number of groups. + // The number of groups is Token->UserAndGroups-1 (since the count + // includes the user ID). Then the lengths of each individual group + // must be added. + // + + RequiredLength = (ULONG)sizeof(TOKEN_GROUPS) + + ((Token->UserAndGroupCount - ANYSIZE_ARRAY - 1) * + ((ULONG)sizeof(SID_AND_ATTRIBUTES)) ); + + Index = 1; + while (Index < Token->UserAndGroupCount) { + + RequiredLength += SeLengthSid( Token->UserAndGroups[Index].Sid ); + + Index += 1; + + } // endwhile + + LocalGroups = ExAllocatePool( PagedPool, RequiredLength ); + + if (LocalGroups == NULL) { + SepReleaseTokenReadLock( Token ); + return( STATUS_INSUFFICIENT_RESOURCES ); + } + + // + // Now copy the groups. + // + + LocalGroups->GroupCount = Token->UserAndGroupCount - 1; + + PSid = (PSID)( (ULONG)LocalGroups + + (ULONG)sizeof(TOKEN_GROUPS) + + ( (Token->UserAndGroupCount - ANYSIZE_ARRAY - 1) * + (ULONG)sizeof(SID_AND_ATTRIBUTES) ) + ); + + RtlCopySidAndAttributesArray( + (ULONG)(Token->UserAndGroupCount - 1), + &(Token->UserAndGroups[1]), + RequiredLength, + LocalGroups->Groups, + PSid, + ((PSID *)&Ignore), + ((PULONG)&Ignore) + ); + + SepReleaseTokenReadLock( Token ); + return STATUS_SUCCESS; + } + + + case TokenPrivileges: + { + PTOKEN_PRIVILEGES LocalPrivileges; + + LocalPrivileges = (PTOKEN_PRIVILEGES)(*TokenInformation); + + // + // Gain exclusive access to the token to prevent changes + // from occuring to the privileges. + // + + SepAcquireTokenReadLock( Token ); + + // + // Return the length required now in case not enough buffer + // was provided by the caller and we have to return an error. + // + + RequiredLength = (ULONG)sizeof(TOKEN_PRIVILEGES) + + ((Token->PrivilegeCount - ANYSIZE_ARRAY) * + ((ULONG)sizeof(LUID_AND_ATTRIBUTES)) ); + + LocalPrivileges = ExAllocatePool( PagedPool, RequiredLength ); + + if (LocalPrivileges == NULL) { + SepReleaseTokenReadLock( Token ); + return( STATUS_INSUFFICIENT_RESOURCES ); + } + + // + // Return the token privileges. + // + + LocalPrivileges->PrivilegeCount = Token->PrivilegeCount; + + RtlCopyLuidAndAttributesArray( + Token->PrivilegeCount, + Token->Privileges, + LocalPrivileges->Privileges + ); + + SepReleaseTokenReadLock( Token ); + return STATUS_SUCCESS; + } + + + case TokenOwner: + { + PTOKEN_OWNER LocalOwner; + + LocalOwner = (PTOKEN_OWNER)(*TokenInformation); + + // + // Gain exclusive access to the token to prevent changes + // from occuring to the owner. + // + + SepAcquireTokenReadLock( Token ); + + // + // Return the length required now in case not enough buffer + // was provided by the caller and we have to return an error. + // + + PSid = Token->UserAndGroups[Token->DefaultOwnerIndex].Sid; + RequiredLength = (ULONG)sizeof(TOKEN_OWNER) + + SeLengthSid( PSid ); + + LocalOwner = ExAllocatePool( PagedPool, RequiredLength ); + + if (LocalOwner == NULL) { + SepReleaseTokenReadLock( Token ); + return( STATUS_INSUFFICIENT_RESOURCES ); + } + + // + // Return the owner SID + // + + PSid = (PSID)((ULONG)LocalOwner + + (ULONG)sizeof(TOKEN_OWNER)); + + LocalOwner->Owner = PSid; + + Status = RtlCopySid( + (RequiredLength - (ULONG)sizeof(TOKEN_OWNER)), + PSid, + Token->UserAndGroups[Token->DefaultOwnerIndex].Sid + ); + + ASSERT( NT_SUCCESS(Status) ); + + SepReleaseTokenReadLock( Token ); + return STATUS_SUCCESS; + } + + + case TokenPrimaryGroup: + { + PTOKEN_PRIMARY_GROUP LocalPrimaryGroup; + + LocalPrimaryGroup = (PTOKEN_PRIMARY_GROUP)(*TokenInformation); + + // + // Gain exclusive access to the token to prevent changes + // from occuring to the owner. + // + + SepAcquireTokenReadLock( Token ); + + // + // Return the length required now in case not enough buffer + // was provided by the caller and we have to return an error. + // + + RequiredLength = (ULONG)sizeof(TOKEN_PRIMARY_GROUP) + + SeLengthSid( Token->PrimaryGroup ); + + LocalPrimaryGroup = ExAllocatePool( PagedPool, RequiredLength ); + + if (LocalPrimaryGroup == NULL) { + SepReleaseTokenReadLock( Token ); + return( STATUS_INSUFFICIENT_RESOURCES ); + } + + // + // Return the primary group SID + // + + PSid = (PSID)((ULONG)LocalPrimaryGroup + + (ULONG)sizeof(TOKEN_PRIMARY_GROUP)); + + LocalPrimaryGroup->PrimaryGroup = PSid; + + Status = RtlCopySid( (RequiredLength - (ULONG)sizeof(TOKEN_PRIMARY_GROUP)), + PSid, + Token->PrimaryGroup + ); + + ASSERT( NT_SUCCESS(Status) ); + + SepReleaseTokenReadLock( Token ); + return STATUS_SUCCESS; + } + + + case TokenDefaultDacl: + { + PTOKEN_DEFAULT_DACL LocalDefaultDacl; + + LocalDefaultDacl = (PTOKEN_DEFAULT_DACL)(*TokenInformation); + + // + // Gain exclusive access to the token to prevent changes + // from occuring to the owner. + // + + SepAcquireTokenReadLock( Token ); + + // + // Return the length required now in case not enough buffer + // was provided by the caller and we have to return an error. + // + + RequiredLength = (ULONG)sizeof(TOKEN_DEFAULT_DACL); + + if (ARGUMENT_PRESENT(Token->DefaultDacl)) { + + RequiredLength += Token->DefaultDacl->AclSize; + } + + LocalDefaultDacl = ExAllocatePool( PagedPool, RequiredLength ); + + if (LocalDefaultDacl == NULL) { + SepReleaseTokenReadLock( Token ); + return( STATUS_INSUFFICIENT_RESOURCES ); + } + + // + // Return the default Dacl + // + + PAcl = (PACL)((ULONG)LocalDefaultDacl + + (ULONG)sizeof(TOKEN_DEFAULT_DACL)); + + if (ARGUMENT_PRESENT(Token->DefaultDacl)) { + + LocalDefaultDacl->DefaultDacl = PAcl; + + RtlMoveMemory( (PVOID)PAcl, + (PVOID)Token->DefaultDacl, + Token->DefaultDacl->AclSize + ); + } else { + + LocalDefaultDacl->DefaultDacl = NULL; + } + + SepReleaseTokenReadLock( Token ); + return STATUS_SUCCESS; + } + + + case TokenSource: + { + PTOKEN_SOURCE LocalSource; + + LocalSource = (PTOKEN_SOURCE)(*TokenInformation); + + // + // The type of a token can not be changed, so + // exclusive access to the token is not necessary. + // + + // + // Return the length required now in case not enough buffer + // was provided by the caller and we have to return an error. + // + + RequiredLength = (ULONG) sizeof(TOKEN_SOURCE); + + LocalSource = ExAllocatePool( PagedPool, RequiredLength ); + + if (LocalSource == NULL) { + return( STATUS_INSUFFICIENT_RESOURCES ); + } + + // + // Return the token source + // + + (*LocalSource) = Token->TokenSource; + + return STATUS_SUCCESS; + } + + + case TokenType: + { + PTOKEN_TYPE LocalType; + + LocalType = (PTOKEN_TYPE)(*TokenInformation); + + // + // The type of a token can not be changed, so + // exclusive access to the token is not necessary. + // + + // + // Return the length required now in case not enough buffer + // was provided by the caller and we have to return an error. + // + + RequiredLength = (ULONG) sizeof(TOKEN_TYPE); + + LocalType = ExAllocatePool( PagedPool, RequiredLength ); + + if (LocalType == NULL) { + return( STATUS_INSUFFICIENT_RESOURCES ); + } + + // + // Return the token type + // + + (*LocalType) = Token->TokenType; + + return STATUS_SUCCESS; + } + + + case TokenImpersonationLevel: + { + PSECURITY_IMPERSONATION_LEVEL LocalImpersonationLevel; + + LocalImpersonationLevel = (PSECURITY_IMPERSONATION_LEVEL)(*TokenInformation); + + // + // The impersonation level of a token can not be changed, so + // exclusive access to the token is not necessary. + // + + // + // Make sure the token is an appropriate type to be retrieving + // the impersonation level from. + // + + if (Token->TokenType != TokenImpersonation) { + + return STATUS_INVALID_INFO_CLASS; + } + + // + // Return the length required now in case not enough buffer + // was provided by the caller and we have to return an error. + // + + RequiredLength = (ULONG) sizeof(SECURITY_IMPERSONATION_LEVEL); + + LocalImpersonationLevel = ExAllocatePool( PagedPool, RequiredLength ); + + if (LocalImpersonationLevel == NULL) { + return( STATUS_INSUFFICIENT_RESOURCES ); + } + + // + // Return the impersonation level + // + + (*LocalImpersonationLevel) = Token->ImpersonationLevel; + + return STATUS_SUCCESS; + } + + + case TokenStatistics: + { + PTOKEN_STATISTICS LocalStatistics; + + LocalStatistics = (PTOKEN_STATISTICS)(*TokenInformation); + + // + // Gain exclusive access to the token. + // + + SepAcquireTokenReadLock( Token ); + + // + // Return the length required now in case not enough buffer + // was provided by the caller and we have to return an error. + // + + RequiredLength = (ULONG)sizeof( TOKEN_STATISTICS ); + + LocalStatistics = ExAllocatePool( PagedPool, RequiredLength ); + + if (LocalStatistics == NULL) { + SepReleaseTokenReadLock( Token ); + return( STATUS_INSUFFICIENT_RESOURCES ); + } + + // + // Return the statistics + // + + LocalStatistics->TokenId = Token->TokenId; + LocalStatistics->AuthenticationId = Token->AuthenticationId; + LocalStatistics->ExpirationTime = Token->ExpirationTime; + LocalStatistics->TokenType = Token->TokenType; + LocalStatistics->ImpersonationLevel = Token->ImpersonationLevel; + LocalStatistics->DynamicCharged = Token->DynamicCharged; + LocalStatistics->DynamicAvailable = Token->DynamicAvailable; + LocalStatistics->GroupCount = Token->UserAndGroupCount-1; + LocalStatistics->PrivilegeCount = Token->PrivilegeCount; + LocalStatistics->ModifiedId = Token->ModifiedId; + + SepReleaseTokenReadLock( Token ); + return STATUS_SUCCESS; + } + + default: + + return STATUS_INVALID_INFO_CLASS; + } +} |