Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Services / Monitoring / system / Diagnosticts / EventLog.cs / 1305376 / EventLog.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- //#define RETRY_ON_ALL_ERRORS namespace System.Diagnostics { using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Runtime.InteropServices; using System.ComponentModel; using System.Diagnostics; using System; using Microsoft.Win32; using Microsoft.Win32.SafeHandles; using System.IO; using System.Collections; using System.Collections.Specialized; using System.Globalization; using System.ComponentModel.Design; using System.Security; using System.Security.Permissions; using System.Reflection; using System.Runtime.Versioning; using System.Runtime.CompilerServices; using System.Diagnostics.CodeAnalysis; ////// [ DefaultEvent("EntryWritten"), InstallerType("System.Diagnostics.EventLogInstaller, " + AssemblyRef.SystemConfigurationInstall), MonitoringDescription(SR.EventLogDesc) ] public class EventLog : Component, ISupportInitialize { private const string EventLogKey = "SYSTEM\\CurrentControlSet\\Services\\EventLog"; internal const string DllName = "EventLogMessages.dll"; private const string eventLogMutexName = "netfxeventlog.1.0"; private const int DefaultMaxSize = 512 * 1024; private const int DefaultRetention = 7 * SecondsPerDay; private const int SecondsPerDay = 60 * 60 * 24; private EventLogInternal m_underlyingEventLog; // Whether we need backward compatible OS patch work or not private static bool s_CheckedOsVersion; private static bool s_SkipRegPatch; private static bool SkipRegPatch { get { if (!s_CheckedOsVersion) { OperatingSystem os = Environment.OSVersion; s_SkipRegPatch = (os.Platform == PlatformID.Win32NT) && (os.Version.Major > 5); s_CheckedOsVersion = true; } return s_SkipRegPatch; } } internal static PermissionSet _UnsafeGetAssertPermSet() { // SEC_NOTE: All callers should already be guarded by EventLogPermission demand. PermissionSet permissionSet = new PermissionSet(PermissionState.None); // We need RegistryPermission RegistryPermission registryPermission = new RegistryPermission(PermissionState.Unrestricted); permissionSet.AddPermission(registryPermission); // It is not enough to just assert RegistryPermission, for some regkeys // we need to assert EnvironmentPermission too EnvironmentPermission environmentPermission = new EnvironmentPermission(PermissionState.Unrestricted); permissionSet.AddPermission(environmentPermission); // For remote machine registry access UnmanagdCodePermission is required. SecurityPermission securityPermission = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode); permissionSet.AddPermission(securityPermission); return permissionSet; } ////// Provides interaction with Windows 2000 event logs. /// ////// public EventLog() : this("", ".", "") { } ////// Initializes a new instance of the ////// class. /// /// public EventLog(string logName) : this(logName, ".", "") { } ///[To be supplied.] ////// public EventLog(string logName, string machineName) : this(logName, machineName, "") { } ///[To be supplied.] ////// public EventLog(string logName, string machineName, string source) { m_underlyingEventLog = new EventLogInternal(logName, machineName, source, this); } ///[To be supplied.] ////// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [MonitoringDescription(SR.LogEntries)] public EventLogEntryCollection Entries { get { return m_underlyingEventLog.Entries; } } ////// Gets the contents of the event log. /// ////// [Browsable(false)] public string LogDisplayName { [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] get { return m_underlyingEventLog.LogDisplayName; } } ////// ////// [TypeConverter("System.Diagnostics.Design.LogConverter, " + AssemblyRef.SystemDesign)] [ReadOnly(true)] [MonitoringDescription(SR.LogLog)] [DefaultValue("")] [SettingsBindable(true)] [SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity", Justification = "[....]: Safe, oldLog.machineName doesn't change")] [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts", Justification = "[....]: By design, see justification above assert")] public string Log { get { return m_underlyingEventLog.Log; } set { EventLogInternal newLog = new EventLogInternal(value, m_underlyingEventLog.MachineName, m_underlyingEventLog.Source, this); EventLogInternal oldLog = m_underlyingEventLog; // EnableRaisingEvents and Close demand Write permission but that permission might be removed upstack // previously we didn't call Close() since we were reusing the same object. We assert the permission here. new EventLogPermission(EventLogPermissionAccess.Write, oldLog.machineName).Assert(); if (oldLog.EnableRaisingEvents) { newLog.onEntryWrittenHandler = oldLog.onEntryWrittenHandler; newLog.EnableRaisingEvents = true; } m_underlyingEventLog = newLog; oldLog.Close(); } } ////// Gets or sets the name of the log to read from and write to. /// ////// [ReadOnly(true)] [MonitoringDescription(SR.LogMachineName)] [DefaultValue(".")] [SettingsBindable(true)] [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts", Justification = "[....]: By design, see justification above assert")] public string MachineName { get { return m_underlyingEventLog.MachineName; } set { EventLogInternal newLog = new EventLogInternal(m_underlyingEventLog.logName, value, m_underlyingEventLog.sourceName, this); EventLogInternal oldLog = m_underlyingEventLog; // EnableRaisingEvents and Close demand Write permission but that permission might be removed upstack // previously we didn't call Close() since we were reusing the same object. We assert the permission here. new EventLogPermission(EventLogPermissionAccess.Write, oldLog.machineName).Assert(); if (oldLog.EnableRaisingEvents) { newLog.onEntryWrittenHandler = oldLog.onEntryWrittenHandler; newLog.EnableRaisingEvents = true; } m_underlyingEventLog = newLog; oldLog.Close(); } } [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Browsable(false)] [ComVisible(false)] public long MaximumKilobytes { get { return m_underlyingEventLog.MaximumKilobytes; } [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] set { m_underlyingEventLog.MaximumKilobytes = value; } } [Browsable(false)] [ComVisible(false)] public OverflowAction OverflowAction { get { return m_underlyingEventLog.OverflowAction; } } [Browsable(false)] [ComVisible(false)] public int MinimumRetentionDays { get { return m_underlyingEventLog.MinimumRetentionDays; } } // EventLogInternal needs to know if the component is in design mode but // the DesignMode property is protected. internal bool ComponentDesignMode { get { return this.DesignMode; } } // Expose for EventLogInternal internal object ComponentGetService(Type service) { return GetService(service); } ////// Gets or sets the name of the computer on which to read or write events. /// ////// [Browsable(false)] [MonitoringDescription(SR.LogMonitoring)] [DefaultValue(false)] public bool EnableRaisingEvents { get { return m_underlyingEventLog.EnableRaisingEvents; } set { m_underlyingEventLog.EnableRaisingEvents = value; } } ////// [Browsable(false)] [DefaultValue(null)] [MonitoringDescription(SR.LogSynchronizingObject)] public ISynchronizeInvoke SynchronizingObject { [HostProtection(Synchronization=true)] get { return m_underlyingEventLog.SynchronizingObject; } set { m_underlyingEventLog.SynchronizingObject = value; } } ////// Represents the object used to marshal the event handler /// calls issued as a result of an ////// change. /// /// [ReadOnly(true)] [TypeConverter("System.Diagnostics.Design.StringValueConverter, " + AssemblyRef.SystemDesign)] [MonitoringDescription(SR.LogSource)] [DefaultValue("")] [SettingsBindable(true)] [SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity", Justification = "[....]: Safe, oldLog.machineName doesn't change")] [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts", Justification = "[....]: By design, see justification above assert")] public string Source { get { return m_underlyingEventLog.Source; } set { EventLogInternal newLog = new EventLogInternal(m_underlyingEventLog.Log, m_underlyingEventLog.MachineName, CheckAndNormalizeSourceName(value), this); EventLogInternal oldLog = m_underlyingEventLog; // EnableRaisingEvents and Close demand Write permission but that permission might be removed upstack // previously we didn't call Close() since we were reusing the same object. We assert the permission here. new EventLogPermission(EventLogPermissionAccess.Write, oldLog.machineName).Assert(); if (oldLog.EnableRaisingEvents) { newLog.onEntryWrittenHandler = oldLog.onEntryWrittenHandler; newLog.EnableRaisingEvents = true; } m_underlyingEventLog = newLog; oldLog.Close(); } } ////// Gets or /// sets the application name (source name) to register and use when writing to the event log. /// ////// [MonitoringDescription(SR.LogEntryWritten)] public event EntryWrittenEventHandler EntryWritten { add { m_underlyingEventLog.EntryWritten += value; } remove { m_underlyingEventLog.EntryWritten -= value; } } ////// Occurs when an entry is written to the event log. /// ////// public void BeginInit() { m_underlyingEventLog.BeginInit(); } ////// [ResourceExposure(ResourceScope.Machine)] // Should anyone ever call this, other than an event log viewer? [ResourceConsumption(ResourceScope.Machine)] public void Clear() { m_underlyingEventLog.Clear(); } ////// Clears /// the event log by removing all entries from it. /// ////// [ResourceExposure(ResourceScope.None)] public void Close() { m_underlyingEventLog.Close(); } ////// Closes the event log and releases read and write handles. /// ////// public static void CreateEventSource(string source, string logName) { CreateEventSource(new EventSourceCreationData(source, logName, ".")); } ///Establishes an application, using the /// specified ///, as a valid event source for /// writing entries /// to a log on the local computer. This method /// can also be used to create /// a new custom log on the local computer. /// [Obsolete("This method has been deprecated. Please use System.Diagnostics.EventLog.CreateEventSource(EventSourceCreationData sourceData) instead. http://go.microsoft.com/fwlink/?linkid=14202")] public static void CreateEventSource(string source, string logName, string machineName) { CreateEventSource(new EventSourceCreationData(source, logName, machineName)); } [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] public static void CreateEventSource(EventSourceCreationData sourceData) { if (sourceData == null) throw new ArgumentNullException("sourceData"); string logName = sourceData.LogName; string source = sourceData.Source; string machineName = sourceData.MachineName; // verify parameters Debug.WriteLineIf(CompModSwitches.EventLog.TraceVerbose, "CreateEventSource: Checking arguments"); if (!SyntaxCheck.CheckMachineName(machineName)) { throw new ArgumentException(SR.GetString(SR.InvalidParameter, "machineName", machineName)); } if (logName == null || logName.Length==0) logName = "Application"; if (!ValidLogName(logName, false)) throw new ArgumentException(SR.GetString(SR.BadLogName)); if (source == null || source.Length==0) throw new ArgumentException(SR.GetString(SR.MissingParameter, "source")); if (source.Length + EventLogKey.Length > 254) throw new ArgumentException(SR.GetString(SR.ParameterTooLong, "source", 254 - EventLogKey.Length)); EventLogPermission permission = new EventLogPermission(EventLogPermissionAccess.Administer, machineName); permission.Demand(); Mutex mutex = null; RuntimeHelpers.PrepareConstrainedRegions(); try { SharedUtils.EnterMutex(eventLogMutexName, ref mutex); Debug.WriteLineIf(CompModSwitches.EventLog.TraceVerbose, "CreateEventSource: Calling SourceExists"); if (SourceExists(source, machineName, true)) { Debug.WriteLineIf(CompModSwitches.EventLog.TraceVerbose, "CreateEventSource: SourceExists returned true"); // don't let them register a source if it already exists // this makes more sense than just doing it anyway, because the source might // be registered under a different log name, and we don't want to create // duplicates. if (".".Equals(machineName)) throw new ArgumentException(SR.GetString(SR.LocalSourceAlreadyExists, source)); else throw new ArgumentException(SR.GetString(SR.SourceAlreadyExists, source, machineName)); } Debug.WriteLineIf(CompModSwitches.EventLog.TraceVerbose, "CreateEventSource: Getting DllPath"); //SECREVIEW: Note that EventLog permission is demanded above. PermissionSet permissionSet = _UnsafeGetAssertPermSet(); permissionSet.Assert(); RegistryKey baseKey = null; RegistryKey eventKey = null; RegistryKey logKey = null; RegistryKey sourceLogKey = null; RegistryKey sourceKey = null; try { Debug.WriteLineIf(CompModSwitches.EventLog.TraceVerbose, "CreateEventSource: Getting local machine regkey"); if (machineName == ".") baseKey = Registry.LocalMachine; else baseKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, machineName); eventKey = baseKey.OpenSubKey("SYSTEM\\CurrentControlSet\\Services\\EventLog", true); if (eventKey == null) { if (!".".Equals(machineName)) throw new InvalidOperationException(SR.GetString(SR.RegKeyMissing, "SYSTEM\\CurrentControlSet\\Services\\EventLog", logName, source, machineName)); else throw new InvalidOperationException(SR.GetString(SR.LocalRegKeyMissing, "SYSTEM\\CurrentControlSet\\Services\\EventLog", logName, source)); } // The event log system only treats the first 8 characters of the log name as // significant. If they're creating a new log, but that new log has the same // first 8 characters as another log, the system will think they're the same. // Throw an exception to let them know. logKey = eventKey.OpenSubKey(logName, true); if (logKey == null && logName.Length >= 8) { // check for Windows embedded logs file names string logNameFirst8 = logName.Substring(0,8); if ( string.Compare(logNameFirst8,"AppEvent",StringComparison.OrdinalIgnoreCase) ==0 || string.Compare(logNameFirst8,"SecEvent",StringComparison.OrdinalIgnoreCase) ==0 || string.Compare(logNameFirst8,"SysEvent",StringComparison.OrdinalIgnoreCase) ==0 ) throw new ArgumentException(SR.GetString(SR.InvalidCustomerLogName, logName)); string sameLogName = FindSame8FirstCharsLog(eventKey, logName); if ( sameLogName != null ) throw new ArgumentException(SR.GetString(SR.DuplicateLogName, logName, sameLogName)); } bool createLogKey = (logKey == null); if (createLogKey) { if (SourceExists(logName, machineName, true)) { // don't let them register a log name that already // exists as source name, a source with the same // name as the log will have to be created by default if (".".Equals(machineName)) throw new ArgumentException(SR.GetString(SR.LocalLogAlreadyExistsAsSource, logName)); else throw new ArgumentException(SR.GetString(SR.LogAlreadyExistsAsSource, logName, machineName)); } logKey = eventKey.CreateSubKey(logName); // NOTE: We shouldn't set "Sources" explicitly, the OS will automatically set it. // The EventLog service doesn't use it for anything it is just an helping hand for event viewer filters. // Writing this value explicitly might confuse the service as it might perceive it as a change and // start initializing again if (!SkipRegPatch) logKey.SetValue("Sources", new string[] {logName, source}, RegistryValueKind.MultiString); SetSpecialLogRegValues(logKey, logName); // A source with the same name as the log has to be created // by default. It is the behavior expected by EventLog API. sourceLogKey = logKey.CreateSubKey(logName); SetSpecialSourceRegValues(sourceLogKey, sourceData); } if (logName != source) { if (!createLogKey) { SetSpecialLogRegValues(logKey, logName); if (!SkipRegPatch) { string[] sources = logKey.GetValue("Sources") as string[]; if (sources == null) logKey.SetValue("Sources", new string[] {logName, source}, RegistryValueKind.MultiString); else { // We have a ---- with OS EventLog here. // OS might update Sources as well. We should avoid writing the // source name if OS beats us. if( Array.IndexOf(sources, source) == -1) { string[] newsources = new string[sources.Length + 1]; Array.Copy(sources, newsources, sources.Length); newsources[sources.Length] = source; logKey.SetValue("Sources", newsources, RegistryValueKind.MultiString); } } } } sourceKey = logKey.CreateSubKey(source); SetSpecialSourceRegValues(sourceKey, sourceData); } } finally { if (baseKey != null) baseKey.Close(); if (eventKey != null) eventKey.Close(); if (logKey != null) { logKey.Flush(); logKey.Close(); } if (sourceLogKey != null) { sourceLogKey.Flush(); sourceLogKey.Close(); } if (sourceKey != null) { sourceKey.Flush(); sourceKey.Close(); } // Revert registry and environment permission asserts CodeAccessPermission.RevertAssert(); } } finally { if (mutex != null) { mutex.ReleaseMutex(); mutex.Close(); } } } ///Establishes an application, using the specified /// ///as a valid event source for writing /// entries to a log on the computer /// specified by . This method can also be used to create a new /// custom log on the given computer. /// [ResourceExposure(ResourceScope.Machine)] // See why someone would delete an event log [ResourceConsumption(ResourceScope.Machine)] public static void Delete(string logName) { Delete(logName, "."); } ////// Removes /// an event /// log from the local computer. /// ////// [ResourceExposure(ResourceScope.Machine)] // See why someone would delete an event log [ResourceConsumption(ResourceScope.Machine)] public static void Delete(string logName, string machineName) { if (!SyntaxCheck.CheckMachineName(machineName)) throw new ArgumentException(SR.GetString(SR.InvalidParameterFormat, "machineName")); if (logName == null || logName.Length==0) throw new ArgumentException(SR.GetString(SR.NoLogName)); if (!ValidLogName(logName, false)) throw new InvalidOperationException(SR.GetString(SR.BadLogName)); EventLogPermission permission = new EventLogPermission(EventLogPermissionAccess.Administer, machineName); permission.Demand(); //Check environment before even trying to play with the registry SharedUtils.CheckEnvironment(); //SECREVIEW: Note that EventLog permission is demanded above. PermissionSet permissionSet = _UnsafeGetAssertPermSet(); permissionSet.Assert(); RegistryKey eventlogkey = null; Mutex mutex = null; RuntimeHelpers.PrepareConstrainedRegions(); try { SharedUtils.EnterMutex(eventLogMutexName, ref mutex); try { eventlogkey = GetEventLogRegKey(machineName, true); if (eventlogkey == null) { // there's not even an event log service on the machine. // or, more likely, we don't have the access to read the registry. throw new InvalidOperationException(SR.GetString(SR.RegKeyNoAccess, "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\EventLog", machineName)); } using (RegistryKey logKey = eventlogkey.OpenSubKey(logName)) { if (logKey == null) throw new InvalidOperationException(SR.GetString(SR.MissingLog, logName, machineName)); //clear out log before trying to delete it //that way, if we can't delete the log file, no entries will persist because it has been cleared EventLog logToClear = new EventLog(logName, machineName); try { logToClear.Clear(); } finally { logToClear.Close(); } // string filename = null; try { //most of the time, the "File" key does not exist, but we'll still give it a whirl filename = (string) logKey.GetValue("File"); } catch { } if (filename != null) { try { File.Delete(filename); } catch { } } } // now delete the registry entry eventlogkey.DeleteSubKeyTree(logName); } finally { if (eventlogkey != null) eventlogkey.Close(); // Revert registry and environment permission asserts CodeAccessPermission.RevertAssert(); } } finally { if (mutex != null) mutex.ReleaseMutex(); } } ////// Removes /// an /// event /// log from the specified computer. /// ////// [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] public static void DeleteEventSource(string source) { DeleteEventSource(source, "."); } ////// Removes the event source /// registration from the event log of the local computer. /// ////// [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] public static void DeleteEventSource(string source, string machineName) { if (!SyntaxCheck.CheckMachineName(machineName)) { throw new ArgumentException(SR.GetString(SR.InvalidParameter, "machineName", machineName)); } EventLogPermission permission = new EventLogPermission(EventLogPermissionAccess.Administer, machineName); permission.Demand(); //Check environment before looking at the registry SharedUtils.CheckEnvironment(); //SECREVIEW: Note that EventLog permission is demanded above. PermissionSet permissionSet = _UnsafeGetAssertPermSet(); permissionSet.Assert(); Mutex mutex = null; RuntimeHelpers.PrepareConstrainedRegions(); try { SharedUtils.EnterMutex(eventLogMutexName, ref mutex); RegistryKey key = null; // First open the key read only so we can do some checks. This is important so we get the same // exceptions even if we don't have write access to the reg key. using (key = FindSourceRegistration(source, machineName, true)) { if (key == null) { if (machineName == null) throw new ArgumentException(SR.GetString(SR.LocalSourceNotRegistered, source)); else throw new ArgumentException(SR.GetString(SR.SourceNotRegistered, source, machineName, "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\EventLog")); } // Check parent registry key (Event Log Name) and if it's equal to source, then throw an exception. // The reason: each log registry key must always contain subkey (i.e. source) with the same name. string keyname = key.Name; int index = keyname.LastIndexOf('\\'); if ( string.Compare(keyname, index+1, source, 0, keyname.Length - index, StringComparison.Ordinal) == 0 ) throw new InvalidOperationException(SR.GetString(SR.CannotDeleteEqualSource, source)); } try { // now open it read/write to try to do the actual delete key = FindSourceRegistration(source, machineName, false); key.DeleteSubKeyTree(source); if (!SkipRegPatch) { string[] sources = (string[]) key.GetValue("Sources"); ArrayList newsources = new ArrayList(sources.Length - 1); for (int i=0; i/// Removes /// the application's event source registration from the specified computer. /// ////// protected override void Dispose(bool disposing) { if(m_underlyingEventLog != null) { m_underlyingEventLog.Dispose(disposing); } base.Dispose(disposing); } /// /// public void EndInit() { m_underlyingEventLog.EndInit(); } ////// public static bool Exists(string logName) { return Exists(logName, "."); } ////// Determines whether the log /// exists on the local computer. /// ////// [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] public static bool Exists(string logName, string machineName) { if (!SyntaxCheck.CheckMachineName(machineName)) throw new ArgumentException(SR.GetString(SR.InvalidParameterFormat, "machineName")); EventLogPermission permission = new EventLogPermission(EventLogPermissionAccess.Administer, machineName); permission.Demand(); if (logName == null || logName.Length==0) return false; //Check environment before looking at the registry SharedUtils.CheckEnvironment(); //SECREVIEW: Note that EventLog permission is demanded above. PermissionSet permissionSet = _UnsafeGetAssertPermSet(); permissionSet.Assert(); RegistryKey eventkey = null; RegistryKey logKey = null; try { eventkey = GetEventLogRegKey(machineName, false); if (eventkey == null) return false; logKey = eventkey.OpenSubKey(logName, false); // try to find log file key immediately. return (logKey != null ); } finally { if (eventkey != null) eventkey.Close(); if (logKey != null) logKey.Close(); // Revert registry and environment permission asserts CodeAccessPermission.RevertAssert(); } } // Try to find log file name with the same 8 first characters. // Returns 'null' if no "same first 8 chars" log is found. logName.Length must be > 7 private static string FindSame8FirstCharsLog(RegistryKey keyParent, string logName) { string logNameFirst8 = logName.Substring(0, 8); string[] logNames = keyParent.GetSubKeyNames(); for (int i = 0; i < logNames.Length; i++) { string currentLogName = logNames[i]; if ( currentLogName.Length >= 8 && string.Compare(currentLogName.Substring(0, 8), logNameFirst8, StringComparison.OrdinalIgnoreCase) == 0) return currentLogName; } return null; // not found } ////// Determines whether the /// log exists on the specified computer. /// ////// Gets a RegistryKey that points to the LogName entry in the registry that is /// the parent of the given source on the given machine, or null if none is found. /// [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] private static RegistryKey FindSourceRegistration(string source, string machineName, bool readOnly) { return FindSourceRegistration(source, machineName, readOnly, false); } ////// Gets a RegistryKey that points to the LogName entry in the registry that is /// the parent of the given source on the given machine, or null if none is found. /// [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] private static RegistryKey FindSourceRegistration(string source, string machineName, bool readOnly, bool wantToCreate) { if (source != null && source.Length != 0) { //Check environment before looking at the registry SharedUtils.CheckEnvironment(); //SECREVIEW: Any call to this function must have demmanded // EventLogPermission before. PermissionSet permissionSet = _UnsafeGetAssertPermSet(); permissionSet.Assert(); RegistryKey eventkey = null; try { eventkey = GetEventLogRegKey(machineName, !readOnly); if (eventkey == null) { // there's not even an event log service on the machine. // or, more likely, we don't have the access to read the registry. return null; } StringBuilder inaccessibleLogs = null; // Most machines will return only { "Application", "System", "Security" }, // but you can create your own if you want. string[] logNames = eventkey.GetSubKeyNames(); for (int i = 0; i < logNames.Length; i++) { // see if the source is registered in this log. // NOTE: A source name must be unique across ALL LOGS! RegistryKey sourceKey = null; try { RegistryKey logKey = eventkey.OpenSubKey(logNames[i], /*writable*/!readOnly); if (logKey != null) { sourceKey = logKey.OpenSubKey(source, /*writable*/!readOnly); if (sourceKey != null) { // found it return logKey; } } // else logKey is null, so we don't need to Close it } catch (UnauthorizedAccessException) { if (inaccessibleLogs == null) { inaccessibleLogs = new StringBuilder(logNames[i]); } else { inaccessibleLogs.Append(", "); inaccessibleLogs.Append(logNames[i]); } } catch (SecurityException) { if (inaccessibleLogs == null) { inaccessibleLogs = new StringBuilder(logNames[i]); } else { inaccessibleLogs.Append(", "); inaccessibleLogs.Append(logNames[i]); } } finally { if (sourceKey != null) sourceKey.Close(); } } if (inaccessibleLogs != null) throw new SecurityException(SR.GetString(wantToCreate ? SR.SomeLogsInaccessibleToCreate : SR.SomeLogsInaccessible, inaccessibleLogs.ToString())); } finally { if (eventkey != null) eventkey.Close(); // Revert registry and environment permission asserts CodeAccessPermission.RevertAssert(); } // didn't see it anywhere } return null; } ////// public static EventLog[] GetEventLogs() { return GetEventLogs("."); } ////// Searches for all event logs on the local computer and /// creates an array of ////// objects to contain the /// list. /// /// [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] public static EventLog[] GetEventLogs(string machineName) { if (!SyntaxCheck.CheckMachineName(machineName)) { throw new ArgumentException(SR.GetString(SR.InvalidParameter, "machineName", machineName)); } EventLogPermission permission = new EventLogPermission(EventLogPermissionAccess.Administer, machineName); permission.Demand(); //Check environment before looking at the registry SharedUtils.CheckEnvironment(); string[] logNames = new string[0]; //SECREVIEW: Note that EventLogPermission is just demmanded above PermissionSet permissionSet = _UnsafeGetAssertPermSet(); permissionSet.Assert(); RegistryKey eventkey = null; try { // we figure out what logs are on the machine by looking in the registry. eventkey = GetEventLogRegKey(machineName, false); if (eventkey == null) // there's not even an event log service on the machine. // or, more likely, we don't have the access to read the registry. throw new InvalidOperationException(SR.GetString(SR.RegKeyMissingShort, EventLogKey, machineName)); // Most machines will return only { "Application", "System", "Security" }, // but you can create your own if you want. logNames = eventkey.GetSubKeyNames(); } finally { if (eventkey != null) eventkey.Close(); // Revert registry and environment permission asserts CodeAccessPermission.RevertAssert(); } // now create EventLog objects that point to those logs EventLog[] logs = new EventLog[logNames.Length]; for (int i = 0; i < logNames.Length; i++) { EventLog log = new EventLog(logNames[i], machineName); logs[i] = log; } return logs; } [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] internal static RegistryKey GetEventLogRegKey(string machine, bool writable) { RegistryKey lmkey = null; try { if (machine.Equals(".")) { lmkey = Registry.LocalMachine; } else { lmkey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, machine); } if (lmkey != null) return lmkey.OpenSubKey(EventLogKey, writable); } finally { if (lmkey != null) lmkey.Close(); } return null; } [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] internal static string GetDllPath(string machineName) { return Path.Combine(SharedUtils.GetLatestBuildDllDirectory(machineName), DllName); } ////// Searches for all event logs on the given computer and /// creates an array of ////// objects to contain the /// list. /// /// public static bool SourceExists(string source) { return SourceExists(source, "."); } ////// Determines whether an event source is registered on the local computer. /// ////// [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] public static bool SourceExists(string source, string machineName) { return SourceExists(source, machineName, false); } ////// Determines whether an event /// source is registered on a specified computer. /// ////// [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] [SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity", Justification = "[....]: Safe, machineName doesn't change")] private static bool SourceExists(string source, string machineName, bool wantToCreate) { if (!SyntaxCheck.CheckMachineName(machineName)) { throw new ArgumentException(SR.GetString(SR.InvalidParameter, "machineName", machineName)); } EventLogPermission permission = new EventLogPermission(EventLogPermissionAccess.Write, machineName); permission.Demand(); using (RegistryKey keyFound = FindSourceRegistration(source, machineName, true, wantToCreate)) { return (keyFound != null); } } ////// Determines whether an event /// source is registered on a specified computer. /// ////// Gets the name of the log that the given source name is registered in. /// public static string LogNameFromSourceName(string source, string machineName) { EventLogPermission permission = new EventLogPermission(EventLogPermissionAccess.Administer, machineName); permission.Demand(); return _InternalLogNameFromSourceName(source, machineName); } // No permission check, use with care! [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] private static string _InternalLogNameFromSourceName(string source, string machineName) { using (RegistryKey key = FindSourceRegistration(source, machineName, true)) { if (key == null) return ""; else { string name = key.Name; int whackPos = name.LastIndexOf('\\'); // this will work even if whackPos is -1 return name.Substring(whackPos+1); } } } [ComVisible(false)] [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] public void ModifyOverflowPolicy(OverflowAction action, int retentionDays) { m_underlyingEventLog.ModifyOverflowPolicy(action, retentionDays); } [ComVisible(false)] [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] public void RegisterDisplayName(string resourceFile, long resourceId) { m_underlyingEventLog.RegisterDisplayName(resourceFile, resourceId); } // The reasoning behind filling these values is historical. WS03 RTM had a ---- // between registry changes and EventLog service, which made the service wait 2 secs // before retrying to see whether all regkey values are present. To avoid this // potential lag (worst case up to n*2 secs where n is the number of required regkeys) // between creation and being able to write events, we started filling some of these // values explicitly but for XP and latter OS releases like WS03 SP1 and Vista this // is not necessary and in some cases like the "File" key it's plain wrong to write. private static void SetSpecialLogRegValues(RegistryKey logKey, string logName) { // Set all the default values for this log. AutoBackupLogfiles only makes sense in // Win2000 SP4, WinXP SP1, and Win2003, but it should alright elsewhere. // Since we use this method on the existing system logs as well as our own, // we need to make sure we don't overwrite any existing values. if (logKey.GetValue("MaxSize") == null) logKey.SetValue("MaxSize", DefaultMaxSize, RegistryValueKind.DWord); if (logKey.GetValue("AutoBackupLogFiles") == null) logKey.SetValue("AutoBackupLogFiles", 0, RegistryValueKind.DWord); if (!SkipRegPatch) { // In Vista, "retention of events for 'n' days" concept is removed if (logKey.GetValue("Retention") == null) logKey.SetValue("Retention", DefaultRetention, RegistryValueKind.DWord); if (logKey.GetValue("File") == null) { string filename; if (logName.Length > 8) filename = @"%SystemRoot%\System32\config\" + logName.Substring(0,8) + ".evt"; else filename = @"%SystemRoot%\System32\config\" + logName + ".evt"; logKey.SetValue("File", filename, RegistryValueKind.ExpandString); } } } [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] private static void SetSpecialSourceRegValues(RegistryKey sourceLogKey, EventSourceCreationData sourceData) { if (String.IsNullOrEmpty(sourceData.MessageResourceFile)) sourceLogKey.SetValue("EventMessageFile", GetDllPath(sourceData.MachineName), RegistryValueKind.ExpandString); else sourceLogKey.SetValue("EventMessageFile", FixupPath(sourceData.MessageResourceFile), RegistryValueKind.ExpandString); if (!String.IsNullOrEmpty(sourceData.ParameterResourceFile)) sourceLogKey.SetValue("ParameterMessageFile", FixupPath(sourceData.ParameterResourceFile), RegistryValueKind.ExpandString); if (!String.IsNullOrEmpty(sourceData.CategoryResourceFile)) { sourceLogKey.SetValue("CategoryMessageFile", FixupPath(sourceData.CategoryResourceFile), RegistryValueKind.ExpandString); sourceLogKey.SetValue("CategoryCount", sourceData.CategoryCount, RegistryValueKind.DWord); } } [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] private static string FixupPath(string path) { if (path[0] == '%') return path; else return Path.GetFullPath(path); } // Format message in specific DLL. Returnon failure. internal static string TryFormatMessage(SafeLibraryHandle hModule, uint messageNum, string[] insertionStrings) { if (insertionStrings.Length == 0) { // UnsafeTryFromatMessage will set FORMAT_MESSAGE_IGNORE_INSERTS when calling into the OS // when there are no insertion strings, in this case we don't have to guard against insertionStrings // not having enough data since it is unused when FORMAT_MESSAGE_IGNORE_INSERTS is specified return UnsafeTryFormatMessage(hModule, messageNum, insertionStrings); } // If you pass in an empty array UnsafeTryFormatMessage will just pull out the message. string formatString = UnsafeTryFormatMessage(hModule, messageNum, new string[0]); if (formatString == null) { return null; } int largestNumber = 0; for (int i = 0; i < formatString.Length; i++) { if (formatString[i] == '%') { // See if a number follows this, if so, grab the number. if(formatString.Length > i + 1) { StringBuilder sb = new StringBuilder(); while (i + 1 < formatString.Length && Char.IsDigit(formatString[i + 1])) { sb.Append(formatString[i + 1]); i++; } // move over the non number character that broke us out of the loop i++; if (sb.Length > 0) { int num = -1; if (Int32.TryParse(sb.ToString(), NumberStyles.None, CultureInfo.InvariantCulture, out num)) { largestNumber = Math.Max(largestNumber, num); } } } } } // Replacement strings are 1 indexed. if (largestNumber > insertionStrings.Length) { string[] newStrings = new string[largestNumber]; Array.Copy(insertionStrings, newStrings, insertionStrings.Length); for (int i = insertionStrings.Length; i < newStrings.Length; i++) { newStrings[i] = "%" + (i + 1); } insertionStrings = newStrings; } return UnsafeTryFormatMessage(hModule, messageNum, insertionStrings); } // FormatMessageW will AV if you don't pass in enough format strings. If you call TryFormatMessage we ensure insertionStrings // is long enough. You don't want to call this directly unless you're sure insertionStrings is long enough! internal static string UnsafeTryFormatMessage(SafeLibraryHandle hModule, uint messageNum, string[] insertionStrings) { string msg = null; int msgLen = 0; StringBuilder buf = new StringBuilder(1024); int flags = NativeMethods.FORMAT_MESSAGE_FROM_HMODULE | NativeMethods.FORMAT_MESSAGE_ARGUMENT_ARRAY; IntPtr[] addresses = new IntPtr[insertionStrings.Length]; GCHandle[] handles = new GCHandle[insertionStrings.Length]; GCHandle stringsRoot = GCHandle.Alloc(addresses, GCHandleType.Pinned); // Make sure that we don't try to pass in a zero length array of addresses. If there are no insertion strings, // we'll use the FORMAT_MESSAGE_IGNORE_INSERTS flag . // If you change this behavior, make sure you look at TryFormatMessage which depends on this behavior! if (insertionStrings.Length == 0) { flags |= NativeMethods.FORMAT_MESSAGE_IGNORE_INSERTS; } try { for (int i=0; i 0) { msg = buf.ToString(); // chop off a single CR/LF pair from the end if there is one. FormatMessage always appends one extra. if (msg.Length > 1 && msg[msg.Length-1] == '\n') msg = msg.Substring(0, msg.Length-2); } return msg; } // CharIsPrintable used to be Char.IsPrintable, but Jay removed it and // is forcing people to use the Unicode categories themselves. Copied // the code here. private static bool CharIsPrintable(char c) { UnicodeCategory uc = Char.GetUnicodeCategory(c); return (!(uc == UnicodeCategory.Control) || (uc == UnicodeCategory.Format) || (uc == UnicodeCategory.LineSeparator) || (uc == UnicodeCategory.ParagraphSeparator) || (uc == UnicodeCategory.OtherNotAssigned)); } // SECREVIEW: Make sure this method catches all the strange cases. internal static bool ValidLogName(string logName, bool ignoreEmpty) { // No need to trim here since the next check will verify that there are no spaces. // We need to ignore the empty string as an invalid log name sometimes because it can // be passed in from our default constructor. if (logName.Length == 0 && !ignoreEmpty) return false; //any space, backslash, asterisk, or question mark is bad //any non-printable characters are also bad foreach (char c in logName) if (!CharIsPrintable(c) || (c == '\\') || (c == '*') || (c == '?')) return false; return true; } /// /// public void WriteEntry(string message) { WriteEntry(message, EventLogEntryType.Information, (short) 0, 0, null); } ////// Writes an information type entry with the given message text to the event log. /// ////// public static void WriteEntry(string source, string message) { WriteEntry(source, message, EventLogEntryType.Information, (short) 0, 0, null); } ////// public void WriteEntry(string message, EventLogEntryType type) { WriteEntry(message, type, (short) 0, 0, null); } ////// Writes an entry of the specified ///to the event log. Valid types are /// , , , /// , and . /// /// public static void WriteEntry(string source, string message, EventLogEntryType type) { WriteEntry(source, message, type, (short) 0, 0, null); } ///[To be supplied.] ////// public void WriteEntry(string message, EventLogEntryType type, int eventID) { WriteEntry(message, type, eventID, 0, null); } ////// Writes an entry of the specified ////// and with the /// user-defined /// to /// the event log. /// /// public static void WriteEntry(string source, string message, EventLogEntryType type, int eventID) { WriteEntry(source, message, type, eventID, 0, null); } ///[To be supplied.] ////// public void WriteEntry(string message, EventLogEntryType type, int eventID, short category) { WriteEntry(message, type, eventID, category, null); } ////// Writes an entry of the specified type with the /// user-defined ///and /// to the event log. The /// can be used by the event viewer to filter events in the log. /// /// public static void WriteEntry(string source, string message, EventLogEntryType type, int eventID, short category) { WriteEntry(source, message, type, eventID, category, null); } ///[To be supplied.] ////// public static void WriteEntry(string source, string message, EventLogEntryType type, int eventID, short category, byte[] rawData) { using (EventLogInternal log = new EventLogInternal("", ".", CheckAndNormalizeSourceName(source))) { log.WriteEntry(message, type, eventID, category, rawData); } } ///[To be supplied.] ////// public void WriteEntry(string message, EventLogEntryType type, int eventID, short category, byte[] rawData) { m_underlyingEventLog.WriteEntry(message, type, eventID, category, rawData); } [ComVisible(false)] public void WriteEvent(EventInstance instance, params Object[] values) { WriteEvent(instance, null, values); } [ComVisible(false)] public void WriteEvent(EventInstance instance, byte[] data, params Object[] values) { m_underlyingEventLog.WriteEvent(instance, data, values); } public static void WriteEvent(string source, EventInstance instance, params Object[] values) { using (EventLogInternal log = new EventLogInternal("", ".", CheckAndNormalizeSourceName(source))) { log.WriteEvent(instance, null, values); } } public static void WriteEvent(string source, EventInstance instance, byte[] data, params Object[] values) { using (EventLogInternal log = new EventLogInternal("", ".", CheckAndNormalizeSourceName(source))) { log.WriteEvent(instance, data, values); } } // The EventLog.set_Source used to do some normalization and throw some exceptions. We mimic that behavior here. private static string CheckAndNormalizeSourceName(string source) { if (source == null) source = string.Empty; // this 254 limit is the max length of a registry key. if (source.Length + EventLogKey.Length > 254) throw new ArgumentException(SR.GetString(SR.ParameterTooLong, "source", 254 - EventLogKey.Length)); return source; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007./// Writes an entry of the specified type with the /// user-defined ///and to the event log, and appends binary data to /// the message. The Event Viewer does not interpret this data; it /// displays raw data only in a combined hexadecimal and text format. ///
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- QueueProcessor.cs
- TreeViewHitTestInfo.cs
- UpdateTracker.cs
- DoubleCollectionConverter.cs
- Error.cs
- Win32Exception.cs
- TextEditorCharacters.cs
- _ListenerResponseStream.cs
- AncestorChangedEventArgs.cs
- WebConfigurationHost.cs
- ClientRequest.cs
- IncrementalHitTester.cs
- PolicyManager.cs
- PathGradientBrush.cs
- WebPartAuthorizationEventArgs.cs
- HostingEnvironment.cs
- Stackframe.cs
- EdmTypeAttribute.cs
- StreamMarshaler.cs
- AuthStoreRoleProvider.cs
- HtmlImage.cs
- DependencyPropertyDescriptor.cs
- MatrixKeyFrameCollection.cs
- GetMemberBinder.cs
- CroppedBitmap.cs
- FileDialog_Vista_Interop.cs
- SplitContainer.cs
- XmlSchemaAny.cs
- StringFormat.cs
- DropTarget.cs
- OracleCommandBuilder.cs
- ToolStripSeparatorRenderEventArgs.cs
- ClientScriptManager.cs
- ActiveXHelper.cs
- KerberosRequestorSecurityTokenAuthenticator.cs
- UpdateTracker.cs
- DetailsViewUpdateEventArgs.cs
- ParserExtension.cs
- SqlDataReaderSmi.cs
- HttpGetServerProtocol.cs
- TextElementCollection.cs
- StatusBar.cs
- SessionStateModule.cs
- ProcessHostFactoryHelper.cs
- NamespaceCollection.cs
- XmlReturnWriter.cs
- BmpBitmapEncoder.cs
- selecteditemcollection.cs
- ComplexObject.cs
- UrlPath.cs
- CommandBinding.cs
- DataViewManagerListItemTypeDescriptor.cs
- EndOfStreamException.cs
- MaterializeFromAtom.cs
- GiveFeedbackEvent.cs
- HttpModuleAction.cs
- LinkArea.cs
- WinFormsUtils.cs
- DataGridColumnCollection.cs
- XmlDocumentFragment.cs
- FileChangesMonitor.cs
- NativeMethods.cs
- ReliableMessagingVersionConverter.cs
- SafeFindHandle.cs
- InputElement.cs
- securestring.cs
- SqlHelper.cs
- SignatureConfirmationElement.cs
- RsaKeyIdentifierClause.cs
- HebrewCalendar.cs
- XmlObjectSerializerWriteContextComplex.cs
- _HelperAsyncResults.cs
- Stylesheet.cs
- WindowPattern.cs
- TypeGeneratedEventArgs.cs
- CuspData.cs
- XPathDocumentBuilder.cs
- LassoSelectionBehavior.cs
- DataRecordInternal.cs
- ImageSourceValueSerializer.cs
- MailAddress.cs
- MembershipSection.cs
- CodeVariableReferenceExpression.cs
- CodeStatement.cs
- TableStyle.cs
- DaylightTime.cs
- _NegotiateClient.cs
- XmlIgnoreAttribute.cs
- Encoder.cs
- ObjectListGeneralPage.cs
- EntityCommandCompilationException.cs
- ContractMapping.cs
- PropertyIdentifier.cs
- XmlIlVisitor.cs
- DataGridViewMethods.cs
- XmlSchemaDocumentation.cs
- InputDevice.cs
- PrimarySelectionAdorner.cs
- SqlConnectionStringBuilder.cs
- IsolatedStoragePermission.cs