mirror of
https://gitlab.winehq.org/wine/wine.git
synced 2024-11-21 17:09:06 -07:00
Merge branch 'mr/default-explorer-token' into 'master'
explorer, services: Use admin tokens when appropriate. See merge request wine/wine!6602
This commit is contained in:
commit
bb3a7726ba
11 changed files with 113 additions and 21 deletions
|
@ -28,6 +28,7 @@
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
#include "winerror.h"
|
#include "winerror.h"
|
||||||
#include "winternl.h"
|
#include "winternl.h"
|
||||||
|
#include "winuser.h"
|
||||||
#include "aclapi.h"
|
#include "aclapi.h"
|
||||||
#include "winnt.h"
|
#include "winnt.h"
|
||||||
#include "sddl.h"
|
#include "sddl.h"
|
||||||
|
@ -8571,6 +8572,42 @@ static void test_elevation(void)
|
||||||
CloseHandle(token);
|
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)
|
static void test_group_as_file_owner(void)
|
||||||
{
|
{
|
||||||
char sd_buffer[200], sid_buffer[100];
|
char sd_buffer[200], sid_buffer[100];
|
||||||
|
@ -8717,6 +8754,7 @@ START_TEST(security)
|
||||||
test_AccessCheck();
|
test_AccessCheck();
|
||||||
test_token_attr();
|
test_token_attr();
|
||||||
test_GetTokenInformation();
|
test_GetTokenInformation();
|
||||||
|
test_admin_elevation();
|
||||||
test_LookupAccountSid();
|
test_LookupAccountSid();
|
||||||
test_LookupAccountName();
|
test_LookupAccountName();
|
||||||
test_security_descriptor();
|
test_security_descriptor();
|
||||||
|
|
|
@ -704,8 +704,8 @@ BOOL WINAPI DuplicateTokenEx( HANDLE token, DWORD access, LPSECURITY_ATTRIBUTES
|
||||||
BOOL WINAPI GetTokenInformation( HANDLE token, TOKEN_INFORMATION_CLASS class,
|
BOOL WINAPI GetTokenInformation( HANDLE token, TOKEN_INFORMATION_CLASS class,
|
||||||
LPVOID info, DWORD len, LPDWORD retlen )
|
LPVOID info, DWORD len, LPDWORD retlen )
|
||||||
{
|
{
|
||||||
TRACE("(%p, %s, %p, %ld, %p):\n",
|
TRACE("(%p, %d [%s], %p, %ld, %p):\n",
|
||||||
token,
|
token, class,
|
||||||
(class == TokenUser) ? "TokenUser" :
|
(class == TokenUser) ? "TokenUser" :
|
||||||
(class == TokenGroups) ? "TokenGroups" :
|
(class == TokenGroups) ? "TokenGroups" :
|
||||||
(class == TokenPrivileges) ? "TokenPrivileges" :
|
(class == TokenPrivileges) ? "TokenPrivileges" :
|
||||||
|
@ -721,6 +721,8 @@ BOOL WINAPI GetTokenInformation( HANDLE token, TOKEN_INFORMATION_CLASS class,
|
||||||
(class == TokenGroupsAndPrivileges) ? "TokenGroupsAndPrivileges" :
|
(class == TokenGroupsAndPrivileges) ? "TokenGroupsAndPrivileges" :
|
||||||
(class == TokenSessionReference) ? "TokenSessionReference" :
|
(class == TokenSessionReference) ? "TokenSessionReference" :
|
||||||
(class == TokenSandBoxInert) ? "TokenSandBoxInert" :
|
(class == TokenSandBoxInert) ? "TokenSandBoxInert" :
|
||||||
|
(class == TokenElevation) ? "TokenElevation" :
|
||||||
|
(class == TokenElevationType) ? "TokenElevationType" :
|
||||||
"Unknown",
|
"Unknown",
|
||||||
info, len, retlen);
|
info, len, retlen);
|
||||||
|
|
||||||
|
|
|
@ -1837,6 +1837,19 @@ NTSTATUS WINAPI NtSetInformationProcess( HANDLE handle, PROCESSINFOCLASS class,
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
case ProcessWineSetAdminToken:
|
||||||
|
SERVER_START_REQ( create_primary_admin_token )
|
||||||
|
{
|
||||||
|
if (!(ret = wine_server_call( req )))
|
||||||
|
{
|
||||||
|
HANDLE token = wine_server_ptr_handle( reply->token );
|
||||||
|
PROCESS_ACCESS_TOKEN info = { .Token = token, .Thread = NULL };
|
||||||
|
ret = NtSetInformationProcess( handle, ProcessAccessToken, &info, sizeof(info) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SERVER_END_REQ;
|
||||||
|
return ret;
|
||||||
|
|
||||||
case ProcessPowerThrottlingState:
|
case ProcessPowerThrottlingState:
|
||||||
FIXME( "ProcessPowerThrottlingState - stub\n" );
|
FIXME( "ProcessPowerThrottlingState - stub\n" );
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
|
|
@ -516,7 +516,7 @@ NTSTATUS WINAPI NtQueryInformationToken( HANDLE token, TOKEN_INFORMATION_CLASS c
|
||||||
|
|
||||||
req->handle = wine_server_obj_handle( token );
|
req->handle = wine_server_obj_handle( token );
|
||||||
status = wine_server_call( req );
|
status = wine_server_call( req );
|
||||||
if (!status) *type = reply->elevation;
|
if (!status) *type = reply->elevation_type;
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
break;
|
break;
|
||||||
|
@ -528,7 +528,7 @@ NTSTATUS WINAPI NtQueryInformationToken( HANDLE token, TOKEN_INFORMATION_CLASS c
|
||||||
|
|
||||||
req->handle = wine_server_obj_handle( token );
|
req->handle = wine_server_obj_handle( token );
|
||||||
status = wine_server_call( req );
|
status = wine_server_call( req );
|
||||||
if (!status) elevation->TokenIsElevated = (reply->elevation == TokenElevationTypeFull);
|
if (!status) elevation->TokenIsElevated = reply->is_elevated;
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -765,8 +765,7 @@ HWND get_desktop_window(void)
|
||||||
static const WCHAR system_dir[] = {'C',':','\\','w','i','n','d','o','w','s','\\',
|
static const WCHAR system_dir[] = {'C',':','\\','w','i','n','d','o','w','s','\\',
|
||||||
's','y','s','t','e','m','3','2','\\',0};
|
's','y','s','t','e','m','3','2','\\',0};
|
||||||
RTL_USER_PROCESS_PARAMETERS params = { sizeof(params), sizeof(params) };
|
RTL_USER_PROCESS_PARAMETERS params = { sizeof(params), sizeof(params) };
|
||||||
ULONG_PTR buffer[offsetof( PS_ATTRIBUTE_LIST, Attributes[2] ) / sizeof(ULONG_PTR)];
|
PS_ATTRIBUTE_LIST ps_attr;
|
||||||
PS_ATTRIBUTE_LIST *ps_attr = (PS_ATTRIBUTE_LIST *)buffer;
|
|
||||||
PS_CREATE_INFO create_info;
|
PS_CREATE_INFO create_info;
|
||||||
WCHAR desktop[MAX_PATH];
|
WCHAR desktop[MAX_PATH];
|
||||||
PEB *peb = NtCurrentTeb()->Peb;
|
PEB *peb = NtCurrentTeb()->Peb;
|
||||||
|
@ -799,30 +798,24 @@ HWND get_desktop_window(void)
|
||||||
RtlInitUnicodeString( ¶ms.WindowTitle, appnameW + 4 );
|
RtlInitUnicodeString( ¶ms.WindowTitle, appnameW + 4 );
|
||||||
RtlInitUnicodeString( ¶ms.Desktop, desktop );
|
RtlInitUnicodeString( ¶ms.Desktop, desktop );
|
||||||
|
|
||||||
ps_attr->Attributes[0].Attribute = PS_ATTRIBUTE_IMAGE_NAME;
|
ps_attr.TotalLength = sizeof(ps_attr);
|
||||||
ps_attr->Attributes[0].Size = sizeof(appnameW) - sizeof(WCHAR);
|
ps_attr.Attributes[0].Attribute = PS_ATTRIBUTE_IMAGE_NAME;
|
||||||
ps_attr->Attributes[0].ValuePtr = (WCHAR *)appnameW;
|
ps_attr.Attributes[0].Size = sizeof(appnameW) - sizeof(WCHAR);
|
||||||
ps_attr->Attributes[0].ReturnLength = NULL;
|
ps_attr.Attributes[0].ValuePtr = (WCHAR *)appnameW;
|
||||||
|
ps_attr.Attributes[0].ReturnLength = NULL;
|
||||||
ps_attr->Attributes[1].Attribute = PS_ATTRIBUTE_TOKEN;
|
|
||||||
ps_attr->Attributes[1].Size = sizeof(HANDLE);
|
|
||||||
ps_attr->Attributes[1].ValuePtr = GetCurrentThreadEffectiveToken();
|
|
||||||
ps_attr->Attributes[1].ReturnLength = NULL;
|
|
||||||
|
|
||||||
ps_attr->TotalLength = offsetof( PS_ATTRIBUTE_LIST, Attributes[2] );
|
|
||||||
|
|
||||||
if (NtCurrentTeb64() && !NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR])
|
if (NtCurrentTeb64() && !NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR])
|
||||||
{
|
{
|
||||||
NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR] = TRUE;
|
NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR] = TRUE;
|
||||||
status = NtCreateUserProcess( &process, &thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS,
|
status = NtCreateUserProcess( &process, &thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS,
|
||||||
NULL, NULL, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED, ¶ms,
|
NULL, NULL, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED, ¶ms,
|
||||||
&create_info, ps_attr );
|
&create_info, &ps_attr );
|
||||||
NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR] = FALSE;
|
NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR] = FALSE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
status = NtCreateUserProcess( &process, &thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS,
|
status = NtCreateUserProcess( &process, &thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS,
|
||||||
NULL, NULL, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED, ¶ms,
|
NULL, NULL, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED, ¶ms,
|
||||||
&create_info, ps_attr );
|
&create_info, &ps_attr );
|
||||||
if (!status)
|
if (!status)
|
||||||
{
|
{
|
||||||
NtResumeThread( thread, NULL );
|
NtResumeThread( thread, NULL );
|
||||||
|
|
|
@ -872,6 +872,7 @@ NTSTATUS WINAPI wow64_NtSetInformationProcess( UINT *args )
|
||||||
case ProcessPagePriority: /* MEMORY_PRIORITY_INFORMATION */
|
case ProcessPagePriority: /* MEMORY_PRIORITY_INFORMATION */
|
||||||
case ProcessPowerThrottlingState: /* PROCESS_POWER_THROTTLING_STATE */
|
case ProcessPowerThrottlingState: /* PROCESS_POWER_THROTTLING_STATE */
|
||||||
case ProcessLeapSecondInformation: /* PROCESS_LEAP_SECOND_INFO */
|
case ProcessLeapSecondInformation: /* PROCESS_LEAP_SECOND_INFO */
|
||||||
|
case ProcessWineSetAdminToken: /* NULL */
|
||||||
return NtSetInformationProcess( handle, class, ptr, len );
|
return NtSetInformationProcess( handle, class, ptr, len );
|
||||||
|
|
||||||
case ProcessAccessToken: /* PROCESS_ACCESS_TOKEN */
|
case ProcessAccessToken: /* PROCESS_ACCESS_TOKEN */
|
||||||
|
|
|
@ -1897,6 +1897,7 @@ typedef enum _PROCESSINFOCLASS {
|
||||||
#ifdef __WINESRC__
|
#ifdef __WINESRC__
|
||||||
ProcessWineMakeProcessSystem = 1000,
|
ProcessWineMakeProcessSystem = 1000,
|
||||||
ProcessWineLdtCopy,
|
ProcessWineLdtCopy,
|
||||||
|
ProcessWineSetAdminToken,
|
||||||
#endif
|
#endif
|
||||||
} PROCESSINFOCLASS;
|
} PROCESSINFOCLASS;
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#define COBJMACROS
|
#define COBJMACROS
|
||||||
#define OEMRESOURCE
|
#define OEMRESOURCE
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <winternl.h>
|
||||||
#include <rpc.h>
|
#include <rpc.h>
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
|
@ -1208,6 +1209,7 @@ void manage_desktop( WCHAR *arg )
|
||||||
HMODULE shell32;
|
HMODULE shell32;
|
||||||
HANDLE thread;
|
HANDLE thread;
|
||||||
DWORD id;
|
DWORD id;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
/* get the rest of the command line (if any) */
|
/* get the rest of the command line (if any) */
|
||||||
while (*p && !is_whitespace(*p)) p++;
|
while (*p && !is_whitespace(*p)) p++;
|
||||||
|
@ -1260,6 +1262,10 @@ void manage_desktop( WCHAR *arg )
|
||||||
SetThreadDesktop( desktop );
|
SetThreadDesktop( desktop );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* the desktop process should always have an admin token */
|
||||||
|
status = NtSetInformationProcess( GetCurrentProcess(), ProcessWineSetAdminToken, NULL, 0 );
|
||||||
|
if (status) WARN( "couldn't set admin token for desktop, error %08lx\n", status );
|
||||||
|
|
||||||
/* create the desktop window */
|
/* create the desktop window */
|
||||||
hwnd = CreateWindowExW( 0, DESKTOP_CLASS_ATOM, NULL,
|
hwnd = CreateWindowExW( 0, DESKTOP_CLASS_ATOM, NULL,
|
||||||
WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 0, 0, 0, 0, 0, &guid );
|
WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 0, 0, 0, 0, 0, &guid );
|
||||||
|
|
|
@ -1279,6 +1279,13 @@ int __cdecl main(int argc, char *argv[])
|
||||||
JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info;
|
JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info;
|
||||||
HANDLE started_event, process_monitor_thread;
|
HANDLE started_event, process_monitor_thread;
|
||||||
DWORD err;
|
DWORD err;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
/* FIXME: Until we start honoring each service's lpServiceStartName, we want
|
||||||
|
services to inherit a default admin token. */
|
||||||
|
status = NtSetInformationProcess( GetCurrentProcess(), ProcessWineSetAdminToken, NULL, 0 );
|
||||||
|
if (status)
|
||||||
|
WARN( "couldn't set admin token, error %08lx\n", status );
|
||||||
|
|
||||||
job_object = CreateJobObjectW(NULL, NULL);
|
job_object = CreateJobObjectW(NULL, NULL);
|
||||||
job_limit.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
|
job_limit.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
|
||||||
|
|
|
@ -3305,6 +3305,13 @@ enum caret_state
|
||||||
@END
|
@END
|
||||||
|
|
||||||
|
|
||||||
|
/* Create a new primary admin token with Default elevation. */
|
||||||
|
@REQ(create_primary_admin_token)
|
||||||
|
@REPLY
|
||||||
|
obj_handle_t token; /* handle to the token */
|
||||||
|
@END
|
||||||
|
|
||||||
|
|
||||||
/* Open a security token */
|
/* Open a security token */
|
||||||
@REQ(open_token)
|
@REQ(open_token)
|
||||||
obj_handle_t handle; /* handle to the thread or process */
|
obj_handle_t handle; /* handle to the thread or process */
|
||||||
|
@ -3762,7 +3769,8 @@ typedef union
|
||||||
unsigned int session_id; /* token session id */
|
unsigned int session_id; /* token session id */
|
||||||
int primary; /* is the token primary or impersonation? */
|
int primary; /* is the token primary or impersonation? */
|
||||||
int impersonation_level; /* level of 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 group_count; /* the number of groups the token is a member of */
|
||||||
int privilege_count; /* the number of privileges the token has */
|
int privilege_count; /* the number of privileges the token has */
|
||||||
@END
|
@END
|
||||||
|
|
|
@ -1209,6 +1209,22 @@ DECL_HANDLER(create_token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* create a new primary admin token with Default elevation */
|
||||||
|
DECL_HANDLER(create_primary_admin_token)
|
||||||
|
{
|
||||||
|
struct token *token = token_create_admin( TRUE, SecurityIdentification,
|
||||||
|
TokenElevationTypeDefault, default_session_id );
|
||||||
|
if (!token)
|
||||||
|
{
|
||||||
|
set_error( STATUS_UNSUCCESSFUL );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reply->token = alloc_handle( current->process, token, TOKEN_ALL_ACCESS, 0 );
|
||||||
|
release_object( token );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* open a security token */
|
/* open a security token */
|
||||||
DECL_HANDLER(open_token)
|
DECL_HANDLER(open_token)
|
||||||
{
|
{
|
||||||
|
@ -1538,7 +1554,14 @@ DECL_HANDLER(get_token_info)
|
||||||
reply->session_id = token->session_id;
|
reply->session_id = token->session_id;
|
||||||
reply->primary = token->primary;
|
reply->primary = token->primary;
|
||||||
reply->impersonation_level = token->impersonation_level;
|
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->group_count = list_count( &token->groups );
|
||||||
reply->privilege_count = list_count( &token->privileges );
|
reply->privilege_count = list_count( &token->privileges );
|
||||||
release_object( token );
|
release_object( token );
|
||||||
|
|
Loading…
Reference in a new issue