Zac*_*lan 9 .net c# windows-services
我有一个运行为mydomain\userA的Windows服务.我希望能够从服务中运行任意.exes.通常,我使用Process.Start()并且它工作正常,但在某些情况下我想以不同的用户(mydomain\userB)运行可执行文件.
如果我更改ProcessStartInfo,我用来启动进程以包含凭据,我开始收到错误 - 或者是一个错误对话框,显示"应用程序无法正确初始化(0xc0000142).单击确定以终止应用程序."或者"访问被拒绝"Win32Exception.如果我从命令行运行进程启动代码而不是在服务中运行它,则进程将使用正确的凭据开始(我已通过设置ProcessStartInfo来运行whoami.exe并捕获命令行输出来验证这一点) ).
我也尝试使用WindowsIdentity.Impersonate()进行模拟,但这没有用 - 据我所知,模拟只会影响当前线程,启动新进程会继承进程的安全描述符,而不是当前线程.
我在一个独立的测试域中运行它,因此userA和userB都是域管理员,并且两者都在域范围内具有"登录即服务"权限.
Ste*_*tin 17
使用ProcessStartInfo启动新进程时,该进程将在启动过程的同一窗口站和桌面中启动.如果您使用不同的凭据,则用户通常没有足够的权限在该桌面上运行.如果user32.dll尝试在新进程中初始化而无法初始化错误,则会导致无法初始化错误.
要解决此问题,您必须首先检索与窗口站和桌面关联的安全描述符,并为您的用户添加适当的DACL权限,然后在新凭据下启动您的进程.
编辑:有关如何执行此操作和示例代码的详细说明在这里有点长,所以我将一篇文章与代码放在一起.
//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))
{
}
Run Code Online (Sandbox Code Playgroud)
Mar*_*ryl 11
根据@StephenMartin的回答.
使用Process该类启动的新进程在启动过程中在相同的窗口站和桌面中运行.如果使用不同的凭据运行新进程,则新进程将无权访问窗口站和桌面.什么导致错误,如0xC0000142.
以下是一个"紧凑"独立代码,用于授予用户访问当前窗口站和桌面的权限.它不需要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;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
14459 次 |
| 最近记录: |