Kelly's Space

Coding 'n stuff

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.

Advertisements

2 responses to “Configuring Event Log Permissions in C#

  1. Napoleon Crowe October 2, 2014 at 7:39 am

    Are you still using NeoBatch? We are looking to get all the errors into the “neoBatch” windows event log so that our NMS can pull that data when a job fails. only full errors go by defaul and looking to get the warnings over there as well.

    • kellyhpdx October 2, 2014 at 9:28 am

      I think what you’re looking for is to set the @CBR_MESS_LEVEL_EVENTLOG=W environment variable for the COBOL program step. This will output all messages of warning or higher to the event log. I know that NetCOBOL for Windows has this option, though I’m not sure if NetCOBOL for .NET does as well.

      You can use the ENV parameter on the JOB or EXEC statement to set this option, or you can set it system-wide by creating an environment variable.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: