Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/advapi32/tests/security.c | 257 +++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+)
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index 604d70ca34d..1cd6e3ccbdc 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c @@ -8019,6 +8019,262 @@ 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); + 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 +8342,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();