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 );
|
|||
|
}
|
|||
|
|
|||
|
|