2045 lines
57 KiB
C
2045 lines
57 KiB
C
/*++
|
||
|
||
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 "pch.h"
|
||
|
||
#pragma hdrstop
|
||
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE,NtQueryInformationToken)
|
||
#pragma alloc_text(PAGE,SeQueryAuthenticationIdToken)
|
||
#pragma alloc_text(PAGE,SeQueryInformationToken)
|
||
#pragma alloc_text(PAGE,SeQuerySessionIdToken)
|
||
#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.
|
||
|
||
TokenGroups => TOKEN_GROUPS 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;
|
||
ULONG GroupsLength;
|
||
ULONG RestrictedSidsLength;
|
||
ULONG PrivilegesLength;
|
||
|
||
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;
|
||
PTOKEN_GROUPS_AND_PRIVILEGES LocalGroupsAndPrivileges;
|
||
|
||
PSID PSid;
|
||
PACL PAcl;
|
||
|
||
PVOID Ignore;
|
||
ULONG SessionId;
|
||
|
||
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
|
||
SeTokenObjectType, // 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_PTR)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
|
||
SeTokenObjectType, // ObjectType
|
||
PreviousMode, // AccessMode
|
||
(PVOID *)&Token, // Object
|
||
NULL // GrantedAccess
|
||
);
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
return Status;
|
||
}
|
||
|
||
Index = 1;
|
||
|
||
//
|
||
// 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)) );
|
||
|
||
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_PTR)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 TokenRestrictedSids:
|
||
|
||
LocalGroups = (PTOKEN_GROUPS)TokenInformation;
|
||
|
||
Status = ObReferenceObjectByHandle(
|
||
TokenHandle, // Handle
|
||
TOKEN_QUERY, // DesiredAccess
|
||
SeTokenObjectType, // ObjectType
|
||
PreviousMode, // AccessMode
|
||
(PVOID *)&Token, // Object
|
||
NULL // GrantedAccess
|
||
);
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
return Status;
|
||
}
|
||
|
||
Index = 0;
|
||
|
||
//
|
||
// 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->RestrictedSidCount) *
|
||
((ULONG)sizeof(SID_AND_ATTRIBUTES)) -
|
||
ANYSIZE_ARRAY * sizeof(SID_AND_ATTRIBUTES) );
|
||
|
||
while (Index < Token->RestrictedSidCount) {
|
||
|
||
RequiredLength += SeLengthSid( Token->RestrictedSids[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->RestrictedSidCount;
|
||
|
||
PSid = (PSID)( (ULONG_PTR)LocalGroups +
|
||
(ULONG)sizeof(TOKEN_GROUPS) +
|
||
( (Token->RestrictedSidCount ) *
|
||
(ULONG)sizeof(SID_AND_ATTRIBUTES) -
|
||
ANYSIZE_ARRAY * sizeof(SID_AND_ATTRIBUTES) )
|
||
);
|
||
|
||
RtlCopySidAndAttributesArray(
|
||
(ULONG)(Token->RestrictedSidCount),
|
||
Token->RestrictedSids,
|
||
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
|
||
SeTokenObjectType, // 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
|
||
SeTokenObjectType, // 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_PTR)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
|
||
SeTokenObjectType, // 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_PTR)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
|
||
SeTokenObjectType, // ObjectType
|
||
PreviousMode, // AccessMode
|
||
(PVOID *)&Token, // Object
|
||
NULL // GrantedAccess
|
||
);
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
return Status;
|
||
}
|
||
|
||
RequiredLength = (ULONG)sizeof(TOKEN_DEFAULT_DACL);
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
|
||
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_PTR)LocalDefaultDacl +
|
||
(ULONG)sizeof(TOKEN_DEFAULT_DACL));
|
||
|
||
try {
|
||
|
||
if (ARGUMENT_PRESENT(Token->DefaultDacl)) {
|
||
|
||
LocalDefaultDacl->DefaultDacl = PAcl;
|
||
|
||
RtlCopyMemory( (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
|
||
SeTokenObjectType, // 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
|
||
SeTokenObjectType, // 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
|
||
SeTokenObjectType, // 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
|
||
SeTokenObjectType, // ObjectType
|
||
PreviousMode, // AccessMode
|
||
(PVOID *)&Token, // Object
|
||
NULL // GrantedAccess
|
||
);
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
return Status;
|
||
}
|
||
|
||
RequiredLength = (ULONG)sizeof( TOKEN_STATISTICS );
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
|
||
|
||
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 {
|
||
ULONG Size;
|
||
|
||
LocalStatistics->TokenId = Token->TokenId;
|
||
LocalStatistics->AuthenticationId = Token->AuthenticationId;
|
||
LocalStatistics->ExpirationTime = Token->ExpirationTime;
|
||
LocalStatistics->TokenType = Token->TokenType;
|
||
LocalStatistics->ImpersonationLevel = Token->ImpersonationLevel;
|
||
LocalStatistics->DynamicCharged = Token->DynamicCharged;
|
||
|
||
Size = Token->DynamicCharged - SeLengthSid( Token->PrimaryGroup );;
|
||
|
||
if (Token->DefaultDacl) {
|
||
Size -= Token->DefaultDacl->AclSize;
|
||
}
|
||
LocalStatistics->DynamicAvailable = Size;
|
||
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;
|
||
|
||
case TokenSessionId:
|
||
|
||
if ( TokenInformationLength != sizeof(ULONG) )
|
||
return( STATUS_INFO_LENGTH_MISMATCH );
|
||
|
||
Status = ObReferenceObjectByHandle(
|
||
TokenHandle, // Handle
|
||
TOKEN_QUERY, // DesiredAccess
|
||
SeTokenObjectType, // ObjectType
|
||
PreviousMode, // AccessMode
|
||
(PVOID *)&Token, // Object
|
||
NULL // GrantedAccess
|
||
);
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Get SessionId for the token
|
||
//
|
||
SeQuerySessionIdToken( (PACCESS_TOKEN)Token,
|
||
&SessionId);
|
||
|
||
try {
|
||
|
||
*(PULONG)TokenInformation = SessionId;
|
||
*ReturnLength = sizeof(ULONG);
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
ObDereferenceObject( Token );
|
||
return GetExceptionCode();
|
||
}
|
||
|
||
ObDereferenceObject( Token );
|
||
return( STATUS_SUCCESS );
|
||
|
||
|
||
case TokenGroupsAndPrivileges:
|
||
|
||
LocalGroupsAndPrivileges = (PTOKEN_GROUPS_AND_PRIVILEGES)TokenInformation;
|
||
|
||
Status = ObReferenceObjectByHandle(
|
||
TokenHandle, // Handle
|
||
TOKEN_QUERY, // DesiredAccess
|
||
SeTokenObjectType, // 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.
|
||
// The data arrangement is as follows:
|
||
// GroupsAndPrivileges struct
|
||
// User and Groups
|
||
// Restricted sids
|
||
// Privileges
|
||
//
|
||
|
||
PrivilegesLength = Token->PrivilegeCount *
|
||
((ULONG)sizeof(LUID_AND_ATTRIBUTES));
|
||
|
||
GroupsLength = Token->UserAndGroupCount *
|
||
((ULONG)sizeof(SID_AND_ATTRIBUTES));
|
||
|
||
RestrictedSidsLength = Token->RestrictedSidCount *
|
||
((ULONG)sizeof(SID_AND_ATTRIBUTES));
|
||
|
||
Index = 0;
|
||
while (Index < Token->UserAndGroupCount) {
|
||
|
||
GroupsLength += SeLengthSid( Token->UserAndGroups[Index].Sid );
|
||
|
||
Index += 1;
|
||
|
||
} // endwhile
|
||
|
||
Index = 0;
|
||
while (Index < Token->RestrictedSidCount) {
|
||
|
||
RestrictedSidsLength += SeLengthSid( Token->RestrictedSids[Index].Sid );
|
||
|
||
Index += 1;
|
||
|
||
} // endwhile
|
||
|
||
RequiredLength = (ULONG)sizeof(TOKEN_GROUPS_AND_PRIVILEGES) +
|
||
PrivilegesLength + RestrictedSidsLength + GroupsLength;
|
||
//
|
||
// 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, followed by restricted sids, followed by
|
||
// privileges.
|
||
//
|
||
|
||
try {
|
||
|
||
LocalGroupsAndPrivileges->AuthenticationId = Token->AuthenticationId;
|
||
|
||
LocalGroupsAndPrivileges->SidLength = GroupsLength;
|
||
LocalGroupsAndPrivileges->SidCount = Token->UserAndGroupCount;
|
||
LocalGroupsAndPrivileges->Sids = (PSID_AND_ATTRIBUTES) ((ULONG_PTR)LocalGroupsAndPrivileges +
|
||
(ULONG)sizeof(TOKEN_GROUPS_AND_PRIVILEGES));
|
||
|
||
LocalGroupsAndPrivileges->RestrictedSidLength = RestrictedSidsLength;
|
||
LocalGroupsAndPrivileges->RestrictedSidCount = Token->RestrictedSidCount;
|
||
|
||
//
|
||
// To distinguish between a restricted token with zero sids and
|
||
// a non-restrcited token.
|
||
//
|
||
|
||
if (SeTokenIsRestricted((PACCESS_TOKEN) Token))
|
||
{
|
||
LocalGroupsAndPrivileges->RestrictedSids = (PSID_AND_ATTRIBUTES) ((ULONG_PTR) LocalGroupsAndPrivileges->Sids +
|
||
GroupsLength);
|
||
}
|
||
else
|
||
{
|
||
LocalGroupsAndPrivileges->RestrictedSids = NULL;
|
||
}
|
||
|
||
LocalGroupsAndPrivileges->PrivilegeLength = PrivilegesLength;
|
||
LocalGroupsAndPrivileges->PrivilegeCount = Token->PrivilegeCount;
|
||
LocalGroupsAndPrivileges->Privileges = (PLUID_AND_ATTRIBUTES) ((ULONG_PTR) LocalGroupsAndPrivileges->Sids + GroupsLength +
|
||
RestrictedSidsLength);
|
||
|
||
PSid = (PSID)( (ULONG_PTR)LocalGroupsAndPrivileges->Sids +
|
||
(Token->UserAndGroupCount *
|
||
(ULONG)sizeof(SID_AND_ATTRIBUTES))
|
||
);
|
||
|
||
RtlCopySidAndAttributesArray(
|
||
(ULONG)Token->UserAndGroupCount,
|
||
Token->UserAndGroups,
|
||
GroupsLength - (Token->UserAndGroupCount * ((ULONG)sizeof(SID_AND_ATTRIBUTES))),
|
||
LocalGroupsAndPrivileges->Sids,
|
||
PSid,
|
||
((PSID *)&Ignore),
|
||
((PULONG)&Ignore)
|
||
);
|
||
|
||
PSid = (PSID)((ULONG_PTR)LocalGroupsAndPrivileges->RestrictedSids +
|
||
((Token->RestrictedSidCount ) *
|
||
(ULONG)sizeof(SID_AND_ATTRIBUTES))
|
||
);
|
||
|
||
if (LocalGroupsAndPrivileges->RestrictedSidCount > 0)
|
||
{
|
||
RtlCopySidAndAttributesArray(
|
||
(ULONG)(Token->RestrictedSidCount),
|
||
Token->RestrictedSids,
|
||
RestrictedSidsLength - (Token->RestrictedSidCount * ((ULONG)sizeof(SID_AND_ATTRIBUTES))),
|
||
LocalGroupsAndPrivileges->RestrictedSids,
|
||
PSid,
|
||
((PSID *)&Ignore),
|
||
((PULONG)&Ignore)
|
||
);
|
||
}
|
||
|
||
RtlCopyLuidAndAttributesArray(
|
||
Token->PrivilegeCount,
|
||
Token->Privileges,
|
||
LocalGroupsAndPrivileges->Privileges
|
||
);
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
||
SepReleaseTokenReadLock( Token );
|
||
ObDereferenceObject( Token );
|
||
return GetExceptionCode();
|
||
}
|
||
|
||
|
||
SepReleaseTokenReadLock( Token );
|
||
ObDereferenceObject( Token );
|
||
return STATUS_SUCCESS;
|
||
|
||
|
||
case TokenSandBoxInert:
|
||
|
||
try {
|
||
*ReturnLength = sizeof(ULONG);
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
return GetExceptionCode();
|
||
}
|
||
|
||
if ( TokenInformationLength < sizeof(ULONG) ) {
|
||
return( STATUS_INFO_LENGTH_MISMATCH );
|
||
}
|
||
|
||
Status = ObReferenceObjectByHandle(
|
||
TokenHandle, // Handle
|
||
TOKEN_QUERY, // DesiredAccess
|
||
SeTokenObjectType, // ObjectType
|
||
PreviousMode, // AccessMode
|
||
(PVOID *)&Token, // Object
|
||
NULL // GrantedAccess
|
||
);
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
return Status;
|
||
}
|
||
|
||
try {
|
||
|
||
//
|
||
// If the flag is present in the token then return TRUE.
|
||
// Else return FALSE.
|
||
//
|
||
|
||
*(PULONG)TokenInformation = (Token->TokenFlags & TOKEN_SANDBOX_INERT)
|
||
? TRUE : FALSE;
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
ObDereferenceObject( Token );
|
||
return GetExceptionCode();
|
||
}
|
||
|
||
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;
|
||
|
||
//
|
||
// 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_PTR)LocalUser + (ULONG)sizeof(TOKEN_USER) );
|
||
|
||
RtlCopySidAndAttributesArray(
|
||
1,
|
||
Token->UserAndGroups,
|
||
RequiredLength,
|
||
&(LocalUser->User),
|
||
PSid,
|
||
((PSID *)&Ignore),
|
||
((PULONG)&Ignore)
|
||
);
|
||
|
||
SepReleaseTokenReadLock( Token );
|
||
*TokenInformation = LocalUser;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
case TokenGroups:
|
||
{
|
||
PTOKEN_GROUPS LocalGroups;
|
||
|
||
//
|
||
// 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_PTR)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 );
|
||
*TokenInformation = LocalGroups;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
case TokenPrivileges:
|
||
{
|
||
PTOKEN_PRIVILEGES LocalPrivileges;
|
||
|
||
//
|
||
// 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 );
|
||
*TokenInformation = LocalPrivileges;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
case TokenOwner:
|
||
{
|
||
PTOKEN_OWNER LocalOwner;
|
||
|
||
//
|
||
// 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_PTR)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 );
|
||
*TokenInformation = LocalOwner;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
case TokenPrimaryGroup:
|
||
{
|
||
PTOKEN_PRIMARY_GROUP LocalPrimaryGroup;
|
||
|
||
//
|
||
// 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_PTR)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 );
|
||
*TokenInformation = LocalPrimaryGroup;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
case TokenDefaultDacl:
|
||
{
|
||
PTOKEN_DEFAULT_DACL LocalDefaultDacl;
|
||
|
||
RequiredLength = (ULONG)sizeof(TOKEN_DEFAULT_DACL);
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
|
||
|
||
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_PTR)LocalDefaultDacl +
|
||
(ULONG)sizeof(TOKEN_DEFAULT_DACL));
|
||
|
||
if (ARGUMENT_PRESENT(Token->DefaultDacl)) {
|
||
|
||
LocalDefaultDacl->DefaultDacl = PAcl;
|
||
|
||
RtlCopyMemory( (PVOID)PAcl,
|
||
(PVOID)Token->DefaultDacl,
|
||
Token->DefaultDacl->AclSize
|
||
);
|
||
} else {
|
||
|
||
LocalDefaultDacl->DefaultDacl = NULL;
|
||
}
|
||
|
||
SepReleaseTokenReadLock( Token );
|
||
*TokenInformation = LocalDefaultDacl;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
case TokenSource:
|
||
{
|
||
PTOKEN_SOURCE LocalSource;
|
||
|
||
//
|
||
// 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;
|
||
*TokenInformation = LocalSource;
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
case TokenType:
|
||
{
|
||
PTOKEN_TYPE LocalType;
|
||
|
||
//
|
||
// 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;
|
||
*TokenInformation = LocalType;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
case TokenImpersonationLevel:
|
||
{
|
||
PSECURITY_IMPERSONATION_LEVEL LocalImpersonationLevel;
|
||
|
||
//
|
||
// 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;
|
||
*TokenInformation = LocalImpersonationLevel;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
case TokenStatistics:
|
||
{
|
||
PTOKEN_STATISTICS LocalStatistics;
|
||
ULONG Size;
|
||
|
||
//
|
||
// 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) {
|
||
return( STATUS_INSUFFICIENT_RESOURCES );
|
||
}
|
||
|
||
//
|
||
// Gain exclusive access to the token.
|
||
//
|
||
|
||
SepAcquireTokenReadLock( Token );
|
||
|
||
//
|
||
// 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;
|
||
|
||
Size = Token->DynamicCharged - SeLengthSid( Token->PrimaryGroup );
|
||
|
||
if (Token->DefaultDacl) {
|
||
Size -= Token->DefaultDacl->AclSize;
|
||
}
|
||
|
||
LocalStatistics->DynamicAvailable = Size;
|
||
LocalStatistics->DynamicAvailable = Token->DynamicAvailable;
|
||
LocalStatistics->GroupCount = Token->UserAndGroupCount-1;
|
||
LocalStatistics->PrivilegeCount = Token->PrivilegeCount;
|
||
LocalStatistics->ModifiedId = Token->ModifiedId;
|
||
|
||
SepReleaseTokenReadLock( Token );
|
||
*TokenInformation = LocalStatistics;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
case TokenSessionId:
|
||
|
||
/*
|
||
* Get SessionId for the token
|
||
*/
|
||
SeQuerySessionIdToken( (PACCESS_TOKEN)Token,
|
||
(PULONG)TokenInformation );
|
||
|
||
return( STATUS_SUCCESS );
|
||
|
||
default:
|
||
|
||
return STATUS_INVALID_INFO_CLASS;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
SeQuerySessionIdToken(
|
||
PACCESS_TOKEN Token,
|
||
PULONG SessionId
|
||
)
|
||
|
||
/*++
|
||
|
||
|
||
Routine Description:
|
||
|
||
Gets the SessionId from the specified token object.
|
||
|
||
Arguments:
|
||
|
||
Token (input)
|
||
Opaque kernel ACCESS_TOKEN pointer
|
||
SessionId (output)
|
||
pointer to location to return SessionId
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - no error
|
||
|
||
--*/
|
||
{
|
||
|
||
PAGED_CODE();
|
||
|
||
/*
|
||
* Get the SessionId.
|
||
*/
|
||
SepAcquireTokenReadLock( ((PTOKEN)Token) );
|
||
(*SessionId) = ((PTOKEN)Token)->SessionId;
|
||
SepReleaseTokenReadLock( ((PTOKEN)Token) );
|
||
return( STATUS_SUCCESS );
|
||
}
|
||
|
||
|