Monthly Archives: August 2014

How to access the ‘Service Controller Database’ remotely on a Workgoup network

After having some issues with my home computers not being able to ‘see’ each others services I started digging around for solutions – having already checked all the other possible problems. The main issue is that all these computers are running on an old fashioned ‘Workgroup’ since I don’t have an Active Directory Controller (no Windows Servers). Thus all the machines connect using the same username/password combination.

I’ve made sure of things like firewalls, user accounts (as mentioned already), UAC etc. are all ok but still I got the ‘Cannot open Service Control Manager Database’ error (Access denied (5)). I started suspecting there must be another level of security that is blocking access to view/start/stop Windows services across different machines. Then I stumbled across articles describing ACLs and the issue that to this day Microsoft has not exposed Service ACL’s through .Net yet (yet they have things like File and Registry ACLs exposed through System.Security namespace…).

The only way to get to these ACL’s are through old fashioned Win32 APIs or using the SC.exe utility. I’ve read that someone wrote a C# wrapper class for these somewhere but I could not find any remaining source of this through Google. Bummer… Then using the SC.exe utility through some nasty loosely coupled integration is the only solution…

To view the current DACL (Discretionary Access Control List) for ‘Service Controll Manager’ you can use the followig command on the source/host computer you want to connect to:

sc sdshow scmanager

That should give you something like this:

D:(A;;CC;;;AU)(A;;CCLCRPRC;;;IU)(A;;CCLCRPRC;;;SU)(A;;CCLCRPWPRC;;;SY)(A;;KA;;;BA)S:(AU;FA;KA;;;WD)(AU;OIIOFA;GA;;;WD)

Now, the part that was relevant to me using a ‘Workgroup’ network is the (…AU) part because for some reason even though I’m using the same user account/Password on all machines – and this account is an Administrator on each machine, the system only recognize the user as part of the Authenticated users group ONLY. Thus the  (A;;CC;;;AU) part is not sufficient to allow access to the service control manager database…

To get access to the Service Controller Database you need permissions like this: (A;;CCLCRPRC;;;AU)

To understand what all those letters use please refer to ‘Best practices and guidance for writers of service discretionary access control lists‘ which explains the whole lot. The following command can be used to ‘fix’ the access to the ‘Service Controller Database’: (note that is is just an example!! Check the output of the previous command first)

 sc.exe sdset scmanager D:(A;;CCLCRPRC;;;AU)(A;;CCLCRPRC;;;IU)(A;;CCLCRPRC;;;SU)(A;;CCLCRPWPRC;;;SY)(A;;KA;;;BA)S:(AU;FA;KA;;;WD)(AU;OIIOFA;GA;;;WD)

After running this you should be able to access the  ‘Service Controller Database’ remotely (assuming all the other things have been checked). All good and wonderful! uhmm… Then I discover this does not display all services… bugger again..

Actually there are two parts to the original problem – as I discovered that each Windows service on its own has an ACL that can/should be set. Some ‘system’ services already come with permissions for AU (Authenticated Users) so they are visible by default. Most other and particularly my custom created services don’t have the right ACLs set. To fix that is simple… Just repeat the process above for that particular service – like this (for my QuickMon 3 Service):

Sc sdshow "Quickmon 3 service"

This should give an output like this:

D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)

As you can see it does not have any permissions for AU. To fix access to that server you simply have to add the AU permissions like this:

sc.exe sdset "Quickmon 3 service" D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)

Now of course you have to repeat this for each Windows Service you need access to…

To help in this process I created the following PowerShell script that list all Windows Servers plus their ACLs:

$services = @{}
Get-Service | foreach {
    $DACL = sc.exe sdshow $_.ServiceName
    $service = @{
        'ServiceName' = $_.ServiceName
        'DisplayName' = $_.DisplayName
        'ServiceType' = [string]$_.ServiceType
        'DependsOn'   = [string]$_.ServicesDependedOn
        'State'       = [string]$_.Status
        'DACL' = ([string]$DACL).Trim()
    }
    $serviceObj = New-Object -TypeName PSObject -Property $service
    $services.Add($_.ServiceName,$serviceObj)
}
$services.Values | select ServiceName, DisplayName, ServiceType, State, DependsOn, DACL | Sort-Object ServiceName

Now you have to repeat the whole process for each service… And that is how it’s done… Enough to keep you out of mischief or perhaps enough to get you into it again…