I want to check some Windows services status on different remote servers like this:
ServiceController sc = new ServiceController(\"MyWindowsService\", \"COM
Non-admin users can connect to the Service Control Manager remotely, provided they have the "Access this computer from the network" user right. By default this right is granted to all users.
Access to individual services is controlled by the ACL on each service. You must already know the service name, because a non-admin user cannot enumerate services remotely.
The default security descriptor for a service is as follows:
D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)
You can determine the security descriptor for a service using the sc sdshow
command. The string format is described in Security Descriptor Definition Language on MSDN.
OK, let's expand out that security descriptor string. This is a bit tricky because the mapping between the SDDL permissions and equivalent security manager permissions does not appear to be well documented in MSDN or in the SDK headers; luckily, Wayne Martin has already done the heavy lifting for us and posted the results in the blog entry Service Control Manager Security for non-admins.
D: - this part is the DACL, the permissions on the service.
Since all the entries are allow entries, the order isn't significant; I'll list them from least to most privilege for convenience.
(A;;CCLCSWLOCRRC;;;IU) - allow the interactive user the following rights:
CC - SERVICE_QUERY_CONFIG (the right to query the service configuration)
LC - SERVICE_QUERY_STATUS (the right to query the service status)
SW - SERVICE_ENUMERATE_DEPENDENTS (the right to see service dependencies)
LO - SERVICE_INTERROGATE (the right to send SERVICE_CONTROL_INTERROGATE)
CR - SERVICE_USER_DEFINED_CONTROL (the right to send a user defined control)
RC - READ_CONTROL (the right to see the permissions)
(A;;CCLCSWLOCRRC;;;SU) - allow services the following rights:
same as for the interactive user
(A;;CCLCSWRPWPDTLOCRRC;;;SY) - allow local system the following rights:
same as for the interactive user, plus:
RP - SERVICE_START (the right to start the service)
WP - SERVICE_STOP (the right to stop the service)
DT - SERVICE_PAUSE_CONTINUE (the right to send pause and continue requests)
(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA) - allow the Administrators group:
same as for local system, plus:
DC - SERVICE_CHANGE_CONFIG (the right to reconfigure the service)
SD - DELETE (the right to delete the service)
WD - WRITE_DAC (permission to change the permissions)
WO - WRITE_OWNER (permission to take ownership)
The second part of the security descriptor string (S:(...)
) is the SACL, which controls what auditing is done. We're not interested in that at the moment.
You will notice that there are no allow permissions applicable to non-administrative remote users. To give remote access to a particular user, add an allow ACE for that user with the same permissions as the interactive user.
If this is your own service, you can change the permissions when the service is installed using the SetServiceObjectSecurity function. You could also write a program using this function to change the permissions on an existing service.
Alternatively, you can use sc sdset
at the command line to set the permissions for an existing service based on a SDDL string. You will first need to look up the SID string for the user; in a domain, you can do this using Active Directory Users and Computers. The SID string can be seen via the Attribute Editor tab, in the objectSid attribute. (Unfortunately you can't copy and paste that way. Suggestions for more convenient methods of looking up a user's SID are welcomed.)
If the SID string were S-1-5-21-131085535662-8349591032-725385543-5981
, for example, the command line would be
sc sdset myservice D:(A;;CCLCSWLOCRRC;;;S-1-5-21-131085535662-8349591032-725385543-5981)(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)
(You do not need to specify the SACL; if absent, the existing SACL will be retained.)