When I was a young lad in college, I wrote undetectable viral hacks, keyboard sniffers, and collected more passwords than I care to count. (Thankfully, the statute of limitations—this was 20 years ago—has run out.) I never stole anything or wrecked anyone's data, but I did encourage a young fellow to send roses to his girlfriend and hooked a football player, Napolean XXXXXXX (last name omitted), up on a blind date. I understand the allure of going and being places one isn't allowed, but this crap makes life a pain in the butt for the rest of us.
I wonder whether you should hate hackers and those nitwits who tweak Trojans, so the rest of us have to keep sending money to McAfee?! I also wonder if maybe the sparring and jousting among programmers, Microsoft and hackers, and cyber thieves aren't necessary to push the technology forward, at least as far as security is concerned, so we all are protected from worse—cyber terrorists. With the economy in the shape it's in, an effective cyber terror attack could push the economy into the trash compactor and send normally sane people running for the bunker. The unfortunate net effect in my little community is like taking off my shoes at airport security—I have to re-learn how to do little things over.
Writing to the EventLog
If you wanted to write to the EventLog, you can still create an instance of the EventLog and call WriteEntry. By default, your entry will be written to the Application log. If you wanted to create a new log source—a dictionary entry for your application—you could write code like that shown in Listing 1.
Listing 1: Code that tries to create an event source but is doomed to fail due to a lack of permissions to the Security log.
Imports System.Diagnostics Partial Class _Default Inherits System.Web.UI.Page Protected Sub Page_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load If (Not EventLog.SourceExists("MyApp")) Then EventLog.CreateEventSource(("MyApp", "Application") End If 'Write entry here EventLog.WriteEntry(SOURCE, "Test") End Sub End Class
The code checks to see whether the source exists; if not, it creates it. The EventLog uses queuing (it might be DCOM, I don't remember and it's not important right now), but there can be a latency between doing things to the EventLog and those tasks actually completing. In short, this means that it is better to create an event source in advance of needing it.
The problem with the preceding code is that it won't work. If you try to create or use a custom log, you are going to get a security exception (see Figure 1)—for sure under Windows Vista, Visual Studio 2008, and IIS 7 (and Cassini). I am not sure how many other back-combinations will cause this error; the point is that it's going to be a challenge going forward. Worse, having searched the Web thoroughly, Google returns blogs and articles that instruct one to hack the Registry security permissions for EventLogs (bad idea and not a sustainable approach) or write a look that edits the Registry with code (also clumsy). The best approach is none of these.
Figure 1: A SecurityException if you invoke SourceExists, CreateEventSource, of WriteEntry and a particular EventLog source doesn't exist.
To lead you to the solution—at least how I got there—think about these things:
- You don't want any old application updating the Registry; if some generally bad person or just a dipstick can modify your Registry, you are in for potentially disastrous problems.
- Trying to create a Registry log source will cause a security exception.
- Hacking the Registry yourself is a good way to muck up a server without outside forces or evil super-villain intercession.
- The EventLog has a built-in latency—due to DCOM queuing; well, I am pretty sure it's DCOM—so you want to establish custom event logs and sources in advance.
What do these things tell you? That's right. You need an installer for Registry changes. An installer is run by a separate application, InstallUtil.exe, that has the proper security permissions; InstallUtil needs to be run using Administrative privileges and isn't deployed in your web application. So, besides being more work and frustrating for you and me, this approach will work and will frustrate the nefarious intentions of evil-doers—at least as far as the EventLog is concerned.
Creating an Installer
The idea behind installers is that these chunks of code are separate from your deployed applications. As separate code, an installer can be run with administrative privileges (which your deployed applications probably won't be) and then taken out of the deployment environment. The benefit is that you get your application configured but reduce the risk of having code that can do things such as change the Registry in your deployment environment.
An installer is basically a DLL that contains a class that inherits from System.Configuration.Install.Installer, has the RunInstaller(True) attribute decorating the class, and some code that performs some kind of configuration. In this case, the "some code" is code that creates the event source needed for the web application demo (shown in Listing 1). To create the installer, create a separate class project file, add a reference to the System.Configuration.Install.dll to the project, and add the code in Listing 2.
Listing 2: An installer that creates an event source "MyApp" in the Application log.
Imports System.Diagnostics Imports System.Configuration.Install Imports System.ComponentModel <RunInstaller(True)> _ Public Class MyEventLogInstaller Inherits Installer Public Sub New() Dim log As EventLogInstaller = New EventLogInstaller() log.Source = "MyApp" log.Log = "Application" Installers.Add(log) End Sub End Class
Running the Installer
The next thing you need to do is to run the installer. Installers are run with InstallUtil, passing the installer assembly to the InstallUtil.exe utility. To create the MyApp event source using the installer from Listing 2, complete these steps:
- Click Start|All Programs|Microsoft Visual Studio 2008|Visual Studio Tools.
- Right-click Visual Studio 2008 Command Prompt and select Run as administrator.
- In the command prompt, change to the folder containing MyEventLogInstaller and enter.
- InstallUtil MyEventLogInstaller.dll in the command prompt.
After completing the steps, you should see output that looks something like the output in Figure 2. If there is a problem with your installer, it will be indicated in the console output. Take corrective action and re-try the installer using the numbered steps above.
Figure 2: Console output from the installer.
Writing to the EventLog from a Web Application
You can write an event entry to the event log using the Application log and an existing source, but it is a common practice to isolate log entries by application-specific sources. The difficulty is that source names are stored in the Registry and have to be unique across logs. Hence, when you try to create an event source in a web application, the EventLog class will hang up on the Security log—it will check to see whether the source exists in the Security log.
To test the event source created by the installer, you can run the code in Listing 1. That code should run now. You also can check the Registry to see whether the source exists. The following key should reflect the source as created by the code in Listing 2.