我有一个以mydomain \ userA身份运行的Windows服务。我希望能够从服务中运行任意.exes。通常,我使用Process.Start()并且它工作正常,但在某些情况下,我想以不同的用户(mydomain \ userB)运行可执行文件。
如果我更改了ProcessStartInfo,我用来启动进程以包含凭据,我开始收到错误 - 错误对话框显示“应用程序无法正确初始化(0xc0000142)。单击确定以终止应用程序。” ,或“访问被拒绝”Win32Exception。如果我从命令行运行进程启动代码而不是在服务中运行它,则进程将使用正确的凭据开始(我已通过设置ProcessStartInfo来运行whoami.exe并捕获命令行输出来验证这一点) )。
我也尝试使用WindowsIdentity.Impersonate()进行模拟,但这没有用 - 据我理解,模拟只会影响当前线程,启动新进程会继承进程的安全描述符,而不是当前的线程。
我在一个独立的测试域中运行它,因此userA和userB都是域管理员,并且两者都在域范围内具有“作为服务登录”。
答案 0 :(得分:17)
使用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))
{
}
答案 1 :(得分:10)
使用Process
类启动的新进程与启动进程在同一窗口站和桌面中运行。如果您使用不同的凭据运行新进程,则新进程将无权访问窗口站和桌面。什么导致错误,如0xC0000142。
以下是" compact"独立代码,授予用户访问当前窗口站和桌面的权限。它不需要AsproLock库。
public static void GrantAccessToWindowStationAndDesktop(string username)
{
IntPtr handle;
const int WindowStationAllAccess = 0x000f037f;
handle = GetProcessWindowStation();
GrantAccess(username, handle, WindowStationAllAccess);
const int DesktopRightsAllAccess = 0x000f01ff;
handle = GetThreadDesktop(GetCurrentThreadId());
GrantAccess(username, handle, DesktopRightsAllAccess);
}
private static void GrantAccess(string username, IntPtr handle, int accessMask)
{
SafeHandle safeHandle = new NoopSafeHandle(handle);
GenericSecurity security =
new GenericSecurity(
false, ResourceType.WindowObject, safeHandle, AccessControlSections.Access);
security.AddAccessRule(
new GenericAccessRule(
new NTAccount(username), accessMask, AccessControlType.Allow));
security.Persist(safeHandle, AccessControlSections.Access);
}
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr GetProcessWindowStation();
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr GetThreadDesktop(int dwThreadId);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern int GetCurrentThreadId();
// All the code to manipulate a security object is available in .NET framework,
// but its API tries to be type-safe and handle-safe, enforcing a special implementation
// (to an otherwise generic WinAPI) for each handle type. This is to make sure
// only a correct set of permissions can be set for corresponding object types and
// mainly that handles do not leak.
// Hence the AccessRule and the NativeObjectSecurity classes are abstract.
// This is the simplest possible implementation that yet allows us to make use
// of the existing .NET implementation, sparing necessity to
// P/Invoke the underlying WinAPI.
private class GenericAccessRule : AccessRule
{
public GenericAccessRule(
IdentityReference identity, int accessMask, AccessControlType type) :
base(identity, accessMask, false, InheritanceFlags.None,
PropagationFlags.None, type)
{
}
}
private class GenericSecurity : NativeObjectSecurity
{
public GenericSecurity(
bool isContainer, ResourceType resType, SafeHandle objectHandle,
AccessControlSections sectionsRequested)
: base(isContainer, resType, objectHandle, sectionsRequested)
{
}
new public void Persist(SafeHandle handle, AccessControlSections includeSections)
{
base.Persist(handle, includeSections);
}
new public void AddAccessRule(AccessRule rule)
{
base.AddAccessRule(rule);
}
#region NativeObjectSecurity Abstract Method Overrides
public override Type AccessRightType
{
get { throw new NotImplementedException(); }
}
public override AccessRule AccessRuleFactory(
System.Security.Principal.IdentityReference identityReference,
int accessMask, bool isInherited, InheritanceFlags inheritanceFlags,
PropagationFlags propagationFlags, AccessControlType type)
{
throw new NotImplementedException();
}
public override Type AccessRuleType
{
get { return typeof(AccessRule); }
}
public override AuditRule AuditRuleFactory(
System.Security.Principal.IdentityReference identityReference, int accessMask,
bool isInherited, InheritanceFlags inheritanceFlags,
PropagationFlags propagationFlags, AuditFlags flags)
{
throw new NotImplementedException();
}
public override Type AuditRuleType
{
get { return typeof(AuditRule); }
}
#endregion
}
// Handles returned by GetProcessWindowStation and GetThreadDesktop should not be closed
private class NoopSafeHandle : SafeHandle
{
public NoopSafeHandle(IntPtr handle) :
base(handle, false)
{
}
public override bool IsInvalid
{
get { return false; }
}
protected override bool ReleaseHandle()
{
return true;
}
}
答案 2 :(得分:3)
根据@Stephen Martin和Martin Prikryl的回答。
此代码可帮助您使用服务中的不同用户凭据运行流程 我现在已经优化了源代码 现在也可以删除和设置权利。
namespace QlikConnectorPSExecute
{
#region Usings
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Principal;
#endregion
//inspired by: http://stackoverflow.com/questions/677874/starting-a-process-with-credentials-from-a-windows-service
public class WindowsGrandAccess : IDisposable
{
#region DLL-Import
// All the code to manipulate a security object is available in .NET framework,
// but its API tries to be type-safe and handle-safe, enforcing a special implementation
// (to an otherwise generic WinAPI) for each handle type. This is to make sure
// only a correct set of permissions can be set for corresponding object types and
// mainly that handles do not leak.
// Hence the AccessRule and the NativeObjectSecurity classes are abstract.
// This is the simplest possible implementation that yet allows us to make use
// of the existing .NET implementation, sparing necessity to
// P/Invoke the underlying WinAPI.
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr GetProcessWindowStation();
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr GetThreadDesktop(int dwThreadId);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern int GetCurrentThreadId();
#endregion
#region Variables && Properties
public static int WindowStationAllAccess { get; private set; } = 0x000f037f;
public static int DesktopRightsAllAccess { get; private set; } = 0x000f01ff;
private GenericSecurity WindowStationSecurity {get; set;}
private GenericSecurity DesktopSecurity { get; set; }
private int? OldWindowStationMask { get; set; }
private int? OldDesktopMask { get; set; }
private NTAccount AccountInfo { get; set; }
private SafeHandle WsSafeHandle { get; set; }
private SafeHandle DSafeHandle { get; set; }
#endregion
#region Constructor & Dispose
public WindowsGrandAccess(NTAccount accountInfo, int windowStationMask, int desktopMask)
{
if (accountInfo != null)
Init(accountInfo, windowStationMask, desktopMask);
}
public void Dispose()
{
try
{
if (AccountInfo == null)
return;
RestAccessMask(OldWindowStationMask, WindowStationAllAccess, WindowStationSecurity, WsSafeHandle);
RestAccessMask(OldDesktopMask, DesktopRightsAllAccess, DesktopSecurity, DSafeHandle);
}
catch (Exception ex)
{
throw new Exception($"The object \"{nameof(WindowsGrandAccess)}\" could not be dispose.", ex);
}
}
#endregion
#region Methods
private void Init(NTAccount accountInfo, int windowStationMask, int desktopMask)
{
AccountInfo = accountInfo;
WsSafeHandle = new NoopSafeHandle(GetProcessWindowStation());
WindowStationSecurity = new GenericSecurity(false, ResourceType.WindowObject, WsSafeHandle, AccessControlSections.Access);
DSafeHandle = new NoopSafeHandle(GetThreadDesktop(GetCurrentThreadId()));
DesktopSecurity = new GenericSecurity(false, ResourceType.WindowObject, DSafeHandle, AccessControlSections.Access);
OldWindowStationMask = ReadAccessMask(WindowStationSecurity, WsSafeHandle, windowStationMask);
OldDesktopMask = ReadAccessMask(DesktopSecurity, DSafeHandle, desktopMask);
}
private AuthorizationRuleCollection GetAccessRules(GenericSecurity security)
{
return security.GetAccessRules(true, false, typeof(NTAccount));
}
private int? ReadAccessMask(GenericSecurity security, SafeHandle safeHandle, int accessMask)
{
var ruels = GetAccessRules(security);
var username = AccountInfo.Value;
if (!username.Contains("\\"))
username = $"{Environment.MachineName}\\{username}";
var userResult = ruels.Cast<GrantAccessRule>().SingleOrDefault(r => r.IdentityReference.Value.ToLower() == username.ToLower() && accessMask == r.PublicAccessMask);
if (userResult == null)
{
AddGrandAccess(security, accessMask, safeHandle);
userResult = ruels.Cast<GrantAccessRule>().SingleOrDefault(r => r.IdentityReference.Value.ToLower() == username.ToLower());
if (userResult != null)
return userResult.PublicAccessMask;
}
else
return userResult.PublicAccessMask;
return null;
}
private void AddGrandAccess(GenericSecurity security, int accessMask, SafeHandle safeHandle)
{
var rule = new GrantAccessRule(AccountInfo, accessMask, AccessControlType.Allow);
security.AddAccessRule(rule);
security.Persist(safeHandle, AccessControlSections.Access);
}
private void RemoveGrantAccess(GenericSecurity security, int accessMask, SafeHandle safeHandle)
{
var rule = new GrantAccessRule(AccountInfo, accessMask, AccessControlType.Allow);
security.RemoveAccessRule(rule);
security.Persist(safeHandle, AccessControlSections.Access);
}
private void SetGrandAccess(GenericSecurity security, int accessMask, SafeHandle safeHandle)
{
var rule = new GrantAccessRule(AccountInfo, accessMask, AccessControlType.Allow);
security.SetAccessRule(rule);
security.Persist(safeHandle, AccessControlSections.Access);
}
private void RestAccessMask(int? oldAccessMask, int fullAccessMask, GenericSecurity security, SafeHandle safeHandle)
{
if (oldAccessMask == null)
RemoveGrantAccess(security, fullAccessMask, safeHandle);
else if (oldAccessMask != fullAccessMask)
{
SetGrandAccess(security, oldAccessMask.Value, safeHandle);
}
}
#endregion
#region private classes
private class GenericSecurity : NativeObjectSecurity
{
public GenericSecurity(
bool isContainer, ResourceType resType, SafeHandle objectHandle,
AccessControlSections sectionsRequested)
: base(isContainer, resType, objectHandle, sectionsRequested) { }
new public void Persist(SafeHandle handle, AccessControlSections includeSections)
{
base.Persist(handle, includeSections);
}
new public void AddAccessRule(AccessRule rule)
{
base.AddAccessRule(rule);
}
new public bool RemoveAccessRule(AccessRule rule)
{
return base.RemoveAccessRule(rule);
}
new public void SetAccessRule(AccessRule rule)
{
base.SetAccessRule(rule);
}
new public AuthorizationRuleCollection GetAccessRules(bool includeExplicit, bool includeInherited, Type targetType)
{
return base.GetAccessRules(includeExplicit, includeInherited, targetType);
}
public override Type AccessRightType
{
get { throw new NotImplementedException(); }
}
public override AccessRule AccessRuleFactory(
System.Security.Principal.IdentityReference identityReference,
int accessMask, bool isInherited, InheritanceFlags inheritanceFlags,
PropagationFlags propagationFlags, AccessControlType type)
{
return new GrantAccessRule(identityReference, accessMask, isInherited, inheritanceFlags, propagationFlags, type);
}
public override Type AccessRuleType
{
get { return typeof(AccessRule); }
}
public override AuditRule AuditRuleFactory(
System.Security.Principal.IdentityReference identityReference, int accessMask,
bool isInherited, InheritanceFlags inheritanceFlags,
PropagationFlags propagationFlags, AuditFlags flags)
{
throw new NotImplementedException();
}
public override Type AuditRuleType
{
get { return typeof(AuditRule); }
}
}
private class GrantAccessRule : AccessRule
{
public GrantAccessRule(IdentityReference identity, int accessMask, bool isInherited,
InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags,
AccessControlType type) :
base(identity, accessMask, isInherited,
inheritanceFlags, propagationFlags, type) { }
public GrantAccessRule(IdentityReference identity, int accessMask, AccessControlType type) :
base(identity, accessMask, false, InheritanceFlags.None,
PropagationFlags.None, type) { }
public int PublicAccessMask
{
get { return base.AccessMask; }
}
}
// Handles returned by GetProcessWindowStation and GetThreadDesktop should not be closed
private class NoopSafeHandle : SafeHandle
{
public NoopSafeHandle(IntPtr handle) :
base(handle, false) {}
public override bool IsInvalid
{
get { return false; }
}
protected override bool ReleaseHandle()
{
return true;
}
}
#endregion
}
}
使用样本
using (var windowsAccess = new WindowsGrandAccess(accountInfo, WindowsGrandAccess.WindowStationAllAccess, WindowsGrandAccess.DesktopRightsAllAccess))
{
...
}
谢谢。
答案 3 :(得分:2)
这是以下症状:
- 权利不足;
- 图书馆的失败负荷;
使用Filemon检测某些拒绝访问或
WinDbg在调试器中运行应用程序并查看任何问题。
答案 4 :(得分:2)
我已经用Python重新实现了Martin Prikryl的答案,我希望有人觉得有用。
我遇到了在Python脚本中运行子进程的问题。我使用pythonnet
软件包以其他用户身份运行System.Diagnostics.Process
。我的问题是子进程未运行,并且没有收到stdout或stderr。
# Import .NET objects using pythonnet
from System.Diagnostics import Process
# Use .NET API to run a subprocess using the given executable
# as the target user, in the provided working directory.
process = Process()
process.StartInfo.UseShellExecute = False
process.StartInfo.CreateNoWindow = True
process.StartInfo.LoadUserProfile = True
process.StartInfo.RedirectStandardOutput = True
process.StartInfo.RedirectStandardError = True
process.StartInfo.WorkingDirectory = working_dir
process.StartInfo.Domain = "mydomain"
process.StartInfo.UserName = username.lower().replace("mydomain\\", "")
process.StartInfo.PasswordInClearText = password
process.StartInfo.FileName = executable
process.StartInfo.Arguments = " ".join(args)
# Run the subprocess.
process.Start()
# Read subprocess console output
stdout = process.StandardOutput.ReadToEnd()
stderr = process.StandardError.ReadToEnd()
log.info(f"\n{executable} subprocess stdout:\n\n{stdout}")
log.info(f"{executable} subprocess stderr:\n\n{stderr}")
log.info(f"Done running {executable} as {username}.")
我使用了Martin Prikryl的答案,但是我使用pyWin32库在Python中重新实现了它,从而解决了我的问题。
import win32api, win32process, win32service, win32security
WINDOW_STATION_ALL_ACCESS = 983935
DESKTOP_RIGHTS_ALL_ACCESS = 983551
SE_WINDOW_OBJECT = 7
DACL_SECURITY_INFORMATION = 4
def set_access(user, handle, access):
info = win32security.GetSecurityInfo(
handle, SE_WINDOW_OBJECT, DACL_SECURITY_INFORMATION
)
dacl = info.GetSecurityDescriptorDacl()
dacl.AddAccessAllowedAce(win32security.ACL_REVISION, access, user)
win32security.SetSecurityInfo(
handle, SE_WINDOW_OBJECT, DACL_SECURITY_INFORMATION, None, None, dacl, None
)
username = "mattsegal"
user, domain, user_type = win32security.LookupAccountName("", username)
thread_id = win32api.GetCurrentThreadId()
station_handle = win32process.GetProcessWindowStation()
desktop_handle = win32service.GetThreadDesktop(thread_id)
set_access(user, station_handle, WINDOW_STATION_ALL_ACCESS)
set_access(user, desktop_handle, DESKTOP_RIGHTS_ALL_ACCESS)
答案 5 :(得分:0)
您是如何设置域名,用户和密码的?您是否正确设置域以及密码(它必须使用SecureString)。
另外,您是否设置了WorkingDirectory属性?使用UserName和Password时,文档说明您必须设置WorkingDirectory属性。
答案 6 :(得分:0)
可能由服务启动的任何进程也必须具有“作为服务登录”权限。
如果您用于启动第二个流程的用户ID没有该框的管理权限,则可能就是这种情况。
一个简单的测试是更改本地安全策略,以便为用户标识“作为服务登录”并再次尝试。
编辑:在附加信息之后..
在这一个上放牧Google,看来0xc0000142与无法初始化所需的DLL有关。服务已打开,生成的流程需要什么?在任何情况下,它看起来都与启动的过程有关,而不是你是如何做的。
答案 7 :(得分:0)
我今天遇到了这个问题,我花了很多时间试图解决这个问题。我最终做的是将服务创建为交互式(使用services.msc中的允许服务与桌面交互复选框)。一旦我这样做,0xc0000142错误就消失了。