Here's my Windows/.NET security stack:
- A Windows Service running as LocalSystem on a Windows Server 2003 box.
- A .NET 3.5 Website running on the same box, under "default" production server IIS settings (so probably as NETWORKSERVICE user?)
On my default VS2008 DEV environment I have this one method, which gets called from the ASP.NET app, which works fine:
private static void StopStartReminderService() {
ServiceController svcController = new ServiceController("eTimeSheetReminderService");
if (svcController != null) {
try {
svcController.Stop();
svcController.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(10));
svcController.Start();
} catch (Exception ex) {
General.ErrorHandling.LogError(ex);
}
}
}
When I run this on the production server, I get the following error from the ServiceController:
Source: System.ServiceProcess -> System.ServiceProcess.ServiceController -> IntPtr GetServiceHandle(Int32) -> System.InvalidOperationException Message: Cannot open eTimeSheetReminderService service on computer '.'.
Why is this happening, and how do I fix it?
EDIT:
The answer is below, mostly in comments, but to clarify:
- The issue was Security related, and occurred because the NETWORKSERVICE account did not have sufficient rights to Start/Stop a service
- I created a Local User Account, and added it to the PowerUsers Group (this group has almost admin rights)
- I don't want my whole Web App to impersonate that user all the time, so I impersonate only in the method where I manipulate the service. I do this by using the following resources to help me do it in code:
MS KB article and this, just to get a better understanding
NOTE: I don't impersonate via the web.config, I do it in code. See the MS KB Article above.
This was a good question that intrigued me as well...
So here is what I did to solve this problem:
Step 3: Use Impersonation to impersonate the use created in Step 1 to start and stop the Service
Update for IIS 8 (and maybe some slightly earlier versions)
The usergroup IIS_WPG does not exist anymore. It has changed to IIS_IUSRS.
Also, to start stop a service it is not neccesary to give full permissions (F). Permissions to start, stop and pause a service (TOP) should be enough. As such the command should be:
Note that you need to point the command prompt (preferably elevated to run as administrator) to
C:\Windows\System32
Folder before running this command.Also make sure that you have copied the subinacl.exe file to
C:\Windows\System32
from the installation directory if there is an error.Just a hunch, but it does not appear to me the error is necessarily related to security. Did you give the service the same name on the production server?
If your web application has the database and windows service can access it, you can just use the flag in the DB to restart the service. In the service, you can read this flag and restart if not busy etc. Only in case if you can modify the code of the service. If it's third party service you can create your own windows service and use database config to control (restart) services. It's the safe way and gives you much more flexibility and security.
To give IIS permission to start/stop a particular service:
subinacl /service {yourServiceName} /grant=IIS_WPG=F
This grants full service control rights for that particular service to the built-in IIS_WPG group. (This works for IIS6 / Win2k3.) YMMV for newer versions of IIS.)
Try adding this to your Web.Config.