3b84da0fe159945ed1c72d538a2f1e2cf85af95e
[mono.git] / mcs / class / referencesource / System.ServiceModel / System / ServiceModel / Diagnostics / MessageLogger.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4
5 namespace System.ServiceModel.Diagnostics
6 {
7     using System.Collections.Generic;
8     using System.Diagnostics;
9     using System.IO;
10     using System.Runtime;
11     using System.Runtime.Diagnostics;
12     using System.Security;
13     using System.ServiceModel;
14     using System.ServiceModel.Channels;
15     using System.ServiceModel.Configuration;
16     using System.ServiceModel.Diagnostics.Application;
17     using System.ServiceModel.Dispatcher;
18     using System.Xml;
19
20     [Flags]
21     internal enum MessageLoggingSource : int
22     {
23         None = 0,
24         TransportReceive = 2,
25         TransportSend = 4,
26         Transport = TransportReceive | TransportSend,
27         ServiceLevelReceiveDatagram = 16,
28         ServiceLevelSendDatagram = 32,
29         ServiceLevelReceiveRequest = 64,
30         ServiceLevelSendRequest = 128,
31         ServiceLevelReceiveReply = 256,
32         ServiceLevelSendReply = 512,
33         ServiceLevelReceive = ServiceLevelReceiveReply | ServiceLevelReceiveRequest | ServiceLevelReceiveDatagram,
34         ServiceLevelSend = ServiceLevelSendReply | ServiceLevelSendRequest | ServiceLevelSendDatagram,
35         ServiceLevelService = ServiceLevelSendReply | ServiceLevelReceiveRequest | ServiceLevelReceiveDatagram,
36         ServiceLevelProxy = ServiceLevelReceiveReply | ServiceLevelSendRequest | ServiceLevelSendDatagram,
37         ServiceLevel = ServiceLevelReceive | ServiceLevelSend,
38         Malformed = 1024,
39         LastChance = 2048,
40         All = int.MaxValue
41     }
42
43     internal static class MessageLogger
44     {
45         const string MessageTraceSourceName = "System.ServiceModel.MessageLogging";
46         const string DefaultTraceListenerName = "Default";
47         const int Unlimited = -1;
48
49         static MessageLoggingSource sources = default(MessageLoggingSource);
50         static bool logKnownPii;
51         static bool logMessageBody = false;
52         static int maxMessagesToLog;
53         static int numberOfMessagesToLog;
54         static int maxMessageSize;
55         static PiiTraceSource messageTraceSource;
56         static bool attemptedTraceSourceInitialization = false;
57         static bool initialized = false;
58         static bool initializing = false;
59         static bool inPartialTrust = false;
60         static object syncObject = new object();
61         static object filterLock = new object();
62         static List<XPathMessageFilter> messageFilterTable;
63         static bool lastWriteSucceeded = true;
64         static string[][] piiBodyPaths;
65         static string[][] piiHeadersPaths;
66         static string[] securityActions;
67
68         static int FilterCount
69         {
70             get { return MessageLogger.Filters.Count; }
71         }
72
73         static bool FilterMessages
74         {
75             get { return MessageLogger.FilterCount > 0 && (MessageLogger.numberOfMessagesToLog > 0 || MessageLogger.numberOfMessagesToLog == MessageLogger.Unlimited); }
76         }
77
78         internal static bool LogKnownPii
79         {
80             get 
81             {
82                 Fx.Assert(MessageLogger.initialized, "MessageLogger should be initialized before trying to retrieve LogKnownPii");
83                 return MessageLogger.logKnownPii; 
84             }
85             set
86             {
87                 MessageLogger.logKnownPii = value;
88             }
89         }
90
91         internal static bool LogMalformedMessages
92         {
93             get { return (MessageLogger.Sources & MessageLoggingSource.Malformed) != 0; }
94             set
95             {
96                 lock (MessageLogger.syncObject)
97                 {
98                     bool shouldProcessAudit = ShouldProcessAudit(MessageLoggingSource.Malformed, value);
99                     if (value)
100                     {
101                         EnsureMessageTraceSource();
102                         if (!MessageLogger.inPartialTrust)
103                         {
104                             MessageLogger.sources |= MessageLoggingSource.Malformed;
105                         }
106                     }
107                     else
108                     {
109                         MessageLogger.sources &= MessageLoggingSource.All & ~MessageLoggingSource.Malformed;
110                     }
111                     if (shouldProcessAudit)
112                     {
113                         ProcessAudit(value);
114                     }
115                 }
116             }
117         }
118
119         internal static bool LogMessagesAtServiceLevel
120         {
121             get { return (MessageLogger.Sources & MessageLoggingSource.ServiceLevel) != 0; }
122             set
123             {
124                 lock (MessageLogger.syncObject)
125                 {
126                     bool shouldProcessAudit = ShouldProcessAudit(MessageLoggingSource.ServiceLevel, value);
127                     if (value)
128                     {
129                         EnsureMessageTraceSource();
130                         if (!MessageLogger.inPartialTrust)
131                         {
132                             MessageLogger.sources |= MessageLoggingSource.ServiceLevel;
133                         }
134                     }
135                     else
136                     {
137                         MessageLogger.sources &= MessageLoggingSource.All & ~MessageLoggingSource.ServiceLevel;
138                     }
139                     if (shouldProcessAudit)
140                     {
141                         ProcessAudit(value);
142                     }
143                 }
144             }
145         }
146
147         internal static bool LogMessagesAtTransportLevel
148         {
149             get { return (MessageLogger.Sources & MessageLoggingSource.Transport) != 0; }
150             set
151             {
152                 lock (MessageLogger.syncObject)
153                 {
154                     bool shouldProcessAudit = ShouldProcessAudit(MessageLoggingSource.Transport, value);
155                     if (value)
156                     {
157                         EnsureMessageTraceSource();
158                         if (!MessageLogger.inPartialTrust)
159                         {
160                             MessageLogger.sources |= MessageLoggingSource.Transport;
161                         }
162                     }
163                     else
164                     {
165                         MessageLogger.sources &= MessageLoggingSource.All & ~MessageLoggingSource.Transport;
166                     }
167                     if (shouldProcessAudit)
168                     {
169                         ProcessAudit(value);
170                     }
171                 }
172             }
173         }
174
175         internal static bool LogMessageBody
176         {
177             get
178             {
179                 Fx.Assert(MessageLogger.initialized, "");
180                 return logMessageBody;
181             }
182             set { logMessageBody = value; }
183         }
184
185         internal static bool LoggingEnabled
186         {
187             get { return MessageLogger.Sources != default(MessageLoggingSource); }
188         }
189
190         internal static int MaxMessageSize
191         {
192             get
193             {
194                 Fx.Assert(MessageLogger.initialized, "");
195                 return maxMessageSize;
196             }
197             set { maxMessageSize = value; }
198         }
199
200         internal static int MaxNumberOfMessagesToLog
201         {
202             get
203             {
204                 Fx.Assert(MessageLogger.initialized, "");
205                 return maxMessagesToLog;
206             }
207             set
208             {
209                 //resetting the max resets the actual counter
210                 lock (MessageLogger.syncObject)
211                 {
212                     maxMessagesToLog = value;
213                     MessageLogger.numberOfMessagesToLog = maxMessagesToLog;
214                 }
215             }
216         }
217
218         static List<XPathMessageFilter> Filters
219         {
220             get
221             {
222                 if (MessageLogger.messageFilterTable == null)
223                 {
224                     lock (MessageLogger.filterLock)
225                     {
226                         if (MessageLogger.messageFilterTable == null)
227                         {
228                             List<XPathMessageFilter> temp = new List<XPathMessageFilter>();
229                             MessageLogger.messageFilterTable = temp;
230                         }
231                     }
232                 }
233
234                 return MessageLogger.messageFilterTable;
235             }
236         }
237
238         static MessageLoggingSource Sources
239         {
240             get
241             {
242                 if (!MessageLogger.initialized)
243                 {
244                     MessageLogger.EnsureInitialized();
245                 }
246                 return MessageLogger.sources;
247             }
248         }
249
250         static bool AddFilter(XPathMessageFilter filter)
251         {
252             if (filter == null)
253             {
254                 filter = new XPathMessageFilter(""); //if there is an empty add filter tag, add a match-all filter
255             }
256
257             MessageLogger.Filters.Add(filter);
258             return true;
259         }
260
261         internal static bool ShouldLogMalformed
262         {
263             get { return ShouldLogMessages(MessageLoggingSource.Malformed); }
264         }
265
266         static bool ShouldLogMessages(MessageLoggingSource source)
267         {
268             return (source & MessageLogger.Sources) != 0 &&
269                    ((MessageLogger.MessageTraceSource != null) ||
270                    ((source & MessageLoggingSource.Malformed) != 0 && TD.MessageLogWarningIsEnabled()) ||
271                    TD.MessageLogInfoIsEnabled());
272         }
273
274         internal static void LogMessage(MessageLoggingSource source, string data)
275         {
276             try
277             {
278                 if (ShouldLogMessages(MessageLoggingSource.Malformed))
279                 {
280                     LogInternal(source, data);
281                 }
282             }
283 #pragma warning suppress 56500 // covered by FxCOP
284             catch (Exception e)
285             {
286                 if (Fx.IsFatal(e)) throw;
287                 FailedToLogMessage(e);
288             }
289         }
290
291         internal static void LogMessage(Stream stream, MessageLoggingSource source)
292         {
293             try
294             {
295                 ThrowIfNotMalformed(source);
296                 if (ShouldLogMessages(source))
297                 {
298                     LogInternal(new MessageLogTraceRecord(stream, source));
299                 }
300             }
301 #pragma warning suppress 56500 // covered by FxCOP
302             catch (Exception e)
303             {
304                 if (Fx.IsFatal(e)) throw;
305                 FailedToLogMessage(e);
306             }
307         }
308
309         internal static void LogMessage(ArraySegment<byte> buffer, MessageLoggingSource source)
310         {
311             try
312             {
313                 ThrowIfNotMalformed(source);
314                 if (ShouldLogMessages(source))
315                 {
316                     LogInternal(new MessageLogTraceRecord(buffer, source));
317                 }
318             }
319 #pragma warning suppress 56500 // covered by FxCOP
320             catch (Exception e)
321             {
322                 if (Fx.IsFatal(e)) throw;
323                 FailedToLogMessage(e);
324             }
325         }
326
327         internal static void LogMessage(ref Message message, XmlReader reader, MessageLoggingSource source)
328         {
329             Fx.Assert(null != message, "");
330             try
331             {
332                 if (ShouldLogMessages(source))
333                 {
334                     LogMessageImpl(ref message, reader, source);
335                 }
336             }
337 #pragma warning suppress 56500 // covered by FxCOP
338             catch (Exception e)
339             {
340                 if (Fx.IsFatal(e)) throw;
341                 FailedToLogMessage(e);
342             }
343         }
344
345         internal static void LogMessage(ref Message message, MessageLoggingSource source)
346         {
347             LogMessage(ref message, null, source);
348         }
349
350         static void LogMessageImpl(ref Message message, XmlReader reader, MessageLoggingSource source)
351         {
352             ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? TraceUtility.ExtractActivity(message) : null;
353             using (ServiceModelActivity.BoundOperation(activity))
354             {
355                 if (ShouldLogMessages(source) && (MessageLogger.numberOfMessagesToLog > 0 || MessageLogger.numberOfMessagesToLog == MessageLogger.Unlimited))
356                 {
357                     bool lastChance = (source & MessageLoggingSource.LastChance) != 0 || (source & MessageLoggingSource.TransportSend) != 0;
358                     source &= ~MessageLoggingSource.LastChance;
359                     // MessageLogger doesn't log AddressingVersion.None in the encoder since we want to make sure we log 
360                     // as much of the message as possible. So let the Transport log later.
361                     if ((lastChance || message is NullMessage || message.Version.Addressing != AddressingVersion.None)
362                             && MatchFilters(message, source))
363                     {
364                         if (MessageLogger.numberOfMessagesToLog == MessageLogger.Unlimited || MessageLogger.numberOfMessagesToLog > 0)
365                         {
366                             MessageLogTraceRecord record = new MessageLogTraceRecord(ref message, reader, source, MessageLogger.LogMessageBody);
367                             LogInternal(record);
368                         }
369                     }
370                 }
371             }
372         }
373
374         static bool HasSecurityAction(Message message)
375         {
376             Fx.Assert(null != message, "");
377
378             string action = message.Headers.Action;
379             bool result = false;
380             if (String.IsNullOrEmpty(action))
381             {
382                 result = true;
383             }
384             else
385             {
386                 foreach (string securityAction in MessageLogger.SecurityActions)
387                 {
388                     if (0 == String.CompareOrdinal(action, securityAction))
389                     {
390                         result = true;
391                         break;
392                     }
393                 }
394             }
395
396             return result;
397         }
398
399         static void LogInternal(MessageLogTraceRecord record)
400         {
401             Fx.Assert(null != record, "record cannot be null");
402
403             PlainXmlWriter xmlWriter = new PlainXmlWriter(MessageLogger.MaxMessageSize);
404
405             try
406             {
407                 record.WriteTo(xmlWriter);
408                 xmlWriter.Close();
409                 TraceXPathNavigator navigator = xmlWriter.Navigator;
410                 
411                 if ((MessageLogger.messageTraceSource != null && 
412                     !MessageLogger.messageTraceSource.ShouldLogPii) ||
413                     !MessageLogger.LogKnownPii)
414                 {
415                     navigator.RemovePii(MessageLogger.PiiHeadersPaths);
416                     if (MessageLogger.LogMessageBody && null != record.Message)
417                     {
418                         if (HasSecurityAction(record.Message))
419                         {
420                             navigator.RemovePii(MessageLogger.PiiBodyPaths);
421                         }
422                     }
423                 }
424
425                 LogInternal(record.MessageLoggingSource, navigator);
426             }
427             catch (PlainXmlWriter.MaxSizeExceededException)
428             {
429                 if (DiagnosticUtility.ShouldTraceWarning)
430                 {
431                     TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.MessageNotLoggedQuotaExceeded,
432                         SR.GetString(SR.TraceCodeMessageNotLoggedQuotaExceeded), record.Message);
433                 }
434             }
435         }
436
437         static void IncrementLoggedMessagesCount(object data)
438         {
439             if (MessageLogger.numberOfMessagesToLog > 0)
440             {
441                 lock (MessageLogger.syncObject)
442                 {
443                     if (MessageLogger.numberOfMessagesToLog > 0)
444                     {
445                         MessageLogger.numberOfMessagesToLog--;
446                         if (0 == MessageLogger.numberOfMessagesToLog)
447                         {
448                             if (DiagnosticUtility.ShouldTraceInformation)
449                             {
450                                 TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.MessageCountLimitExceeded,
451                                     SR.GetString(SR.TraceCodeMessageCountLimitExceeded), data);
452                             }
453                         }
454                     }
455                 }
456             }
457
458             lock (MessageLogger.syncObject)
459             {
460                 if (!MessageLogger.lastWriteSucceeded)
461                 {
462                     MessageLogger.lastWriteSucceeded = true;
463                 }
464             }
465         }
466
467         static void FailedToLogMessage(Exception e)
468         {
469             //If something goes wrong, we do not want to fail the app, just log one event log entry per block of failures
470             bool shouldLogError = false;
471             lock (MessageLogger.syncObject)
472             {
473                 if (MessageLogger.lastWriteSucceeded)
474                 {
475                     MessageLogger.lastWriteSucceeded = false;
476                     shouldLogError = true;
477                 }
478             }
479             if (shouldLogError)
480             {
481                 DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error,
482                     (ushort)System.Runtime.Diagnostics.EventLogCategory.MessageLogging,
483                     (uint)System.Runtime.Diagnostics.EventLogEventId.FailedToLogMessage,
484                     e.ToString());
485             }
486         }
487
488         static void LogInternal(MessageLoggingSource source, object data)
489         {
490             if ((source & MessageLoggingSource.Malformed) != 0)
491             {
492                 if (!TD.MessageLogWarning(data.ToString()))
493                 {
494                     if (TD.MessageLogEventSizeExceededIsEnabled())
495                     {
496                         TD.MessageLogEventSizeExceeded();
497                     }
498                 }
499             }
500             else
501             {
502                 if (!TD.MessageLogInfo(data.ToString()))
503                 {
504                     if (TD.MessageLogEventSizeExceededIsEnabled())
505                     {
506                         TD.MessageLogEventSizeExceeded();
507                     }                   
508                 }
509             }
510             if (MessageLogger.MessageTraceSource != null)
511             {
512                 MessageLogger.MessageTraceSource.TraceData(TraceEventType.Information, 0, data);
513             }
514             IncrementLoggedMessagesCount(data);
515         }
516
517         static bool MatchFilters(Message message, MessageLoggingSource source)
518         {
519             bool result = true;
520             if (MessageLogger.FilterMessages && (source & MessageLoggingSource.Malformed) == 0)
521             {
522                 result = false;
523                 List<XPathMessageFilter> filtersToRemove = new List<XPathMessageFilter>();
524                 lock (MessageLogger.syncObject)
525                 {
526                     foreach (XPathMessageFilter filter in MessageLogger.Filters)
527                     {
528                         try
529                         {
530                             if (filter.Match(message))
531                             {
532                                 result = true;
533                                 break;
534                             }
535                         }
536                         catch (FilterInvalidBodyAccessException)
537                         {
538                             filtersToRemove.Add(filter);
539                         }
540                         catch (MessageFilterException e)
541                         {
542                             if (DiagnosticUtility.ShouldTraceInformation)
543                             {
544                                 TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.FilterNotMatchedNodeQuotaExceeded,
545                                     SR.GetString(SR.TraceCodeFilterNotMatchedNodeQuotaExceeded), e, message);
546                             }
547                         }
548                     }
549
550                     foreach (XPathMessageFilter filter in filtersToRemove)
551                     {
552                         MessageLogger.Filters.Remove(filter);
553                         PlainXmlWriter writer = new PlainXmlWriter();
554                         filter.WriteXPathTo(writer, null, ConfigurationStrings.Filter, null, true);
555                         DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error,
556                             (ushort)System.Runtime.Diagnostics.EventLogCategory.MessageLogging,
557                             (uint)System.Runtime.Diagnostics.EventLogEventId.RemovedBadFilter,
558                             writer.Navigator.ToString());
559                     }
560
561                     if (MessageLogger.FilterCount == 0)
562                     {
563                         result = true;
564                     }
565                 }
566             }
567
568             return result;
569         }
570
571         static void ReadFiltersFromConfig(DiagnosticSection section)
572         {
573             for (int i = 0; i < section.MessageLogging.Filters.Count; i++)
574             {
575                 XPathMessageFilterElement xfe = section.MessageLogging.Filters[i];
576                 AddFilter(xfe.Filter);
577             }
578         }
579
580         internal static TraceSource MessageTraceSource
581         {
582             get
583             {
584                 return MessageLogger.messageTraceSource;
585             }
586         }
587
588         internal static void EnsureInitialized()
589         {
590             lock (MessageLogger.syncObject)
591             {
592                 if (!MessageLogger.initialized && !MessageLogger.initializing)
593                 {
594                     try
595                     {
596                         Initialize();
597                     }
598 #pragma warning suppress 56500 // covered by FxCOP
599                     catch (SecurityException securityException)
600                     {
601                         // message logging is not support in PT, write the trace
602                         MessageLogger.inPartialTrust = true;
603                         if (DiagnosticUtility.ShouldTraceWarning)
604                         {
605                             TraceUtility.TraceEvent(TraceEventType.Warning,
606                                 TraceCode.TraceHandledException,
607                                 SR.GetString(SR.PartialTrustMessageLoggingNotEnabled),
608                                 null,
609                                 securityException);
610                         }
611                         // also write to event log
612                         LogNonFatalInitializationException(
613                             new SecurityException(
614                                 SR.GetString(SR.PartialTrustMessageLoggingNotEnabled),
615                                 securityException));
616                         
617                     }
618                     MessageLogger.initialized = true;
619                 }
620             }
621         }
622
623         static void EnsureMessageTraceSource()
624         {
625             if (!MessageLogger.initialized)
626             {
627                 MessageLogger.EnsureInitialized();
628             }
629             if (null == MessageLogger.MessageTraceSource && !MessageLogger.attemptedTraceSourceInitialization)
630             {
631                 InitializeMessageTraceSource();
632             }
633         }
634
635         static string[][] PiiBodyPaths
636         {
637             get
638             {
639                 if (piiBodyPaths == null)
640                     piiBodyPaths = new string[][] { 
641                                 new string[] { MessageLogTraceRecord.MessageLogTraceRecordElementName, "Envelope", "Body", "RequestSecurityToken" },
642                                 new string[] { MessageLogTraceRecord.MessageLogTraceRecordElementName, "Envelope", "Body", "RequestSecurityTokenResponse" },
643                                 new string[] { MessageLogTraceRecord.MessageLogTraceRecordElementName, "Envelope", "Body", "RequestSecurityTokenResponseCollection" }
644                             };
645                 return piiBodyPaths;
646             }
647         }
648
649         static string[][] PiiHeadersPaths
650         {
651             get
652             {
653                 if (piiHeadersPaths == null)
654                     piiHeadersPaths = new string[][] { 
655                                 new string[] { MessageLogTraceRecord.MessageLogTraceRecordElementName, "Envelope", "Header", "Security" },
656                                 new string[] { MessageLogTraceRecord.MessageLogTraceRecordElementName, "Envelope", "Header", "IssuedTokens" }
657                             };
658                 return piiHeadersPaths;
659             }
660         }
661
662         static string[] SecurityActions
663         {
664             get
665             {
666                 if (securityActions == null)
667                     securityActions = new string[] { 
668                                       "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue", 
669                                       "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue",
670                                       "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Renew",
671                                       "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Renew",
672                                       "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Cancel",
673                                       "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Cancel",
674                                       "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Validate",
675                                       "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Validate",
676                                       "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT",
677                                       "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/SCT",
678                                       "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT/Amend",
679                                       "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/SCT/Amend",
680                                       "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT/Renew",
681                                       "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/SCT/Renew",
682                                       "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT/Cancel",
683                                       "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/SCT/Cancel",
684                                       "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/KET",
685                                       "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/KET",
686                                       "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RST/SCT",
687                                       "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RSTR/SCT",
688                                       "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RST/SCT-Amend",
689                                       "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RSTR/SCT-Amend",
690                                       "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RST/Issue",
691                                       "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RSTR/Issue",
692                                       "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RST/Renew",
693                                       "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RSTR/Renew",
694                                       "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RST/Validate",
695                                       "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RSTR/Validate",
696                                       "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RST/KET",
697                                       "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RSTR/KET"
698                                     };
699                 return securityActions;
700             }
701         }
702
703         [Fx.Tag.SecurityNote(Critical = "Calls SecurityCritical method UnsafeGetSection which elevates in order to load config.",
704             Safe = "Does not leak any config objects.")]
705         [SecuritySafeCritical]
706         static void Initialize()
707         {
708             MessageLogger.initializing = true;
709             DiagnosticSection section = DiagnosticSection.UnsafeGetSection();
710
711             if (section != null)
712             {
713                 MessageLogger.LogKnownPii = section.MessageLogging.LogKnownPii && MachineSettingsSection.EnableLoggingKnownPii;
714                 MessageLogger.LogMalformedMessages = section.MessageLogging.LogMalformedMessages;
715                 MessageLogger.LogMessageBody = section.MessageLogging.LogEntireMessage;
716                 MessageLogger.LogMessagesAtServiceLevel = section.MessageLogging.LogMessagesAtServiceLevel;
717                 MessageLogger.LogMessagesAtTransportLevel = section.MessageLogging.LogMessagesAtTransportLevel;
718                 MessageLogger.MaxNumberOfMessagesToLog = section.MessageLogging.MaxMessagesToLog;
719                 MessageLogger.MaxMessageSize = section.MessageLogging.MaxSizeOfMessageToLog;
720
721                 ReadFiltersFromConfig(section);
722             }
723         }
724
725         static void InitializeMessageTraceSource()
726         {
727             try
728             {
729                 MessageLogger.attemptedTraceSourceInitialization = true;
730                 PiiTraceSource tempSource = new PiiTraceSource(MessageLogger.MessageTraceSourceName, DiagnosticUtility.EventSourceName);
731                 tempSource.Switch.Level = SourceLevels.Information;
732                 tempSource.Listeners.Remove(MessageLogger.DefaultTraceListenerName);
733                 if (tempSource.Listeners.Count > 0)
734                 {
735                     AppDomain.CurrentDomain.DomainUnload += new EventHandler(ExitOrUnloadEventHandler);
736                     AppDomain.CurrentDomain.ProcessExit += new EventHandler(ExitOrUnloadEventHandler);
737                     AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(ExitOrUnloadEventHandler);
738                 }
739                 else
740                 {
741                     tempSource = null;
742                 }
743
744                 MessageLogger.messageTraceSource = tempSource;
745             }
746             catch (System.Configuration.ConfigurationErrorsException)
747             {
748                 throw;
749             }
750 #pragma warning suppress 56500 // covered by FxCOP
751             catch (SecurityException securityException)
752             {
753                 // message logging is not support in PT, write the trace
754                 MessageLogger.inPartialTrust = true;
755                 if (DiagnosticUtility.ShouldTraceWarning)
756                 {
757                     TraceUtility.TraceEvent(TraceEventType.Warning,
758                         TraceCode.TraceHandledException,
759                         SR.GetString(SR.PartialTrustMessageLoggingNotEnabled),
760                         null,
761                         securityException);
762                 }
763                 // also write to event log
764                 LogNonFatalInitializationException(
765                     new SecurityException(
766                         SR.GetString(SR.PartialTrustMessageLoggingNotEnabled),
767                         securityException));
768             }
769             catch (Exception e)
770             {
771                 MessageLogger.messageTraceSource = null;
772
773                 if (Fx.IsFatal(e)) throw;
774
775                 LogNonFatalInitializationException(e);
776             }
777         }
778
779         [Fx.Tag.SecurityNote(Critical = "Calls into an unsafe method to log event.",
780             Safe = "Event identities cannot be spoofed as they are constants determined inside the method.")]
781         [SecuritySafeCritical]
782         static void LogNonFatalInitializationException(Exception e)
783         {
784             DiagnosticUtility.UnsafeEventLog.UnsafeLogEvent(TraceEventType.Critical,
785                 (ushort)System.Runtime.Diagnostics.EventLogCategory.MessageLogging,
786                 (uint)System.Runtime.Diagnostics.EventLogEventId.FailedToCreateMessageLoggingTraceSource,
787                 true,
788                 e.ToString());
789         }
790
791         static void ExitOrUnloadEventHandler(object sender, EventArgs e)
792         {
793             lock (MessageLogger.syncObject)
794             {
795                 if (null != MessageLogger.MessageTraceSource)
796                 {
797                     //Flush is called automatically on close by StreamWriter
798                     MessageLogger.MessageTraceSource.Close();
799                     MessageLogger.messageTraceSource = null;
800                 }
801             }
802         }
803
804         static void ThrowIfNotMalformed(MessageLoggingSource source)
805         {
806             if ((source & MessageLoggingSource.Malformed) == 0)
807             {
808                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.OnlyMalformedMessagesAreSupported), "source"));
809             }
810         }
811
812         static void ProcessAudit(bool turningOn)
813         {
814             if (turningOn)
815             {
816                 if (null != MessageLogger.messageTraceSource)
817                 {
818                     DiagnosticUtility.EventLog.LogEvent(TraceEventType.Information,
819                         (ushort)System.Runtime.Diagnostics.EventLogCategory.MessageLogging,
820                     (uint)System.Runtime.Diagnostics.EventLogEventId.MessageLoggingOn);
821                 }
822             }
823             else
824             {
825                 DiagnosticUtility.EventLog.LogEvent(TraceEventType.Information,
826                     (ushort)System.Runtime.Diagnostics.EventLogCategory.MessageLogging,
827                     (uint)System.Runtime.Diagnostics.EventLogEventId.MessageLoggingOff);
828             }
829         }
830
831         static bool ShouldProcessAudit(MessageLoggingSource source, bool turningOn)
832         {
833             bool result = false;
834             if (turningOn)
835             {
836                 result = MessageLogger.sources == MessageLoggingSource.None;
837             }
838             else
839             {
840                 result = MessageLogger.sources == source;
841             }
842
843             return result;
844         }
845     }
846 }
847