我有一个以 mydomain\userA 身份运行的 Windows 服务。我希望能够从服务运行任意 .exe。通常,我使用 Process.Start() 并且它工作正常,但在某些情况下我想以不同的用户(mydomain\userB)运行可执行文件。
如果我更改用于启动进程的 ProcessStartInfo 以包含凭据,我就会开始收到错误 - 要么出现错误对话框,显示“应用程序无法正确初始化 (0xc0000142)。单击“确定”终止应用程序。”,要么出现错误消息“访问被拒绝”Win32Exception。如果我从命令行运行进程启动代码而不是在服务中运行它,则进程将使用正确的凭据启动(我已通过将 ProcessStartInfo 设置为运行 whoami.exe 并捕获命令行输出来验证这一点)。
我还尝试过使用 WindowsIdentity.Impersonate() 进行模拟,但这并没有起作用 - 据我了解,模拟仅影响当前线程,并且启动新进程会继承进程的安全描述符,而不是当前线程。
我在一个隔离的测试域中运行它,因此 userA 和 userB 都是域管理员,并且都具有域范围内的“作为服务登录”权限。
当您使用 ProcessStartInfo 启动新进程时,该进程将在与启动进程相同的窗口站和桌面中启动。如果您使用不同的凭据,那么用户通常没有足够的权限在该桌面上运行。当 user32.dll 尝试在新进程中初始化但无法初始化时,会导致初始化失败错误。
要解决此问题,您必须首先检索与窗口站和桌面关联的安全描述符,并为您的用户向 DACL 添加适当的权限,然后在新凭据下启动您的进程。
编辑:关于如何执行此操作的详细描述和示例代码在这里有点长,所以我整理了一个article与代码。
//The following security adjustments are necessary to give the new
//process sufficient permission to run in the service's window station
//and desktop. This uses classes from the AsproLock library also from
//Asprosys.
IntPtr hWinSta = GetProcessWindowStation();
WindowStationSecurity ws = new WindowStationSecurity(hWinSta,
System.Security.AccessControl.AccessControlSections.Access);
ws.AddAccessRule(new WindowStationAccessRule("LaunchProcessUser",
WindowStationRights.AllAccess, System.Security.AccessControl.AccessControlType.Allow));
ws.AcceptChanges();
IntPtr hDesk = GetThreadDesktop(GetCurrentThreadId());
DesktopSecurity ds = new DesktopSecurity(hDesk,
System.Security.AccessControl.AccessControlSections.Access);
ds.AddAccessRule(new DesktopAccessRule("LaunchProcessUser",
DesktopRights.AllAccess, System.Security.AccessControl.AccessControlType.Allow));
ds.AcceptChanges();
EventLog.WriteEntry("Launching application.", EventLogEntryType.Information);
using (Process process = Process.Start(psi))
{
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)