advapi32/tests: Add some tests for token elevation.

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2021-02-16 23:31:10 -06:00 committed by Alexandre Julliard
parent 16955db2aa
commit 133e061244
1 changed files with 263 additions and 0 deletions

View File

@ -8019,6 +8019,268 @@ static void test_GetKernelObjectSecurity(void)
free(sd);
}
static void check_different_token(HANDLE token1, HANDLE token2)
{
TOKEN_STATISTICS stats1, stats2;
DWORD size;
BOOL ret;
ret = GetTokenInformation(token1, TokenStatistics, &stats1, sizeof(stats1), &size);
ok(ret, "got error %u\n", GetLastError());
ret = GetTokenInformation(token2, TokenStatistics, &stats2, sizeof(stats2), &size);
ok(ret, "got error %u\n", GetLastError());
ok(memcmp(&stats1.TokenId, &stats2.TokenId, sizeof(LUID)), "expected different IDs\n");
}
static void test_elevation(void)
{
TOKEN_LINKED_TOKEN linked, linked2;
DWORD orig_type, type, size;
TOKEN_ELEVATION elevation;
HANDLE token, token2;
BOOL ret;
ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | READ_CONTROL | TOKEN_DUPLICATE
| TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_DEFAULT, &token);
ok(ret, "got error %u\n", GetLastError());
ret = GetTokenInformation(token, TokenElevationType, &type, sizeof(type), &size);
ok(ret, "got error %u\n", GetLastError());
orig_type = type;
ret = GetTokenInformation(token, TokenElevation, &elevation, sizeof(elevation), &size);
ok(ret, "got error %u\n", GetLastError());
ret = GetTokenInformation(token, TokenLinkedToken, &linked, sizeof(linked), &size);
if (!ret && GetLastError() == ERROR_NO_SUCH_LOGON_SESSION) /* fails on w2008s64 */
{
win_skip("Failed to get linked token.\n");
CloseHandle(token);
return;
}
todo_wine ok(ret, "got error %u\n", GetLastError());
if (!ret) return;
if (type == TokenElevationTypeDefault)
{
ok(elevation.TokenIsElevated == FALSE, "got elevation %#x\n", elevation.TokenIsElevated);
ok(!linked.LinkedToken, "expected no linked token\n");
}
else if (type == TokenElevationTypeLimited)
{
ok(elevation.TokenIsElevated == FALSE, "got elevation %#x\n", elevation.TokenIsElevated);
ok(!!linked.LinkedToken, "expected a linked token\n");
TEST_GRANTED_ACCESS(linked.LinkedToken, TOKEN_ALL_ACCESS);
ret = GetTokenInformation(linked.LinkedToken, TokenElevationType, &type, sizeof(type), &size);
ok(ret, "got error %u\n", GetLastError());
ok(type == TokenElevationTypeFull, "got type %#x\n", type);
ret = GetTokenInformation(linked.LinkedToken, TokenElevation, &elevation, sizeof(elevation), &size);
ok(ret, "got error %u\n", GetLastError());
ok(elevation.TokenIsElevated == TRUE, "got elevation %#x\n", elevation.TokenIsElevated);
/* Asking for the linked token again gives us a different token. */
ret = GetTokenInformation(token, TokenLinkedToken, &linked2, sizeof(linked2), &size);
ok(ret, "got error %u\n", GetLastError());
ret = GetTokenInformation(linked2.LinkedToken, TokenElevationType, &type, sizeof(type), &size);
ok(ret, "got error %u\n", GetLastError());
ok(type == TokenElevationTypeFull, "got type %#x\n", type);
ret = GetTokenInformation(linked2.LinkedToken, TokenElevation, &elevation, sizeof(elevation), &size);
ok(ret, "got error %u\n", GetLastError());
ok(elevation.TokenIsElevated == TRUE, "got elevation %#x\n", elevation.TokenIsElevated);
check_different_token(linked.LinkedToken, linked2.LinkedToken);
CloseHandle(linked2.LinkedToken);
/* Asking for the linked token's linked token gives us a new limited token. */
ret = GetTokenInformation(linked.LinkedToken, TokenLinkedToken, &linked2, sizeof(linked2), &size);
ok(ret, "got error %u\n", GetLastError());
ret = GetTokenInformation(linked2.LinkedToken, TokenElevationType, &type, sizeof(type), &size);
ok(ret, "got error %u\n", GetLastError());
ok(type == TokenElevationTypeLimited, "got type %#x\n", type);
ret = GetTokenInformation(linked2.LinkedToken, TokenElevation, &elevation, sizeof(elevation), &size);
ok(ret, "got error %u\n", GetLastError());
ok(elevation.TokenIsElevated == FALSE, "got elevation %#x\n", elevation.TokenIsElevated);
check_different_token(token, linked2.LinkedToken);
CloseHandle(linked2.LinkedToken);
CloseHandle(linked.LinkedToken);
type = TokenElevationTypeLimited;
ret = SetTokenInformation(token, TokenElevationType, &type, sizeof(type));
ok(!ret, "expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %u\n", GetLastError());
elevation.TokenIsElevated = FALSE;
ret = SetTokenInformation(token, TokenElevation, &elevation, sizeof(elevation));
ok(!ret, "expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %u\n", GetLastError());
}
else
{
ok(elevation.TokenIsElevated == TRUE, "got elevation %#x\n", elevation.TokenIsElevated);
ok(!!linked.LinkedToken, "expected a linked token\n");
TEST_GRANTED_ACCESS(linked.LinkedToken, TOKEN_ALL_ACCESS);
ret = GetTokenInformation(linked.LinkedToken, TokenElevationType, &type, sizeof(type), &size);
ok(ret, "got error %u\n", GetLastError());
ok(type == TokenElevationTypeLimited, "got type %#x\n", type);
ret = GetTokenInformation(linked.LinkedToken, TokenElevation, &elevation, sizeof(elevation), &size);
ok(ret, "got error %u\n", GetLastError());
ok(elevation.TokenIsElevated == FALSE, "got elevation %#x\n", elevation.TokenIsElevated);
/* Asking for the linked token again gives us a different token. */
ret = GetTokenInformation(token, TokenLinkedToken, &linked2, sizeof(linked2), &size);
ok(ret, "got error %u\n", GetLastError());
ret = GetTokenInformation(linked2.LinkedToken, TokenElevationType, &type, sizeof(type), &size);
ok(ret, "got error %u\n", GetLastError());
ok(type == TokenElevationTypeLimited, "got type %#x\n", type);
ret = GetTokenInformation(linked2.LinkedToken, TokenElevation, &elevation, sizeof(elevation), &size);
ok(ret, "got error %u\n", GetLastError());
ok(elevation.TokenIsElevated == FALSE, "got elevation %#x\n", elevation.TokenIsElevated);
check_different_token(linked.LinkedToken, linked2.LinkedToken);
CloseHandle(linked2.LinkedToken);
/* Asking for the linked token's linked token gives us a new elevated token. */
ret = GetTokenInformation(linked.LinkedToken, TokenLinkedToken, &linked2, sizeof(linked2), &size);
ok(ret, "got error %u\n", GetLastError());
ret = GetTokenInformation(linked2.LinkedToken, TokenElevationType, &type, sizeof(type), &size);
ok(ret, "got error %u\n", GetLastError());
ok(type == TokenElevationTypeFull, "got type %#x\n", type);
ret = GetTokenInformation(linked2.LinkedToken, TokenElevation, &elevation, sizeof(elevation), &size);
ok(ret, "got error %u\n", GetLastError());
ok(elevation.TokenIsElevated == TRUE, "got elevation %#x\n", elevation.TokenIsElevated);
check_different_token(token, linked2.LinkedToken);
CloseHandle(linked2.LinkedToken);
CloseHandle(linked.LinkedToken);
type = TokenElevationTypeLimited;
ret = SetTokenInformation(token, TokenElevationType, &type, sizeof(type));
ok(!ret, "expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %u\n", GetLastError());
elevation.TokenIsElevated = FALSE;
ret = SetTokenInformation(token, TokenElevation, &elevation, sizeof(elevation));
ok(!ret, "expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %u\n", GetLastError());
}
ret = DuplicateTokenEx(token, TOKEN_ALL_ACCESS, NULL, SecurityAnonymous, TokenPrimary, &token2);
ok(ret, "got error %u\n", GetLastError());
ret = GetTokenInformation(token2, TokenElevationType, &type, sizeof(type), &size);
ok(ret, "got error %u\n", GetLastError());
ok(type == orig_type, "expected same type\n");
ret = GetTokenInformation(token2, TokenElevation, &elevation, sizeof(elevation), &size);
ok(ret, "got error %u\n", GetLastError());
ok(elevation.TokenIsElevated == (type == TokenElevationTypeFull), "got elevation %#x\n", elevation.TokenIsElevated);
ret = GetTokenInformation(token2, TokenLinkedToken, &linked, sizeof(linked), &size);
ok(ret, "got error %u\n", GetLastError());
if (type == TokenElevationTypeDefault)
ok(!linked.LinkedToken, "expected no linked token\n");
else
ok(!!linked.LinkedToken, "expected a linked token\n");
CloseHandle(linked.LinkedToken);
CloseHandle(token2);
ret = CreateRestrictedToken(token, 0, 0, NULL, 0, NULL, 0, NULL, &token2);
ok(ret, "got error %u\n", GetLastError());
ret = GetTokenInformation(token2, TokenElevationType, &type, sizeof(type), &size);
ok(ret, "got error %u\n", GetLastError());
ok(type == orig_type, "expected same type\n");
ret = GetTokenInformation(token2, TokenElevation, &elevation, sizeof(elevation), &size);
ok(ret, "got error %u\n", GetLastError());
ok(elevation.TokenIsElevated == (type == TokenElevationTypeFull), "got elevation %#x\n", elevation.TokenIsElevated);
ret = GetTokenInformation(token2, TokenLinkedToken, &linked, sizeof(linked), &size);
ok(ret, "got error %u\n", GetLastError());
if (type == TokenElevationTypeDefault)
ok(!linked.LinkedToken, "expected no linked token\n");
else
ok(!!linked.LinkedToken, "expected a linked token\n");
CloseHandle(linked.LinkedToken);
CloseHandle(token2);
if (type != TokenElevationTypeDefault)
{
char prev_privs_buffer[128], acl_buffer[256], prev_acl_buffer[256];
TOKEN_PRIVILEGES privs, *prev_privs = (TOKEN_PRIVILEGES *)prev_privs_buffer;
TOKEN_DEFAULT_DACL *prev_acl = (TOKEN_DEFAULT_DACL *)prev_acl_buffer;
TOKEN_DEFAULT_DACL *ret_acl = (TOKEN_DEFAULT_DACL *)acl_buffer;
TOKEN_DEFAULT_DACL default_acl;
PRIVILEGE_SET priv_set;
BOOL ret, is_member;
DWORD size;
ACL acl;
/* Linked tokens do not preserve privilege modifications. */
privs.PrivilegeCount = 1;
ret = LookupPrivilegeValueA(NULL, "SeChangeNotifyPrivilege", &privs.Privileges[0].Luid);
ok(ret, "got error %u\n", GetLastError());
privs.Privileges[0].Attributes = SE_PRIVILEGE_REMOVED;
ret = AdjustTokenPrivileges(token, FALSE, &privs, sizeof(prev_privs_buffer), prev_privs, &size);
ok(ret, "got error %u\n", GetLastError());
priv_set.PrivilegeCount = 1;
priv_set.Control = 0;
priv_set.Privilege[0] = privs.Privileges[0];
ret = PrivilegeCheck(token, &priv_set, &is_member);
ok(ret, "got error %u\n", GetLastError());
ok(!is_member, "not a member\n");
ret = GetTokenInformation(token, TokenLinkedToken, &linked, sizeof(linked), &size);
ok(ret, "got error %u\n", GetLastError());
ret = PrivilegeCheck(linked.LinkedToken, &priv_set, &is_member);
ok(ret, "got error %u\n", GetLastError());
ok(is_member, "not a member\n");
CloseHandle(linked.LinkedToken);
ret = AdjustTokenPrivileges(token, FALSE, prev_privs, 0, NULL, NULL);
ok(ret, "got error %u\n", GetLastError());
/* Linked tokens do not preserve default DACL modifications. */
ret = GetTokenInformation(token, TokenDefaultDacl, prev_acl, sizeof(prev_acl_buffer), &size);
ok(ret, "got error %u\n", GetLastError());
ok(prev_acl->DefaultDacl->AceCount, "expected non-empty default DACL\n");
InitializeAcl(&acl, sizeof(acl), ACL_REVISION);
default_acl.DefaultDacl = &acl;
ret = SetTokenInformation(token, TokenDefaultDacl, &default_acl, sizeof(default_acl));
ok(ret, "got error %u\n", GetLastError());
ret = GetTokenInformation(token, TokenDefaultDacl, ret_acl, sizeof(acl_buffer), &size);
ok(ret, "got error %u\n", GetLastError());
ok(!ret_acl->DefaultDacl->AceCount, "expected empty default DACL\n");
ret = GetTokenInformation(token, TokenLinkedToken, &linked, sizeof(linked), &size);
ok(ret, "got error %u\n", GetLastError());
ret = GetTokenInformation(linked.LinkedToken, TokenDefaultDacl, ret_acl, sizeof(acl_buffer), &size);
ok(ret, "got error %u\n", GetLastError());
ok(ret_acl->DefaultDacl->AceCount, "expected non-empty default DACL\n");
CloseHandle(linked.LinkedToken);
ret = SetTokenInformation(token, TokenDefaultDacl, prev_acl, sizeof(*prev_acl));
ok(ret, "got error %u\n", GetLastError());
}
CloseHandle(token);
}
START_TEST(security)
{
init();
@ -8086,6 +8348,7 @@ START_TEST(security)
test_pseudo_handle_security();
test_duplicate_token();
test_GetKernelObjectSecurity();
test_elevation();
/* Must be the last test, modifies process token */
test_token_security_descriptor();