When queried by NtQueryInformationToken(TokenElevation).
---
As the test shows, a TokenElevation query is more complex than a check against the elevation type.
GOG Galaxy's updater relies on this behavior when its service is launched with a TokenElevationTypeDefault token (which doesn't currently happen, but I have patches in the works for that).
From: Tim Clem tclem@codeweavers.com
When queried by NtQueryInformationToken(TokenElevation). --- dlls/advapi32/tests/security.c | 37 ++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/security.c | 4 ++-- server/protocol.def | 3 ++- server/token.c | 9 ++++++++- 4 files changed, 49 insertions(+), 4 deletions(-)
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index 319d7b20bd6..f21778587d8 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c @@ -8561,6 +8561,42 @@ static void test_elevation(void) CloseHandle(token); }
+static void test_admin_elevation(void) +{ + /* Tokens with elevation type TokenElevationTypeDefault should still come + back as elevated from a TokenElevation query if they belong to the admin + group. The owner of the desktop window should have such a token. */ + DWORD tid, pid; + HANDLE hproc, htok; + TOKEN_ELEVATION_TYPE elevation_type; + TOKEN_ELEVATION elevation; + DWORD size; + BOOL ret; + + tid = GetWindowThreadProcessId(GetDesktopWindow(), &pid); + ok(tid, "got error %lu\n", GetLastError()); + + hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); + ok(hproc != NULL, "got error %lu\n", GetLastError()); + + ret = OpenProcessToken(hproc, TOKEN_READ, &htok); + ok(ret, "got error %lu\n", GetLastError()); + + CloseHandle(hproc); + + size = sizeof(elevation_type); + ret = GetTokenInformation(htok, TokenElevationType, &elevation_type, size, &size); + ok(ret, "got error %lu\n", GetLastError()); + ok(elevation_type == TokenElevationTypeDefault, "unexpected elevation type %d\n", elevation_type); + + size = sizeof(elevation); + ret = GetTokenInformation(htok, TokenElevation, &elevation, size, &size); + ok(ret, "got error %lu\n", GetLastError()); + ok(elevation.TokenIsElevated, "expected token to be elevated\n"); + + CloseHandle(htok); +} + static void test_group_as_file_owner(void) { char sd_buffer[200], sid_buffer[100]; @@ -8747,6 +8783,7 @@ START_TEST(security) test_duplicate_token(); test_GetKernelObjectSecurity(); test_elevation(); + test_admin_elevation(); test_group_as_file_owner(); test_IsValidSecurityDescriptor(); test_window_security(); diff --git a/dlls/ntdll/unix/security.c b/dlls/ntdll/unix/security.c index b355909a01b..84e71154585 100644 --- a/dlls/ntdll/unix/security.c +++ b/dlls/ntdll/unix/security.c @@ -575,7 +575,7 @@ NTSTATUS WINAPI NtQueryInformationToken( HANDLE token, TOKEN_INFORMATION_CLASS c
req->handle = wine_server_obj_handle( token ); status = wine_server_call( req ); - if (!status) *type = reply->elevation; + if (!status) *type = reply->elevation_type; } SERVER_END_REQ; break; @@ -587,7 +587,7 @@ NTSTATUS WINAPI NtQueryInformationToken( HANDLE token, TOKEN_INFORMATION_CLASS c
req->handle = wine_server_obj_handle( token ); status = wine_server_call( req ); - if (!status) elevation->TokenIsElevated = (reply->elevation == TokenElevationTypeFull); + if (!status) elevation->TokenIsElevated = reply->is_elevated; } SERVER_END_REQ; break; diff --git a/server/protocol.def b/server/protocol.def index 8bfce724756..016c0e125dd 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3781,7 +3781,8 @@ struct handle_info unsigned int session_id; /* token session id */ int primary; /* is the token primary or impersonation? */ int impersonation_level; /* level of impersonation */ - int elevation; /* elevation type */ + int elevation_type; /* elevation type (TokenElevation*) */ + int is_elevated; /* is the token elevated as per GetTokenInformation(TokenElevation) */ int group_count; /* the number of groups the token is a member of */ int privilege_count; /* the number of privileges the token has */ @END diff --git a/server/token.c b/server/token.c index 7e20c670a16..3cdb9e5be5f 100644 --- a/server/token.c +++ b/server/token.c @@ -1540,7 +1540,14 @@ DECL_HANDLER(get_token_info) reply->session_id = token->session_id; reply->primary = token->primary; reply->impersonation_level = token->impersonation_level; - reply->elevation = token->elevation; + reply->elevation_type = token->elevation; + /* Tokens with TokenElevationTypeDefault are considered elevated for the + purposes of GetTokenInformation(TokenElevation) if they belong to the + admins group. */ + if (token->elevation == TokenElevationTypeDefault) + reply->is_elevated = token_sid_present( token, &builtin_admins_sid, FALSE ); + else + reply->is_elevated = token->elevation == TokenElevationTypeFull; reply->group_count = list_count( &token->groups ); reply->privilege_count = list_count( &token->privileges ); release_object( token );
advapi32 test failures on Windows are unrelated - see, e.g., [the pipeline for this MR](https://gitlab.winehq.org/piotr/wine/-/pipelines/40951).