I use Java JNA to execute Windows API commands.
I have a background service running as local-system. From this background service, I'd like to spawn a new process, e.g. notepad.exe on the currently active desktop and user. The new process should not run elevated but with the active logged-in users rights.
I use
- WTSGetActiveConsoleSessionId to get the active session
- WTSQueryUserToken to get the related token
- CreateProcessAsUser to start the process
This works fine if I build a jar and launch the jar with java -jar my.jar from the local-system account.
However, I run the code from an Install4j Installer, which is, more or less, a JVM wrapped in an exe. The same code fails now, and CreateProcessAsUser results in error code 5 (no access)
- I compared the tokens, and could not find any difference. Same user, owner, groups, and privileges.
- I tried using process monitor to find anything special: nothing
- I tried to use CreateProcessWithTokenW instead of CreateProcessAsUser. The process launches but exits immediately(Maybe a Windowstation/Desktop issue)
Expected result: The "child" process starts and shows the UI on the currently active desktop.
Actual result: Errorcode 5 on CreateProcessAsUser
final PROCESS_INFORMATION processInformation = new PROCESS_INFORMATION();
final int activeConsoleSessionId = Kernel32Ext.INSTANCE.WTSGetActiveConsoleSessionId();
final PointerByReference userPrimaryProcessToken = new PointerByReference();
if (!Wtsapi32Ext.INSTANCE.WTSQueryUserToken(activeConsoleSessionId, userPrimaryProcessToken)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
final STARTUPINFO startupInfo = new STARTUPINFO();
startupInfo.clear();
startupInfo.lpDesktop = "winsta0\\default";
startupInfo.wShowWindow = new WORD(1);
startupInfo.cb = new DWORD(processInformation.size());
final String cmdString = "C:\\Windows\\System32\\notepad.exe";
if (!AdvapiExt.INSTANCE.CreateProcessAsUser(new HANDLE(userPrimaryProcessToken.getValue()), null, cmdString, null, null, true, Kernel32.CREATE_UNICODE_ENVIRONMENT, null, "c:\\", startupInfo, processInformation)) {
final int error = Kernel32.INSTANCE.GetLastError();
throw new Win32Exception(error);
}
This is not a real answer, but after a system restart and windows updates, I cannot reproduce the problem anymore. If I ever manage to reproduce it again, I will continue the investigation.
A few things a noticed before the problem "disappeared":
1. Before updating windows, I enabled the program execution audit(local security policies), and saw in the windows logs, that, according to the logs, the application got started, even there was no window or running process, and the CreateProcessAsUser returned with an error...
2. The problem did only happen if services.exe was in the calling-chain. If I started the application directly via psexe as a local system process, everything went fine.