You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4net-dev@logging.apache.org by ni...@apache.org on 2004/11/12 23:33:30 UTC
cvs commit: logging-log4net/src/Appender AdoNetAppender.cs EventLogAppender.cs FileAppender.cs NetSendAppender.cs RollingFileAppender.cs
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)