I ran into a situation recently where I had a Windows service running under a domain service account, e.g., MyDomain\SvcUser. As part of its operation, the service needed to clear the Event Log after reading its contents. By default, non-administrative accounts cannot clear an event log.
Granting 'clear' access on an event log to a service account is not as simple as it might sound.
After reading this post by Rory McCaw, I learned that the permissions are controlled by a custom security descriptor stored in the registry.
The key is stored here:
MACHINE\System\CurrentControlSet\Services\EventLog\[CustomLognName]\CustomSD
This applies to Window Server 2003, apparently the security on the event log has changed from the prior version.
In the CustomSD key, you will find some long string like this:
O:BAG:SYD:(D;;0xf0007;;;AN)(D;;0xf0007;;;BG)(A;;0xf0007;;;SY)(A;;0x7;;;BA)(A;;0x7;;;SO)(A;;0x3;;;IU)(A;;0x3;;;SU)(A;;0x3;;;S-1-5-3)
(from Rory's blog)
The first part is the 'Owner' ACL [ O:BA ], which tells you the Owner is the Builtin Administrators
The next part is the 'Group' ACL [G:SY], the primary group is the Local System account
The last, long group is the Discretionary ACL (or DACL) D:(...)(...) which grants discretionary access on a user-by-user basis.
Each DACL entry is in the form (A;;0x7;;;S-1-5-21-467819145....)
which is Allow or Deny; then the permissions (for the event log, 0x7 is full control); followed by the SID of the user to be granted/denied the permission.
To put this information to use, I have created a command line utility that allows one to easily update the permissions on an event log. I will post some code here when I have time to rewrite it. Here are some of the highlights:
Using the System.Security.Principal namespace
// Get the account SID
NTAccount ntAccount = new NTAccount("MyDomain", "MyAccount");
SecurityIdentifier sid = ( SecurityIdentifier ) ntAccount.Translate( typeof( SecurityIdentifier ) );
//Open the Security Descriptor from the registry
// using the Microsoft.Win32 namespace
string eventLogName = "MyEventLogName";
string sddl = Registry.GetValue( @"HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\EventLog\" + eventLogName, "CustomSD", string.Empty ).ToString();
// Omitted: Code to concatenate together the SID and the permission level to update the security descriptor
//Save back the updated Security descriptor to the registry
Registry.SetValue( @"HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\EventLog\" + eventLogName, "CustomSD", updatedSDDL );
So now your service accounts can have full control over an event log without having administrative rights on the computer.
My unanswered question is this: what class will allow me to manipulate the security descriptor directly? When I attempt to instantiate one of the security descriptor classes like this:
CommonSecurityDescriptor sd = new CommonSecurityDescriptor( false, false, eventLogSDDL );
// omitted code to add ACEs to DACL
sd.GetSddlForm( AccessControlSections.All );
Trying to convert the security descriptor back to a SDDL string results in some extra stuff in the string:
Input:
O:BAG:SYD:(D;;0xf0007;;;AN)(D;;0xf0007;;;BG)(A;;0xf0007;;;SY)(A;;0x7;;;BA)(A;;0x7;;;SO)(A;;0x3;;;IU)(A;;0x3;;;SU)(A;;0x3;;;S-1-5-3)
Outputs:
O:BAG:SYD:(D;;CCDCLCSDRCWDWO;;;AN)(D;;CCDCLCSDRCWDWO;;;BG)(A;;CCDC;;;S-1-5-3)(A;;CCDC;;;IU)(A;;CCDC;;;SU)(A;;CCDCLCSDRCWDWO;;;SY)(A;;CCDCLC;;;BA)(A;;CCDCLC;;;SO)
Does anyone know how to manipulate the SDDL correctly via .Net?