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.
Clearly mucking about in the Registry or event logs could be a hugely potential security risk, so this is just one of many areas where the wheel-of-torture that is security gets tightened down. If you have had any difficulties creating and using the event log for ASP.NET, this article should help you “learn” to do it right (again).
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.
Viewing the Written Event Entry in Visual Studio
After you re-run the code in Listing 1, there will be an EventLog entry for each time you run the code in Listing 1. You can press and hold the Windows key + R and enter Eventvwr to open the event viewer, or you can view the event in Visual Studio’s Server Explorer (see Figure 3). To view the event in the Server Explorer, follow these steps:
- Open the Server Explorer.
- Expand the server node.
- Expand the Event Logs node.
- Expand the Application node.
- Scroll down to the MyApp source and expand that node (shown in Figure 3).
Figure 3: The entry written to the new event source.
You can see the value of the event entry by clicking the entry you are interested in and opening the Visual Studio Properties window. You can see the “Test” message for the code in Listing 1 and item in Figure 3 in the Properties window in Figure 4.
Figure 4: The properties of the event entry can be viewed from the Server Explorer and the Properties window.
The downside is that this is a lot more work than calling CreateEventSource. Perhaps it’s a small price to pay to further protect your servers, but it is more work. Avoid Registry hacks because these are not generally good practices and your IT administrator or your cloud computing provider will likely not allow this approach.
Earlier versions of Windows and .NET permitted you to check for and create an event source with a couple of lines of code. As security features are ratcheted down, it will create more work for programmers (in this economy, more work is more better), but the work is sometimes nuisance work. A good strategy is to create an application event source for each application; unfortunately, you will not be able to do this from within your web application. Instead, create a DLL, run the InstallUtil.exe with administrative privileges, and use an installer to create the event source. You only need to do this one time per environment, so it’s not that big of a deal, especially if it helps you sleep better at night.
About the Author
Paul Kimmel is the VB Today columnist for www.codeguru.com and has written several books on object-oriented programming and .NET. Check out his book LINQ Unleashed for C#, now available on Amazon.com and at fine bookstores everywhere. Look for his upcoming book Teach Yourself the ADO.NET Entity Framework in 24 Hours. You may contact him for technology questions at [email protected]. Paul Kimmel is a Technical Evangelist for Developer Express, Inc.
Copyright © 2009 by Paul T. Kimmel. All Rights Reserved.