reactos/ntoskrnl/se/token.c

3975 lines
128 KiB
C
Raw Normal View History

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/se/token.c
* PURPOSE: Security manager
*
* PROGRAMMERS: David Welch <welch@cwcom.net>
*/
/* INCLUDES *******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(INIT, SepInitializeTokenImplementation)
#endif
#include <ntlsa.h>
typedef struct _TOKEN_AUDIT_POLICY_INFORMATION
{
ULONG PolicyCount;
struct
{
ULONG Category;
UCHAR Value;
} Policies[1];
} TOKEN_AUDIT_POLICY_INFORMATION, *PTOKEN_AUDIT_POLICY_INFORMATION;
/* GLOBALS ********************************************************************/
POBJECT_TYPE SeTokenObjectType = NULL;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
ERESOURCE SepTokenLock; // FIXME: Global lock!
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
TOKEN_SOURCE SeSystemTokenSource = {"*SYSTEM*", {0}};
LUID SeSystemAuthenticationId = SYSTEM_LUID;
LUID SeAnonymousAuthenticationId = ANONYMOUS_LOGON_LUID;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
static GENERIC_MAPPING SepTokenMapping = {
TOKEN_READ,
TOKEN_WRITE,
TOKEN_EXECUTE,
TOKEN_ALL_ACCESS
};
static const INFORMATION_CLASS_INFO SeTokenInformationClass[] = {
/* Class 0 not used, blame MS! */
ICI_SQ_SAME( 0, 0, 0),
/* TokenUser */
ICI_SQ_SAME( sizeof(TOKEN_USER), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
/* TokenGroups */
ICI_SQ_SAME( sizeof(TOKEN_GROUPS), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
/* TokenPrivileges */
ICI_SQ_SAME( sizeof(TOKEN_PRIVILEGES), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
/* TokenOwner */
ICI_SQ_SAME( sizeof(TOKEN_OWNER), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
/* TokenPrimaryGroup */
ICI_SQ_SAME( sizeof(TOKEN_PRIMARY_GROUP), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
/* TokenDefaultDacl */
ICI_SQ_SAME( sizeof(TOKEN_DEFAULT_DACL), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
/* TokenSource */
ICI_SQ_SAME( sizeof(TOKEN_SOURCE), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
/* TokenType */
ICI_SQ_SAME( sizeof(TOKEN_TYPE), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
/* TokenImpersonationLevel */
ICI_SQ_SAME( sizeof(SECURITY_IMPERSONATION_LEVEL), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
/* TokenStatistics */
ICI_SQ_SAME( sizeof(TOKEN_STATISTICS), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
/* TokenRestrictedSids */
ICI_SQ_SAME( sizeof(TOKEN_GROUPS), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
/* TokenSessionId */
ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY | ICIF_SET ),
/* TokenGroupsAndPrivileges */
ICI_SQ_SAME( sizeof(TOKEN_GROUPS_AND_PRIVILEGES), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
/* TokenSessionReference */
ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_SET | ICIF_QUERY_SIZE_VARIABLE ),
/* TokenSandBoxInert */
ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
/* TokenAuditPolicy */
ICI_SQ_SAME( /* FIXME */0, sizeof(ULONG), ICIF_QUERY | ICIF_SET | ICIF_QUERY_SIZE_VARIABLE ),
/* TokenOrigin */
ICI_SQ_SAME( sizeof(TOKEN_ORIGIN), sizeof(ULONG), ICIF_QUERY | ICIF_SET | ICIF_QUERY_SIZE_VARIABLE ),
};
/* FUNCTIONS *****************************************************************/
static NTSTATUS
SepCompareTokens(IN PTOKEN FirstToken,
IN PTOKEN SecondToken,
OUT PBOOLEAN Equal)
{
BOOLEAN Restricted, IsEqual = FALSE;
ASSERT(FirstToken != SecondToken);
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Lock the tokens */
SepAcquireTokenLockShared(FirstToken);
SepAcquireTokenLockShared(SecondToken);
/* FIXME: Check if every SID that is present in either token is also present in the other one */
Restricted = SeTokenIsRestricted(FirstToken);
if (Restricted == SeTokenIsRestricted(SecondToken))
{
if (Restricted)
{
/* FIXME: Check if every SID that is restricted in either token is also restricted in the other one */
}
/* FIXME: Check if every privilege that is present in either token is also present in the other one */
DPRINT1("FIXME: Pretending tokens are equal!\n");
IsEqual = TRUE;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Unlock the tokens */
SepReleaseTokenLock(SecondToken);
SepReleaseTokenLock(FirstToken);
*Equal = IsEqual;
return STATUS_SUCCESS;
}
static
VOID
SepUpdateSinglePrivilegeFlagToken(
_Inout_ PTOKEN Token,
_In_ ULONG Index)
{
ULONG TokenFlag;
ASSERT(Index < Token->PrivilegeCount);
/* The high part of all values we are interested in is 0 */
if (Token->Privileges[Index].Luid.HighPart != 0)
{
return;
}
/* Check for certain privileges to update flags */
if (Token->Privileges[Index].Luid.LowPart == SE_CHANGE_NOTIFY_PRIVILEGE)
{
TokenFlag = TOKEN_HAS_TRAVERSE_PRIVILEGE;
}
else if (Token->Privileges[Index].Luid.LowPart == SE_BACKUP_PRIVILEGE)
{
TokenFlag = TOKEN_HAS_BACKUP_PRIVILEGE;
}
else if (Token->Privileges[Index].Luid.LowPart == SE_RESTORE_PRIVILEGE)
{
TokenFlag = TOKEN_HAS_RESTORE_PRIVILEGE;
}
else if (Token->Privileges[Index].Luid.LowPart == SE_IMPERSONATE_PRIVILEGE)
{
TokenFlag = TOKEN_HAS_IMPERSONATE_PRIVILEGE;
}
else
{
/* Nothing to do */
return;
}
/* Check if the specified privilege is enabled */
if (Token->Privileges[Index].Attributes & SE_PRIVILEGE_ENABLED)
{
/* It is enabled, so set the flag */
Token->TokenFlags |= TokenFlag;
}
else
{
/* Is is disabled, so remove the flag */
Token->TokenFlags &= ~TokenFlag;
}
}
static
VOID
SepUpdatePrivilegeFlagsToken(
_Inout_ PTOKEN Token)
{
ULONG i;
/* Loop all privileges */
for (i = 0; i < Token->PrivilegeCount; i++)
{
/* Updates the flags dor this privilege */
SepUpdateSinglePrivilegeFlagToken(Token, i);
}
}
static
VOID
SepRemovePrivilegeToken(
_Inout_ PTOKEN Token,
_In_ ULONG Index)
{
ULONG MoveCount;
ASSERT(Index < Token->PrivilegeCount);
/* Calculate the number of trailing privileges */
MoveCount = Token->PrivilegeCount - Index - 1;
if (MoveCount != 0)
{
/* Move them one location ahead */
RtlMoveMemory(&Token->Privileges[Index],
&Token->Privileges[Index + 1],
MoveCount * sizeof(LUID_AND_ATTRIBUTES));
}
/* Update privilege count */
Token->PrivilegeCount--;
}
VOID
NTAPI
SepFreeProxyData(PVOID ProxyData)
{
UNIMPLEMENTED;
}
NTSTATUS
NTAPI
SepCopyProxyData(PVOID* Dest,
PVOID Src)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
NTAPI
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
SeExchangePrimaryToken(
_In_ PEPROCESS Process,
_In_ PACCESS_TOKEN NewAccessToken,
_Out_ PACCESS_TOKEN* OldAccessToken)
{
PTOKEN OldToken;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
PTOKEN NewToken = (PTOKEN)NewAccessToken;
PAGED_CODE();
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
if (NewToken->TokenType != TokenPrimary)
return STATUS_BAD_TOKEN_TYPE;
if (NewToken->TokenInUse)
{
BOOLEAN IsEqual;
NTSTATUS Status;
/* Maybe we're trying to set the same token */
OldToken = PsReferencePrimaryToken(Process);
if (OldToken == NewToken)
{
/* So it's a nop. */
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
*OldAccessToken = OldToken;
return STATUS_SUCCESS;
}
Status = SepCompareTokens(OldToken, NewToken, &IsEqual);
if (!NT_SUCCESS(Status))
{
PsDereferencePrimaryToken(OldToken);
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
*OldAccessToken = NULL;
return Status;
}
if (!IsEqual)
{
PsDereferencePrimaryToken(OldToken);
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
*OldAccessToken = NULL;
return STATUS_TOKEN_ALREADY_IN_USE;
}
/* Silently return STATUS_SUCCESS but do not set the new token,
* as it's already in use elsewhere. */
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
*OldAccessToken = OldToken;
return STATUS_SUCCESS;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Lock the new token */
SepAcquireTokenLockExclusive(NewToken);
/* Mark new token in use */
NewToken->TokenInUse = TRUE;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
// TODO: Set a correct SessionId for NewToken
/* Unlock the new token */
SepReleaseTokenLock(NewToken);
/* Reference the new token */
ObReferenceObject(NewToken);
/* Replace the old with the new */
OldToken = ObFastReplaceObject(&Process->Token, NewToken);
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Lock the old token */
SepAcquireTokenLockExclusive(OldToken);
/* Mark the old token as free */
OldToken->TokenInUse = FALSE;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Unlock the old token */
SepReleaseTokenLock(OldToken);
*OldAccessToken = (PACCESS_TOKEN)OldToken;
return STATUS_SUCCESS;
}
VOID
NTAPI
SeDeassignPrimaryToken(PEPROCESS Process)
{
PTOKEN OldToken;
/* Remove the Token */
OldToken = ObFastReplaceObject(&Process->Token, NULL);
/* Mark the Old Token as free */
OldToken->TokenInUse = FALSE;
/* Dereference the Token */
ObDereferenceObject(OldToken);
}
static ULONG
RtlLengthSidAndAttributes(ULONG Count,
PSID_AND_ATTRIBUTES Src)
{
ULONG i;
ULONG uLength;
PAGED_CODE();
uLength = Count * sizeof(SID_AND_ATTRIBUTES);
for (i = 0; i < Count; i++)
uLength += RtlLengthSid(Src[i].Sid);
return uLength;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
static NTSTATUS
SepFindPrimaryGroupAndDefaultOwner(
_In_ PTOKEN Token,
_In_ PSID PrimaryGroup,
_In_opt_ PSID DefaultOwner,
_Out_opt_ PULONG PrimaryGroupIndex,
_Out_opt_ PULONG DefaultOwnerIndex)
{
ULONG i;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* We should return at least a search result */
if (!PrimaryGroupIndex && !DefaultOwnerIndex)
return STATUS_INVALID_PARAMETER;
if (PrimaryGroupIndex)
{
/* Initialize with an invalid index */
// Token->PrimaryGroup = NULL;
*PrimaryGroupIndex = Token->UserAndGroupCount;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
if (DefaultOwnerIndex)
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
if (DefaultOwner)
{
/* An owner is specified: check whether this is actually the user */
if (RtlEqualSid(Token->UserAndGroups[0].Sid, DefaultOwner))
{
/*
* It's the user (first element in array): set it
* as the owner and stop the search for it.
*/
*DefaultOwnerIndex = 0;
DefaultOwnerIndex = NULL;
}
else
{
/* An owner is specified: initialize with an invalid index */
*DefaultOwnerIndex = Token->UserAndGroupCount;
}
}
else
{
/*
* No owner specified: set the user (first element in array)
* as the owner and stop the search for it.
*/
*DefaultOwnerIndex = 0;
DefaultOwnerIndex = NULL;
}
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Validate and set the primary group and default owner indices */
for (i = 0; i < Token->UserAndGroupCount; i++)
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Stop the search if we have found what we searched for */
if (!PrimaryGroupIndex && !DefaultOwnerIndex)
break;
if (DefaultOwnerIndex && DefaultOwner &&
RtlEqualSid(Token->UserAndGroups[i].Sid, DefaultOwner) &&
(Token->UserAndGroups[i].Attributes & SE_GROUP_OWNER))
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Owner is found, stop the search for it */
*DefaultOwnerIndex = i;
DefaultOwnerIndex = NULL;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
if (PrimaryGroupIndex &&
RtlEqualSid(Token->UserAndGroups[i].Sid, PrimaryGroup))
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Primary group is found, stop the search for it */
// Token->PrimaryGroup = Token->UserAndGroups[i].Sid;
*PrimaryGroupIndex = i;
PrimaryGroupIndex = NULL;
}
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
if (DefaultOwnerIndex)
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
if (*DefaultOwnerIndex == Token->UserAndGroupCount)
return STATUS_INVALID_OWNER;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
if (PrimaryGroupIndex)
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
if (*PrimaryGroupIndex == Token->UserAndGroupCount)
// if (Token->PrimaryGroup == NULL)
return STATUS_INVALID_PRIMARY_GROUP;
}
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
SepDuplicateToken(
_In_ PTOKEN Token,
_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_ BOOLEAN EffectiveOnly,
_In_ TOKEN_TYPE TokenType,
_In_ SECURITY_IMPERSONATION_LEVEL Level,
_In_ KPROCESSOR_MODE PreviousMode,
_Out_ PTOKEN* NewAccessToken)
{
NTSTATUS Status;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
PTOKEN AccessToken;
PVOID EndMem;
ULONG VariableLength;
ULONG TotalSize;
PAGED_CODE();
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Compute how much size we need to allocate for the token */
VariableLength = Token->VariableLength;
TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
Status = ObCreateObject(PreviousMode,
SeTokenObjectType,
ObjectAttributes,
PreviousMode,
NULL,
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
TotalSize,
0,
0,
(PVOID*)&AccessToken);
if (!NT_SUCCESS(Status))
{
DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status);
return Status;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Zero out the buffer and initialize the token */
RtlZeroMemory(AccessToken, TotalSize);
ExAllocateLocallyUniqueId(&AccessToken->TokenId);
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
AccessToken->TokenType = TokenType;
AccessToken->ImpersonationLevel = Level;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
AccessToken->TokenLock = &SepTokenLock; // FIXME: Global lock!
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Copy the immutable fields */
RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier,
&Token->TokenSource.SourceIdentifier);
RtlCopyMemory(AccessToken->TokenSource.SourceName,
Token->TokenSource.SourceName,
sizeof(Token->TokenSource.SourceName));
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
AccessToken->AuthenticationId = Token->AuthenticationId;
AccessToken->ParentTokenId = Token->ParentTokenId;
AccessToken->ExpirationTime = Token->ExpirationTime;
AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Lock the source token and copy the mutable fields */
SepAcquireTokenLockExclusive(Token);
AccessToken->SessionId = Token->SessionId;
RtlCopyLuid(&AccessToken->ModifiedId, &Token->ModifiedId);
AccessToken->TokenFlags = Token->TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
/* Copy and reference the logon session */
// RtlCopyLuid(&AccessToken->AuthenticationId, &Token->AuthenticationId);
Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
if (!NT_SUCCESS(Status))
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* No logon session could be found, bail out */
DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status);
/* Set the flag for proper cleanup by the delete procedure */
AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
goto Quit;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Assign the data that reside in the TOKEN's variable information area */
AccessToken->VariableLength = VariableLength;
EndMem = (PVOID)&AccessToken->VariablePart;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Copy the privileges */
AccessToken->PrivilegeCount = 0;
AccessToken->Privileges = NULL;
if (Token->Privileges && (Token->PrivilegeCount > 0))
{
ULONG PrivilegesLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
ASSERT(VariableLength >= PrivilegesLength);
AccessToken->PrivilegeCount = Token->PrivilegeCount;
AccessToken->Privileges = EndMem;
EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
VariableLength -= PrivilegesLength;
RtlCopyMemory(AccessToken->Privileges,
Token->Privileges,
AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
}
/* Copy the user and groups */
AccessToken->UserAndGroupCount = 0;
AccessToken->UserAndGroups = NULL;
if (Token->UserAndGroups && (Token->UserAndGroupCount > 0))
{
AccessToken->UserAndGroupCount = Token->UserAndGroupCount;
AccessToken->UserAndGroups = EndMem;
EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount,
Token->UserAndGroups,
VariableLength,
AccessToken->UserAndGroups,
EndMem,
&EndMem,
&VariableLength);
if (!NT_SUCCESS(Status))
{
DPRINT1("RtlCopySidAndAttributesArray(UserAndGroups) failed (Status 0x%lx)\n", Status);
goto Quit;
}
}
#if 1
{
ULONG PrimaryGroupIndex;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Find the token primary group */
Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken,
Token->PrimaryGroup,
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
NULL,
&PrimaryGroupIndex,
NULL);
if (!NT_SUCCESS(Status))
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status);
goto Quit;
}
AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
#else
AccessToken->PrimaryGroup = (PVOID)((ULONG_PTR)AccessToken + (ULONG_PTR)Token->PrimaryGroup - (ULONG_PTR)Token->UserAndGroups);
#endif
AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Copy the restricted SIDs */
AccessToken->RestrictedSidCount = 0;
AccessToken->RestrictedSids = NULL;
if (Token->RestrictedSids && (Token->RestrictedSidCount > 0))
{
AccessToken->RestrictedSidCount = Token->RestrictedSidCount;
AccessToken->RestrictedSids = EndMem;
EndMem = &AccessToken->RestrictedSids[AccessToken->RestrictedSidCount];
VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->RestrictedSids);
Status = RtlCopySidAndAttributesArray(AccessToken->RestrictedSidCount,
Token->RestrictedSids,
VariableLength,
AccessToken->RestrictedSids,
EndMem,
&EndMem,
&VariableLength);
if (!NT_SUCCESS(Status))
{
DPRINT1("RtlCopySidAndAttributesArray(RestrictedSids) failed (Status 0x%lx)\n", Status);
goto Quit;
}
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
//
// FIXME: Implement the "EffectiveOnly" option, that removes all
// the disabled parts (privileges and groups) of the token.
//
//
// NOTE: So far our dynamic area only contains
// the default dacl, so this makes the following
// code pretty simple. The day where it stores
// other data, the code will require adaptations.
//
/* Now allocate the TOKEN's dynamic information area and set the data */
AccessToken->DynamicAvailable = 0; // Unused memory in the dynamic area.
AccessToken->DynamicPart = NULL;
if (Token->DynamicPart && Token->DefaultDacl)
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool,
Token->DefaultDacl->AclSize,
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
TAG_TOKEN_DYNAMIC);
if (AccessToken->DynamicPart == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
goto Quit;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
EndMem = (PVOID)AccessToken->DynamicPart;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
AccessToken->DefaultDacl = EndMem;
RtlCopyMemory(AccessToken->DefaultDacl,
Token->DefaultDacl,
Token->DefaultDacl->AclSize);
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Unlock the source token */
SepReleaseTokenLock(Token);
/* Return the token */
*NewAccessToken = AccessToken;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
Status = STATUS_SUCCESS;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
Quit:
if (!NT_SUCCESS(Status))
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Unlock the source token */
SepReleaseTokenLock(Token);
/* Dereference the token, the delete procedure will clean it up */
ObDereferenceObject(AccessToken);
}
return Status;
}
NTSTATUS
NTAPI
SeSubProcessToken(IN PTOKEN ParentToken,
OUT PTOKEN *Token,
IN BOOLEAN InUse,
IN ULONG SessionId)
{
PTOKEN NewToken;
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
/* Initialize the attributes and duplicate it */
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
Status = SepDuplicateToken(ParentToken,
&ObjectAttributes,
FALSE,
TokenPrimary,
ParentToken->ImpersonationLevel,
KernelMode,
&NewToken);
if (NT_SUCCESS(Status))
{
/* Insert it */
Status = ObInsertObject(NewToken,
NULL,
0,
0,
NULL,
NULL);
if (NT_SUCCESS(Status))
{
/* Set the session ID */
NewToken->SessionId = SessionId;
NewToken->TokenInUse = InUse;
/* Return the token */
*Token = NewToken;
}
}
/* Return status */
return Status;
}
NTSTATUS
NTAPI
SeIsTokenChild(IN PTOKEN Token,
OUT PBOOLEAN IsChild)
{
PTOKEN ProcessToken;
LUID ProcessTokenId, CallerParentId;
/* Assume failure */
*IsChild = FALSE;
/* Reference the process token */
ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess());
if (!ProcessToken)
return STATUS_UNSUCCESSFUL;
/* Get its token ID */
ProcessTokenId = ProcessToken->TokenId;
/* Dereference the token */
ObFastDereferenceObject(&PsGetCurrentProcess()->Token, ProcessToken);
/* Get our parent token ID */
CallerParentId = Token->ParentTokenId;
/* Compare the token IDs */
if (RtlEqualLuid(&CallerParentId, &ProcessTokenId))
*IsChild = TRUE;
/* Return success */
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
SeIsTokenSibling(IN PTOKEN Token,
OUT PBOOLEAN IsSibling)
{
PTOKEN ProcessToken;
LUID ProcessParentId, ProcessAuthId;
LUID CallerParentId, CallerAuthId;
/* Assume failure */
*IsSibling = FALSE;
/* Reference the process token */
ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess());
if (!ProcessToken)
return STATUS_UNSUCCESSFUL;
/* Get its parent and authentication IDs */
ProcessParentId = ProcessToken->ParentTokenId;
ProcessAuthId = ProcessToken->AuthenticationId;
/* Dereference the token */
ObFastDereferenceObject(&PsGetCurrentProcess()->Token, ProcessToken);
/* Get our parent and authentication IDs */
CallerParentId = Token->ParentTokenId;
CallerAuthId = Token->AuthenticationId;
/* Compare the token IDs */
if (RtlEqualLuid(&CallerParentId, &ProcessParentId) &&
RtlEqualLuid(&CallerAuthId, &ProcessAuthId))
{
*IsSibling = TRUE;
}
/* Return success */
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
SeCopyClientToken(IN PACCESS_TOKEN Token,
IN SECURITY_IMPERSONATION_LEVEL Level,
IN KPROCESSOR_MODE PreviousMode,
OUT PACCESS_TOKEN* NewToken)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
PAGED_CODE();
InitializeObjectAttributes(&ObjectAttributes,
NULL,
0,
NULL,
NULL);
Status = SepDuplicateToken(Token,
&ObjectAttributes,
FALSE,
TokenImpersonation,
Level,
PreviousMode,
(PTOKEN*)NewToken);
return Status;
}
VOID
NTAPI
SepDeleteToken(PVOID ObjectBody)
{
PTOKEN AccessToken = (PTOKEN)ObjectBody;
DPRINT("SepDeleteToken()\n");
/* Dereference the logon session */
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
if ((AccessToken->TokenFlags & TOKEN_SESSION_NOT_REFERENCED) == 0)
SepRmDereferenceLogonSession(&AccessToken->AuthenticationId);
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Delete the dynamic information area */
if (AccessToken->DynamicPart)
ExFreePoolWithTag(AccessToken->DynamicPart, TAG_TOKEN_DYNAMIC);
}
VOID
INIT_FUNCTION
NTAPI
SepInitializeTokenImplementation(VOID)
{
UNICODE_STRING Name;
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
ExInitializeResource(&SepTokenLock); // FIXME: Global lock!
DPRINT("Creating Token Object Type\n");
/* Initialize the Token type */
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
RtlInitUnicodeString(&Name, L"Token");
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
ObjectTypeInitializer.SecurityRequired = TRUE;
ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(TOKEN);
ObjectTypeInitializer.GenericMapping = SepTokenMapping;
ObjectTypeInitializer.PoolType = PagedPool;
ObjectTypeInitializer.ValidAccessMask = TOKEN_ALL_ACCESS;
ObjectTypeInitializer.UseDefaultObject = TRUE;
ObjectTypeInitializer.DeleteProcedure = SepDeleteToken;
ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &SeTokenObjectType);
}
VOID
NTAPI
SeAssignPrimaryToken(IN PEPROCESS Process,
IN PTOKEN Token)
{
PAGED_CODE();
/* Sanity checks */
ASSERT(Token->TokenType == TokenPrimary);
ASSERT(!Token->TokenInUse);
/* Clean any previous token */
if (Process->Token.Object) SeDeassignPrimaryToken(Process);
/* Set the new token */
ObReferenceObject(Token);
Token->TokenInUse = TRUE;
ObInitializeFastReference(&Process->Token, Token);
}
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
NTSTATUS
NTAPI
SepCreateToken(
_Out_ PHANDLE TokenHandle,
_In_ KPROCESSOR_MODE PreviousMode,
_In_ ACCESS_MASK DesiredAccess,
_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_ TOKEN_TYPE TokenType,
_In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
_In_ PLUID AuthenticationId,
_In_ PLARGE_INTEGER ExpirationTime,
_In_ PSID_AND_ATTRIBUTES User,
_In_ ULONG GroupCount,
_In_ PSID_AND_ATTRIBUTES Groups,
_In_ ULONG GroupsLength,
_In_ ULONG PrivilegeCount,
_In_ PLUID_AND_ATTRIBUTES Privileges,
_In_opt_ PSID Owner,
_In_ PSID PrimaryGroup,
_In_opt_ PACL DefaultDacl,
_In_ PTOKEN_SOURCE TokenSource,
_In_ BOOLEAN SystemToken)
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
NTSTATUS Status;
PTOKEN AccessToken;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
ULONG TokenFlags = 0;
ULONG PrimaryGroupIndex, DefaultOwnerIndex;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
LUID TokenId;
LUID ModifiedId;
PVOID EndMem;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
ULONG PrivilegesLength;
ULONG UserGroupsLength;
ULONG VariableLength;
ULONG TotalSize;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
ULONG i;
PAGED_CODE();
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
/* Loop all groups */
for (i = 0; i < GroupCount; i++)
{
/* Check for mandatory groups */
if (Groups[i].Attributes & SE_GROUP_MANDATORY)
{
/* Force them to be enabled */
Groups[i].Attributes |= (SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT);
}
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
/* Check of the group is an admin group */
if (RtlEqualSid(SeAliasAdminsSid, Groups[i].Sid))
{
/* Remember this so we can optimize queries later */
TokenFlags |= TOKEN_HAS_ADMIN_GROUP;
}
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Allocate unique IDs for the token */
ExAllocateLocallyUniqueId(&TokenId);
ExAllocateLocallyUniqueId(&ModifiedId);
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Compute how much size we need to allocate for the token */
/* Privileges size */
PrivilegesLength = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
/* User and groups size */
UserGroupsLength = (1 + GroupCount) * sizeof(SID_AND_ATTRIBUTES);
UserGroupsLength += RtlLengthSid(User->Sid);
for (i = 0; i < GroupCount; i++)
{
UserGroupsLength += RtlLengthSid(Groups[i].Sid);
}
UserGroupsLength = ALIGN_UP_BY(UserGroupsLength, sizeof(PVOID));
/* Add the additional groups array length */
UserGroupsLength += ALIGN_UP_BY(GroupsLength, sizeof(PVOID));
VariableLength = PrivilegesLength + UserGroupsLength;
TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Status = ObCreateObject(PreviousMode,
SeTokenObjectType,
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
ObjectAttributes,
PreviousMode,
NULL,
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
TotalSize,
0,
0,
(PVOID*)&AccessToken);
if (!NT_SUCCESS(Status))
{
DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status);
return Status;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Zero out the buffer and initialize the token */
RtlZeroMemory(AccessToken, TotalSize);
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
RtlCopyLuid(&AccessToken->TokenId, &TokenId);
AccessToken->TokenType = TokenType;
AccessToken->ImpersonationLevel = ImpersonationLevel;
AccessToken->TokenLock = &SepTokenLock; // FIXME: Global lock!
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier,
&TokenSource->SourceIdentifier);
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
RtlCopyMemory(AccessToken->TokenSource.SourceName,
TokenSource->SourceName,
sizeof(TokenSource->SourceName));
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
AccessToken->ExpirationTime = *ExpirationTime;
RtlCopyLuid(&AccessToken->ModifiedId, &ModifiedId);
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
AccessToken->TokenFlags = TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Copy and reference the logon session */
RtlCopyLuid(&AccessToken->AuthenticationId, AuthenticationId);
Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
if (!NT_SUCCESS(Status))
{
/* No logon session could be found, bail out */
DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status);
/* Set the flag for proper cleanup by the delete procedure */
AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
goto Quit;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Assign the data that reside in the TOKEN's variable information area */
AccessToken->VariableLength = VariableLength;
EndMem = (PVOID)&AccessToken->VariablePart;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Copy the privileges */
AccessToken->PrivilegeCount = PrivilegeCount;
AccessToken->Privileges = NULL;
if (PrivilegeCount > 0)
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
AccessToken->Privileges = EndMem;
EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
VariableLength -= PrivilegesLength;
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
RtlCopyMemory(AccessToken->Privileges,
Privileges,
PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
else
{
RtlCopyMemory(AccessToken->Privileges,
Privileges,
PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
}
if (!NT_SUCCESS(Status))
goto Quit;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Update the privilege flags */
SepUpdatePrivilegeFlagsToken(AccessToken);
/* Copy the user and groups */
AccessToken->UserAndGroupCount = 1 + GroupCount;
AccessToken->UserAndGroups = EndMem;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Status = RtlCopySidAndAttributesArray(1,
User,
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
VariableLength,
&AccessToken->UserAndGroups[0],
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
EndMem,
&EndMem,
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
&VariableLength);
if (!NT_SUCCESS(Status))
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
goto Quit;
Status = RtlCopySidAndAttributesArray(GroupCount,
Groups,
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
VariableLength,
&AccessToken->UserAndGroups[1],
EndMem,
&EndMem,
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
&VariableLength);
if (!NT_SUCCESS(Status))
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
goto Quit;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Find the token primary group and default owner */
Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken,
PrimaryGroup,
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
Owner,
&PrimaryGroupIndex,
&DefaultOwnerIndex);
if (!NT_SUCCESS(Status))
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status);
goto Quit;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid;
AccessToken->DefaultOwnerIndex = DefaultOwnerIndex;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Now allocate the TOKEN's dynamic information area and set the data */
AccessToken->DynamicAvailable = 0; // Unused memory in the dynamic area.
AccessToken->DynamicPart = NULL;
if (DefaultDacl != NULL)
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool,
DefaultDacl->AclSize,
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
TAG_TOKEN_DYNAMIC);
if (AccessToken->DynamicPart == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
goto Quit;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
EndMem = (PVOID)AccessToken->DynamicPart;
AccessToken->DefaultDacl = EndMem;
RtlCopyMemory(AccessToken->DefaultDacl,
DefaultDacl,
DefaultDacl->AclSize);
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Insert the token only if it's not the system token, otherwise return it directly */
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
if (!SystemToken)
{
Status = ObInsertObject(AccessToken,
NULL,
DesiredAccess,
0,
NULL,
TokenHandle);
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
if (!NT_SUCCESS(Status))
{
DPRINT1("ObInsertObject() failed (Status 0x%lx)\n", Status);
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
}
}
else
{
/* Return pointer instead of handle */
*TokenHandle = (HANDLE)AccessToken;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
Quit:
if (!NT_SUCCESS(Status))
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Dereference the token, the delete procedure will clean it up */
ObDereferenceObject(AccessToken);
}
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
return Status;
}
PTOKEN
NTAPI
SepCreateSystemProcessToken(VOID)
{
LUID_AND_ATTRIBUTES Privileges[25];
ULONG GroupAttributes, OwnerAttributes;
SID_AND_ATTRIBUTES Groups[32];
LARGE_INTEGER Expiration;
SID_AND_ATTRIBUTES UserSid;
ULONG GroupsLength;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
PSID PrimaryGroup;
OBJECT_ATTRIBUTES ObjectAttributes;
PSID Owner;
ULONG i;
PTOKEN Token;
NTSTATUS Status;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
/* Don't ever expire */
Expiration.QuadPart = -1;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
/* All groups mandatory and enabled */
GroupAttributes = SE_GROUP_ENABLED | SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT;
OwnerAttributes = SE_GROUP_ENABLED | SE_GROUP_OWNER | SE_GROUP_ENABLED_BY_DEFAULT;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* User is Local System */
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
UserSid.Sid = SeLocalSystemSid;
UserSid.Attributes = 0;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Primary group is Local System */
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
PrimaryGroup = SeLocalSystemSid;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Owner is Administrators */
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Owner = SeAliasAdminsSid;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Groups are Administrators, World, and Authenticated Users */
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Groups[0].Sid = SeAliasAdminsSid;
Groups[0].Attributes = OwnerAttributes;
Groups[1].Sid = SeWorldSid;
Groups[1].Attributes = GroupAttributes;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
Groups[2].Sid = SeAuthenticatedUsersSid;
Groups[2].Attributes = GroupAttributes;
GroupsLength = sizeof(SID_AND_ATTRIBUTES) +
SeLengthSid(Groups[0].Sid) +
SeLengthSid(Groups[1].Sid) +
SeLengthSid(Groups[2].Sid);
ASSERT(GroupsLength <= sizeof(Groups));
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
/* Setup the privileges */
i = 0;
Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
Privileges[i++].Luid = SeTcbPrivilege;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Privileges[i].Attributes = 0;
Privileges[i++].Luid = SeCreateTokenPrivilege;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Privileges[i].Attributes = 0;
Privileges[i++].Luid = SeTakeOwnershipPrivilege;
Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Privileges[i++].Luid = SeCreatePagefilePrivilege;
Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Privileges[i++].Luid = SeLockMemoryPrivilege;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Privileges[i].Attributes = 0;
Privileges[i++].Luid = SeAssignPrimaryTokenPrivilege;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Privileges[i].Attributes = 0;
Privileges[i++].Luid = SeIncreaseQuotaPrivilege;
Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Privileges[i++].Luid = SeIncreaseBasePriorityPrivilege;
Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Privileges[i++].Luid = SeCreatePermanentPrivilege;
Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Privileges[i++].Luid = SeDebugPrivilege;
Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Privileges[i++].Luid = SeAuditPrivilege;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Privileges[i].Attributes = 0;
Privileges[i++].Luid = SeSecurityPrivilege;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Privileges[i].Attributes = 0;
Privileges[i++].Luid = SeSystemEnvironmentPrivilege;
Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Privileges[i++].Luid = SeChangeNotifyPrivilege;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Privileges[i].Attributes = 0;
Privileges[i++].Luid = SeBackupPrivilege;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Privileges[i].Attributes = 0;
Privileges[i++].Luid = SeRestorePrivilege;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Privileges[i].Attributes = 0;
Privileges[i++].Luid = SeShutdownPrivilege;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Privileges[i].Attributes = 0;
Privileges[i++].Luid = SeLoadDriverPrivilege;
Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Privileges[i++].Luid = SeProfileSingleProcessPrivilege;
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Privileges[i].Attributes = 0;
Privileges[i++].Luid = SeSystemtimePrivilege;
ASSERT(i == 20);
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
/* Setup the object attributes */
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
ASSERT(SeSystemDefaultDacl != NULL);
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
/* Create the token */
Status = SepCreateToken((PHANDLE)&Token,
KernelMode,
0,
&ObjectAttributes,
TokenPrimary,
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
SecurityAnonymous,
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
&SeSystemAuthenticationId,
&Expiration,
&UserSid,
3,
Groups,
GroupsLength,
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
20,
Privileges,
Owner,
PrimaryGroup,
SeSystemDefaultDacl,
&SeSystemTokenSource,
TRUE);
ASSERT(Status == STATUS_SUCCESS);
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
/* Return the token */
return Token;
}
/* PUBLIC FUNCTIONS ***********************************************************/
/*
* @unimplemented
*/
NTSTATUS
NTAPI
SeFilterToken(IN PACCESS_TOKEN ExistingToken,
IN ULONG Flags,
IN PTOKEN_GROUPS SidsToDisable OPTIONAL,
IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL,
IN PTOKEN_GROUPS RestrictedSids OPTIONAL,
OUT PACCESS_TOKEN * FilteredToken)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*
* NOTE: SeQueryInformationToken is just NtQueryInformationToken without all
* the bells and whistles needed for user-mode buffer access protection.
*/
NTSTATUS
NTAPI
SeQueryInformationToken(IN PACCESS_TOKEN AccessToken,
IN TOKEN_INFORMATION_CLASS TokenInformationClass,
OUT PVOID *TokenInformation)
{
NTSTATUS Status;
PTOKEN Token = (PTOKEN)AccessToken;
ULONG RequiredLength;
union
{
PSID PSid;
ULONG Ulong;
} Unused;
PAGED_CODE();
if (TokenInformationClass >= MaxTokenInfoClass)
{
DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
return STATUS_INVALID_INFO_CLASS;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
// TODO: Lock the token
switch (TokenInformationClass)
{
case TokenUser:
{
PTOKEN_USER tu;
DPRINT("SeQueryInformationToken(TokenUser)\n");
RequiredLength = sizeof(TOKEN_USER) +
RtlLengthSid(Token->UserAndGroups[0].Sid);
/* Allocate the output buffer */
tu = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
if (tu == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
Status = RtlCopySidAndAttributesArray(1,
&Token->UserAndGroups[0],
RequiredLength - sizeof(TOKEN_USER),
&tu->User,
(PSID)(tu + 1),
&Unused.PSid,
&Unused.Ulong);
/* Return the structure */
*TokenInformation = tu;
Status = STATUS_SUCCESS;
break;
}
case TokenGroups:
{
PTOKEN_GROUPS tg;
ULONG SidLen;
PSID Sid;
DPRINT("SeQueryInformationToken(TokenGroups)\n");
RequiredLength = sizeof(tg->GroupCount) +
RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]);
SidLen = RequiredLength - sizeof(tg->GroupCount) -
((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES));
/* Allocate the output buffer */
tg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
if (tg == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)));
tg->GroupCount = Token->UserAndGroupCount - 1;
Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1,
&Token->UserAndGroups[1],
SidLen,
&tg->Groups[0],
Sid,
&Unused.PSid,
&Unused.Ulong);
/* Return the structure */
*TokenInformation = tg;
Status = STATUS_SUCCESS;
break;
}
case TokenPrivileges:
{
PTOKEN_PRIVILEGES tp;
DPRINT("SeQueryInformationToken(TokenPrivileges)\n");
RequiredLength = sizeof(tp->PrivilegeCount) +
(Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
/* Allocate the output buffer */
tp = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
if (tp == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
tp->PrivilegeCount = Token->PrivilegeCount;
RtlCopyLuidAndAttributesArray(Token->PrivilegeCount,
Token->Privileges,
&tp->Privileges[0]);
/* Return the structure */
*TokenInformation = tp;
Status = STATUS_SUCCESS;
break;
}
case TokenOwner:
{
PTOKEN_OWNER to;
ULONG SidLen;
DPRINT("SeQueryInformationToken(TokenOwner)\n");
SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
RequiredLength = sizeof(TOKEN_OWNER) + SidLen;
/* Allocate the output buffer */
to = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
if (to == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
to->Owner = (PSID)(to + 1);
Status = RtlCopySid(SidLen,
to->Owner,
Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
/* Return the structure */
*TokenInformation = to;
Status = STATUS_SUCCESS;
break;
}
case TokenPrimaryGroup:
{
PTOKEN_PRIMARY_GROUP tpg;
ULONG SidLen;
DPRINT("SeQueryInformationToken(TokenPrimaryGroup)\n");
SidLen = RtlLengthSid(Token->PrimaryGroup);
RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen;
/* Allocate the output buffer */
tpg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
if (tpg == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
tpg->PrimaryGroup = (PSID)(tpg + 1);
Status = RtlCopySid(SidLen,
tpg->PrimaryGroup,
Token->PrimaryGroup);
/* Return the structure */
*TokenInformation = tpg;
Status = STATUS_SUCCESS;
break;
}
case TokenDefaultDacl:
{
PTOKEN_DEFAULT_DACL tdd;
DPRINT("SeQueryInformationToken(TokenDefaultDacl)\n");
RequiredLength = sizeof(TOKEN_DEFAULT_DACL);
if (Token->DefaultDacl != NULL)
RequiredLength += Token->DefaultDacl->AclSize;
/* Allocate the output buffer */
tdd = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
if (tdd == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
if (Token->DefaultDacl != NULL)
{
tdd->DefaultDacl = (PACL)(tdd + 1);
RtlCopyMemory(tdd->DefaultDacl,
Token->DefaultDacl,
Token->DefaultDacl->AclSize);
}
else
{
tdd->DefaultDacl = NULL;
}
/* Return the structure */
*TokenInformation = tdd;
Status = STATUS_SUCCESS;
break;
}
case TokenSource:
{
PTOKEN_SOURCE ts;
DPRINT("SeQueryInformationToken(TokenSource)\n");
RequiredLength = sizeof(TOKEN_SOURCE);
/* Allocate the output buffer */
ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
if (ts == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
*ts = Token->TokenSource;
/* Return the structure */
*TokenInformation = ts;
Status = STATUS_SUCCESS;
break;
}
case TokenType:
{
PTOKEN_TYPE tt;
DPRINT("SeQueryInformationToken(TokenType)\n");
RequiredLength = sizeof(TOKEN_TYPE);
/* Allocate the output buffer */
tt = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
if (tt == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
*tt = Token->TokenType;
/* Return the structure */
*TokenInformation = tt;
Status = STATUS_SUCCESS;
break;
}
case TokenImpersonationLevel:
{
PSECURITY_IMPERSONATION_LEVEL sil;
DPRINT("SeQueryInformationToken(TokenImpersonationLevel)\n");
RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL);
/* Fail if the token is not an impersonation token */
if (Token->TokenType != TokenImpersonation)
{
Status = STATUS_INVALID_INFO_CLASS;
break;
}
/* Allocate the output buffer */
sil = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
if (sil == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
*sil = Token->ImpersonationLevel;
/* Return the structure */
*TokenInformation = sil;
Status = STATUS_SUCCESS;
break;
}
case TokenStatistics:
{
PTOKEN_STATISTICS ts;
DPRINT("SeQueryInformationToken(TokenStatistics)\n");
RequiredLength = sizeof(TOKEN_STATISTICS);
/* Allocate the output buffer */
ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
if (ts == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
ts->TokenId = Token->TokenId;
ts->AuthenticationId = Token->AuthenticationId;
ts->ExpirationTime = Token->ExpirationTime;
ts->TokenType = Token->TokenType;
ts->ImpersonationLevel = Token->ImpersonationLevel;
ts->DynamicCharged = Token->DynamicCharged;
ts->DynamicAvailable = Token->DynamicAvailable;
ts->GroupCount = Token->UserAndGroupCount - 1;
ts->PrivilegeCount = Token->PrivilegeCount;
ts->ModifiedId = Token->ModifiedId;
/* Return the structure */
*TokenInformation = ts;
Status = STATUS_SUCCESS;
break;
}
/*
* The following 4 cases are only implemented in NtQueryInformationToken
*/
#if 0
case TokenOrigin:
{
PTOKEN_ORIGIN to;
DPRINT("SeQueryInformationToken(TokenOrigin)\n");
RequiredLength = sizeof(TOKEN_ORIGIN);
/* Allocate the output buffer */
to = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
if (to == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlCopyLuid(&to->OriginatingLogonSession,
&Token->AuthenticationId);
/* Return the structure */
*TokenInformation = to;
Status = STATUS_SUCCESS;
break;
}
case TokenGroupsAndPrivileges:
DPRINT1("SeQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n");
Status = STATUS_NOT_IMPLEMENTED;
break;
case TokenRestrictedSids:
{
PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation;
ULONG SidLen;
PSID Sid;
DPRINT("SeQueryInformationToken(TokenRestrictedSids)\n");
RequiredLength = sizeof(tg->GroupCount) +
RtlLengthSidAndAttributes(Token->RestrictedSidCount, Token->RestrictedSids);
SidLen = RequiredLength - sizeof(tg->GroupCount) -
(Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
/* Allocate the output buffer */
tg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
if (tg == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
(Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)));
tg->GroupCount = Token->RestrictedSidCount;
Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount,
Token->RestrictedSids,
SidLen,
&tg->Groups[0],
Sid,
&Unused.PSid,
&Unused.Ulong);
/* Return the structure */
*TokenInformation = tg;
Status = STATUS_SUCCESS;
break;
}
case TokenSandBoxInert:
DPRINT1("SeQueryInformationToken(TokenSandboxInert) not implemented\n");
Status = STATUS_NOT_IMPLEMENTED;
break;
#endif
case TokenSessionId:
{
DPRINT("SeQueryInformationToken(TokenSessionId)\n");
Status = SeQuerySessionIdToken(Token, (PULONG)TokenInformation);
break;
}
default:
DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
Status = STATUS_INVALID_INFO_CLASS;
break;
}
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
SeQuerySessionIdToken(IN PACCESS_TOKEN Token,
IN PULONG pSessionId)
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
PAGED_CODE();
/* Lock the token */
SepAcquireTokenLockShared(Token);
*pSessionId = ((PTOKEN)Token)->SessionId;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Unlock the token */
SepReleaseTokenLock(Token);
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
SeQueryAuthenticationIdToken(IN PACCESS_TOKEN Token,
OUT PLUID LogonId)
{
PAGED_CODE();
*LogonId = ((PTOKEN)Token)->AuthenticationId;
return STATUS_SUCCESS;
}
/*
* @implemented
*/
SECURITY_IMPERSONATION_LEVEL
NTAPI
SeTokenImpersonationLevel(IN PACCESS_TOKEN Token)
{
PAGED_CODE();
return ((PTOKEN)Token)->ImpersonationLevel;
}
/*
* @implemented
*/
TOKEN_TYPE NTAPI
SeTokenType(IN PACCESS_TOKEN Token)
{
PAGED_CODE();
return ((PTOKEN)Token)->TokenType;
}
/*
* @implemented
*/
BOOLEAN
NTAPI
SeTokenIsAdmin(IN PACCESS_TOKEN Token)
{
PAGED_CODE();
// NOTE: Win7+ instead really checks the list of groups in the token
// (since TOKEN_HAS_ADMIN_GROUP == TOKEN_WRITE_RESTRICTED ...)
return (((PTOKEN)Token)->TokenFlags & TOKEN_HAS_ADMIN_GROUP) != 0;
}
/*
* @implemented
*/
BOOLEAN
NTAPI
SeTokenIsRestricted(IN PACCESS_TOKEN Token)
{
PAGED_CODE();
return (((PTOKEN)Token)->TokenFlags & TOKEN_IS_RESTRICTED) != 0;
}
/*
* @implemented
* @note First introduced in NT 5.1 SP2 x86 (5.1.2600.2622), absent in NT 5.2,
* then finally re-introduced in Vista+.
*/
BOOLEAN
NTAPI
SeTokenIsWriteRestricted(IN PACCESS_TOKEN Token)
{
PAGED_CODE();
// NOTE: NT 5.1 SP2 x86 checks the SE_BACKUP_PRIVILEGES_CHECKED flag
// while Vista+ checks the TOKEN_WRITE_RESTRICTED flag as one expects.
return (((PTOKEN)Token)->TokenFlags & SE_BACKUP_PRIVILEGES_CHECKED) != 0;
}
/* SYSTEM CALLS ***************************************************************/
/*
* @implemented
*/
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
_Must_inspect_result_
__kernel_entry
NTSTATUS
NTAPI
NtQueryInformationToken(
_In_ HANDLE TokenHandle,
_In_ TOKEN_INFORMATION_CLASS TokenInformationClass,
_Out_writes_bytes_to_opt_(TokenInformationLength, *ReturnLength)
PVOID TokenInformation,
_In_ ULONG TokenInformationLength,
_Out_ PULONG ReturnLength)
{
NTSTATUS Status;
KPROCESSOR_MODE PreviousMode;
PTOKEN Token;
ULONG RequiredLength;
union
{
PSID PSid;
ULONG Ulong;
} Unused;
PAGED_CODE();
PreviousMode = ExGetPreviousMode();
/* Check buffers and class validity */
Status = DefaultQueryInfoBufferCheck(TokenInformationClass,
SeTokenInformationClass,
RTL_NUMBER_OF(SeTokenInformationClass),
TokenInformation,
TokenInformationLength,
ReturnLength,
NULL,
PreviousMode);
if (!NT_SUCCESS(Status))
{
DPRINT("NtQueryInformationToken() failed, Status: 0x%x\n", Status);
return Status;
}
Status = ObReferenceObjectByHandle(TokenHandle,
(TokenInformationClass == TokenSource) ? TOKEN_QUERY_SOURCE : TOKEN_QUERY,
SeTokenObjectType,
PreviousMode,
(PVOID*)&Token,
NULL);
if (NT_SUCCESS(Status))
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Lock the token */
SepAcquireTokenLockShared(Token);
switch (TokenInformationClass)
{
case TokenUser:
{
PTOKEN_USER tu = (PTOKEN_USER)TokenInformation;
DPRINT("NtQueryInformationToken(TokenUser)\n");
RequiredLength = sizeof(TOKEN_USER) +
RtlLengthSid(Token->UserAndGroups[0].Sid);
_SEH2_TRY
{
if (TokenInformationLength >= RequiredLength)
{
Status = RtlCopySidAndAttributesArray(1,
&Token->UserAndGroups[0],
RequiredLength - sizeof(TOKEN_USER),
&tu->User,
(PSID)(tu + 1),
&Unused.PSid,
&Unused.Ulong);
}
else
{
Status = STATUS_BUFFER_TOO_SMALL;
}
if (ReturnLength != NULL)
{
*ReturnLength = RequiredLength;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
break;
}
case TokenGroups:
{
PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation;
DPRINT("NtQueryInformationToken(TokenGroups)\n");
RequiredLength = sizeof(tg->GroupCount) +
RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]);
_SEH2_TRY
{
if (TokenInformationLength >= RequiredLength)
{
ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) -
((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES));
PSID Sid = (PSID_AND_ATTRIBUTES)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)));
tg->GroupCount = Token->UserAndGroupCount - 1;
Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1,
&Token->UserAndGroups[1],
SidLen,
&tg->Groups[0],
Sid,
&Unused.PSid,
&Unused.Ulong);
}
else
{
Status = STATUS_BUFFER_TOO_SMALL;
}
if (ReturnLength != NULL)
{
*ReturnLength = RequiredLength;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
break;
}
case TokenPrivileges:
{
PTOKEN_PRIVILEGES tp = (PTOKEN_PRIVILEGES)TokenInformation;
DPRINT("NtQueryInformationToken(TokenPrivileges)\n");
RequiredLength = sizeof(tp->PrivilegeCount) +
(Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
_SEH2_TRY
{
if (TokenInformationLength >= RequiredLength)
{
tp->PrivilegeCount = Token->PrivilegeCount;
RtlCopyLuidAndAttributesArray(Token->PrivilegeCount,
Token->Privileges,
&tp->Privileges[0]);
}
else
{
Status = STATUS_BUFFER_TOO_SMALL;
}
if (ReturnLength != NULL)
{
*ReturnLength = RequiredLength;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
break;
}
case TokenOwner:
{
PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation;
ULONG SidLen;
DPRINT("NtQueryInformationToken(TokenOwner)\n");
SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
RequiredLength = sizeof(TOKEN_OWNER) + SidLen;
_SEH2_TRY
{
if (TokenInformationLength >= RequiredLength)
{
to->Owner = (PSID)(to + 1);
Status = RtlCopySid(SidLen,
to->Owner,
Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
}
else
{
Status = STATUS_BUFFER_TOO_SMALL;
}
if (ReturnLength != NULL)
{
*ReturnLength = RequiredLength;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
break;
}
case TokenPrimaryGroup:
{
PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation;
ULONG SidLen;
DPRINT("NtQueryInformationToken(TokenPrimaryGroup)\n");
SidLen = RtlLengthSid(Token->PrimaryGroup);
RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen;
_SEH2_TRY
{
if (TokenInformationLength >= RequiredLength)
{
tpg->PrimaryGroup = (PSID)(tpg + 1);
Status = RtlCopySid(SidLen,
tpg->PrimaryGroup,
Token->PrimaryGroup);
}
else
{
Status = STATUS_BUFFER_TOO_SMALL;
}
if (ReturnLength != NULL)
{
*ReturnLength = RequiredLength;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
break;
}
case TokenDefaultDacl:
{
PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation;
DPRINT("NtQueryInformationToken(TokenDefaultDacl)\n");
RequiredLength = sizeof(TOKEN_DEFAULT_DACL);
if (Token->DefaultDacl != NULL)
RequiredLength += Token->DefaultDacl->AclSize;
_SEH2_TRY
{
if (TokenInformationLength >= RequiredLength)
{
if (Token->DefaultDacl != NULL)
{
tdd->DefaultDacl = (PACL)(tdd + 1);
RtlCopyMemory(tdd->DefaultDacl,
Token->DefaultDacl,
Token->DefaultDacl->AclSize);
}
else
{
tdd->DefaultDacl = NULL;
}
}
else
{
Status = STATUS_BUFFER_TOO_SMALL;
}
if (ReturnLength != NULL)
{
*ReturnLength = RequiredLength;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
break;
}
case TokenSource:
{
PTOKEN_SOURCE ts = (PTOKEN_SOURCE)TokenInformation;
DPRINT("NtQueryInformationToken(TokenSource)\n");
RequiredLength = sizeof(TOKEN_SOURCE);
_SEH2_TRY
{
if (TokenInformationLength >= RequiredLength)
{
*ts = Token->TokenSource;
}
else
{
Status = STATUS_BUFFER_TOO_SMALL;
}
if (ReturnLength != NULL)
{
*ReturnLength = RequiredLength;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
break;
}
case TokenType:
{
PTOKEN_TYPE tt = (PTOKEN_TYPE)TokenInformation;
DPRINT("NtQueryInformationToken(TokenType)\n");
RequiredLength = sizeof(TOKEN_TYPE);
_SEH2_TRY
{
if (TokenInformationLength >= RequiredLength)
{
*tt = Token->TokenType;
}
else
{
Status = STATUS_BUFFER_TOO_SMALL;
}
if (ReturnLength != NULL)
{
*ReturnLength = RequiredLength;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
break;
}
case TokenImpersonationLevel:
{
PSECURITY_IMPERSONATION_LEVEL sil = (PSECURITY_IMPERSONATION_LEVEL)TokenInformation;
DPRINT("NtQueryInformationToken(TokenImpersonationLevel)\n");
/* Fail if the token is not an impersonation token */
if (Token->TokenType != TokenImpersonation)
{
Status = STATUS_INVALID_INFO_CLASS;
break;
}
RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL);
_SEH2_TRY
{
if (TokenInformationLength >= RequiredLength)
{
*sil = Token->ImpersonationLevel;
}
else
{
Status = STATUS_BUFFER_TOO_SMALL;
}
if (ReturnLength != NULL)
{
*ReturnLength = RequiredLength;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
break;
}
case TokenStatistics:
{
PTOKEN_STATISTICS ts = (PTOKEN_STATISTICS)TokenInformation;
DPRINT("NtQueryInformationToken(TokenStatistics)\n");
RequiredLength = sizeof(TOKEN_STATISTICS);
_SEH2_TRY
{
if (TokenInformationLength >= RequiredLength)
{
ts->TokenId = Token->TokenId;
ts->AuthenticationId = Token->AuthenticationId;
ts->ExpirationTime = Token->ExpirationTime;
ts->TokenType = Token->TokenType;
ts->ImpersonationLevel = Token->ImpersonationLevel;
ts->DynamicCharged = Token->DynamicCharged;
ts->DynamicAvailable = Token->DynamicAvailable;
ts->GroupCount = Token->UserAndGroupCount - 1;
ts->PrivilegeCount = Token->PrivilegeCount;
ts->ModifiedId = Token->ModifiedId;
}
else
{
Status = STATUS_BUFFER_TOO_SMALL;
}
if (ReturnLength != NULL)
{
*ReturnLength = RequiredLength;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
break;
}
case TokenOrigin:
{
PTOKEN_ORIGIN to = (PTOKEN_ORIGIN)TokenInformation;
DPRINT("NtQueryInformationToken(TokenOrigin)\n");
RequiredLength = sizeof(TOKEN_ORIGIN);
_SEH2_TRY
{
if (TokenInformationLength >= RequiredLength)
{
RtlCopyLuid(&to->OriginatingLogonSession,
&Token->AuthenticationId);
}
else
{
Status = STATUS_BUFFER_TOO_SMALL;
}
if (ReturnLength != NULL)
{
*ReturnLength = RequiredLength;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
break;
}
case TokenGroupsAndPrivileges:
DPRINT1("NtQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n");
Status = STATUS_NOT_IMPLEMENTED;
break;
case TokenRestrictedSids:
{
PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation;
DPRINT("NtQueryInformationToken(TokenRestrictedSids)\n");
RequiredLength = sizeof(tg->GroupCount) +
RtlLengthSidAndAttributes(Token->RestrictedSidCount, Token->RestrictedSids);
_SEH2_TRY
{
if (TokenInformationLength >= RequiredLength)
{
ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) -
(Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
PSID Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
(Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)));
tg->GroupCount = Token->RestrictedSidCount;
Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount,
Token->RestrictedSids,
SidLen,
&tg->Groups[0],
Sid,
&Unused.PSid,
&Unused.Ulong);
}
else
{
Status = STATUS_BUFFER_TOO_SMALL;
}
if (ReturnLength != NULL)
{
*ReturnLength = RequiredLength;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
break;
}
case TokenSandBoxInert:
DPRINT1("NtQueryInformationToken(TokenSandboxInert) not implemented\n");
Status = STATUS_NOT_IMPLEMENTED;
break;
case TokenSessionId:
{
ULONG SessionId = 0;
DPRINT("NtQueryInformationToken(TokenSessionId)\n");
Status = SeQuerySessionIdToken(Token, &SessionId);
if (NT_SUCCESS(Status))
{
_SEH2_TRY
{
/* Buffer size was already verified, no need to check here again */
*(PULONG)TokenInformation = SessionId;
if (ReturnLength != NULL)
{
*ReturnLength = sizeof(ULONG);
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
break;
}
default:
DPRINT1("NtQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
Status = STATUS_INVALID_INFO_CLASS;
break;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Unlock and dereference the token */
SepReleaseTokenLock(Token);
ObDereferenceObject(Token);
}
return Status;
}
/*
* NtSetTokenInformation: Partly implemented.
* Unimplemented:
* TokenOrigin, TokenDefaultDacl
*/
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
_Must_inspect_result_
__kernel_entry
NTSTATUS
NTAPI
NtSetInformationToken(
_In_ HANDLE TokenHandle,
_In_ TOKEN_INFORMATION_CLASS TokenInformationClass,
_In_reads_bytes_(TokenInformationLength) PVOID TokenInformation,
_In_ ULONG TokenInformationLength)
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
NTSTATUS Status;
PTOKEN Token;
KPROCESSOR_MODE PreviousMode;
ULONG NeededAccess = TOKEN_ADJUST_DEFAULT;
PAGED_CODE();
PreviousMode = ExGetPreviousMode();
Status = DefaultSetInfoBufferCheck(TokenInformationClass,
SeTokenInformationClass,
RTL_NUMBER_OF(SeTokenInformationClass),
TokenInformation,
TokenInformationLength,
PreviousMode);
if (!NT_SUCCESS(Status))
{
/* Invalid buffers */
DPRINT("NtSetInformationToken() failed, Status: 0x%x\n", Status);
return Status;
}
if (TokenInformationClass == TokenSessionId)
{
NeededAccess |= TOKEN_ADJUST_SESSIONID;
}
Status = ObReferenceObjectByHandle(TokenHandle,
NeededAccess,
SeTokenObjectType,
PreviousMode,
(PVOID*)&Token,
NULL);
if (NT_SUCCESS(Status))
{
switch (TokenInformationClass)
{
case TokenOwner:
{
if (TokenInformationLength >= sizeof(TOKEN_OWNER))
{
PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation;
PSID InputSid = NULL, CapturedSid;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
ULONG DefaultOwnerIndex;
_SEH2_TRY
{
InputSid = to->Owner;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
_SEH2_YIELD(goto Cleanup);
}
_SEH2_END;
Status = SepCaptureSid(InputSid,
PreviousMode,
PagedPool,
FALSE,
&CapturedSid);
if (NT_SUCCESS(Status))
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Lock the token */
SepAcquireTokenLockExclusive(Token);
/* Find the owner amongst the existing token user and groups */
Status = SepFindPrimaryGroupAndDefaultOwner(Token,
NULL,
CapturedSid,
NULL,
&DefaultOwnerIndex);
if (NT_SUCCESS(Status))
{
/* Found it */
Token->DefaultOwnerIndex = DefaultOwnerIndex;
ExAllocateLocallyUniqueId(&Token->ModifiedId);
}
/* Unlock the token */
SepReleaseTokenLock(Token);
SepReleaseSid(CapturedSid,
PreviousMode,
FALSE);
}
}
else
{
Status = STATUS_INFO_LENGTH_MISMATCH;
}
break;
}
case TokenPrimaryGroup:
{
if (TokenInformationLength >= sizeof(TOKEN_PRIMARY_GROUP))
{
PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation;
PSID InputSid = NULL, CapturedSid;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
ULONG PrimaryGroupIndex;
_SEH2_TRY
{
InputSid = tpg->PrimaryGroup;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
_SEH2_YIELD(goto Cleanup);
}
_SEH2_END;
Status = SepCaptureSid(InputSid,
PreviousMode,
PagedPool,
FALSE,
&CapturedSid);
if (NT_SUCCESS(Status))
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Lock the token */
SepAcquireTokenLockExclusive(Token);
/* Find the primary group amongst the existing token user and groups */
Status = SepFindPrimaryGroupAndDefaultOwner(Token,
CapturedSid,
NULL,
&PrimaryGroupIndex,
NULL);
if (NT_SUCCESS(Status))
{
/* Found it */
Token->PrimaryGroup = Token->UserAndGroups[PrimaryGroupIndex].Sid;
ExAllocateLocallyUniqueId(&Token->ModifiedId);
}
/* Unlock the token */
SepReleaseTokenLock(Token);
SepReleaseSid(CapturedSid,
PreviousMode,
FALSE);
}
}
else
{
Status = STATUS_INFO_LENGTH_MISMATCH;
}
break;
}
case TokenDefaultDacl:
{
if (TokenInformationLength >= sizeof(TOKEN_DEFAULT_DACL))
{
PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation;
PACL InputAcl = NULL;
_SEH2_TRY
{
InputAcl = tdd->DefaultDacl;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
_SEH2_YIELD(goto Cleanup);
}
_SEH2_END;
if (InputAcl != NULL)
{
PACL CapturedAcl;
/* Capture and copy the dacl */
Status = SepCaptureAcl(InputAcl,
PreviousMode,
PagedPool,
TRUE,
&CapturedAcl);
if (NT_SUCCESS(Status))
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
ULONG DynamicLength;
/* Lock the token */
SepAcquireTokenLockExclusive(Token);
//
// NOTE: So far our dynamic area only contains
// the default dacl, so this makes the following
// code pretty simple. The day where it stores
// other data, the code will require adaptations.
//
DynamicLength = Token->DynamicAvailable;
// Add here any other data length present in the dynamic area...
if (Token->DefaultDacl)
DynamicLength += Token->DefaultDacl->AclSize;
/* Reallocate the dynamic area if it is too small */
Status = STATUS_SUCCESS;
if ((DynamicLength < CapturedAcl->AclSize) ||
(Token->DynamicPart == NULL))
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
PVOID NewDynamicPart;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
NewDynamicPart = ExAllocatePoolWithTag(PagedPool,
CapturedAcl->AclSize,
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
TAG_TOKEN_DYNAMIC);
if (NewDynamicPart == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
else
{
if (Token->DynamicPart != NULL)
{
// RtlCopyMemory(NewDynamicPart, Token->DynamicPart, DynamicLength);
ExFreePoolWithTag(Token->DynamicPart, TAG_TOKEN_DYNAMIC);
}
Token->DynamicPart = NewDynamicPart;
Token->DynamicAvailable = 0;
}
}
else
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
{
Token->DynamicAvailable = DynamicLength - CapturedAcl->AclSize;
}
if (NT_SUCCESS(Status))
{
/* Set the new dacl */
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
Token->DefaultDacl = (PVOID)Token->DynamicPart;
RtlCopyMemory(Token->DefaultDacl,
CapturedAcl,
CapturedAcl->AclSize);
ExAllocateLocallyUniqueId(&Token->ModifiedId);
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Unlock the token */
SepReleaseTokenLock(Token);
ExFreePoolWithTag(CapturedAcl, TAG_ACL);
}
}
else
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Lock the token */
SepAcquireTokenLockExclusive(Token);
/* Clear the default dacl if present */
if (Token->DefaultDacl != NULL)
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
Token->DynamicAvailable += Token->DefaultDacl->AclSize;
RtlZeroMemory(Token->DefaultDacl, Token->DefaultDacl->AclSize);
Token->DefaultDacl = NULL;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
ExAllocateLocallyUniqueId(&Token->ModifiedId);
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Unlock the token */
SepReleaseTokenLock(Token);
}
}
else
{
Status = STATUS_INFO_LENGTH_MISMATCH;
}
break;
}
case TokenSessionId:
{
ULONG SessionId = 0;
_SEH2_TRY
{
/* Buffer size was already verified, no need to check here again */
SessionId = *(PULONG)TokenInformation;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
_SEH2_YIELD(goto Cleanup);
}
_SEH2_END;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Check for TCB privilege */
if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
{
Status = STATUS_PRIVILEGE_NOT_HELD;
break;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Lock the token */
SepAcquireTokenLockExclusive(Token);
Token->SessionId = SessionId;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
ExAllocateLocallyUniqueId(&Token->ModifiedId);
/* Unlock the token */
SepReleaseTokenLock(Token);
break;
}
case TokenSessionReference:
{
ULONG SessionReference;
_SEH2_TRY
{
/* Buffer size was already verified, no need to check here again */
SessionReference = *(PULONG)TokenInformation;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
_SEH2_YIELD(goto Cleanup);
}
_SEH2_END;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Check for TCB privilege */
if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
{
Status = STATUS_PRIVILEGE_NOT_HELD;
goto Cleanup;
}
/* Check if it is 0 */
if (SessionReference == 0)
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
ULONG OldTokenFlags;
/* Lock the token */
SepAcquireTokenLockExclusive(Token);
/* Atomically set the flag in the token */
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
OldTokenFlags = RtlInterlockedSetBits(&Token->TokenFlags,
TOKEN_SESSION_NOT_REFERENCED);
/*
* If the flag was already set, do not dereference again
* the logon session. Use SessionReference as an indicator
* to know whether to really dereference the session.
*/
if (OldTokenFlags == Token->TokenFlags)
SessionReference = ULONG_MAX;
/* Unlock the token */
SepReleaseTokenLock(Token);
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Dereference the logon session if needed */
if (SessionReference == 0)
SepRmDereferenceLogonSession(&Token->AuthenticationId);
break;
}
case TokenAuditPolicy:
{
PTOKEN_AUDIT_POLICY_INFORMATION PolicyInformation =
(PTOKEN_AUDIT_POLICY_INFORMATION)TokenInformation;
SEP_AUDIT_POLICY AuditPolicy;
ULONG i;
_SEH2_TRY
{
ProbeForRead(PolicyInformation,
FIELD_OFFSET(TOKEN_AUDIT_POLICY_INFORMATION,
Policies[PolicyInformation->PolicyCount]),
sizeof(ULONG));
/* Loop all policies in the structure */
for (i = 0; i < PolicyInformation->PolicyCount; i++)
{
/* Set the corresponding bits in the packed structure */
switch (PolicyInformation->Policies[i].Category)
{
case AuditCategorySystem:
AuditPolicy.PolicyElements.System = PolicyInformation->Policies[i].Value;
break;
case AuditCategoryLogon:
AuditPolicy.PolicyElements.Logon = PolicyInformation->Policies[i].Value;
break;
case AuditCategoryObjectAccess:
AuditPolicy.PolicyElements.ObjectAccess = PolicyInformation->Policies[i].Value;
break;
case AuditCategoryPrivilegeUse:
AuditPolicy.PolicyElements.PrivilegeUse = PolicyInformation->Policies[i].Value;
break;
case AuditCategoryDetailedTracking:
AuditPolicy.PolicyElements.DetailedTracking = PolicyInformation->Policies[i].Value;
break;
case AuditCategoryPolicyChange:
AuditPolicy.PolicyElements.PolicyChange = PolicyInformation->Policies[i].Value;
break;
case AuditCategoryAccountManagement:
AuditPolicy.PolicyElements.AccountManagement = PolicyInformation->Policies[i].Value;
break;
case AuditCategoryDirectoryServiceAccess:
AuditPolicy.PolicyElements.DirectoryServiceAccess = PolicyInformation->Policies[i].Value;
break;
case AuditCategoryAccountLogon:
AuditPolicy.PolicyElements.AccountLogon = PolicyInformation->Policies[i].Value;
break;
}
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
_SEH2_YIELD(goto Cleanup);
}
_SEH2_END;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Check for TCB privilege */
if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
{
Status = STATUS_PRIVILEGE_NOT_HELD;
break;
}
/* Lock the token */
SepAcquireTokenLockExclusive(Token);
/* Set the new audit policy */
Token->AuditPolicy = AuditPolicy;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
ExAllocateLocallyUniqueId(&Token->ModifiedId);
/* Unlock the token */
SepReleaseTokenLock(Token);
break;
}
case TokenOrigin:
{
TOKEN_ORIGIN TokenOrigin;
_SEH2_TRY
{
/* Copy the token origin */
TokenOrigin = *(PTOKEN_ORIGIN)TokenInformation;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
_SEH2_YIELD(goto Cleanup);
}
_SEH2_END;
/* Check for TCB privilege */
if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
{
Status = STATUS_PRIVILEGE_NOT_HELD;
break;
}
/* Lock the token */
SepAcquireTokenLockExclusive(Token);
/* Check if there is no token origin set yet */
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
if (RtlIsZeroLuid(&Token->OriginatingLogonSession))
{
/* Set the token origin */
Token->OriginatingLogonSession =
TokenOrigin.OriginatingLogonSession;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
ExAllocateLocallyUniqueId(&Token->ModifiedId);
}
/* Unlock the token */
SepReleaseTokenLock(Token);
break;
}
default:
{
DPRINT1("Invalid TokenInformationClass: 0x%lx\n",
TokenInformationClass);
Status = STATUS_INVALID_INFO_CLASS;
break;
}
}
Cleanup:
ObDereferenceObject(Token);
}
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetInformationToken failed with Status 0x%lx\n", Status);
}
return Status;
}
/*
* @implemented
*
* NOTE: Some sources claim 4th param is ImpersonationLevel, but on W2K
* this is certainly NOT true, although I can't say for sure that EffectiveOnly
* is correct either. -Gunnar
* This is true. EffectiveOnly overrides SQOS.EffectiveOnly. - IAI
* NOTE for readers: http://hex.pp.ua/nt/NtDuplicateToken.php is therefore
* wrong in that regard, while MSDN documentation is correct.
*/
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
_Must_inspect_result_
__kernel_entry
NTSTATUS
NTAPI
NtDuplicateToken(
_In_ HANDLE ExistingTokenHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_ BOOLEAN EffectiveOnly,
_In_ TOKEN_TYPE TokenType,
_Out_ PHANDLE NewTokenHandle)
{
KPROCESSOR_MODE PreviousMode;
HANDLE hToken;
PTOKEN Token;
PTOKEN NewToken;
PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService;
BOOLEAN QoSPresent;
OBJECT_HANDLE_INFORMATION HandleInformation;
NTSTATUS Status;
PAGED_CODE();
if (TokenType != TokenImpersonation &&
TokenType != TokenPrimary)
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
{
return STATUS_INVALID_PARAMETER;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
}
PreviousMode = KeGetPreviousMode();
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
ProbeForWriteHandle(NewTokenHandle);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
Status = SepCaptureSecurityQualityOfService(ObjectAttributes,
PreviousMode,
PagedPool,
FALSE,
&CapturedSecurityQualityOfService,
&QoSPresent);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtDuplicateToken() failed to capture QoS! Status: 0x%x\n", Status);
return Status;
}
Status = ObReferenceObjectByHandle(ExistingTokenHandle,
TOKEN_DUPLICATE,
SeTokenObjectType,
PreviousMode,
(PVOID*)&Token,
&HandleInformation);
if (!NT_SUCCESS(Status))
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
DPRINT1("Failed to reference token (Status 0x%lx)\n", Status);
SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
PreviousMode,
FALSE);
return Status;
}
/*
* Fail, if the original token is an impersonation token and the caller
* tries to raise the impersonation level of the new token above the
* impersonation level of the original token.
*/
if (Token->TokenType == TokenImpersonation)
{
if (QoSPresent &&
CapturedSecurityQualityOfService->ImpersonationLevel >Token->ImpersonationLevel)
{
ObDereferenceObject(Token);
SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
PreviousMode,
FALSE);
return STATUS_BAD_IMPERSONATION_LEVEL;
}
}
/*
* Fail, if a primary token is to be created from an impersonation token
* and and the impersonation level of the impersonation token is below SecurityImpersonation.
*/
if (Token->TokenType == TokenImpersonation &&
TokenType == TokenPrimary &&
Token->ImpersonationLevel < SecurityImpersonation)
{
ObDereferenceObject(Token);
SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
PreviousMode,
FALSE);
return STATUS_BAD_IMPERSONATION_LEVEL;
}
Status = SepDuplicateToken(Token,
ObjectAttributes,
EffectiveOnly,
TokenType,
(QoSPresent ? CapturedSecurityQualityOfService->ImpersonationLevel : SecurityAnonymous),
PreviousMode,
&NewToken);
ObDereferenceObject(Token);
if (NT_SUCCESS(Status))
{
Status = ObInsertObject(NewToken,
NULL,
(DesiredAccess ? DesiredAccess : HandleInformation.GrantedAccess),
0,
NULL,
&hToken);
if (NT_SUCCESS(Status))
{
_SEH2_TRY
{
*NewTokenHandle = hToken;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
}
/* Free the captured structure */
SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
PreviousMode,
FALSE);
return Status;
}
NTSTATUS NTAPI
NtAdjustGroupsToken(IN HANDLE TokenHandle,
IN BOOLEAN ResetToDefault,
IN PTOKEN_GROUPS NewState,
IN ULONG BufferLength,
OUT PTOKEN_GROUPS PreviousState OPTIONAL,
OUT PULONG ReturnLength)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
static
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
NTSTATUS
SepAdjustPrivileges(
_Inout_ PTOKEN Token,
_In_ BOOLEAN DisableAllPrivileges,
_In_opt_ PLUID_AND_ATTRIBUTES NewState,
_In_ ULONG NewStateCount,
_Out_opt_ PTOKEN_PRIVILEGES PreviousState,
_In_ BOOLEAN ApplyChanges,
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
_Out_ PULONG ChangedPrivileges,
_Out_ PBOOLEAN ChangesMade)
{
ULONG i, j, PrivilegeCount, ChangeCount, NewAttributes;
/* Count the found privileges and those that need to be changed */
PrivilegeCount = 0;
ChangeCount = 0;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
*ChangesMade = FALSE;
/* Loop all privileges in the token */
for (i = 0; i < Token->PrivilegeCount; i++)
{
/* Shall all of them be disabled? */
if (DisableAllPrivileges)
{
/* The new attributes are the old ones, but disabled */
NewAttributes = Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED;
}
else
{
/* Otherwise loop all provided privileges */
for (j = 0; j < NewStateCount; j++)
{
/* Check if this is the LUID we are looking for */
if (RtlEqualLuid(&Token->Privileges[i].Luid, &NewState[j].Luid))
{
DPRINT("Found privilege\n");
/* Copy SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED */
NewAttributes = NewState[j].Attributes;
NewAttributes &= (SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED);
NewAttributes |= Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED;
/* Stop looking */
break;
}
}
/* Check if we didn't find the privilege */
if (j == NewStateCount)
{
/* Continue with the token's next privilege */
continue;
}
}
/* We found a privilege, count it */
PrivilegeCount++;
/* Does the privilege need to be changed? */
if (Token->Privileges[i].Attributes != NewAttributes)
{
/* Does the caller want the old privileges? */
if (PreviousState != NULL)
{
/* Copy the old privilege */
PreviousState->Privileges[ChangeCount] = Token->Privileges[i];
}
/* Does the caller want to apply the changes? */
if (ApplyChanges)
{
/* Shall we remove the privilege? */
if (NewAttributes & SE_PRIVILEGE_REMOVED)
{
/* Set the token as disabled and update flags for it */
Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
SepUpdateSinglePrivilegeFlagToken(Token, i);
/* Remove the privilege */
SepRemovePrivilegeToken(Token, i);
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
*ChangesMade = TRUE;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Fix the running index and continue with next one */
i--;
continue;
}
/* Set the new attributes and update flags */
Token->Privileges[i].Attributes = NewAttributes;
SepUpdateSinglePrivilegeFlagToken(Token, i);
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
*ChangesMade = TRUE;
}
/* Increment the change count */
ChangeCount++;
}
}
/* Set the number of saved privileges */
if (PreviousState != NULL)
PreviousState->PrivilegeCount = ChangeCount;
/* Return the number of changed privileges */
*ChangedPrivileges = ChangeCount;
/* Check if we missed some */
if (!DisableAllPrivileges && (PrivilegeCount < NewStateCount))
{
return STATUS_NOT_ALL_ASSIGNED;
}
return STATUS_SUCCESS;
}
/*
* @implemented
*/
_Must_inspect_result_
__kernel_entry
NTSTATUS
NTAPI
NtAdjustPrivilegesToken(
_In_ HANDLE TokenHandle,
_In_ BOOLEAN DisableAllPrivileges,
_In_opt_ PTOKEN_PRIVILEGES NewState,
_In_ ULONG BufferLength,
_Out_writes_bytes_to_opt_(BufferLength,*ReturnLength)
PTOKEN_PRIVILEGES PreviousState,
_When_(PreviousState!=NULL, _Out_) PULONG ReturnLength)
{
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
NTSTATUS Status;
KPROCESSOR_MODE PreviousMode;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
PTOKEN Token;
PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
ULONG CapturedCount = 0;
ULONG CapturedLength = 0;
ULONG NewStateSize = 0;
ULONG ChangeCount;
ULONG RequiredLength;
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
BOOLEAN ChangesMade = FALSE;
PAGED_CODE();
DPRINT("NtAdjustPrivilegesToken() called\n");
/* Fail, if we do not disable all privileges but NewState is NULL */
if (DisableAllPrivileges == FALSE && NewState == NULL)
return STATUS_INVALID_PARAMETER;
PreviousMode = KeGetPreviousMode();
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
/* Probe NewState */
if (DisableAllPrivileges == FALSE)
{
/* First probe the header */
ProbeForRead(NewState, sizeof(TOKEN_PRIVILEGES), sizeof(ULONG));
CapturedCount = NewState->PrivilegeCount;
NewStateSize = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[CapturedCount]);
ProbeForRead(NewState, NewStateSize, sizeof(ULONG));
}
/* Probe PreviousState and ReturnLength */
if (PreviousState != NULL)
{
ProbeForWrite(PreviousState, BufferLength, sizeof(ULONG));
ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
else
{
/* This is kernel mode, we trust the caller */
if (DisableAllPrivileges == FALSE)
CapturedCount = NewState->PrivilegeCount;
}
/* Do we need to capture the new state? */
if (DisableAllPrivileges == FALSE)
{
_SEH2_TRY
{
/* Capture the new state array of privileges */
Status = SeCaptureLuidAndAttributesArray(NewState->Privileges,
CapturedCount,
PreviousMode,
NULL,
0,
PagedPool,
TRUE,
&CapturedPrivileges,
&CapturedLength);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
if (!NT_SUCCESS(Status))
return Status;
}
/* Reference the token */
Status = ObReferenceObjectByHandle(TokenHandle,
TOKEN_ADJUST_PRIVILEGES | (PreviousState != NULL ? TOKEN_QUERY : 0),
SeTokenObjectType,
PreviousMode,
(PVOID*)&Token,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to reference token (Status 0x%lx)\n", Status);
/* Release the captured privileges */
if (CapturedPrivileges != NULL)
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
{
SeReleaseLuidAndAttributesArray(CapturedPrivileges,
PreviousMode,
TRUE);
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
}
return Status;
}
/* Lock the token */
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
SepAcquireTokenLockExclusive(Token);
/* Count the privileges that need to be changed, do not apply them yet */
Status = SepAdjustPrivileges(Token,
DisableAllPrivileges,
CapturedPrivileges,
CapturedCount,
NULL,
FALSE,
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
&ChangeCount,
&ChangesMade);
/* Check if the caller asked for the previous state */
if (PreviousState != NULL)
{
/* Calculate the required length */
RequiredLength = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[ChangeCount]);
/* Try to return the required buffer length */
_SEH2_TRY
{
*ReturnLength = RequiredLength;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Do cleanup and return the exception code */
Status = _SEH2_GetExceptionCode();
_SEH2_YIELD(goto Cleanup);
}
_SEH2_END;
/* Fail, if the buffer length is smaller than the required length */
if (BufferLength < RequiredLength)
{
Status = STATUS_BUFFER_TOO_SMALL;
goto Cleanup;
}
}
/* Now enter SEH, since we might return the old privileges */
_SEH2_TRY
{
/* This time apply the changes */
Status = SepAdjustPrivileges(Token,
DisableAllPrivileges,
CapturedPrivileges,
CapturedCount,
PreviousState,
TRUE,
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
&ChangeCount,
&ChangesMade);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Do cleanup and return the exception code */
Status = _SEH2_GetExceptionCode();
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
ChangesMade = TRUE; // Force write.
_SEH2_YIELD(goto Cleanup);
}
_SEH2_END;
Cleanup:
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Touch the token if we made changes */
if (ChangesMade)
ExAllocateLocallyUniqueId(&Token->ModifiedId);
/* Unlock and dereference the token */
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
SepReleaseTokenLock(Token);
ObDereferenceObject(Token);
/* Release the captured privileges */
if (CapturedPrivileges != NULL)
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
{
SeReleaseLuidAndAttributesArray(CapturedPrivileges,
PreviousMode,
TRUE);
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
}
DPRINT ("NtAdjustPrivilegesToken() done\n");
return Status;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
__kernel_entry
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
NTSTATUS
NTAPI
NtCreateToken(
_Out_ PHANDLE TokenHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_ TOKEN_TYPE TokenType,
_In_ PLUID AuthenticationId,
_In_ PLARGE_INTEGER ExpirationTime,
_In_ PTOKEN_USER TokenUser,
_In_ PTOKEN_GROUPS TokenGroups,
_In_ PTOKEN_PRIVILEGES TokenPrivileges,
_In_opt_ PTOKEN_OWNER TokenOwner,
_In_ PTOKEN_PRIMARY_GROUP TokenPrimaryGroup,
_In_opt_ PTOKEN_DEFAULT_DACL TokenDefaultDacl,
_In_ PTOKEN_SOURCE TokenSource)
{
HANDLE hToken;
KPROCESSOR_MODE PreviousMode;
ULONG PrivilegeCount, GroupCount;
PSID OwnerSid, PrimaryGroupSid;
PACL DefaultDacl;
LARGE_INTEGER LocalExpirationTime = {{0, 0}};
LUID LocalAuthenticationId;
TOKEN_SOURCE LocalTokenSource;
SECURITY_QUALITY_OF_SERVICE LocalSecurityQos;
PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
PSID_AND_ATTRIBUTES CapturedUser = NULL;
PSID_AND_ATTRIBUTES CapturedGroups = NULL;
PSID CapturedOwnerSid = NULL;
PSID CapturedPrimaryGroupSid = NULL;
PACL CapturedDefaultDacl = NULL;
ULONG PrivilegesLength, UserLength, GroupsLength;
NTSTATUS Status;
PAGED_CODE();
PreviousMode = ExGetPreviousMode();
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
ProbeForWriteHandle(TokenHandle);
if (ObjectAttributes != NULL)
{
ProbeForRead(ObjectAttributes,
sizeof(OBJECT_ATTRIBUTES),
sizeof(ULONG));
LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
}
ProbeForRead(AuthenticationId,
sizeof(LUID),
sizeof(ULONG));
LocalAuthenticationId = *AuthenticationId;
LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime);
ProbeForRead(TokenUser,
sizeof(TOKEN_USER),
sizeof(ULONG));
ProbeForRead(TokenGroups,
sizeof(TOKEN_GROUPS),
sizeof(ULONG));
GroupCount = TokenGroups->GroupCount;
ProbeForRead(TokenPrivileges,
sizeof(TOKEN_PRIVILEGES),
sizeof(ULONG));
PrivilegeCount = TokenPrivileges->PrivilegeCount;
if (TokenOwner != NULL)
{
ProbeForRead(TokenOwner,
sizeof(TOKEN_OWNER),
sizeof(ULONG));
OwnerSid = TokenOwner->Owner;
}
else
{
OwnerSid = NULL;
}
ProbeForRead(TokenPrimaryGroup,
sizeof(TOKEN_PRIMARY_GROUP),
sizeof(ULONG));
PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
if (TokenDefaultDacl != NULL)
{
ProbeForRead(TokenDefaultDacl,
sizeof(TOKEN_DEFAULT_DACL),
sizeof(ULONG));
DefaultDacl = TokenDefaultDacl->DefaultDacl;
}
else
{
DefaultDacl = NULL;
}
ProbeForRead(TokenSource,
sizeof(TOKEN_SOURCE),
sizeof(ULONG));
LocalTokenSource = *TokenSource;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
else
{
if (ObjectAttributes != NULL)
LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
LocalAuthenticationId = *AuthenticationId;
LocalExpirationTime = *ExpirationTime;
GroupCount = TokenGroups->GroupCount;
PrivilegeCount = TokenPrivileges->PrivilegeCount;
OwnerSid = TokenOwner ? TokenOwner->Owner : NULL;
PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
DefaultDacl = TokenDefaultDacl ? TokenDefaultDacl->DefaultDacl : NULL;
LocalTokenSource = *TokenSource;
}
/* Check token type */
if ((TokenType < TokenPrimary) ||
(TokenType > TokenImpersonation))
{
return STATUS_BAD_TOKEN_TYPE;
}
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
/* Check for token creation privilege */
if (!SeSinglePrivilegeCheck(SeCreateTokenPrivilege, PreviousMode))
{
return STATUS_PRIVILEGE_NOT_HELD;
}
/* Capture the user SID and attributes */
Status = SeCaptureSidAndAttributesArray(&TokenUser->User,
1,
PreviousMode,
NULL,
0,
PagedPool,
FALSE,
&CapturedUser,
&UserLength);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* Capture the groups SID and attributes array */
Status = SeCaptureSidAndAttributesArray(&TokenGroups->Groups[0],
GroupCount,
PreviousMode,
NULL,
0,
PagedPool,
FALSE,
&CapturedGroups,
&GroupsLength);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* Capture privileges */
Status = SeCaptureLuidAndAttributesArray(&TokenPrivileges->Privileges[0],
PrivilegeCount,
PreviousMode,
NULL,
0,
PagedPool,
FALSE,
&CapturedPrivileges,
&PrivilegesLength);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* Capture the token owner SID */
if (TokenOwner != NULL)
{
Status = SepCaptureSid(OwnerSid,
PreviousMode,
PagedPool,
FALSE,
&CapturedOwnerSid);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
}
/* Capture the token primary group SID */
Status = SepCaptureSid(PrimaryGroupSid,
PreviousMode,
PagedPool,
FALSE,
&CapturedPrimaryGroupSid);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
/* Capture DefaultDacl */
if (DefaultDacl != NULL)
{
Status = SepCaptureAcl(DefaultDacl,
PreviousMode,
NonPagedPool,
FALSE,
&CapturedDefaultDacl);
if (!NT_SUCCESS(Status))
{
goto Cleanup;
}
}
/* Call the internal function */
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Status = SepCreateToken(&hToken,
PreviousMode,
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
DesiredAccess,
ObjectAttributes,
TokenType,
LocalSecurityQos.ImpersonationLevel,
&LocalAuthenticationId,
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
&LocalExpirationTime,
CapturedUser,
GroupCount,
CapturedGroups,
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
0, // FIXME: Should capture
PrivilegeCount,
CapturedPrivileges,
CapturedOwnerSid,
CapturedPrimaryGroupSid,
CapturedDefaultDacl,
&LocalTokenSource,
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
FALSE);
if (NT_SUCCESS(Status))
{
_SEH2_TRY
{
*TokenHandle = hToken;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
Cleanup:
/* Release what we captured */
SeReleaseSidAndAttributesArray(CapturedUser, PreviousMode, FALSE);
SeReleaseSidAndAttributesArray(CapturedGroups, PreviousMode, FALSE);
SeReleaseLuidAndAttributesArray(CapturedPrivileges, PreviousMode, FALSE);
SepReleaseSid(CapturedOwnerSid, PreviousMode, FALSE);
SepReleaseSid(CapturedPrimaryGroupSid, PreviousMode, FALSE);
SepReleaseAcl(CapturedDefaultDacl, PreviousMode, FALSE);
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtOpenThreadTokenEx(IN HANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN BOOLEAN OpenAsSelf,
IN ULONG HandleAttributes,
OUT PHANDLE TokenHandle)
{
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
PETHREAD Thread, NewThread;
HANDLE hToken;
PTOKEN Token, NewToken = NULL, PrimaryToken;
BOOLEAN CopyOnOpen, EffectiveOnly;
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
SE_IMPERSONATION_STATE ImpersonationState;
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_DESCRIPTOR SecurityDescriptor;
PACL Dacl = NULL;
KPROCESSOR_MODE PreviousMode;
NTSTATUS Status;
BOOLEAN RestoreImpersonation = FALSE;
PAGED_CODE();
PreviousMode = ExGetPreviousMode();
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
ProbeForWriteHandle(TokenHandle);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
/* Validate object attributes */
HandleAttributes = ObpValidateAttributes(HandleAttributes, PreviousMode);
/*
* At first open the thread token for information access and verify
* that the token associated with thread is valid.
*/
Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_QUERY_INFORMATION,
PsThreadType, PreviousMode, (PVOID*)&Thread,
NULL);
if (!NT_SUCCESS(Status))
{
return Status;
}
Token = PsReferenceImpersonationToken(Thread, &CopyOnOpen, &EffectiveOnly,
&ImpersonationLevel);
if (Token == NULL)
{
ObDereferenceObject(Thread);
return STATUS_NO_TOKEN;
}
if (ImpersonationLevel == SecurityAnonymous)
{
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
PsDereferenceImpersonationToken(Token);
ObDereferenceObject(Thread);
return STATUS_CANT_OPEN_ANONYMOUS;
}
/*
* Revert to self if OpenAsSelf is specified.
*/
if (OpenAsSelf)
{
RestoreImpersonation = PsDisableImpersonation(PsGetCurrentThread(),
&ImpersonationState);
}
if (CopyOnOpen)
{
Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_ALL_ACCESS,
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
PsThreadType, KernelMode,
(PVOID*)&NewThread, NULL);
if (NT_SUCCESS(Status))
{
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
PrimaryToken = PsReferencePrimaryToken(NewThread->ThreadsProcess);
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Status = SepCreateImpersonationTokenDacl(Token, PrimaryToken, &Dacl);
ObFastDereferenceObject(&NewThread->ThreadsProcess->Token, PrimaryToken);
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
if (NT_SUCCESS(Status))
{
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
if (Dacl)
{
RtlCreateSecurityDescriptor(&SecurityDescriptor,
SECURITY_DESCRIPTOR_REVISION);
RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl,
FALSE);
}
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
InitializeObjectAttributes(&ObjectAttributes, NULL, HandleAttributes,
NULL, Dacl ? &SecurityDescriptor : NULL);
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
Status = SepDuplicateToken(Token, &ObjectAttributes, EffectiveOnly,
TokenImpersonation, ImpersonationLevel,
KernelMode, &NewToken);
if (NT_SUCCESS(Status))
{
ObReferenceObject(NewToken);
Status = ObInsertObject(NewToken, NULL, DesiredAccess, 0, NULL,
&hToken);
}
}
}
}
else
{
Status = ObOpenObjectByPointer(Token, HandleAttributes,
NULL, DesiredAccess, SeTokenObjectType,
PreviousMode, &hToken);
}
if (Dacl) ExFreePoolWithTag(Dacl, TAG_ACL);
if (RestoreImpersonation)
{
PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState);
}
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
ObDereferenceObject(Token);
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
if (NT_SUCCESS(Status) && CopyOnOpen)
{
PsImpersonateClient(Thread, NewToken, FALSE, EffectiveOnly, ImpersonationLevel);
}
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
if (NewToken) ObDereferenceObject(NewToken);
[NTOS]: While attempting to ressucitate the user-mode shutdown code in CSRSS (disabled since 2006), it seemed clear that one of the main steps is to obtain the caller's LUID in order to kill the right processes. This LUID is obtained from the current thread's token, and we know it's the callers since we're supposed to impersonate the caller. Unfortunately, impersonation failed, making the whole process fail. Impersonation failed because NtImpersonateThread was actually inverting the THREAD_IMPERSONATE rights, asking the client thread for the server's permissions, and vice versa. Fixing this resulted in yet another failure. Analysis of this failure showed that even opening the server (ie: current) thread for THREAD_DIRECT_IMPERSONATION failed, which is unusual since the current thread should have access to all its rights. This is determined in PspCreateThread when the ETHREAD->GrantedAccess field is set. Continuing onto this path, tracing revealed that GrantedAccess was merely 0x1607F and not 0x1F3FF as expected, meaning that not all rights were given, including the impersonate right (0x200), explaining the failure, but not the deeper reason behind it. Attempting to identify which code path set this GrantedAccess, the SepAccessCheck routine came to light. A bug there caused MAXIMUM_ALLOWED accesses to fail in certain scenarios, such as when the object had no security descriptor, because MAXIMUM_ALLOWED would be granted as an absolute value, when instead of it is a flag that should grant GENERIC_ALL. Fixing that bug, the failure continued. Further analysis identified that the Administrators SID was being found with GENERIC_READ + WRITE + EXECUTE access, and no SID was found for GENERIC_ALL access. This happened when searching the system token's default DACL, which is assigned to the kernel (but for kernel-mode callers, this check was skipped), smss, winlogon, etc. The code for creating this system token was heavily hacked, so the function to create the system token, as well as NtCreateToken were refactored to use a common piece of token-creating code. Furthermode, the system token was correctly created with Local System as the user, and Administrators as one of the groups. Finally, SeDefaultDacl was used (already setup properly) instead of a badly configured Default DACL. The new shared code also correctly sets the SE_GROUP_ENABLED flag on all SE_GROUP_MANDATORY groups, and scans tokens to set the TOKEN_HAS_ADMIN_GROUP and TOKEN_HAS_TRAVERSE_PRIVILEGE flags which were not previously set. With the correct system token and default DACL, the Local System SID was now found, but the failure continued. This was revealed to be due to an even deeper rooted problem, as the SepIsSidInToken routine checked for SE_GROUP_ENABLED before listing a SID as "present". Although this is correct for actual groups, the User SID will never have the SE_GROUP_ENABLED flag as it is not a group. This caused any granted access ACE belonging to a user (instead of a group) to be ignored, causing either access check failures, or limited rights returned (in the MAXIMUM_ALLOWED case). Upon fixing this bug, the NtImpersonateThread call finally returned success, since the rights were now correct. Promptly upon calling NtOpenThreadToken to query the LUID however, the system ASSERTED with FALSE. The code at fault was a line in NtOpenThreadTokenEx which forcefully ASSERTed if the impersonation code path was taken, presumably because this was never tested, and ReactOS would actually always fail impersonation attempts due to the bugs fixed above. This routine was thus quickly reworked to fix some mistakes (such as forgetting to actually impersonate the client, incorrect referencing/dereferencing of thread/tokens, and assumptions about DACL creation success). Having fixed the NtOpenThreadTokenEx routine, the LUID query now went through for the impersonated token, but soon causing a user-mode crash, due to an incorrect parameter reference in the CsrGetProcessLuid function in the csrsrv code by Alex (which I copy/pasted to reduce code duplication). Fixing this final bug finally allowed the correct LUID to be queried and I was able to continue development of not-yet-commited user-mode shutdown code. svn path=/trunk/; revision=46028
2010-03-09 10:35:58 +00:00
if (CopyOnOpen && NewThread) ObDereferenceObject(NewThread);
ObDereferenceObject(Thread);
if (NT_SUCCESS(Status))
{
_SEH2_TRY
{
*TokenHandle = hToken;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
return Status;
}
/*
* @implemented
*/
NTSTATUS NTAPI
NtOpenThreadToken(IN HANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN BOOLEAN OpenAsSelf,
OUT PHANDLE TokenHandle)
{
return NtOpenThreadTokenEx(ThreadHandle, DesiredAccess, OpenAsSelf, 0,
TokenHandle);
}
/*
* @unimplemented
*/
NTSTATUS
NTAPI
NtCompareTokens(IN HANDLE FirstTokenHandle,
IN HANDLE SecondTokenHandle,
OUT PBOOLEAN Equal)
{
KPROCESSOR_MODE PreviousMode;
PTOKEN FirstToken, SecondToken;
BOOLEAN IsEqual;
NTSTATUS Status;
PAGED_CODE();
PreviousMode = ExGetPreviousMode();
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
ProbeForWriteBoolean(Equal);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
Status = ObReferenceObjectByHandle(FirstTokenHandle,
TOKEN_QUERY,
SeTokenObjectType,
PreviousMode,
(PVOID*)&FirstToken,
NULL);
if (!NT_SUCCESS(Status))
return Status;
Status = ObReferenceObjectByHandle(SecondTokenHandle,
TOKEN_QUERY,
SeTokenObjectType,
PreviousMode,
(PVOID*)&SecondToken,
NULL);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(FirstToken);
return Status;
}
if (FirstToken != SecondToken)
{
Status = SepCompareTokens(FirstToken,
SecondToken,
&IsEqual);
}
else
{
IsEqual = TRUE;
}
ObDereferenceObject(SecondToken);
[NTOS:SE] Overhaul the token management code. - Overhaul SepCreateToken() and SepDuplicateToken() so that they implement the "variable information area" of the token, where immutable lists of user & groups and privileges reside, and the "dynamic information area" (allocated separately in paged pool), where mutable data such as the token's default DACL is stored. Perform the necessary adaptations in SepDeleteToken() and in NtSetInformationToken(). - Actually dereference the token's logon session, when needed, in the 'TokenSessionReference' case in NtSetInformationToken(). - Overhaul SepFindPrimaryGroupAndDefaultOwner() so that it returns the indices of candidate primary group and default owner within the token's user & groups array. This allows for fixing the 'TokenOwner' and 'TokenPrimaryGroup' cases of NtSetInformationToken(), since the owner or primary group being set *MUST* already exist in the token's user & groups array (as a by-product, memory corruptions that existed before due to the broken way of setting these properties disappear too). - Lock tokens every time operations are performed on them (NOTE: we still use a global token lock!). - Touch the ModifiedId LUID member of tokens everytime a write operation (property change, etc...) is made on them. - Fix some group attributes in the SYSTEM process token, SepCreateSystemProcessToken(). - Make the SeCreateTokenPrivilege mandatory when calling NtCreateToken(). - Update the token pool tags. - Explicitly use the Ex*ResourceLite() versions of the locking functions in the token locking macros.
2018-06-26 20:50:53 +00:00
ObDereferenceObject(FirstToken);
if (NT_SUCCESS(Status))
{
_SEH2_TRY
{
*Equal = IsEqual;
}
_SEH2_EXCEPT(ExSystemExceptionFilter())
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
return Status;
}
NTSTATUS
NTAPI
NtFilterToken(IN HANDLE ExistingTokenHandle,
IN ULONG Flags,
IN PTOKEN_GROUPS SidsToDisable OPTIONAL,
IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL,
IN PTOKEN_GROUPS RestrictedSids OPTIONAL,
OUT PHANDLE NewTokenHandle)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @unimplemented
*/
NTSTATUS
NTAPI
NtImpersonateAnonymousToken(IN HANDLE Thread)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/* EOF */