Saturday, July 31, 2010

Security Issues with EventSources in EventLogs

If you rely on the System.Diagnostics.EventLog class to log your server-side errors (such as those that may occur in a web service), you may run into security issues if you try to use an EventSource that doesn’t already exist. Since this is server-side, the easiest thing to do is to use a Web Service web method, which can just be accessed through IE.It only needs to be done once. Here's the web method:

The line containing "Events.EventSources" is simply an Enum containing the names of EventSources you might use in your app. If you only have one, then you can just get rid of that whole foreach loop and just hardcode the name of your source in the if.

[WebMethod(Description = "Set server Event Log sources.")]
public string SetEventLogSources(string Username, string Password, string Domain)
{
//This will keep track of the impersonation token
const int LOGON_TYPE_INTERACTIVE = 2;
const int LOGON_TYPE_PROVIDER_DEFAULT = 0;
string logName = "Application";
IntPtr userToken = IntPtr.Zero;

if (LogonUser(Username, Domain, Password, LOGON_TYPE_INTERACTIVE, LOGON_TYPE_PROVIDER_DEFAULT, ref userToken))
{
//Initialize user token
WindowsIdentity oIdentity = new WindowsIdentity(userToken);
WindowsImpersonationContext oContext = oIdentity.Impersonate();

foreach (string source in Enum.GetNames(typeof(Events.EventSources)))
{
if (EventLog.SourceExists(source) == false)
EventLog.CreateEventSource(source, logName);
}

//Undo impersonation
oContext.Undo();

return "Event source registration successful!";
}
else
{
return "Unable to process user credentials for event source registration.";
}
}

// Using this api to get an accessToken of specific Windows User by its user name and password
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static public extern bool LogonUser(string userName, string domain, string passWord, int logonType, int logonProvider, ref IntPtr accessToken);

Be sure you have included the following “using”s:

using System.Diagnostics;
using System.Security.Principal;
using System.Runtime.InteropServices;