Wine currently runs all processes with an elevated administrator token. As described in bug 40613, some applications refuse to be run with such a token.
This patch set addresses the situation by creating all processes with an unelevated adminstrator token by default. When a process attempts to elevate itself through one of several mechanisms—which would show a UAC prompt on Windows—we instead silently elevate the process, as if the user had granted access through the UAC prompt.
This works for almost all applications. I have found only one application which didn't get the memo, and actually asks the user to right click and run as administrator, namely PaintTool SAI. Fortunately, 063a377df4f, combined with the shell32 patch in this series, allows a Wine user to elevate that process by opening explorer.exe, right-clicking, and selecting Run as Administrator, just like on Windows.
This patch series has been in Wine-Staging for about three years. This was partly to try to find and fix all the different creative ways that applications tried to elevate themselves, but mostly because I needed to find a solution for PaintTool SAI, and never quite got the time to implement run-as-administrator in shell32.
EDIT: Now only includes the patches elevating processes through specific methods (runas, msi).
-- v3: https://gitlab.winehq.org/wine/wine/-/merge_requests/5118
From: Zebediah Figura z.figura12@gmail.com
Like all other verbs, the actual command line template is specified in the registry. The elevation seems to be hardcoded into shell32 for this specific verb.
The Foobar2000 installer requires administrator privileges, and elevates itself in this way.
Based on a patch by Michael Müller.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50727 --- dlls/shell32/shlexec.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c index eb9ca4a06df..f0dbb984103 100644 --- a/dlls/shell32/shlexec.c +++ b/dlls/shell32/shlexec.c @@ -293,6 +293,21 @@ static HRESULT SHELL_GetPathFromIDListForExecuteW(LPCITEMIDLIST pidl, LPWSTR psz return hr; }
+static HANDLE get_admin_token(void) +{ + TOKEN_ELEVATION_TYPE type; + TOKEN_LINKED_TOKEN linked; + DWORD size; + + if (!GetTokenInformation(GetCurrentThreadEffectiveToken(), TokenElevationType, &type, sizeof(type), &size) + || type == TokenElevationTypeFull) + return NULL; + + if (!GetTokenInformation(GetCurrentThreadEffectiveToken(), TokenLinkedToken, &linked, sizeof(linked), &size)) + return NULL; + return linked.LinkedToken; +} + /************************************************************************* * SHELL_ExecuteW [Internal] * @@ -306,6 +321,7 @@ static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait, UINT gcdret = 0; WCHAR curdir[MAX_PATH]; DWORD dwCreationFlags; + HANDLE token = NULL;
TRACE("Execute %s from directory %s\n", debugstr_w(lpCmd), debugstr_w(psei->lpDirectory));
@@ -327,8 +343,12 @@ static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait, dwCreationFlags = CREATE_UNICODE_ENVIRONMENT; if (!(psei->fMask & SEE_MASK_NO_CONSOLE)) dwCreationFlags |= CREATE_NEW_CONSOLE; - if (CreateProcessW(NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, dwCreationFlags, env, - NULL, &startup, &info)) + + if (psei->lpVerb && !wcsicmp(psei->lpVerb, L"runas")) + token = get_admin_token(); + + if (CreateProcessAsUserW(token, NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, + dwCreationFlags, env, NULL, &startup, &info)) { /* Give 30 seconds to the app to come up, if desired. Probably only needed when starting app immediately before making a DDE connection. */ @@ -348,6 +368,8 @@ static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait, retval = ERROR_BAD_FORMAT; }
+ CloseHandle(token); + TRACE("returning %Iu\n", retval);
psei_out->hInstApp = (HINSTANCE)retval;
From: Zebediah Figura z.figura12@gmail.com
This signifies that UAC is active.
Foobar2000 checks this value, and won't even try to elevate itself otherwise.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50727 --- loader/wine.inf.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 35644cbd285..af40ca0260b 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -374,7 +374,7 @@ HKLM,%CurrentVersion%\Explorer\DriveIcons,,16 HKLM,%CurrentVersion%\Explorer\KindMap,,16 HKLM,%CurrentVersion%\Group Policy,,16 HKLM,%CurrentVersion%\Installer,"InstallerLocation",,"%11%" -HKLM,%CurrentVersion%\Policies\System,"EnableLUA",0x10003,0 +HKLM,%CurrentVersion%\Policies\System,"EnableLUA",0x10001,1 HKLM,%CurrentVersion%\PreviewHandlers,,16 HKLM,%CurrentVersion%\Run,,16 HKLM,%CurrentVersion%\Setup,"BootDir",,"%30%"
From: Zebediah Figura z.figura12@gmail.com
Dragon Naturally Speaking 12.5 manually validates that the custom action server is elevated.
One might imagine that the right approach here is to add a manifest to msiexec; however, msiexec does not always trigger a UAC prompt on Windows.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51143 --- dlls/msi/custom.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/dlls/msi/custom.c b/dlls/msi/custom.c index d1e064f5b65..12a7c3c3676 100644 --- a/dlls/msi/custom.c +++ b/dlls/msi/custom.c @@ -573,12 +573,28 @@ UINT CDECL __wine_msi_call_dll_function(DWORD client_pid, const GUID *guid) return r; }
+static HANDLE get_admin_token(void) +{ + TOKEN_ELEVATION_TYPE type; + TOKEN_LINKED_TOKEN linked; + DWORD size; + + if (!GetTokenInformation(GetCurrentThreadEffectiveToken(), TokenElevationType, &type, sizeof(type), &size) + || type == TokenElevationTypeFull) + return NULL; + + if (!GetTokenInformation(GetCurrentThreadEffectiveToken(), TokenLinkedToken, &linked, sizeof(linked), &size)) + return NULL; + return linked.LinkedToken; +} + static DWORD custom_start_server(MSIPACKAGE *package, DWORD arch) { WCHAR path[MAX_PATH], cmdline[MAX_PATH + 23]; PROCESS_INFORMATION pi = {0}; STARTUPINFOW si = {0}; WCHAR buffer[24]; + HANDLE token; void *cookie; HANDLE pipe;
@@ -600,14 +616,18 @@ static DWORD custom_start_server(MSIPACKAGE *package, DWORD arch) lstrcatW(path, L"\msiexec.exe"); swprintf(cmdline, ARRAY_SIZE(cmdline), L"%s -Embedding %d", path, GetCurrentProcessId());
+ token = get_admin_token(); + if (is_wow64 && arch == SCS_64BIT_BINARY) { Wow64DisableWow64FsRedirection(&cookie); - CreateProcessW(path, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + CreateProcessAsUserW(token, path, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); Wow64RevertWow64FsRedirection(cookie); } else - CreateProcessW(path, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + CreateProcessAsUserW(token, path, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + + if (token) CloseHandle(token);
CloseHandle(pi.hThread);
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=143654
Your paranoid android.
=== debian11b (64 bit WoW report) ===
user32: input.c:3864: Test succeeded inside todo block: button_down_hwnd_todo 1: got MSG_TEST_WIN hwnd 00000000023600F2, msg WM_LBUTTONDOWN, wparam 0x1, lparam 0x320032
wldap32: parse.c:417: Test failed: ldap_connect failed 0x51 parse.c:427: Test failed: ldap_set_optionW should fail: 0 parse.c:431: Test failed: ldap_search_sA failed 0x51 parse.c:432: Test failed: expected res != NULL parse.c:602: Test failed: ldap_connect should succeed, got 0x51 parse.c:604: Test failed: ldap_start_tls_sA should fail, got 0x51 parse.c:205: Test failed: ldap_addA should succeed, got 0xffffffff parse.c:207: Test failed: ldap_addA should succeed, got 0xffffffff parse.c:209: Test failed: ldap_addA should succeed, got 0xffffffff parse.c:216: Test failed: ldap_add_sA should fail, got 0x51 parse.c:218: Test failed: ldap_add_sA should fail, got 0x51 parse.c:220: Test failed: ldap_add_sA should fail, got 0x51 parse.c:227: Test failed: ldap_add_extA should succeed, got 0x51 parse.c:229: Test failed: ldap_add_extA should succeed, got 0x51 parse.c:233: Test failed: ldap_add_extA should succeed, got 0x51 parse.c:240: Test failed: ldap_add_ext_sA should fail, got 0x51 parse.c:242: Test failed: ldap_add_ext_sA should fail, got 0x51 parse.c:244: Test failed: ldap_add_ext_sA should fail, got 0x51 parse.c:259: Test failed: ldap_modifyA should succeed, got 0xffffffff parse.c:261: Test failed: ldap_modifyA should succeed, got 0xffffffff parse.c:263: Test failed: ldap_modifyA should succeed, got 0xffffffff parse.c:270: Test failed: ldap_modify_sA should fail, got 0x51 parse.c:272: Test failed: ldap_modify_sA should fail, got 0x51 parse.c:274: Test failed: ldap_modify_sA should fail, got 0x51 parse.c:281: Test failed: ldap_modify_extA should succeed, got 0x51 parse.c:283: Test failed: ldap_modify_extA should succeed, got 0x51 parse.c:287: Test failed: ldap_modify_extA should succeed, got 0x51 parse.c:294: Test failed: ldap_modify_ext_sA should fail, got 0x51 parse.c:296: Test failed: ldap_modify_ext_sA should fail, got 0x51 parse.c:298: Test failed: ldap_modify_ext_sA should fail, got 0x51 parse.c:311: Test failed: ldap_compareA should succeed, got 0xffffffff parse.c:315: Test failed: ldap_compareA should succeed, got 0xffffffff parse.c:317: Test failed: ldap_compareA should succeed, got 0xffffffff parse.c:324: Test failed: ldap_compare_sA should fail, got 0x51 parse.c:328: Test failed: ldap_compare_sA should fail, got 0x51 parse.c:330: Test failed: ldap_compare_sA should fail, got 0x51 parse.c:337: Test failed: ldap_compare_extA should succeed, got 0x51 parse.c:341: Test failed: ldap_compare_extA should succeed, got 0x51 parse.c:343: Test failed: ldap_compare_extA should succeed, got 0x51 parse.c:345: Test failed: ldap_compare_extA should succeed, got 0x51 parse.c:349: Test failed: ldap_compare_extA should succeed, got 0x51 parse.c:356: Test failed: ldap_compare_ext_sA should fail, got 0x51 parse.c:360: Test failed: ldap_compare_ext_sA should fail, got 0x51 parse.c:362: Test failed: ldap_compare_ext_sA should fail, got 0x51 parse.c:364: Test failed: ldap_compare_ext_sA should fail, got 0x51 parse.c:54: Test failed: ldap_create_sort_controlA failed 0x51 Unhandled exception: page fault on read access to 0xffffffffffffffff in 64-bit code (0x006fffffc98fa0).
By request I'm splitting this series in two.