From: Tim Clem tclem@codeweavers.com
--- dlls/advapi32/tests/security.c | 38 ++++++++++++++++++++++++++++++++++ dlls/kernelbase/security.c | 6 ++++-- dlls/ntdll/unix/security.c | 4 ++-- server/protocol.def | 3 ++- server/token.c | 9 +++++++- 5 files changed, 54 insertions(+), 6 deletions(-)
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index 0917b144648..b51f359a84c 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c @@ -28,6 +28,7 @@ #include "winbase.h" #include "winerror.h" #include "winternl.h" +#include "winuser.h" #include "aclapi.h" #include "winnt.h" #include "sddl.h" @@ -8537,6 +8538,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]; @@ -8683,6 +8720,7 @@ START_TEST(security) test_AccessCheck(); test_token_attr(); test_GetTokenInformation(); + test_admin_elevation(); test_LookupAccountSid(); test_LookupAccountName(); test_security_descriptor(); diff --git a/dlls/kernelbase/security.c b/dlls/kernelbase/security.c index 1dd975a7aad..dcf361882df 100644 --- a/dlls/kernelbase/security.c +++ b/dlls/kernelbase/security.c @@ -704,8 +704,8 @@ BOOL WINAPI DuplicateTokenEx( HANDLE token, DWORD access, LPSECURITY_ATTRIBUTES BOOL WINAPI GetTokenInformation( HANDLE token, TOKEN_INFORMATION_CLASS class, LPVOID info, DWORD len, LPDWORD retlen ) { - TRACE("(%p, %s, %p, %ld, %p):\n", - token, + TRACE("(%p, %d [%s], %p, %ld, %p):\n", + token, class, (class == TokenUser) ? "TokenUser" : (class == TokenGroups) ? "TokenGroups" : (class == TokenPrivileges) ? "TokenPrivileges" : @@ -721,6 +721,8 @@ BOOL WINAPI GetTokenInformation( HANDLE token, TOKEN_INFORMATION_CLASS class, (class == TokenGroupsAndPrivileges) ? "TokenGroupsAndPrivileges" : (class == TokenSessionReference) ? "TokenSessionReference" : (class == TokenSandBoxInert) ? "TokenSandBoxInert" : + (class == TokenElevation) ? "TokenElevation" : + (class == TokenElevationType) ? "TokenElevationType" : "Unknown", info, len, retlen);
diff --git a/dlls/ntdll/unix/security.c b/dlls/ntdll/unix/security.c index 03cf26c1555..956c0ec4723 100644 --- a/dlls/ntdll/unix/security.c +++ b/dlls/ntdll/unix/security.c @@ -516,7 +516,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; @@ -528,7 +528,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 a7a89724d31..a4de7cf5ed9 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3743,7 +3743,8 @@ typedef union 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 698b2627ccb..ab3f4b1b5f7 100644 --- a/server/token.c +++ b/server/token.c @@ -1554,7 +1554,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 );