Starting Remote Windows Services with a ServiceController and Impersonation

I have a .NET MVC3 application that needs to enable and disable a remote service. To do this, I impersonate a specific user account through WindowsIdentity.Impersonate (). To verify user rights, I can log in as a user and run sc.exe \\[server] start [service] from the command line. I also know that the impersonate command works as expected because the application runs anonymously and therefore cannot manage services on my local machine ( . ) Without impersonation, but can manage local services with impersonation. However, when I get together and try to start a remote service, not a local service, I always get the error message "Unable to open the [service] on the computer" [server] "

Has anyone encountered a similar problem? I expected this to be a server configuration, not a .NET problem, until I understand that sc.exe works without problems. The following is an abridged version of the class I'm 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 more note. If instead of the server I point the application to another PC running Windows 7 in the domain and change the impersonation credentials to the name of the owner of this PC, I can really remotely control my services without problems.

Upon request, I add an impersonation code. This 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 before trying 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 a separate service (like me here) just fine - only when I go to start or stop the service in which I encountered a problem.

+4
source share
2 answers

Maybe I found the answer:

In the impersonation method LogonUserA

use LOGON32_LOGON_SERVICE (= 5) instead of LOGON32_LOGON_INTERACTIVE .

Make sure that the user you impersonate is the same user who starts the service.

In my case, the user is included in Local Policies → Start Session as a Service. I have not tested with a user not included in this local policy.

Hope this helps!

+2
source

Well, that was correct if the user you want to impersonate is the administrator of the machine. If this is not the case, you must give the user special rights to start the service.

Since I am not a network administrator, I did not know how to do this, but I found this link that explains how to do this using the subinacl tool:

Download

And finally, the command line will be:

  • subinacl / service SERVICENAME / grant = DOMAINNAME \ USERNAME Users = TO

Users = TO gives the user start / stop rights

In this case, you must impersonate the user in the INTERACTIVE mode, and not in the SERVICE mode

0
source

Source: https://habr.com/ru/post/1387270/


All Articles