nicko       2004/11/12 14:33:30

  Modified:    src/Appender AdoNetAppender.cs EventLogAppender.cs
                        FileAppender.cs NetSendAppender.cs
                        RollingFileAppender.cs
  Added:       src/Core SecurityContext.cs SecurityContextProvider.cs
               src/Util NullSecurityContext.cs WindowsSecurityContext.cs
  Log:
  Added inital SecurityContext classes
  
  Revision  Changes    Path
  1.1                  logging-log4net/src/Core/SecurityContext.cs
  
  Index: SecurityContext.cs
  ===================================================================
  #region Copyright & License
  //
  // Copyright 2001-2004 The Apache Software Foundation
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  // http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  //
  #endregion
  
  using System;
  
  namespace log4net.Core
  {
        /// <summary>
        /// A SecurityContext used by log4net when interacting with protected 
resources
        /// </summary>
        /// <author>Nicko Cadell</author>
        public abstract class SecurityContext
        {
                /// <summary>
                /// Impersonate this SecurityContext
                /// </summary>
                /// <param name="state">State supplied by the caller</param>
                /// <returns>An <see cref="IDisposable"/> instance that will
                /// revoke the impersonation of this SecurityContext, or 
<c>null</c></returns>
                public abstract IDisposable Impersonate(object state);
        }
  }
  
  
  
  1.1                  logging-log4net/src/Core/SecurityContextProvider.cs
  
  Index: SecurityContextProvider.cs
  ===================================================================
  #region Copyright & License
  //
  // Copyright 2001-2004 The Apache Software Foundation
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  // http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  //
  #endregion
  
  using System;
  
  using log4net.Util;
  
  namespace log4net.Core
  {
        /// <summary>
        /// A SecurityContext used by log4net when interacting with protected 
resources
        /// </summary>
        /// <author>Nicko Cadell</author>
        public class SecurityContextProvider
        {
                /// <summary>
                /// The default provider
                /// </summary>
                private static SecurityContextProvider s_defaultProvider = null;
  
                /// <summary>
                /// Gets or sets the default SecurityContextProvider
                /// </summary>
                /// <value>
                /// The default SecurityContextProvider
                /// </value>
                /// <remarks>
                /// <para>
                /// ........... HOW LOOKUP PROVIDER
                /// </para>
                /// </remarks>
                public static SecurityContextProvider DefaultProvider
                {
                        get 
                        {
                                if (s_defaultProvider == null)
                                {
                                        lock(typeof(SecurityContextProvider))
                                        {
                                                if (s_defaultProvider == null)
                                                {
                                                        // Lookup the default 
provider
                                                        s_defaultProvider = 
CreateDefaultProvider();
                                                }
                                        }
                                }
                                return s_defaultProvider;
                        }
                        set 
                        {
                                s_defaultProvider = value;
                        }
                }
  
                private static SecurityContextProvider CreateDefaultProvider()
                {
                        return new SecurityContextProvider();
                }
  
                /// <summary>
                /// Protected default constructor to allow subclassing
                /// </summary>
                protected SecurityContextProvider()
                {
                }
  
                /// <summary>
                /// Create a SecurityContext for a consumer
                /// </summary>
                /// <param name="consumer">The consumer requesting the 
SecurityContext</param>
                /// <returns>An impersonation context</returns>
                /// <remarks>
                /// <para>
                /// The default implementation is to return a <see 
cref="NullSecurityContext"/>.
                /// </para>
                /// </remarks>
                public virtual SecurityContext CreateSecurityContext(object 
consumer)
                {
                        return NullSecurityContext.Instance;
                }
        }
  }
  
  
  
  1.1                  logging-log4net/src/Util/NullSecurityContext.cs
  
  Index: NullSecurityContext.cs
  ===================================================================
  #region Copyright & License
  //
  // Copyright 2001-2004 The Apache Software Foundation
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  // http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  //
  #endregion
  
  using System;
  
  using log4net.Core;
  
  namespace log4net.Util
  {
        /// <summary>
        /// A SecurityContext used when a SecurityContext is not required
        /// </summary>
        /// <author>Nicko Cadell</author>
        public sealed class NullSecurityContext : SecurityContext
        {
                /// <summary>
                /// Singleton instance of NullSecurityContext
                /// </summary>
                public static readonly NullSecurityContext Instance = new 
NullSecurityContext();
  
                /// <summary>
                /// Private constructor
                /// </summary>
                private NullSecurityContext()
                {
                }
  
                /// <summary>
                /// Impersonate this SecurityContext
                /// </summary>
                /// <param name="state">State supplied by the caller</param>
                /// <returns><c>null</c></returns>
                public override IDisposable Impersonate(object state)
                {
                        return null;
                }
        }
  }
  
  
  
  1.1                  logging-log4net/src/Util/WindowsSecurityContext.cs
  
  Index: WindowsSecurityContext.cs
  ===================================================================
  #region Copyright & License
  //
  // Copyright 2001-2004 The Apache Software Foundation
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  // http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  //
  #endregion
  
  // .NET Compact Framework 1.0 has no support for WindowsIdentity
  #if !NETCF 
  // MONO 1.0 has no support for Win32 Logon APIs
  #if !MONO
  // SSCLI 1.0 has no support for Win32 Logon APIs
  #if !SSCLI
  // We don't want framework or platform specific code in the Core version of 
log4net
  #if !CORE
  
  using System;
  using System.Runtime.InteropServices;
  using System.Security.Principal;
  using System.Security.Permissions;
  
  using log4net.Core;
  
  /*
   * Custom Logging Classes to support additional logging levels.
   */
  namespace log4net.Util
  {
        /// <summary>
        /// Impersonate a Windows Account
        /// </summary>
        /// <remarks>
        /// <para>
        /// This <see cref="SecurityContext"/> impersonates a Windows account.
        /// The account is specified using username, domain name and password.
        /// </para>
        /// </remarks>
        public class WindowsSecurityContext : SecurityContext, IOptionHandler
        {
                #region Member Variables
  
                private string m_userName;
                private string m_domainName = Environment.MachineName;
                private string m_password;
                private WindowsIdentity m_identity;
  
                #endregion
  
                #region Constructor
  
                /// <summary>
                /// Default constructor
                /// </summary>
                public WindowsSecurityContext()
                {
                }
  
                #endregion
  
                #region Public Properties
  
                /// <summary>
                /// The Windows username for this security context
                /// </summary>
                public string UserName
                {
                        get { return m_userName; }
                        set { m_userName = value; }
                }
  
                /// <summary>
                /// The Windows domain name for this security context
                /// </summary>
                /// <remarks>
                /// <para>
                /// The default value for <see cref="DomainName"/> is the local 
machine name
                /// taken from the <see cref="Environment.MachineName"/> 
property.
                /// </para>
                /// </remarks>
                public string DomainName
                {
                        get { return m_domainName; }
                        set { m_domainName = value; }
                }
  
                /// <summary>
                /// The password for the Windows account specified by the <see 
cref="UserName"/> and <see cref="DomainName"/> properties.
                /// </summary>
                public string Password
                {
                        get { return m_password; }
                        set { m_password = value; }
                }
  
                #endregion
  
                #region IOptionHandler Members
  
                /// <summary>
                /// Initialize the SecurityContext based on the options set.
                /// </summary>
                /// <remarks>
                /// <para>
                /// This is part of the <see cref="IOptionHandler"/> delayed 
object
                /// activation scheme. The <see cref="ActivateOptions"/> method 
must 
                /// be called on this object after the configuration properties 
have
                /// been set. Until <see cref="ActivateOptions"/> is called this
                /// object is in an undefined state and must not be used. 
                /// </para>
                /// <para>
                /// If any of the configuration properties are modified then 
                /// <see cref="ActivateOptions"/> must be called again.
                /// </para>
                /// <para>
                /// The security context will try to Logon the specified user 
account and
                /// capture a primary token for impersonation.
                /// </para>
                /// </remarks>
                /// <exception cref="ArgumentNullException">The required <see 
cref="UserName" />, 
                /// <see cref="DomainName" /> or <see cref="Password" /> 
properties were not specified.</exception>
                public void ActivateOptions()
                {
                        if (m_userName == null) throw new 
ArgumentNullException("m_userName");
                        if (m_domainName == null) throw new 
ArgumentNullException("m_domainName");
                        if (m_password == null) throw new 
ArgumentNullException("m_password");
  
                        m_identity = LogonUser(m_userName, m_domainName, 
m_password);
                }
  
                #endregion
  
                /// <summary>
                /// Impersonate the Windows account specified by the <see 
cref="UserName"/> and <see cref="DomainName"/> properties.
                /// </summary>
                /// <param name="state">caller provided state</param>
                /// <returns>An <see cref="IDisposable"/> instance that will
                /// revoke the impersonation of this SecurityContext</returns>
                public override IDisposable Impersonate(object state)
                {
                        if (m_identity != null)
                        {
                                return new 
DisposableImpersonationContext(m_identity.Impersonate());
                        }
                        return null;
                }
  
                /// <summary>
                /// Create a <see cref="WindowsIdentity"/> given the userName, 
domainName and password.
                /// </summary>
                /// <param name="userName">the user name</param>
                /// <param name="domainName">the domain name</param>
                /// <param name="password">the password</param>
                /// <returns>the <see cref="WindowsIdentity"/> for the account 
specified</returns>
                /// <remarks>
                /// <para>
                /// Uses the Windows API call LogonUser to get a principal 
token for the account. This
                /// token is used to initialise the WindowsIdentity.
                /// </para>
                /// </remarks>
                private static WindowsIdentity LogonUser(string userName, 
string domainName, string password)
                {
                        const int LOGON32_PROVIDER_DEFAULT = 0;
                        //This parameter causes LogonUser to create a primary 
token.
                        const int LOGON32_LOGON_INTERACTIVE = 2;
  
                        // Call LogonUser to obtain a handle to an access token.
                        IntPtr tokenHandle = IntPtr.Zero;
                        if(!LogonUser(userName, domainName, password, 
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref tokenHandle))
                        {
                                NativeError error = NativeError.GetLastError();
                                throw new Exception("Failed to LogonUser 
["+userName+"] in Domain ["+domainName+"]. Error: "+ error.ToString());
                        }
  
                        const int SecurityImpersonation = 2;
                        IntPtr dupeTokenHandle = IntPtr.Zero;
                        if(!DuplicateToken(tokenHandle, SecurityImpersonation, 
ref dupeTokenHandle))
                        {
                                NativeError error = NativeError.GetLastError();
                                if (tokenHandle != IntPtr.Zero)
                                {
                                        CloseHandle(tokenHandle);
                                }
                                throw new Exception("Failed to DuplicateToken 
after LogonUser. Error: " + error.ToString());
                        }
  
                        WindowsIdentity identity = new 
WindowsIdentity(dupeTokenHandle);
  
                        // Free the tokens.
                        if (dupeTokenHandle != IntPtr.Zero) 
                        {
                                CloseHandle(dupeTokenHandle);
                        }
                        if (tokenHandle != IntPtr.Zero)
                        {
                                CloseHandle(tokenHandle);
                        }
  
                        return identity;
                }
  
                #region Native Method Stubs
  
                [DllImport("advapi32.dll", SetLastError=true)]
                private static extern bool LogonUser(String lpszUsername, 
String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, 
ref IntPtr phToken);
  
                [DllImport("kernel32.dll", CharSet=CharSet.Auto)]
                private extern static bool CloseHandle(IntPtr handle);
  
                [DllImport("advapi32.dll", CharSet=CharSet.Auto, 
SetLastError=true)]
                private extern static bool DuplicateToken(IntPtr 
ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr 
DuplicateTokenHandle);
  
                #endregion
  
                #region DisposableImpersonationContext class
  
                /// <summary>
                /// Helper class to expose the <see 
cref="WindowsImpersonationContext"/>
                /// through the <see cref="IDisposable"/> interface.
                /// </summary>
                private sealed class DisposableImpersonationContext : 
IDisposable
                {
                        private readonly WindowsImpersonationContext 
m_impersonationContext;
  
                        public 
DisposableImpersonationContext(WindowsImpersonationContext impersonationContext)
                        {
                                m_impersonationContext = impersonationContext;
                        }
  
                        public void Dispose()
                        {
                                m_impersonationContext.Undo();
                        }
                }
  
                #endregion
  
        }
  }
  
  #endif // !CORE
  #endif // !SSCLI
  #endif // !MONO
  #endif // !NETCF
  
  
  
  
  1.7       +36 -2     logging-log4net/src/Appender/AdoNetAppender.cs
  
  Index: AdoNetAppender.cs
  ===================================================================
  RCS file: /home/cvs/logging-log4net/src/Appender/AdoNetAppender.cs,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- AdoNetAppender.cs 7 Jun 2004 01:09:38 -0000       1.6
  +++ AdoNetAppender.cs 12 Nov 2004 22:33:30 -0000      1.7
  @@ -292,6 +292,26 @@
                        set { m_useTransactions = value; }
                }
   
  +             /// <summary>
  +             /// Gets or sets the <see cref="SecurityContext"/> used to call 
the NetSend method.
  +             /// </summary>
  +             /// <value>
  +             /// The <see cref="SecurityContext"/> used to call the NetSend 
method.
  +             /// </value>
  +             /// <remarks>
  +             /// <para>
  +             /// Unless a <see cref="SecurityContext"/> specified here for 
this appender
  +             /// the <see cref="SecurityContextProvider.DefaultProvider"/> 
is queried for the
  +             /// security context to use. The default behaviour is to use 
the security context
  +             /// of the current thread.
  +             /// </para>
  +             /// </remarks>
  +             public SecurityContext SecurityContext 
  +             {
  +                     get { return m_securityContext; }
  +                     set { m_securityContext = value; }
  +             }
  +
                #endregion // Public Instance Properties
   
                #region Protected Instance Properties
  @@ -338,6 +358,12 @@
                override public void ActivateOptions() 
                {
                        base.ActivateOptions();
  +
  +                     if (m_securityContext == null)
  +                     {
  +                             m_securityContext = 
SecurityContextProvider.DefaultProvider.CreateSecurityContext(this);
  +                     }
  +
                        InitializeDatabaseConnection();
   
                        // Are we using a command object
  @@ -565,8 +591,11 @@
                                // Set the connection string
                                m_dbConnection.ConnectionString = 
m_connectionString;
   
  -                             // Open the database connection
  -                             m_dbConnection.Open();
  +                             using(SecurityContext.Impersonate(this))
  +                             {
  +                                     // Open the database connection
  +                                     m_dbConnection.Open();
  +                             }
                        }
                        catch (System.Exception e)
                        {
  @@ -694,6 +723,11 @@
                #endregion // Protected Instance Methods
   
                #region Private Instance Fields
  +
  +             /// <summary>
  +             /// The security context to use for privileged calls
  +             /// </summary>
  +             private SecurityContext m_securityContext;
   
                /// <summary>
                /// The <see cref="IDbConnection" /> that will be used
  
  
  
  1.11      +76 -16    logging-log4net/src/Appender/EventLogAppender.cs
  
  Index: EventLogAppender.cs
  ===================================================================
  RCS file: /home/cvs/logging-log4net/src/Appender/EventLogAppender.cs,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- EventLogAppender.cs       10 Sep 2004 20:58:38 -0000      1.10
  +++ EventLogAppender.cs       12 Nov 2004 22:33:30 -0000      1.11
  @@ -44,7 +44,7 @@
        /// <remarks>
        /// <para>
        /// The <c>EventID</c> of the event log entry can be
  -     /// set using the <c>EventLogEventID</c> property (<see 
cref="LoggingEvent.EventProperties"/>)
  +     /// set using the <c>EventLogEventID</c> property (<see 
cref="LoggingEvent.Properties"/>)
        /// on the <see cref="LoggingEvent"/>.
        /// </para>
        /// <para>
  @@ -176,6 +176,26 @@
                        m_levelMapping.Add(mapping);
                }
   
  +             /// <summary>
  +             /// Gets or sets the <see cref="SecurityContext"/> used to 
write to the EventLog.
  +             /// </summary>
  +             /// <value>
  +             /// The <see cref="SecurityContext"/> used to write to the 
EventLog.
  +             /// </value>
  +             /// <remarks>
  +             /// <para>
  +             /// Unless a <see cref="SecurityContext"/> specified here for 
this appender
  +             /// the <see cref="SecurityContextProvider.DefaultProvider"/> 
is queried for the
  +             /// security context to use. The default behaviour is to use 
the security context
  +             /// of the current thread.
  +             /// </para>
  +             /// </remarks>
  +             public SecurityContext SecurityContext 
  +             {
  +                     get { return m_securityContext; }
  +                     set { m_securityContext = value; }
  +             }
  +
                #endregion // Public Instance Properties
   
                #region Implementation of IOptionHandler
  @@ -199,29 +219,59 @@
                override public void ActivateOptions() 
                {
                        base.ActivateOptions();
  -                     if (EventLog.SourceExists(m_applicationName))
  +
  +                     if (m_securityContext == null)
  +                     {
  +                             m_securityContext = 
SecurityContextProvider.DefaultProvider.CreateSecurityContext(this);
  +                     }
  +
  +                     bool sourceAlreadyExists = false;
  +                     string currentLogName = null;
  +
  +                     using(SecurityContext.Impersonate(this))
                        {
  -                             //
  -                             // Re-register this to the current application 
if the user has changed
  -                             // the application / logfile association
  -                             //
  -                             string logName = 
EventLog.LogNameFromSourceName(m_applicationName, m_machineName);
  -                             if (logName != m_logName)
  +                             sourceAlreadyExists = 
EventLog.SourceExists(m_applicationName);
  +                             if (sourceAlreadyExists)
                                {
  -                                     LogLog.Debug("EventLogAppender: 
Changing event source [" + m_applicationName + "] from log [" + logName + "] to 
log [" + m_logName + "]");
  -                                     
EventLog.DeleteEventSource(m_applicationName, m_machineName);
  -                                     
EventLog.CreateEventSource(m_applicationName, m_logName, m_machineName);
  +                                     currentLogName = 
EventLog.LogNameFromSourceName(m_applicationName, m_machineName);
                                }
                        }
  -                     else
  +
  +                     if (sourceAlreadyExists && currentLogName != m_logName)
  +                     {
  +                             LogLog.Debug("EventLogAppender: Changing event 
source [" + m_applicationName + "] from log [" + currentLogName + "] to log [" 
+ m_logName + "]");
  +                     }
  +                     else if (!sourceAlreadyExists)
                        {
                                LogLog.Debug("EventLogAppender: Creating event 
source Source [" + m_applicationName + "] in log " + m_logName + "]");
  -                             EventLog.CreateEventSource(m_applicationName, 
m_logName, m_machineName);
  +                     }
  +
  +                     string registeredLogName = null;
  +
  +                     using(SecurityContext.Impersonate(this))
  +                     {
  +                             if (sourceAlreadyExists && currentLogName != 
m_logName)
  +                             {
  +                                     //
  +                                     // Re-register this to the current 
application if the user has changed
  +                                     // the application / logfile association
  +                                     //
  +                                     
EventLog.DeleteEventSource(m_applicationName, m_machineName);
  +                                     
EventLog.CreateEventSource(m_applicationName, m_logName, m_machineName);
  +
  +                                     registeredLogName = 
EventLog.LogNameFromSourceName(m_applicationName, m_machineName);
  +                             }
  +                             else if (!sourceAlreadyExists)
  +                             {
  +                                     
EventLog.CreateEventSource(m_applicationName, m_logName, m_machineName);
  +
  +                                     registeredLogName = 
EventLog.LogNameFromSourceName(m_applicationName, m_machineName);
  +                             }
                        }
   
                        m_levelMapping.ActivateOptions();
   
  -                     LogLog.Debug("EventLogAppender: Source [" + 
m_applicationName + "] is registered to log [" + 
EventLog.LogNameFromSourceName(m_applicationName, m_machineName) + "]");        
   
  +                     LogLog.Debug("EventLogAppender: Source [" + 
m_applicationName + "] is registered to log [" + registeredLogName + "]");      
    
                }
   
                #endregion // Implementation of IOptionHandler
  @@ -237,7 +287,7 @@
                /// <para>Writes the event to the system event log using the 
                /// <see cref="ApplicationName"/>.</para>
                /// 
  -             /// <para>If the event has an <c>EventID</c> property (see <see 
cref="LoggingEvent.EventProperties"/>)
  +             /// <para>If the event has an <c>EventID</c> property (see <see 
cref="LoggingEvent.Properties"/>)
                /// set then this integer will be used as the event log event 
id.</para>
                /// 
                /// <para>
  @@ -284,7 +334,12 @@
                                        eventTxt = eventTxt.Substring(0, 32000);
                                }
   
  -                             EventLog.WriteEntry(m_applicationName, 
eventTxt, GetEntryType(loggingEvent.Level), eventID);
  +                             EventLogEntryType entryType = 
GetEntryType(loggingEvent.Level);
  +
  +                             using(SecurityContext.Impersonate(this))
  +                             {
  +                                     EventLog.WriteEntry(m_applicationName, 
eventTxt, entryType, eventID);
  +                             }
                        }
                        catch(Exception ex)
                        {
  @@ -366,6 +421,11 @@
                /// Mapping from level object to EventLogEntryType
                /// </summary>
                private LevelMapping m_levelMapping = new LevelMapping();
  +
  +             /// <summary>
  +             /// The security context to use for privileged calls
  +             /// </summary>
  +             private SecurityContext m_securityContext;
   
                #endregion // Private Instance Fields
   
  
  
  
  1.7       +55 -10    logging-log4net/src/Appender/FileAppender.cs
  
  Index: FileAppender.cs
  ===================================================================
  RCS file: /home/cvs/logging-log4net/src/Appender/FileAppender.cs,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- FileAppender.cs   18 Sep 2004 16:34:16 -0000      1.6
  +++ FileAppender.cs   12 Nov 2004 22:33:30 -0000      1.7
  @@ -114,7 +114,7 @@
                virtual public string File
                {
                        get { return m_fileName; }
  -                     set { m_fileName = ConvertToFullPath(value.Trim()); }
  +                     set { m_fileName = value; }
                }
   
                /// <summary>
  @@ -155,6 +155,26 @@
                        set { m_encoding = value; }
                }
   
  +             /// <summary>
  +             /// Gets or sets the <see cref="SecurityContext"/> used to 
write to the file.
  +             /// </summary>
  +             /// <value>
  +             /// The <see cref="SecurityContext"/> used to write to the file.
  +             /// </value>
  +             /// <remarks>
  +             /// <para>
  +             /// Unless a <see cref="SecurityContext"/> specified here for 
this appender
  +             /// the <see cref="SecurityContextProvider.DefaultProvider"/> 
is queried for the
  +             /// security context to use. The default behaviour is to use 
the security context
  +             /// of the current thread.
  +             /// </para>
  +             /// </remarks>
  +             public SecurityContext SecurityContext 
  +             {
  +                     get { return m_securityContext; }
  +                     set { m_securityContext = value; }
  +             }
  +
                #endregion Public Instance Properties
   
                #region Override implementation of AppenderSkeleton
  @@ -181,6 +201,17 @@
                override public void ActivateOptions() 
                {       
                        base.ActivateOptions();
  +
  +                     if (m_securityContext == null)
  +                     {
  +                             m_securityContext = 
SecurityContextProvider.DefaultProvider.CreateSecurityContext(this);
  +                     }
  +
  +                     using(SecurityContext.Impersonate(this))
  +                     {
  +                             m_fileName = 
ConvertToFullPath(m_fileName.Trim());
  +                     }
  +
                        if (m_fileName != null) 
                        {
                                SafeOpenFile(m_fileName, m_appendToFile);
  @@ -284,18 +315,28 @@
                                // Save these for later, allowing retries if 
file open fails
                                m_fileName = fileName;
                                m_appendToFile = append;
  +                             FileStream fileStream = null;
   
  -                             // Ensure that the directory structure exists
  -                             string directoryFullName = 
Path.GetDirectoryName(fileName);
  -
  -                             // Only create the directory if it does not 
exist
  -                             // doing this check here resolves some 
permissions failures
  -                             if (!Directory.Exists(directoryFullName))
  +                             using(SecurityContext.Impersonate(this))
                                {
  -                                     
Directory.CreateDirectory(directoryFullName);
  +                                     // Ensure that the directory structure 
exists
  +                                     string directoryFullName = 
Path.GetDirectoryName(fileName);
  +
  +                                     // Only create the directory if it does 
not exist
  +                                     // doing this check here resolves some 
permissions failures
  +                                     if 
(!Directory.Exists(directoryFullName))
  +                                     {
  +                                             
Directory.CreateDirectory(directoryFullName);
  +                                     }
  +
  +                                     FileMode fileOpenMode = append ? 
FileMode.Append : FileMode.Create;
  +                                     fileStream = new FileStream(fileName, 
fileOpenMode, FileAccess.Write, FileShare.Read);
                                }
   
  -                             SetQWForFiles(new StreamWriter(fileName, 
append, m_encoding));
  +                             if (fileStream != null)
  +                             {
  +                                     SetQWForFiles(new 
StreamWriter(fileStream, m_encoding));
  +                             }
   
                                WriteHeader();
                        }
  @@ -313,7 +354,6 @@
                        QuietWriter = new QuietTextWriter(writer, ErrorHandler);
                }
   
  -
                #endregion Protected Instance Methods
   
                #region Protected Static Methods
  @@ -366,6 +406,11 @@
                /// The encoding to use for the file stream.
                /// </summary>
                private Encoding m_encoding = Encoding.Default;
  +
  +             /// <summary>
  +             /// The security context to use for privileged calls
  +             /// </summary>
  +             private SecurityContext m_securityContext;
   
                #endregion Private Instance Fields
        }
  
  
  
  1.7       +46 -7     logging-log4net/src/Appender/NetSendAppender.cs
  
  Index: NetSendAppender.cs
  ===================================================================
  RCS file: /home/cvs/logging-log4net/src/Appender/NetSendAppender.cs,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- NetSendAppender.cs        24 Jul 2004 14:54:02 -0000      1.6
  +++ NetSendAppender.cs        12 Nov 2004 22:33:30 -0000      1.7
  @@ -161,6 +161,11 @@
                /// </summary>
                private string m_recipient;
   
  +             /// <summary>
  +             /// The security context to use for privileged calls
  +             /// </summary>
  +             private SecurityContext m_securityContext;
  +
                #endregion
   
                #region Constructors
  @@ -229,6 +234,26 @@
                        set { m_server = value; }
                }
   
  +             /// <summary>
  +             /// Gets or sets the <see cref="SecurityContext"/> used to call 
the NetSend method.
  +             /// </summary>
  +             /// <value>
  +             /// The <see cref="SecurityContext"/> used to call the NetSend 
method.
  +             /// </value>
  +             /// <remarks>
  +             /// <para>
  +             /// Unless a <see cref="SecurityContext"/> specified here for 
this appender
  +             /// the <see cref="SecurityContextProvider.DefaultProvider"/> 
is queried for the
  +             /// security context to use. The default behaviour is to use 
the security context
  +             /// of the current thread.
  +             /// </para>
  +             /// </remarks>
  +             public SecurityContext SecurityContext 
  +             {
  +                     get { return m_securityContext; }
  +                     set { m_securityContext = value; }
  +             }
  +
                #endregion
   
                #region Implementation of IOptionHandler
  @@ -261,6 +286,11 @@
                        {
                                throw new ArgumentNullException("Recipient", 
"The required property 'Recipient' was not specified.");
                        }
  +
  +                     if (m_securityContext == null)
  +                     {
  +                             m_securityContext = 
SecurityContextProvider.DefaultProvider.CreateSecurityContext(this);
  +                     }
                }
   
                #endregion
  @@ -278,17 +308,26 @@
                /// </remarks>
                protected override void Append(LoggingEvent loggingEvent) 
                {
  -                     string renderedLoggingEvent = 
RenderLoggingEvent(loggingEvent);
  +                     NativeError nativeError = null;
   
  -                     // Send the message
  -                     int returnValue = NetMessageBufferSend(this.Server, 
this.Recipient, this.Sender, renderedLoggingEvent, renderedLoggingEvent.Length 
* Marshal.SystemDefaultCharSize);   
  +                     // Render the event in the callers security context
  +                     string renderedLoggingEvent = 
RenderLoggingEvent(loggingEvent);
   
  -                     // Log the error if the message could not be sent
  -                     if (returnValue != 0) 
  +                     using(m_securityContext.Impersonate(this))
                        {
  -                             // Lookup the native error
  -                             NativeError nativeError = 
NativeError.GetError(returnValue);
  +                             // Send the message
  +                             int returnValue = 
NetMessageBufferSend(this.Server, this.Recipient, this.Sender, 
renderedLoggingEvent, renderedLoggingEvent.Length * 
Marshal.SystemDefaultCharSize);   
   
  +                             // Log the error if the message could not be 
sent
  +                             if (returnValue != 0) 
  +                             {
  +                                     // Lookup the native error
  +                                     nativeError = 
NativeError.GetError(returnValue);
  +                             }
  +                     }
  +
  +                     if (nativeError != null)
  +                     {
                                // Handle the error over to the ErrorHandler
                                ErrorHandler.Error(nativeError.ToString() + " 
(Params: Server=" + this.Server + ", Recipient=" + this.Recipient + ", Sender=" 
+ this.Sender + ")");
                        }
  
  
  
  1.10      +67 -23    logging-log4net/src/Appender/RollingFileAppender.cs
  
  Index: RollingFileAppender.cs
  ===================================================================
  RCS file: /home/cvs/logging-log4net/src/Appender/RollingFileAppender.cs,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- RollingFileAppender.cs    26 Sep 2004 22:41:08 -0000      1.9
  +++ RollingFileAppender.cs    12 Nov 2004 22:33:30 -0000      1.10
  @@ -510,9 +510,12 @@
                                long currentCount = 0;
                                if (append) 
                                {
  -                                     if (System.IO.File.Exists(fileName))
  +                                     using(SecurityContext.Impersonate(this))
                                        {
  -                                             currentCount = (new 
FileInfo(fileName)).Length;
  +                                             if 
(System.IO.File.Exists(fileName))
  +                                             {
  +                                                     currentCount = (new 
FileInfo(fileName)).Length;
  +                                             }
                                        }
                                }
   
  @@ -545,8 +548,14 @@
                                sName = m_scheduledFilename;
                        }
   
  -                     string fullPath = System.IO.Path.GetFullPath(sName);
  -                     string fileName = System.IO.Path.GetFileName(fullPath);
  +                     string fullPath = null;
  +                     string fileName = null;
  +
  +                     using(SecurityContext.Impersonate(this))
  +                     {
  +                             fullPath = System.IO.Path.GetFullPath(sName);
  +                             fileName = System.IO.Path.GetFileName(fullPath);
  +                     }
   
                        ArrayList arrayFiles = GetExistingFiles(fullPath);
                        InitializeRollBackups(fileName, arrayFiles);
  @@ -571,31 +580,35 @@
                /// </summary>
                /// <param name="baseFilePath"></param>
                /// <returns></returns>
  -             private static ArrayList GetExistingFiles(string baseFilePath)
  +             private ArrayList GetExistingFiles(string baseFilePath)
                {
                        ArrayList alFiles = new ArrayList();
   
  -                     string directory = Path.GetDirectoryName(baseFilePath);
  -                     LogLog.Debug("RollingFileAppender: Searching for 
existing files in ["+directory+"]");
  +                     string directory = null;
   
  -                     if (Directory.Exists(directory))
  +                     using(SecurityContext.Impersonate(this))
                        {
  -                             string baseFileName = 
Path.GetFileName(baseFilePath);
  +                             directory = Path.GetDirectoryName(baseFilePath);
  +                             if (Directory.Exists(directory))
  +                             {
  +                                     string baseFileName = 
Path.GetFileName(baseFilePath);
   
  -                             string[] files = Directory.GetFiles(directory, 
GetWildcardPatternForFile(baseFileName));
  +                                     string[] files = 
Directory.GetFiles(directory, GetWildcardPatternForFile(baseFileName));
        
  -                             if (files != null)
  -                             {
  -                                     for (int i = 0; i < files.Length; i++) 
  +                                     if (files != null)
                                        {
  -                                             string curFileName = 
Path.GetFileName(files[i]);
  -                                             if 
(curFileName.StartsWith(baseFileName))
  +                                             for (int i = 0; i < 
files.Length; i++) 
                                                {
  -                                                     
alFiles.Add(curFileName);
  +                                                     string curFileName = 
Path.GetFileName(files[i]);
  +                                                     if 
(curFileName.StartsWith(baseFileName))
  +                                                     {
  +                                                             
alFiles.Add(curFileName);
  +                                                     }
                                                }
                                        }
                                }
                        }
  +                     LogLog.Debug("RollingFileAppender: Searched for 
existing files in ["+directory+"]");
                        return alFiles;
                }
   
  @@ -606,9 +619,13 @@
                {
                        if (m_staticLogFileName && m_rollDate) 
                        {
  -                             if (System.IO.File.Exists(m_baseFileName)) 
  +                             if (FileExists(m_baseFileName)) 
                                {
  -                                     DateTime last = 
System.IO.File.GetLastWriteTime(m_baseFileName);
  +                                     DateTime last;
  +                                     using(SecurityContext.Impersonate(this))
  +                                     {
  +                                             last = 
System.IO.File.GetLastWriteTime(m_baseFileName);
  +                                     }
                                        LogLog.Debug("RollingFileAppender: 
["+last.ToString(m_datePattern,System.Globalization.DateTimeFormatInfo.InvariantInfo)+"]
 vs. 
["+m_now.ToString(m_datePattern,System.Globalization.DateTimeFormatInfo.InvariantInfo)+"]");
   
                                        if 
(!(last.ToString(m_datePattern,System.Globalization.DateTimeFormatInfo.InvariantInfo).Equals(m_now.ToString(m_datePattern,
 System.Globalization.DateTimeFormatInfo.InvariantInfo)))) 
  @@ -843,6 +860,11 @@
                                m_scheduledFilename = File + 
m_now.ToString(m_datePattern, 
System.Globalization.DateTimeFormatInfo.InvariantInfo);
                        }
   
  +                     if (SecurityContext == null)
  +                     {
  +                             SecurityContext = 
SecurityContextProvider.DefaultProvider.CreateSecurityContext(this);
  +                     }
  +
                        ExistingInit();
        
                        base.ActivateOptions();
  @@ -910,7 +932,7 @@
                /// <param name="toFile">New name for file.</param>
                protected void RollFile(string fromFile, string toFile) 
                {
  -                     if (System.IO.File.Exists(fromFile))
  +                     if (FileExists(fromFile))
                        {
                                // Delete the toFile if it exists
                                DeleteFile(toFile);
  @@ -919,7 +941,10 @@
                                try
                                {
                                        LogLog.Debug("RollingFileAppender: 
Moving [" + fromFile + "] -> [" + toFile + "]");
  -                                     System.IO.File.Move(fromFile, toFile);
  +                                     using(SecurityContext.Impersonate(this))
  +                                     {
  +                                             System.IO.File.Move(fromFile, 
toFile);
  +                                     }
                                }
                                catch(Exception moveEx)
                                {
  @@ -931,6 +956,19 @@
                                LogLog.Warn("RollingFileAppender: Cannot 
RollFile [" + fromFile + "] -> [" + toFile + "]. Source does not exist");
                        }
                }
  +
  +             /// <summary>
  +             /// Test if a file exists at a specified path
  +             /// </summary>
  +             /// <param name="path">the path to the file</param>
  +             /// <returns>true if the file exists</returns>
  +             protected bool FileExists(string path)
  +             {
  +                     using(SecurityContext.Impersonate(this))
  +                     {
  +                             return System.IO.File.Exists(path);
  +                     }
  +             }
     
                /// <summary>
                /// Deletes the specified file if it exists.
  @@ -938,7 +976,7 @@
                /// <param name="fileName">The file to delete.</param>
                protected void DeleteFile(string fileName) 
                {
  -                     if (System.IO.File.Exists(fileName)) 
  +                     if (FileExists(fileName)) 
                        {
                                // We may not have permission to delete the 
file, or the file may be locked
   
  @@ -949,7 +987,10 @@
                                string tempFileName = fileName + "." + 
Environment.TickCount + ".DeletePending";
                                try
                                {
  -                                     System.IO.File.Move(fileName, 
tempFileName);
  +                                     using(SecurityContext.Impersonate(this))
  +                                     {
  +                                             System.IO.File.Move(fileName, 
tempFileName);
  +                                     }
                                        fileToDelete = tempFileName;
                                }
                                catch(Exception moveEx)
  @@ -960,7 +1001,10 @@
                                // Try to delete the file (either the original 
or the moved file)
                                try
                                {
  -                                     System.IO.File.Delete(fileToDelete);
  +                                     using(SecurityContext.Impersonate(this))
  +                                     {
  +                                             
System.IO.File.Delete(fileToDelete);
  +                                     }
                                        LogLog.Debug("RollingFileAppender: 
Deleted file [" + fileName + "]");
                                }
                                catch(Exception deleteEx)
  
  
  

Reply via email to