Kelly's Space

Coding 'n stuff

Monthly Archives: April 2011

Configuring Event Log Permissions in C#

In NetCOBOL, programs can be configured so that errors are written to the Application event log through the environment variable @CBR_MESSAGE=EVENTLOG.  We set this for all COBOL program steps in NeoBatch automatically, but sometimes the user accounts do not have appropriate permissions to write to the event log.  There is no easy way to configure the event log to adjust permissions, you have to use a special registry key with an SDDL string.

SDDL strings (MSDN doc: http://msdn.microsoft.com/en-us/library/aa379567(v=VS.85).aspx) can be a pain to generate by hand.  Luckily the .NET framework comes to the rescue through the RegistrySecurity class.  It has the ability to initialize itself from an SDDL string and return and SDDL string after it has been configured.

To modify permissions of the event log, you need to create a string value called “CustomSD” under the named event log key in HKLM\SYSTEM\CurrentControlSet\Services\EventLog\.  In the case of the application event log, the key would be under “HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application”.  The value of the CustomSD key is an SDDL string.

I’ve written a C# program that takes the log name and user name as parameters, and creates and sets the CustomSD key so the user can write to the event log.  Below is the code:

using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Principal;
using Microsoft.Win32;
using System.Security.AccessControl;

namespace EventLogAccessTool
{
    class Program
    {
        static void Main(string[] args)
        {
            string usage = @"Event Log Access Tool
Usage: EventLogAccessTool <logname> <user>
Where:   logname    - Name of the Windows event log, e.g., Application
         user       - User account (or group) to change access for
         ";
            if (args.Length != 2)
            {
                Console.Error.WriteLine(usage);
                return;
            }

            string logName = args[0];
            if (logName.Trim().Length == 0)
            {
                Console.Error.WriteLine("Invalid logname specified");
                Console.Error.WriteLine(usage);
                return;
            }

            string userAccount = args[1];
            if (userAccount.Trim().Length == 0)
            {
                Console.Error.WriteLine("Invalid user account specified");
                Console.Error.WriteLine(usage);
                return;
            }

            try
            {
                string keyName = @"SYSTEM\CurrentControlSet\Services\EventLog\" + logName;

                using (RegistryKey eventLogKey = Registry.LocalMachine.CreateSubKey(keyName, RegistryKeyPermissionCheck.Default))
                {
                    string existing = eventLogKey.GetValue("CustomSD") as string;
                    if (existing == null)
                    {
                        existing = "O:BAG:SY";  // Owner is built-in administrators and system
                    }
                    else
                    {
                        Console.WriteLine("Existing SDDL is: " + existing);
                    }

                    // We'll use the RegistrySecurity class for creating the SDDL string.
                    // Initialize it with the existing SDDL string.
                    RegistrySecurity acl = new RegistrySecurity();
                    acl.SetSecurityDescriptorSddlForm(existing);

                    // Add the user account so it can query values and set values 
                    // so that it can read and write to the event log
                    RegistryAccessRule ace = new RegistryAccessRule(userAccount, 
                        RegistryRights.QueryValues | RegistryRights.SetValue, 
                        AccessControlType.Allow);

                    acl.AddAccessRule(ace);

                    string newSDDL = acl.GetSecurityDescriptorSddlForm(AccessControlSections.All);
                    
                    Console.WriteLine("New SDDL is: " + newSDDL);
                    // Write out the new SDDL in the CustomSD string value.
                    eventLogKey.SetValue("CustomSD", newSDDL);
                }
            }
            catch(Exception e)
            {
                Console.Error.WriteLine("An error occurred: " + e.Message);
                return;
            }

            Console.WriteLine("Successfully updated the registry");
        }
    }
}

In the event that the event log security gets messed up, simply delete the CustomSD key.