问题描述
予有需要,以便能够把一个远程服务和关闭一个.NET MVC3应用。为了做到这一点,我通过WindowsIdentity.Impersonate冒充特定的用户帐户()。为了验证用户的权限,我可以作为用户登录并执行 SC.EXE \\ [系统]启动[服务]
从命令提示符。我也知道,冒充命令工作正常,因为应用程序运行匿名,因此不能在我的本地机器控制服务(。
)不带模拟,但是的可以的控制本地服务与模拟。然而,当我把它放在一起,尝试启动远程服务,而不是当地的服务,我总是得到错误可以在计算机<$ C $不能打开 [服务]
服务C> [服务器]
有没有人经历过类似的问题?我期待这是一个服务器的配置,而不是.NET的问题,直到我意识到,SC.EXE工作没有问题。下面是类的,我使用的是简化版本:
公共类服务
{
公共字符串名称;
公共BOOL运行;
私人的ServiceController的ServiceController;
公共服务(字符串名称,字符串主机)
{
名称=名称;
ServiceController的=新的ServiceController(名称,主机);
运行= serviceController.Status == ServiceControllerStatus.Running;
}
公共BOOL StartService()
{
ServiceControllerPermission SCP =新ServiceControllerPermission(ServiceControllerPermissionAccess.Control,serviceController.MachineName,姓名);
scp.Assert();
serviceController.Start();
serviceController.WaitForStatus(ServiceControllerStatus.Running,新时间跨度(0,0,5));
serviceController.Refresh();
运行= serviceController.Status == ServiceControllerStatus.Running;
返回运行;
}
}
,还应注意:不是服务器如果我指向另一台Windows 7 PC上的领域的应用,改变模拟凭据那些电脑的主人,我居然能没有问题远程控制他们的服务。
每个请求,我在这里加入了模拟code。这是一个长一点让我忍受:
公共类冒充
{
公共const int的LOGON32_LOGON_INTERACTIVE = 2;
公共const int的LOGON32_PROVIDER_DEFAULT = 0;
WindowsImpersonationContext impersonationContext;
[的DllImport(advapi32.dll中)
公共静态外部INT LogonUserA(字符串lpszUserName,
字符串lpszDomain,
字符串lpszPassword,
INT dwLogonType,
INT dwLogonProvider,
裁判的IntPtr phToken);
[的DllImport(advapi32.dll的,字符集= CharSet.Auto,SetLastError =真)
公共静态外部INT DuplicateToken(IntPtr的hToken,
INT impersonationLevel,
裁判的IntPtr hNewToken);
[的DllImport(advapi32.dll的,字符集= CharSet.Auto,SetLastError =真)
公共静态的extern BOOL了RevertToSelf();
[的DllImport(KERNEL32.DLL,字符集= CharSet.Auto)
公共静态的extern BOOL CloseHandle的(IntPtr的手柄);
公共BOOL impersonateValidUser(用户名字符串,字符串域,字符串密码)
{
的WindowsIdentity tempWindowsIdentity;
IntPtr的令牌= IntPtr.Zero;
IntPtr的tokenDuplicate = IntPtr.Zero;
如果(RevertToSelf的())
{
如果(LogonUserA(用户名,域,密码,LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,楼盘令牌)!= 0)
{
如果(DuplicateToken(令牌,2,参考tokenDuplicate)!= 0)
{
tempWindowsIdentity =新的WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
如果(impersonationContext!= NULL)
{
CloseHandle的(标记);
CloseHandle的(tokenDuplicate);
返回true;
}
}
}
}
如果(令牌!= IntPtr.Zero)
CloseHandle的(标记);
如果(tokenDuplicate!= IntPtr.Zero)
CloseHandle的(tokenDuplicate);
返回false;
}
公共无效undoImpersonation()
{
impersonationContext.Undo();
}
}
我把这code只是试图启动或停止服务之前:
服务S =新服务(服务名称,计算机名);
如果(Impersonation.impersonateValidUser(用户名,域,密码))
{
如果(s.Running)
s.StopService();
其他
s.StartService();
Impersonation.undoImpersonation();
}
这可能是值得指出的是,我可以列出的服务,并获得个性化服务的状态(如我在这里做的)就好了 - 只有当我去启动或停止,我遇到麻烦了服务
也许我已经找到了答案:
在模拟方法的 LogonUserA
使用 LOGON32_LOGON_SERVICE (= 5),而不是 LOGON32_LOGON_INTERACTIVE
请确保您正在模拟用户是运行该服务的用户。
在我的情况下,用户被包含在本地策略 - >启动会话服务。我还没有与用户未包括在该本地策略进行测试。
希望它能帮助!
I have a .NET MVC3 application that needs to be able to turn a remote service on and off. In order to do this I am impersonating a specific user account via WindowsIdentity.Impersonate(). To test the user's permissions I can log in as the user and execute sc.exe \\[server] start [service]
from the command prompt. I also know that the impersonate command is working as expected because the application runs anonymously and therefore cannot control services on my local machine (.
) without impersonation, but can control local services with impersonation. However, when I put it together and attempt to start the remote service rather than local service I always get the error "Cannot open [service]
service on computer '[server]
'"
Has anyone ever experienced a similar issue? I was expecting it to be a server configuration rather than .NET issue until I realized that sc.exe works without issue. Here is an abbreviated version of the class that I am using:
public class Service
{
public string Name;
public bool Running;
private ServiceController serviceController;
public Service(string name, string host)
{
Name = name;
serviceController = new ServiceController(Name, host);
Running = serviceController.Status == ServiceControllerStatus.Running;
}
public bool StartService()
{
ServiceControllerPermission scp = new ServiceControllerPermission(ServiceControllerPermissionAccess.Control, serviceController.MachineName, Name);
scp.Assert();
serviceController.Start();
serviceController.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 5));
serviceController.Refresh();
Running = serviceController.Status == ServiceControllerStatus.Running;
return Running;
}
}
One additional note: If instead of the server I point the application at another Windows 7 PC on the domain and change the impersonation credentials to those of the owner of that PC, I am actually able to remotely control their services without issue.
Per request, I am adding the impersonation code here. It is a little longer so bear with me:
public class Impersonate
{
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_PROVIDER_DEFAULT = 0;
WindowsImpersonationContext impersonationContext;
[DllImport("advapi32.dll")]
public static extern int LogonUserA(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DuplicateToken(IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
public bool impersonateValidUser(String userName, String domain, String password)
{
WindowsIdentity tempWindowsIdentity;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
if (RevertToSelf())
{
if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, ref token) != 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
if (impersonationContext != null)
{
CloseHandle(token);
CloseHandle(tokenDuplicate);
return true;
}
}
}
}
if (token != IntPtr.Zero)
CloseHandle(token);
if (tokenDuplicate != IntPtr.Zero)
CloseHandle(tokenDuplicate);
return false;
}
public void undoImpersonation()
{
impersonationContext.Undo();
}
}
I call this code just before attempting to start or stop the service:
Service s = new Service(ServiceName, MachineName);
if (Impersonation.impersonateValidUser(Username, Domain, Password))
{
if (s.Running)
s.StopService();
else
s.StartService();
Impersonation.undoImpersonation();
}
It may be worth noting that I can list the services and get the status of an individual service (as I do here) just fine - it is only when I go to start or stop the service that I run into trouble.
Maybe I've found the answer:
In the impersonation method LogonUserA
use LOGON32_LOGON_SERVICE (= 5) instead of LOGON32_LOGON_INTERACTIVE.
Make sure that the user that you're impersonating is the same user that runs the service.
In my case, the user is included in Local Policies --> Start session as service. I have not tested with an user not included in that local policy.
Hope it helps!
这篇关于与ServiceController的和模拟启动远程的Windows服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!