This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-daemon.git
The following commit(s) were added to refs/heads/master by this push: new 7219698 Refactoring UAC support so prunsrv does not always require elevation 7219698 is described below commit 7219698dfff088f12560970dd2d4468232a666fd Author: Mark Thomas <ma...@apache.org> AuthorDate: Fri May 17 13:16:44 2024 +0100 Refactoring UAC support so prunsrv does not always require elevation --- src/changes/changes.xml | 4 ++ src/native/windows/apps/prunsrv/prunsrv.c | 92 ++++++++++++++++++++++-- src/native/windows/apps/prunsrv/prunsrv.manifest | 4 -- 3 files changed, 90 insertions(+), 10 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 72d0b51..42515da 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -58,6 +58,10 @@ <action issue="DAEMON-463" dev="markt" type="fix" due-to="michaelo"> jsvc. Fix compilation issue with newer compilers. </action> + <action dev="markt" type="fix"> + Procrun. Refactor UAC support so that elevation is only requested for + actions that require administrator privileges. + </action> <!-- Add --> <action type="add" dev="markt"> Procrun. Add support for hybrid CRT builds. diff --git a/src/native/windows/apps/prunsrv/prunsrv.c b/src/native/windows/apps/prunsrv/prunsrv.c index c4dc990..10323d4 100644 --- a/src/native/windows/apps/prunsrv/prunsrv.c +++ b/src/native/windows/apps/prunsrv/prunsrv.c @@ -1936,6 +1936,64 @@ BOOL docmdRunService(LPAPXCMDLINE lpCmdline) return rv; } +BOOL isRunningAsAdministrator(BOOL *bElevated) { + BOOL rv = FALSE; + HANDLE hToken; + TOKEN_ELEVATION tokenInformation; + DWORD dwSize; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { + goto cleanup; + } + + if (!GetTokenInformation(hToken, TokenElevation, &tokenInformation, sizeof(tokenInformation), &dwSize)) { + goto cleanup; + } + + *bElevated = tokenInformation.TokenIsElevated; + rv = TRUE; + +cleanup: + if (hToken) { + CloseHandle(hToken); + } + return rv; +} + +BOOL restartCurrentProcessWithElevation(DWORD *dwExitCode) { + BOOL rv = FALSE; + TCHAR szPath[MAX_PATH]; + SHELLEXECUTEINFO shellExecuteInfo; + + SetLastError(0); + GetModuleFileName(NULL, szPath, MAX_PATH); + if (GetLastError()) { + goto cleanup; + } + + shellExecuteInfo.cbSize = sizeof(SHELLEXECUTEINFO); + shellExecuteInfo.fMask = SEE_MASK_NOCLOSEPROCESS; + shellExecuteInfo.hwnd = NULL; + shellExecuteInfo.lpVerb = L"runas"; + shellExecuteInfo.lpFile = szPath; + shellExecuteInfo.lpParameters = PathGetArgs(GetCommandLine()); + shellExecuteInfo.lpDirectory = NULL; + shellExecuteInfo.nShow = SW_SHOWNORMAL; + shellExecuteInfo.hInstApp = NULL; + + if (!ShellExecuteEx(&shellExecuteInfo)) { + goto cleanup; + } + WaitForSingleObject(shellExecuteInfo.hProcess, INFINITE); + GetExitCodeProcess(shellExecuteInfo.hProcess, dwExitCode); + + rv = TRUE; + +cleanup: + return rv; +} + + static const char *gSzProc[] = { "", "parse command line arguments", @@ -2039,6 +2097,28 @@ void __cdecl main(int argc, char **argv) t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); } + + if (lpCmdline->dwCmdIndex > 2 && lpCmdline->dwCmdIndex < 8) { + /* Command requires elevation */ + BOOL bElevated; + if (!isRunningAsAdministrator(&bElevated)) { + apxDisplayError(FALSE, NULL, 0, "Unable to determine if process has administrator privileges. Continuing as if it has.\n"); + } else { + if (!bElevated) { + DWORD dwExitCode; + if (!restartCurrentProcessWithElevation(&dwExitCode)) { + apxDisplayError(FALSE, NULL, 0, "Failed to elevate current process.\n"); + rv = lpCmdline->dwCmdIndex + 2; + } else { + if (dwExitCode) { + apxDisplayError(FALSE, NULL, 0, "Running from a command prompt with administrative privileges may show further error details.\n"); + } + rv = dwExitCode; + } + goto cleanup; + } + } + } switch (lpCmdline->dwCmdIndex) { case 1: /* Run Service as console application */ if (!docmdDebugService(lpCmdline)) @@ -2048,23 +2128,23 @@ void __cdecl main(int argc, char **argv) if (!docmdRunService(lpCmdline)) rv = 4; break; - case 3: /* Start service */ + case 3: /* Start service - requires elevation */ if (!docmdStartService(lpCmdline)) rv = 5; break; - case 4: /* Stop Service */ + case 4: /* Stop Service - requires elevation */ if (!docmdStopService(lpCmdline)) rv = 6; break; - case 5: /* Update Service parameters */ + case 5: /* Update Service parameters - requires elevation */ if (!docmdUpdateService(lpCmdline)) rv = 7; break; - case 6: /* Install Service */ + case 6: /* Install Service - requires elevation */ if (!docmdInstallService(lpCmdline)) rv = 8; break; - case 7: /* Delete Service */ + case 7: /* Delete Service - requires elevation */ if (!docmdDeleteService(lpCmdline)) rv = 9; break; @@ -2095,7 +2175,7 @@ cleanup: rv, gSzProc[ix]); if (ix > 2 && !_service_mode) { /* Print something to the user console */ - apxDisplayError(FALSE, NULL, 0, "Failed to %s.", gSzProc[ix]); + apxDisplayError(FALSE, NULL, 0, "Failed to %s.\n", gSzProc[ix]); } } else diff --git a/src/native/windows/apps/prunsrv/prunsrv.manifest b/src/native/windows/apps/prunsrv/prunsrv.manifest index 204a914..431c5d1 100644 --- a/src/native/windows/apps/prunsrv/prunsrv.manifest +++ b/src/native/windows/apps/prunsrv/prunsrv.manifest @@ -25,10 +25,6 @@ </dependency> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> -<!-- Windows UAC support --> -<requestedPrivileges> -<requestedExecutionLevel level="requireAdministrator" uiAccess="false"></requestedExecutionLevel> -</requestedPrivileges> </security> </trustInfo> </assembly>