Skip to content

Commit

Permalink
Refactoring UAC support so prunsrv does not always require elevation
Browse files Browse the repository at this point in the history
  • Loading branch information
markt-asf committed May 17, 2024
1 parent 19bedd3 commit 7219698
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 10 deletions.
4 changes: 4 additions & 0 deletions src/changes/changes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
92 changes: 86 additions & 6 deletions src/native/windows/apps/prunsrv/prunsrv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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))
Expand All @@ -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;
Expand Down Expand Up @@ -2095,7 +2175,7 @@ void __cdecl main(int argc, char **argv)
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
Expand Down
4 changes: 0 additions & 4 deletions src/native/windows/apps/prunsrv/prunsrv.manifest
Original file line number Diff line number Diff line change
Expand Up @@ -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>

0 comments on commit 7219698

Please sign in to comment.