From: Katharina Bogad <katharina@hacked.xyz> Calling CreateProcessAsUserW with a token that has session_id != 0 set should result in the program being started on the token's assoiciated desktop. Currently, WINE doesn't handle multiple users and multiple winstations, so for the moment, if the associated token has a session_id != 0, overwrite the desktop to the default value. This allows serivces started with session_id 0 running non-interactively to get a session_id from wtsapi32 belonging to an interactive session and use CreateProcessAsUserW to open child processes in an interactive environment. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58588 --- dlls/kernelbase/process.c | 27 ++++++++++++++++++++++++++- server/winstation.c | 19 ++++++++++++++++--- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 3656e40280d..d7cd32a4944 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -519,6 +519,11 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR ULONG nt_flags = 0; USHORT machine = 0; NTSTATUS status; + DWORD dwSessionId = 0; + DWORD dwReturnLength; + STARTUPINFOW local_startup_info; + BOOL success; + /* Process the AppName and/or CmdLine to get module name and path */ @@ -541,6 +546,26 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR app_name = name; } + /* Fixup startupinfo->lpDesktop if needed */ + + memcpy(&local_startup_info, startup_info, sizeof(STARTUPINFOW)); + if(token != NULL) + { + success = GetTokenInformation(token, TokenSessionId, &dwSessionId, sizeof(dwSessionId), &dwReturnLength); + + TRACE("success = %u, dwSessionId = %lu\n", success, dwSessionId); + + + if (success && dwSessionId != 0) + { + /* the created process should be attached to an interactive session. + * So we override the winstation for this process. */ + FIXME( "Child process will be started with default desktop\n"); + + local_startup_info.lpDesktop = (WCHAR*)L"winsta0\\default"; + } + } + /* Warn if unsupported features are used */ if (flags & (IDLE_PRIORITY_CLASS | HIGH_PRIORITY_CLASS | REALTIME_PRIORITY_CLASS | @@ -560,7 +585,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR info->hThread = info->hProcess = 0; info->dwProcessId = info->dwThreadId = 0; - if (!(params = create_process_params( app_name, tidy_cmdline, cur_dir, env, flags, startup_info ))) + if (!(params = create_process_params( app_name, tidy_cmdline, cur_dir, env, flags, &local_startup_info ))) { status = STATUS_NO_MEMORY; goto done; diff --git a/server/winstation.c b/server/winstation.c index f6793f3ebba..a9dde71930e 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -500,12 +500,13 @@ void set_process_default_desktop( struct process *process, struct desktop *deskt void connect_process_winstation( struct process *process, struct unicode_str *desktop_path, struct thread *parent_thread, struct process *parent_process ) { - struct unicode_str desktop_name = *desktop_path, winstation_name = {0}; + struct unicode_str desktop_name = *desktop_path, winstation_name = {0}, root_name = {0}, full_winstation_name = {0}; const int attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF; struct winstation *winstation = NULL; struct desktop *desktop = NULL; const WCHAR *wch, *end; obj_handle_t handle; + char ascii_root[50]; /* len of root path + len(str(2**32)) + 4 (to be safe) */ for (wch = desktop_name.str, end = wch + desktop_name.len / sizeof(WCHAR); wch != end; wch++) { @@ -524,9 +525,20 @@ void connect_process_winstation( struct process *process, struct unicode_str *de { winstation = (struct winstation *)get_handle_obj( process, handle, 0, &winstation_ops ); } - else if (winstation_name.len && (winstation = open_named_object( NULL, &winstation_ops, &winstation_name, attributes ))) + else if (winstation_name.len) { - handle = alloc_handle( process, winstation, STANDARD_RIGHTS_REQUIRED | WINSTA_ALL_ACCESS, 0 ); + snprintf(ascii_root, sizeof(ascii_root), "\\Sessions\\%u\\Windows\\WindowStations\\", process->session_id); + ascii_to_unicode_str(ascii_root, &root_name); + + full_winstation_name.len = root_name.len + winstation_name.len; + full_winstation_name.str = malloc(full_winstation_name.len + 2); + memcpy((void*)full_winstation_name.str, root_name.str, root_name.len); + memcpy((void*)(full_winstation_name.str + root_name.len / sizeof(WCHAR)), winstation_name.str, winstation_name.len); + + if((winstation = open_named_object( NULL, &winstation_ops, &full_winstation_name, attributes ))) + { + handle = alloc_handle( process, winstation, STANDARD_RIGHTS_REQUIRED | WINSTA_ALL_ACCESS, 0 ); + } } else if (parent_process->winstation) { @@ -563,6 +575,7 @@ void connect_process_winstation( struct process *process, struct unicode_str *de } if (handle) set_process_default_desktop( process, desktop, handle ); + done: if (desktop) release_object( desktop ); if (winstation) release_object( winstation ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9843