Skip lpDesktop=winsta0\default for SpecificUser launches
Setting lpDesktop on STARTUPINFO forces the child to open that desktop; the LogonUser-derived token in SpecificUser mode usually cannot, since winsta0\default's DACL only grants the currently-logged-in user. The result was STATUS_DLL_INIT_FAILED (exit 0xC0000142) with empty stdio. Only InteractiveUser mode needs the explicit interactive desktop - that whole point of the mode is to land in the user's session. For SpecificUser, leaving lpDesktop null lets the child inherit our service desktop, which works for headless batch tasks (AD reads, file ops, etc.). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -57,7 +57,7 @@ internal static class InteractiveProcessLauncher
|
|||||||
if (!WTSQueryUserToken(sessionId, out var userToken))
|
if (!WTSQueryUserToken(sessionId, out var userToken))
|
||||||
throw LastError("WTSQueryUserToken (must run as SYSTEM)");
|
throw LastError("WTSQueryUserToken (must run as SYSTEM)");
|
||||||
|
|
||||||
try { return LaunchWithToken(userToken, opts); }
|
try { return LaunchWithToken(userToken, opts, useInteractiveDesktop: true); }
|
||||||
finally { CloseHandle(userToken); }
|
finally { CloseHandle(userToken); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ internal static class InteractiveProcessLauncher
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try { return LaunchWithToken(token, opts); }
|
try { return LaunchWithToken(token, opts, useInteractiveDesktop: false); }
|
||||||
finally { CloseHandle(token); }
|
finally { CloseHandle(token); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ internal static class InteractiveProcessLauncher
|
|||||||
return domain;
|
return domain;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LaunchResult LaunchWithToken(IntPtr sourceToken, LaunchOptions opts)
|
private static LaunchResult LaunchWithToken(IntPtr sourceToken, LaunchOptions opts, bool useInteractiveDesktop)
|
||||||
{
|
{
|
||||||
IntPtr primaryToken = IntPtr.Zero;
|
IntPtr primaryToken = IntPtr.Zero;
|
||||||
IntPtr envBlock = IntPtr.Zero;
|
IntPtr envBlock = IntPtr.Zero;
|
||||||
@@ -127,7 +127,10 @@ internal static class InteractiveProcessLauncher
|
|||||||
hStdInput = stdinRead,
|
hStdInput = stdinRead,
|
||||||
hStdOutput = stdoutWrite,
|
hStdOutput = stdoutWrite,
|
||||||
hStdError = stderrWrite,
|
hStdError = stderrWrite,
|
||||||
lpDesktop = @"winsta0\default",
|
// For InteractiveUser we explicitly target the logged-in user's desktop.
|
||||||
|
// For SpecificUser the LogonUser-derived token typically can't open that
|
||||||
|
// DACL; leave lpDesktop null and let the new process inherit ours.
|
||||||
|
lpDesktop = useInteractiveDesktop ? @"winsta0\default" : null,
|
||||||
};
|
};
|
||||||
|
|
||||||
var commandLine = BuildCommandLine(opts.FileName, opts.Arguments);
|
var commandLine = BuildCommandLine(opts.FileName, opts.Arguments);
|
||||||
|
|||||||
Reference in New Issue
Block a user