Search code examples
windowswinapiservice

CreateProcessAsUser with elevated privileges


My service is running under local system permissions, and needs to start an application with administrator permissions in the user session.

What I got is:

  1. WTSGetActiveConsoleSessionID()
  2. WTSQueryUserToken for session ID
  3. CreateProcessAsUser

The problem is I need to run the process (Step 3) as an administrator, without asking the user for the administrator's password.

On Linux systems I would simply do a "su ", but to achieve this on a Windows system?


Solution

  • I've finally found the solution to manage this:

    public void launchProcessInUserSession(String process) throws WindowsAPIException {
    
            final DWORD interactiveSessionId = kernel32.WTSGetActiveConsoleSessionId();
            final DWORD serviceSessionId = getCurrentSessionId();
    
            final HANDLEByReference pExecutionToken = new HANDLEByReference();
    
            final HANDLE currentProcessToken = getCurrentProcessToken();
            try {
    
                final HANDLE interactiveUserToken = getUserToken(interactiveSessionId);
    
                checkAPIError(advapi32.DuplicateTokenEx(currentProcessToken, WinNT.TOKEN_ALL_ACCESS, null, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
                        WinNT.TOKEN_TYPE.TokenPrimary, pExecutionToken));
            } finally {
                kernel32.CloseHandle(currentProcessToken);
            }
    
            final HANDLE executionToken = pExecutionToken.getValue();
            try {
                checkAPIError(advapi32.SetTokenInformation(executionToken, TOKEN_INFORMATION_CLASS.TokenSessionId, new IntByReference(interactiveSessionId.intValue()), DWORD.SIZE));
    
                final WinBase.STARTUPINFO si = new WinBase.STARTUPINFO();
                final PROCESS_INFORMATION processInfo = new WinBase.PROCESS_INFORMATION();
                final int dwFlags = WinBase.DETACHED_PROCESS;
    
                checkAPIError(advapi32.CreateProcessAsUser(executionToken, null, process, null, null, false, dwFlags, null, null, si, processInfo));
                LOGGER.debug("Execution done. Process ID is {}", processInfo.dwProcessId);
            } finally {
                kernel32.CloseHandle(executionToken);
            }
        }