https://git.reactos.org/?p=reactos.git;a=commitdiff;h=39003dd408a605b4e66f1b...
commit 39003dd408a605b4e66f1b040c7333b52e4d8158 Author: George Bișoc george.bisoc@reactos.org AuthorDate: Sat Oct 23 13:55:02 2021 +0200 Commit: George Bișoc george.bisoc@reactos.org CommitDate: Sun Nov 7 14:22:20 2021 +0100
[ADVAPI32] Properly implement CreateRestrictedToken
Instead of duplicating the token and masquerade it as if the token was filtered (which is a big hack), properly implement CreateRestrictedToken function by calling NtFilterToken which it'll create a restricted token for us. --- dll/win32/advapi32/wine/security.c | 209 +++++++++++++++++++++++++++++-------- 1 file changed, 166 insertions(+), 43 deletions(-)
diff --git a/dll/win32/advapi32/wine/security.c b/dll/win32/advapi32/wine/security.c index 449cbd354b4..5651a92276a 100644 --- a/dll/win32/advapi32/wine/security.c +++ b/dll/win32/advapi32/wine/security.c @@ -481,56 +481,179 @@ SetThreadToken(IN PHANDLE ThreadHandle OPTIONAL, return TRUE; }
-/************************************************************************* - * CreateRestrictedToken [ADVAPI32.@] +/** + * @brief + * Creates a filtered token that is a restricted one + * of the regular access token. A restricted token + * can have disabled SIDs, deleted privileges and/or + * restricted SIDs added. * - * Create a new more restricted token from an existing token. + * @param[in] ExistingTokenHandle + * An existing handle to a token where it's to be + * filtered. * - * PARAMS - * baseToken [I] Token to base the new restricted token on - * flags [I] Options - * nDisableSids [I] Length of disableSids array - * disableSids [I] Array of SIDs to disable in the new token - * nDeletePrivs [I] Length of deletePrivs array - * deletePrivs [I] Array of privileges to delete in the new token - * nRestrictSids [I] Length of restrictSids array - * restrictSids [I] Array of SIDs to restrict in the new token - * newToken [O] Address where the new token is stored + * @param[in] Flags + * Privilege flag options. This parameter argument influences how the token + * is filtered. Such parameter can be 0. * - * RETURNS - * Success: TRUE - * Failure: FALSE + * @param[in] DisableSidCount + * The count number of SIDs to disable. + * + * @param[in] SidsToDisable + * An array list with SIDs that have to be disabled in + * a token. + * + * @param[in] DeletePrivilegeCount + * The count number of privileges to be deleted. + * + * @param[in] PrivilegesToDelete + * An array list with privileges that have to be deleted + * in a token. + * + * @param[in] RestrictedSidCount + * The count number of restricted SIDs. + * + * @param[in] SidsToRestrict + * An array list with restricted SIDs to be added into + * the token. If the token already has restricted SIDs + * then the array provided by the caller is redundant + * information alongside with the existing restricted + * SIDs in the token. + * + * @param[out] NewTokenHandle + * The newly received handle to a restricted (filtered) + * token. The caller can use such handle to duplicate + * a new token. + * + * @return + * Returns TRUE if the function has successfully completed + * the operations, otherwise FALSE is returned to indicate + * failure. For further details the caller has to invoke + * GetLastError() API call for extended information + * about the failure. */ BOOL WINAPI CreateRestrictedToken( - HANDLE baseToken, - DWORD flags, - DWORD nDisableSids, - PSID_AND_ATTRIBUTES disableSids, - DWORD nDeletePrivs, - PLUID_AND_ATTRIBUTES deletePrivs, - DWORD nRestrictSids, - PSID_AND_ATTRIBUTES restrictSids, - PHANDLE newToken) -{ - TOKEN_TYPE type; - SECURITY_IMPERSONATION_LEVEL level = SecurityAnonymous; - DWORD size; - - FIXME("(%p, 0x%x, %u, %p, %u, %p, %u, %p, %p): stub\n", - baseToken, flags, nDisableSids, disableSids, - nDeletePrivs, deletePrivs, - nRestrictSids, restrictSids, - newToken); - - size = sizeof(type); - if (!GetTokenInformation( baseToken, TokenType, &type, size, &size )) return FALSE; - if (type == TokenImpersonation) - { - size = sizeof(level); - if (!GetTokenInformation( baseToken, TokenImpersonationLevel, &level, size, &size )) + _In_ HANDLE ExistingTokenHandle, + _In_ DWORD Flags, + _In_ DWORD DisableSidCount, + _In_reads_opt_(DisableSidCount) PSID_AND_ATTRIBUTES SidsToDisable, + _In_ DWORD DeletePrivilegeCount, + _In_reads_opt_(DeletePrivilegeCount) PLUID_AND_ATTRIBUTES PrivilegesToDelete, + _In_ DWORD RestrictedSidCount, + _In_reads_opt_(RestrictedSidCount) PSID_AND_ATTRIBUTES SidsToRestrict, + _Outptr_ PHANDLE NewTokenHandle) +{ + NTSTATUS Status; + BOOL Success; + ULONG Index; + PTOKEN_GROUPS DisableSids = NULL; + PTOKEN_GROUPS RestrictedSids = NULL; + PTOKEN_PRIVILEGES DeletePrivileges = NULL; + + /* + * Capture the elements we're being given from + * the caller and allocate the groups and/or + * privileges that have to be filtered in + * the token. + */ + if (SidsToDisable != NULL) + { + DisableSids = (PTOKEN_GROUPS)LocalAlloc(LMEM_FIXED, DisableSidCount * sizeof(TOKEN_GROUPS)); + if (DisableSids == NULL) + { + /* We failed, bail out */ + SetLastError(RtlNtStatusToDosError(STATUS_INSUFFICIENT_RESOURCES)); return FALSE; + } + + /* Copy the counter and loop the elements to copy the rest */ + DisableSids->GroupCount = DisableSidCount; + for (Index = 0; Index < DisableSidCount; Index++) + { + DisableSids->Groups[Index].Sid = SidsToDisable[Index].Sid; + DisableSids->Groups[Index].Attributes = SidsToDisable[Index].Attributes; + } + } + + if (PrivilegesToDelete != NULL) + { + DeletePrivileges = (PTOKEN_PRIVILEGES)LocalAlloc(LMEM_FIXED, DeletePrivilegeCount * sizeof(TOKEN_PRIVILEGES)); + if (DeletePrivileges == NULL) + { + /* We failed, bail out */ + SetLastError(RtlNtStatusToDosError(STATUS_INSUFFICIENT_RESOURCES)); + Success = FALSE; + goto Cleanup; + } + + /* Copy the counter and loop the elements to copy the rest */ + DeletePrivileges->PrivilegeCount = DeletePrivilegeCount; + for (Index = 0; Index < DeletePrivilegeCount; Index++) + { + DeletePrivileges->Privileges[Index].Luid = PrivilegesToDelete[Index].Luid; + DeletePrivileges->Privileges[Index].Attributes = PrivilegesToDelete[Index].Attributes; + } } - return DuplicateTokenEx( baseToken, MAXIMUM_ALLOWED, NULL, level, type, newToken ); + + if (SidsToRestrict != NULL) + { + RestrictedSids = (PTOKEN_GROUPS)LocalAlloc(LMEM_FIXED, RestrictedSidCount * sizeof(TOKEN_GROUPS)); + if (RestrictedSids == NULL) + { + /* We failed, bail out */ + SetLastError(RtlNtStatusToDosError(STATUS_INSUFFICIENT_RESOURCES)); + Success = FALSE; + goto Cleanup; + } + + /* Copy the counter and loop the elements to copy the rest */ + RestrictedSids->GroupCount = RestrictedSidCount; + for (Index = 0; Index < RestrictedSidCount; Index++) + { + RestrictedSids->Groups[Index].Sid = SidsToRestrict[Index].Sid; + RestrictedSids->Groups[Index].Attributes = SidsToRestrict[Index].Attributes; + } + } + + /* + * Call the NT API to request a token filtering + * operation for us. + */ + Status = NtFilterToken(ExistingTokenHandle, + Flags, + DisableSids, + DeletePrivileges, + RestrictedSids, + NewTokenHandle); + if (!NT_SUCCESS(Status)) + { + /* We failed to do the job, bail out */ + SetLastError(RtlNtStatusToDosError(Status)); + Success = FALSE; + goto Cleanup; + } + + /* If we reach here then we've successfully filtered the token */ + Success = TRUE; + +Cleanup: + /* Free whatever we allocated before */ + if (DisableSids != NULL) + { + LocalFree(DisableSids); + } + + if (DeletePrivileges != NULL) + { + LocalFree(DeletePrivileges); + } + + if (RestrictedSids != NULL) + { + LocalFree(RestrictedSids); + } + + return Success; }
/******************************************************************************