#region Apache License // // Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. // The ASF licenses this file to you 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 // MONO 1.0 Beta mcs does not like #if !A && !B && !C syntax // .NET Compact Framework 1.0 has no support for Win32 NetMessageBufferSend API #if !NETCF // MONO 1.0 has no support for Win32 NetMessageBufferSend API #if !MONO // SSCLI 1.0 has no support for Win32 NetMessageBufferSend API #if !SSCLI // We don't want framework or platform specific code in the CLI version of log4net #if !CLI_1_0 using System; using System.Globalization; using System.Runtime.InteropServices; using log4net.Util; using log4net.Layout; using log4net.Core; namespace log4net.Appender { /// /// Logs entries by sending network messages using the /// native function. /// /// /// /// You can send messages only to names that are active /// on the network. If you send the message to a user name, /// that user must be logged on and running the Messenger /// service to receive the message. /// /// /// The receiver will get a top most window displaying the /// messages one at a time, therefore this appender should /// not be used to deliver a high volume of messages. /// /// /// The following table lists some possible uses for this appender : /// /// /// /// /// Action /// Property Value(s) /// /// /// Send a message to a user account on the local machine /// /// /// = <name of the local machine> /// /// /// = <user name> /// /// /// /// /// Send a message to a user account on a remote machine /// /// /// = <name of the remote machine> /// /// /// = <user name> /// /// /// /// /// Send a message to a domain user account /// /// /// = <name of a domain controller | uninitialized> /// /// /// = <user name> /// /// /// /// /// Send a message to all the names in a workgroup or domain /// /// /// = <workgroup name | domain name>* /// /// /// /// /// Send a message from the local machine to a remote machine /// /// /// = <name of the local machine | uninitialized> /// /// /// = <name of the remote machine> /// /// /// /// /// /// /// Note : security restrictions apply for sending /// network messages, see /// for more information. /// /// /// /// /// An example configuration section to log information /// using this appender from the local machine, named /// LOCAL_PC, to machine OPERATOR_PC : /// /// /// /// /// /// /// /// /// /// Nicko Cadell /// Gert Driesen public class NetSendAppender : AppenderSkeleton { #region Member Variables /// /// The DNS or NetBIOS name of the server on which the function is to execute. /// private string m_server; /// /// The sender of the network message. /// private string m_sender; /// /// The message alias to which the message should be sent. /// private string m_recipient; /// /// The security context to use for privileged calls /// private SecurityContext m_securityContext; #endregion #region Constructors /// /// Initializes the appender. /// /// /// The default constructor initializes all fields to their default values. /// public NetSendAppender() { } #endregion #region Properties /// /// Gets or sets the sender of the message. /// /// /// The sender of the message. /// /// /// If this property is not specified, the message is sent from the local computer. /// public string Sender { get { return m_sender; } set { m_sender = value; } } /// /// Gets or sets the message alias to which the message should be sent. /// /// /// The recipient of the message. /// /// /// This property should always be specified in order to send a message. /// public string Recipient { get { return m_recipient; } set { m_recipient = value; } } /// /// Gets or sets the DNS or NetBIOS name of the remote server on which the function is to execute. /// /// /// DNS or NetBIOS name of the remote server on which the function is to execute. /// /// /// /// For Windows NT 4.0 and earlier, the string should begin with \\. /// /// /// If this property is not specified, the local computer is used. /// /// public string Server { get { return m_server; } set { m_server = value; } } /// /// Gets or sets the used to call the NetSend method. /// /// /// The used to call the NetSend method. /// /// /// /// Unless a specified here for this appender /// the is queried for the /// security context to use. The default behavior is to use the security context /// of the current thread. /// /// public SecurityContext SecurityContext { get { return m_securityContext; } set { m_securityContext = value; } } #endregion #region Implementation of IOptionHandler /// /// Initialize the appender based on the options set. /// /// /// /// This is part of the delayed object /// activation scheme. The method must /// be called on this object after the configuration properties have /// been set. Until is called this /// object is in an undefined state and must not be used. /// /// /// If any of the configuration properties are modified then /// must be called again. /// /// /// The appender will be ignored if no was specified. /// /// /// The required property was not specified. public override void ActivateOptions() { base.ActivateOptions(); if (this.Recipient == null) { throw new ArgumentNullException("Recipient", "The required property 'Recipient' was not specified."); } if (m_securityContext == null) { m_securityContext = SecurityContextProvider.DefaultProvider.CreateSecurityContext(this); } } #endregion #region Override implementation of AppenderSkeleton /// /// This method is called by the method. /// /// The event to log. /// /// /// Sends the event using a network message. /// /// #if NET_4_0 || MONO_4_0 || NETSTANDARD1_3 [System.Security.SecuritySafeCritical] #endif #if !NETSTANDARD1_3 [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, UnmanagedCode = true)] #endif protected override void Append(LoggingEvent loggingEvent) { NativeError nativeError = null; // Render the event in the callers security context string renderedLoggingEvent = RenderLoggingEvent(loggingEvent); using(m_securityContext.Impersonate(this)) { // 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 + ")"); } } /// /// This appender requires a to be set. /// /// true /// /// /// This appender requires a to be set. /// /// override protected bool RequiresLayout { get { return true; } } #endregion #region Stubs For Native Function Calls /// /// Sends a buffer of information to a registered message alias. /// /// The DNS or NetBIOS name of the server on which the function is to execute. /// The message alias to which the message buffer should be sent /// The originator of the message. /// The message text. /// The length, in bytes, of the message text. /// /// /// The following restrictions apply for sending network messages: /// /// /// /// /// Platform /// Requirements /// /// /// Windows NT /// /// /// No special group membership is required to send a network message. /// /// /// Admin, Accounts, Print, or Server Operator group membership is required to /// successfully send a network message on a remote server. /// /// /// /// /// Windows 2000 or later /// /// /// If you send a message on a domain controller that is running Active Directory, /// access is allowed or denied based on the access control list (ACL) for the securable /// object. The default ACL permits only Domain Admins and Account Operators to send a network message. /// /// /// On a member server or workstation, only Administrators and Server Operators can send a network message. /// /// /// /// /// /// /// For more information see Security Requirements for the Network Management Functions. /// /// /// /// /// If the function succeeds, the return value is zero. /// /// [DllImport("netapi32.dll", SetLastError=true)] protected static extern int NetMessageBufferSend( [MarshalAs(UnmanagedType.LPWStr)] string serverName, [MarshalAs(UnmanagedType.LPWStr)] string msgName, [MarshalAs(UnmanagedType.LPWStr)] string fromName, [MarshalAs(UnmanagedType.LPWStr)] string buffer, int bufferSize); #endregion } } #endif // !CLI_1_0 #endif // !SSCLI #endif // !MONO #endif // !NETCF