The Labs \ Source Viewer \ SSCLI \ System.Configuration \ BaseConfigurationRecord

  1. //------------------------------------------------------------------------------
  2. // <copyright file="BaseConfigurationRecord.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.Configuration
  16. {
  17.     using System.Configuration.Internal;
  18.     using System.Collections;
  19.     using System.Collections.Generic;
  20.     using System.Collections.Specialized;
  21.     using System.Configuration;
  22.     using System.Globalization;
  23.     using System.IO;
  24.     using System.Reflection;
  25.     using System.Runtime.InteropServices;
  26.     using System.Security.Permissions;
  27.     using System.Security;
  28.     using System.Text;
  29.     using System.Xml;
  30.    
  31.     //
  32.     // This object represents the configuration for a request path, and is cached per-path.
  33.     //
  34.     internal abstract class BaseConfigurationRecord : IInternalConfigRecord
  35.     {
  36.         protected const string NL = "\r\n";
  37.         protected const string KEYWORD_TRUE = "true";
  38.         protected const string KEYWORD_FALSE = "false";
  39.         protected const string KEYWORD_CONFIGURATION = "configuration";
  40.         protected const string KEYWORD_CONFIGURATION_NAMESPACE = "http://schemas.microsoft.com/.NetConfiguration/v2.0";
  41.         protected const string KEYWORD_CONFIGSECTIONS = "configSections";
  42.         protected const string KEYWORD_SECTION = "section";
  43.         protected const string KEYWORD_SECTION_NAME = "name";
  44.         protected const string KEYWORD_SECTION_TYPE = "type";
  45.         protected const string KEYWORD_SECTION_ALLOWLOCATION = "allowLocation";
  46.         protected const string KEYWORD_SECTION_ALLOWDEFINITION = "allowDefinition";
  47.         protected const string KEYWORD_SECTION_ALLOWDEFINITION_EVERYWHERE = "Everywhere";
  48.         protected const string KEYWORD_SECTION_ALLOWDEFINITION_MACHINEONLY = "MachineOnly";
  49.         protected const string KEYWORD_SECTION_ALLOWDEFINITION_MACHINETOAPPLICATION = "MachineToApplication";
  50.         protected const string KEYWORD_SECTION_ALLOWDEFINITION_MACHINETOWEBROOT = "MachineToWebRoot";
  51.         protected const string KEYWORD_SECTION_ALLOWEXEDEFINITION = "allowExeDefinition";
  52.         protected const string KEYWORD_SECTION_ALLOWEXEDEFINITION_MACHTOROAMING = "MachineToRoamingUser";
  53.         protected const string KEYWORD_SECTION_ALLOWEXEDEFINITION_MACHTOLOCAL = "MachineToLocalUser";
  54.         protected const string KEYWORD_SECTION_RESTARTONEXTERNALCHANGES = "restartOnExternalChanges";
  55.         protected const string KEYWORD_SECTION_REQUIREPERMISSION = "requirePermission";
  56.         protected const string KEYWORD_SECTIONGROUP = "sectionGroup";
  57.         protected const string KEYWORD_SECTIONGROUP_NAME = "name";
  58.         protected const string KEYWORD_SECTIONGROUP_TYPE = "type";
  59.         protected const string KEYWORD_REMOVE = "remove";
  60.         protected const string KEYWORD_CLEAR = "clear";
  61.         protected const string KEYWORD_LOCATION = "location";
  62.         protected const string KEYWORD_LOCATION_PATH = "path";
  63.         protected const string KEYWORD_LOCATION_ALLOWOVERRIDE = "allowOverride";
  64.         protected const string KEYWORD_LOCATION_INHERITINCHILDAPPLICATIONS = "inheritInChildApplications";
  65.         protected const string KEYWORD_CONFIGSOURCE = "configSource";
  66.         protected const string KEYWORD_XMLNS = "xmlns";
  67.         internal const string KEYWORD_PROTECTION_PROVIDER = "configProtectionProvider";
  68.        
  69.         protected const string FORMAT_NEWCONFIGFILE = "<?xml version=\"1.0\" encoding=\"{0}\"?>\r\n";
  70.         protected const string FORMAT_CONFIGURATION = "<configuration>\r\n";
  71.         protected const string FORMAT_CONFIGURATION_NAMESPACE = "<configuration xmlns=\"{0}\">\r\n";
  72.         protected const string FORMAT_CONFIGURATION_ENDELEMENT = "</configuration>";
  73.        
  74.         protected const string FORMAT_LOCATION_NOPATH = "<location allowOverride=\"{0}\" inheritInChildApplications=\"{1}\">\r\n";
  75.         protected const string FORMAT_LOCATION_PATH = "<location path=\"{2}\" allowOverride=\"{0}\" inheritInChildApplications=\"{1}\">\r\n";
  76.         protected const string FORMAT_LOCATION_ENDELEMENT = "</location>";
  77.        
  78.         protected const string FORMAT_SECTION_CONFIGSOURCE = "<{0} configSource=\"{1}\" />";
  79.         protected const string FORMAT_CONFIGSOURCE_FILE = "<?xml version=\"1.0\" encoding=\"{0}\"?>\r\n";
  80.        
  81.         protected const string FORMAT_SECTIONGROUP_ENDELEMENT = "</sectionGroup>";
  82.        
  83.         // Class flags should only be used with the ClassFlags property.
  84.         protected const int ClassSupportsChangeNotifications = 1;
  85.         protected const int ClassSupportsRefresh = 2;
  86.         protected const int ClassSupportsImpersonation = 4;
  87.         protected const int ClassSupportsRestrictedPermissions = 8;
  88.         protected const int ClassSupportsKeepInputs = 16;
  89.         protected const int ClassSupportsDelayedInit = 32;
  90.         protected const int ClassIgnoreLocalErrors = 64;
  91.        
  92.         // Flags to use with the _flags field.
  93.         protected const int ProtectedDataInitialized = 1;
  94.         protected const int Closed = 2;
  95.         protected const int PrefetchAll = 8;
  96.         protected const int IsAboveApplication = 32;
  97.         private const int ContextEvaluated = 128;
  98.         private const int IsLocationListResolved = 256;
  99.         protected const int NamespacePresentInFile = 512;
  100.        
  101.        
  102.         private const int RestrictedPermissionsResolved = 2048;
  103.        
  104.         protected const int IsTrusted = 8192;
  105.        
  106.         protected const int SupportsChangeNotifications = 65536;
  107.         protected const int SupportsRefresh = 131072;
  108.         protected const int SupportsPath = 262144;
  109.         protected const int SupportsKeepInputs = 524288;
  110.         protected const int SupportsLocation = 1048576;
  111.        
  112.         // Flags for Mgmt Configuration Record
  113.         protected const int ForceLocationWritten = 16777216;
  114.         protected const int SuggestLocationRemoval = 33554432;
  115.         protected const int NamespacePresentCurrent = 67108864;
  116.        
  117.         internal const char ConfigPathSeparatorChar = '/';
  118.         internal const string ConfigPathSeparatorString = "/";
  119.         static internal readonly char[] ConfigPathSeparatorParams = new char[] {ConfigPathSeparatorChar};
  120.        
  121.         private static ConfigurationPermission s_unrestrictedConfigPermission;
  122.         // cached ConfigurationPermission
  123.         protected SafeBitVector32 _flags;
  124.         // state
  125.         protected BaseConfigurationRecord _parent;
  126.         // parent record
  127.         protected Hashtable _children;
  128.         // configName -> record
  129.         protected InternalConfigRoot _configRoot;
  130.         // root of configuration
  131.         protected string _configName;
  132.         // the last part of the config path
  133.         protected string _configPath;
  134.         // the full config path
  135.         protected string _locationSubPath;
  136.         // subPath for the config record when editing a location configuration
  137.         private ConfigRecordStreamInfo _configStreamInfo;
  138.         // stream info for the config record
  139.         private object _configContext;
  140.         // Context for config level
  141.         private ProtectedConfigurationSection _protectedConfig;
  142.         // section containing the encryption providers
  143.         private PermissionSet _restrictedPermissions;
  144.         // cached restricted permission set
  145.         private ConfigurationSchemaErrors _initErrors;
  146.         // errors encountered during the parse of the configuration file
  147.         private BaseConfigurationRecord _initDelayedRoot;
  148.         // root of delayed initialization
  149.         // Records information about <configSections> present in this web.config file.
  150.         // config key -> FactoryRecord
  151.         protected Hashtable _factoryRecords;
  152.        
  153.         // Records information about sections that apply to this path,
  154.         // which may be found in this web.config file, in a parent through
  155.         // inheritance, or in a parent through <location>
  156.         // config key -> SectionRecord
  157.         protected Hashtable _sectionRecords;
  158.        
  159.         // Records information about sections in a <location> directive
  160.         // that do not apply to this configPath (sections where path != ".")
  161.         protected ArrayList _locationSections;
  162.        
  163.        
  164.         internal BaseConfigurationRecord()
  165.         {
  166.             // not strictly necessary, but compiler spits out a warning without this initiailization
  167.             _flags = new SafeBitVector32();
  168.         }
  169.        
  170.         // Class flags
  171.         protected abstract SimpleBitVector32 ClassFlags {
  172.             get;
  173.         }
  174.        
  175.         // Create the factory that will evaluate configuration
  176.         protected abstract object CreateSectionFactory(FactoryRecord factoryRecord);
  177.        
  178.         // Create the configuration object
  179.         protected abstract object CreateSection(bool inputIsTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, object parentConfig, ConfigXmlReader reader);
  180.        
  181.         // Use the parent result in creating the child
  182.         protected abstract object UseParentResult(string configKey, object parentResult, SectionRecord sectionRecord);
  183.        
  184.         // Return the runtime object from GetSection
  185.         protected abstract object GetRuntimeObject(object result);
  186.        
  187.         //
  188.         // IInternalConfigRecord methods
  189.         //
  190.        
  191.         public string ConfigPath {
  192.             get { return _configPath; }
  193.         }
  194.        
  195.         public string StreamName {
  196.             get { return ConfigStreamInfo.StreamName; }
  197.         }
  198.        
  199.         public bool HasInitErrors {
  200.             get { return _initErrors.HasErrors(ClassFlags[ClassIgnoreLocalErrors]); }
  201.         }
  202.        
  203.         public void ThrowIfInitErrors()
  204.         {
  205.             ThrowIfParseErrors(_initErrors);
  206.         }
  207.        
  208.         public object GetSection(string configKey)
  209.         {
  210.             #if DBG
  211.             // On debug builds, the config system depends on system.diagnostics,
  212.             // so we must always return a valid result and never throw.
  213.             if (configKey == "system.diagnostics" && !ClassFlags[ClassIgnoreLocalErrors]) {
  214.                 return GetSection(configKey, true, true);
  215.             }
  216.             else {
  217.                 return GetSection(configKey, false, true);
  218.             }
  219.             #else
  220.            
  221.             return GetSection(configKey, false, true);
  222.             #endif
  223.         }
  224.        
  225.         public object GetLkgSection(string configKey)
  226.         {
  227.             return GetSection(configKey, true, true);
  228.         }
  229.        
  230.         public void RefreshSection(string configKey)
  231.         {
  232.             _configRoot.ClearResult(this, configKey, true);
  233.         }
  234.        
  235.         public void Remove()
  236.         {
  237.             _configRoot.RemoveConfigRecord(this);
  238.         }
  239.        
  240.         //
  241.         // end of IInternalConfigRecord methods
  242.         //
  243.        
  244.         internal bool HasStream {
  245.             get { return ConfigStreamInfo.HasStream; }
  246.         }
  247.        
  248.         // Determine which sections should be prefetched during the first scan.
  249.         private bool ShouldPrefetchRawXml(FactoryRecord factoryRecord)
  250.         {
  251.             if (_flags[PrefetchAll])
  252.                 return true;
  253.            
  254.             switch (factoryRecord.ConfigKey) {
  255.                 case BaseConfigurationRecord.RESERVED_SECTION_PROTECTED_CONFIGURATION:
  256.                 case "system.diagnostics":
  257.                 case "appSettings":
  258.                 case "connectionStrings":
  259.                     return true;
  260.             }
  261.            
  262.             return Host.PrefetchSection(factoryRecord.Group, factoryRecord.Name);
  263.         }
  264.        
  265.         protected IDisposable Impersonate()
  266.         {
  267.             IDisposable context = null;
  268.             if (ClassFlags[ClassSupportsImpersonation]) {
  269.                 context = Host.Impersonate();
  270.             }
  271.            
  272.             if (context == null) {
  273.                 context = EmptyImpersonationContext.GetStaticInstance();
  274.             }
  275.            
  276.             return context;
  277.         }
  278.        
  279.         internal PermissionSet GetRestrictedPermissions()
  280.         {
  281.             if (!_flags[RestrictedPermissionsResolved]) {
  282.                 PermissionSet restrictedPermissions;
  283.                 bool isHostReady;
  284.                
  285.                 Host.GetRestrictedPermissions(this, out restrictedPermissions, out isHostReady);
  286.                 if (isHostReady) {
  287.                     _restrictedPermissions = restrictedPermissions;
  288.                     _flags[RestrictedPermissionsResolved] = true;
  289.                 }
  290.             }
  291.            
  292.             return _restrictedPermissions;
  293.         }
  294.        
  295.         internal void Init(IInternalConfigRoot configRoot, BaseConfigurationRecord parent, string configPath, string locationSubPath)
  296.         {
  297.            
  298.             _initErrors = new ConfigurationSchemaErrors();
  299.            
  300.             //
  301.             // try/catch here is only for unexpected exceptions due to errors in
  302.             // our own code, as we always want the configuration record to be
  303.             // usable
  304.             //
  305.             try {
  306.                 _configRoot = (InternalConfigRoot)configRoot;
  307.                 _parent = parent;
  308.                 _configPath = configPath;
  309.                 _locationSubPath = locationSubPath;
  310.                 _configName = ConfigPathUtility.GetName(configPath);
  311.                
  312.                 if (IsLocationConfig) {
  313.                     _configStreamInfo = _parent.ConfigStreamInfo;
  314.                 }
  315.                 else {
  316.                     _configStreamInfo = new ConfigRecordStreamInfo();
  317.                 }
  318.                
  319.                 // no more initialization in case of root config
  320.                 if (IsRootConfig)
  321.                     return;
  322.                
  323.                 // determine what features we support
  324.                 _flags[SupportsChangeNotifications] = ClassFlags[ClassSupportsChangeNotifications] && Host.SupportsChangeNotifications;
  325.                 _flags[SupportsRefresh] = ClassFlags[ClassSupportsRefresh] && Host.SupportsRefresh;
  326.                 _flags[SupportsKeepInputs] = ClassFlags[ClassSupportsKeepInputs] || _flags[SupportsRefresh];
  327.                 _flags[SupportsPath] = Host.SupportsPath;
  328.                 _flags[SupportsLocation] = Host.SupportsLocation;
  329.                
  330.                 // get static state based on the configPath
  331.                 if (_flags[SupportsLocation]) {
  332.                     _flags[IsAboveApplication] = Host.IsAboveApplication(_configPath);
  333.                 }
  334.                
  335.                 _flags[IsTrusted] = Host.IsTrustedConfigPath(_configPath);
  336.                
  337.                 ArrayList locationSubPathInputs = null;
  338.                
  339.                 if (_flags[SupportsLocation]) {
  340.                     //
  341.                     // Treat location inputs from parent record
  342.                     // as though they were bonafide sections in this record.
  343.                     //
  344.                     if (IsLocationConfig && _parent._locationSections != null) {
  345.                         // Resolve paths and check for errors in location sections.
  346.                         _parent.ResolveLocationSections();
  347.                        
  348.                         int i = 0;
  349.                         while (i < _parent._locationSections.Count) {
  350.                             LocationSectionRecord locationSectionRecord = (LocationSectionRecord)_parent._locationSections[i];
  351.                            
  352.                             if (!StringUtil.EqualsIgnoreCase(locationSectionRecord.SectionXmlInfo.SubPath, _locationSubPath)) {
  353.                                 i++;
  354.                             }
  355.                             else {
  356.                                 // remove the locationSectionRecord from the list
  357.                                 _parent._locationSections.RemoveAt(i);
  358.                                
  359.                                 if (locationSubPathInputs == null) {
  360.                                     locationSubPathInputs = new ArrayList();
  361.                                 }
  362.                                
  363.                                 locationSubPathInputs.Add(locationSectionRecord);
  364.                             }
  365.                         }
  366.                     }
  367.                    
  368.                     //
  369.                     // Add location inputs that apply to this path, all the way up the parent hierarchy.
  370.                     //
  371.                     if (Host.IsLocationApplicable(_configPath)) {
  372.                         BaseConfigurationRecord current = _parent;
  373.                         while (!current.IsRootConfig) {
  374.                             if (current._locationSections != null) {
  375.                                 current.ResolveLocationSections();
  376.                                 foreach (LocationSectionRecord locationSectionRecord in current._locationSections) {
  377.                                     // We use the location tag input if:
  378.                                     // - The path matches, and
  379.                                     // - It's not skipped due to inheritInChildApplications setting.
  380.                                     if (StringUtil.EqualsIgnoreCase(locationSectionRecord.SectionXmlInfo.TargetConfigPath, this._configPath) && !ShouldSkipDueToInheritInChildApplications(locationSectionRecord.SectionXmlInfo.SkipInChildApps)) {
  381.                                         // add the location input for this section
  382.                                         SectionRecord sectionRecord = EnsureSectionRecord(locationSectionRecord.ConfigKey, true);
  383.                                         SectionInput sectionInput = new SectionInput(locationSectionRecord.SectionXmlInfo, locationSectionRecord.ErrorsList);
  384.                                        
  385.                                         sectionRecord.AddLocationInput(sectionInput);
  386.                                        
  387.                                         // copy the initialization errors to the record
  388.                                         if (locationSectionRecord.HasErrors) {
  389.                                             this._initErrors.AddSavedLocalErrors(locationSectionRecord.Errors);
  390.                                         }
  391.                                     }
  392.                                 }
  393.                             }
  394.                            
  395.                             current = current._parent;
  396.                         }
  397.                     }
  398.                 }
  399.                
  400.                 if (!IsLocationConfig) {
  401.                     //
  402.                     // If config file exists, open it and parse it once so we can
  403.                     // find what to evaluate later.
  404.                     //
  405.                     InitConfigFromFile();
  406.                 }
  407.                 else {
  408.                     // Add location sections for this record as bonafide sections.
  409.                     if (locationSubPathInputs != null) {
  410.                         foreach (LocationSectionRecord locationSectionRecord in locationSubPathInputs) {
  411.                             // add the file input
  412.                             SectionRecord sectionRecord = EnsureSectionRecord(locationSectionRecord.ConfigKey, true);
  413.                             SectionInput sectionInput = new SectionInput(locationSectionRecord.SectionXmlInfo, locationSectionRecord.ErrorsList);
  414.                             sectionRecord.AddFileInput(sectionInput);
  415.                            
  416.                             // copy the initialization errors to the record
  417.                             if (locationSectionRecord.HasErrors) {
  418.                                 this._initErrors.AddSavedLocalErrors(locationSectionRecord.Errors);
  419.                             }
  420.                         }
  421.                     }
  422.                 }
  423.             }
  424.             //
  425.             // Capture all exceptions and include them in initialization errors.
  426.             //
  427.             catch (Exception e) {
  428.                 string streamname = (ConfigStreamInfo != null) ? ConfigStreamInfo.StreamName : null;
  429.                
  430.                 _initErrors.AddError(ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_error_loading_XML_file), e, streamname, 0), ExceptionAction.Global);
  431.             }
  432.             catch {
  433.                 string streamname = (ConfigStreamInfo != null) ? ConfigStreamInfo.StreamName : null;
  434.                
  435.                 _initErrors.AddError(ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_error_loading_XML_file), null, streamname, 0), ExceptionAction.Global);
  436.             }
  437.         }
  438.        
  439.         // InitConfigFromFile
  440.         //
  441.         // Init the Config From the File.
  442.         //
  443.         private void InitConfigFromFile()
  444.         {
  445.             bool implicitSectionsAdded = false;
  446.            
  447.             try {
  448.                 // If initialization should be delayed, do not read the file.
  449.                 if (ClassFlags[ClassSupportsDelayedInit] && Host.IsInitDelayed(this)) {
  450.                     // determine the root of delayed initialization
  451.                     if (_parent._initDelayedRoot == null) {
  452.                         _initDelayedRoot = this;
  453.                     }
  454.                     else {
  455.                         _initDelayedRoot = _parent._initDelayedRoot;
  456.                     }
  457.                 }
  458.                 else {
  459.                     //
  460.                     // This parent of a record that is not initDelayed must also
  461.                     // not be initDelayed.
  462.                     //
  463.                     Debug.Assert(!_parent.IsInitDelayed, "!_parent.IsInitDelayed");
  464.                    
  465.                     using (Impersonate()) {
  466.                        
  467.                         //
  468.                         // Get the stream name. Note that this may be an expensive operation
  469.                         // for the client configuration host, which is why it comes after the
  470.                         // check for delayed init.
  471.                         //
  472.                         ConfigStreamInfo.StreamName = Host.GetStreamName(_configPath);
  473.                         if (!String.IsNullOrEmpty(ConfigStreamInfo.StreamName)) {
  474.                             // Lets listen to the stream
  475.                             ConfigStreamInfo.StreamVersion = MonitorStream(null, null, ConfigStreamInfo.StreamName);
  476.                             using (Stream stream = Host.OpenStreamForRead(ConfigStreamInfo.StreamName)) {
  477.                                 if (stream == null) {
  478.                                     // There is no stream to load from
  479.                                     return;
  480.                                 }
  481.                                
  482.                                 ConfigStreamInfo.HasStream = true;
  483.                                
  484.                                 // Determine whether or not to prefetch.
  485.                                 _flags[PrefetchAll] = Host.PrefetchAll(_configPath, ConfigStreamInfo.StreamName);
  486.                                
  487.                                 using (XmlUtil xmlUtil = new XmlUtil(stream, ConfigStreamInfo.StreamName, true, _initErrors)) {
  488.                                     ConfigStreamInfo.StreamEncoding = xmlUtil.Reader.Encoding;
  489.                                    
  490.                                     // Read the factories
  491.                                     Hashtable factoryList = ScanFactories(xmlUtil);
  492.                                     _factoryRecords = factoryList;
  493.                                    
  494.                                     // Add implicit sections before scanning sections
  495.                                     AddImplicitSections(null);
  496.                                     implicitSectionsAdded = true;
  497.                                    
  498.                                     // Read the sections themselves
  499.                                     if (xmlUtil.Reader.Depth == 1) {
  500.                                         ScanSections(xmlUtil);
  501.                                     }
  502.                                 }
  503.                             }
  504.                         }
  505.                     }
  506.                 }
  507.             }
  508.             //
  509.             // Capture all exceptions and include them in _initErrors so execution in Init can continue.
  510.             //
  511.             catch (XmlException e) {
  512.                 //
  513.                 // Treat invalid XML as unrecoverable by replacing all errors with the XML error.
  514.                 //
  515.                 _initErrors.SetSingleGlobalError(ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_error_loading_XML_file), e, ConfigStreamInfo.StreamName, 0));
  516.             }
  517.             catch (Exception e) {
  518.                 _initErrors.AddError(ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_error_loading_XML_file), e, ConfigStreamInfo.StreamName, 0), ExceptionAction.Global);
  519.             }
  520.             catch {
  521.                 _initErrors.AddError(ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_error_loading_XML_file), null, ConfigStreamInfo.StreamName, 0), ExceptionAction.Global);
  522.             }
  523.            
  524.             //
  525.             // If there are global errors that make all input invalid,
  526.             // reset our state so that inherited configuration can still be used,
  527.             // including location sections that apply to this file.
  528.             //
  529.             if (_initErrors.HasGlobalErrors) {
  530.                
  531.                 //
  532.                 // Parsing of a section may have been in progress when the exception
  533.                 // was thrown, so clear any accumulated local errors.
  534.                 //
  535.                 _initErrors.ResetLocalErrors();
  536.                
  537.                 //
  538.                 // Stop monitoring any configSource streams, but still continue
  539.                 // to monitor the main config file if it was successfully monitored.
  540.                 //
  541.                 HybridDictionary streamInfos = null;
  542.                 lock (this) {
  543.                     if (ConfigStreamInfo.HasStreamInfos) {
  544.                         streamInfos = ConfigStreamInfo.StreamInfos;
  545.                         ConfigStreamInfo.ClearStreamInfos();
  546.                        
  547.                         if (!String.IsNullOrEmpty(ConfigStreamInfo.StreamName)) {
  548.                             StreamInfo fileStreamInfo = (StreamInfo)streamInfos[ConfigStreamInfo.StreamName];
  549.                            
  550.                             // add this file's streaminfo to the now empty list
  551.                             if (fileStreamInfo != null) {
  552.                                 streamInfos.Remove(ConfigStreamInfo.StreamName);
  553.                                 ConfigStreamInfo.StreamInfos.Add(ConfigStreamInfo.StreamName, fileStreamInfo);
  554.                             }
  555.                         }
  556.                     }
  557.                 }
  558.                
  559.                 // Stop monitoring streams outside the lock, to prevent deadlock.
  560.                 if (streamInfos != null) {
  561.                     foreach (StreamInfo streamInfo in streamInfos.Values) {
  562.                         if (streamInfo.IsMonitored) {
  563.                             Host.StopMonitoringStreamForChanges(streamInfo.StreamName, ConfigStreamInfo.CallbackDelegate);
  564.                         }
  565.                     }
  566.                 }
  567.                
  568.                 // Remove file input
  569.                 if (_sectionRecords != null) {
  570.                     List<SectionRecord> removes = null;
  571.                     foreach (SectionRecord sectionRecord in _sectionRecords.Values) {
  572.                         if (sectionRecord.HasLocationInputs) {
  573.                             // Remove any file input
  574.                             sectionRecord.RemoveFileInput();
  575.                         }
  576.                         else {
  577.                             // Remove the entire section record
  578.                             if (removes == null) {
  579.                                 removes = new List<SectionRecord>();
  580.                             }
  581.                            
  582.                             removes.Add(sectionRecord);
  583.                         }
  584.                     }
  585.                    
  586.                     if (removes != null) {
  587.                         foreach (SectionRecord sectionRecord in removes) {
  588.                             _sectionRecords.Remove(sectionRecord.ConfigKey);
  589.                         }
  590.                     }
  591.                 }
  592.                
  593.                 // Remove all location section input defined here
  594.                 if (_locationSections != null) {
  595.                     _locationSections.Clear();
  596.                 }
  597.                
  598.                 // Remove all factory records
  599.                 if (_factoryRecords != null) {
  600.                     _factoryRecords.Clear();
  601.                 }
  602.             }
  603.            
  604.             if (!implicitSectionsAdded) {
  605.                 // Always add implicit sections no matter we have a file or not.
  606.                 AddImplicitSections(null);
  607.             }
  608.         }
  609.        
  610.         private bool IsInitDelayed {
  611.             get { return _initDelayedRoot != null; }
  612.         }
  613.        
  614.         // RefreshFactoryRecord
  615.         //
  616.         // Refresh the Factory Record for a particular section.
  617.         //
  618.         private void RefreshFactoryRecord(string configKey)
  619.         {
  620.             Hashtable factoryList = null;
  621.             FactoryRecord factoryRecord = null;
  622.             ConfigurationSchemaErrors errors;
  623.            
  624.             errors = new ConfigurationSchemaErrors();
  625.            
  626.             // Get Updated Factory List from File
  627.             int lineNumber = 0;
  628.             try {
  629.                 using (Impersonate()) {
  630.                     using (Stream stream = Host.OpenStreamForRead(ConfigStreamInfo.StreamName)) {
  631.                         if (stream != null) {
  632.                             ConfigStreamInfo.HasStream = true;
  633.                            
  634.                             using (XmlUtil xmlUtil = new XmlUtil(stream, ConfigStreamInfo.StreamName, true, errors)) {
  635.                                 try {
  636.                                     factoryList = ScanFactories(xmlUtil);
  637.                                     ThrowIfParseErrors(xmlUtil.SchemaErrors);
  638.                                 }
  639.                                 catch {
  640.                                     lineNumber = xmlUtil.LineNumber;
  641.                                     throw;
  642.                                 }
  643.                             }
  644.                         }
  645.                     }
  646.                 }
  647.                
  648.                 // Add implicit sections to the factory list
  649.                 if (factoryList == null) {
  650.                     // But if factoryList isn't found in this config, we still try to
  651.                     // add implicit sections to an empty factoryList.
  652.                     factoryList = new Hashtable();
  653.                 }
  654.                
  655.                 AddImplicitSections(factoryList);
  656.                
  657.                 if (factoryList != null) {
  658.                     factoryRecord = (FactoryRecord)factoryList[configKey];
  659.                 }
  660.             }
  661.             //
  662.             // Guarantee that exceptions contain the name of the stream and an approximate line number if available.
  663.             //
  664.             // And don't allow frames up the stack to run exception filters while impersonated.
  665.             catch (Exception e) {
  666.                 errors.AddError(ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_error_loading_XML_file), e, ConfigStreamInfo.StreamName, lineNumber), ExceptionAction.Global);
  667.                
  668.             }
  669.             catch {
  670.                 errors.AddError(ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_error_loading_XML_file), null, ConfigStreamInfo.StreamName, lineNumber), ExceptionAction.Global);
  671.             }
  672.            
  673.             // Set/Add/Remove Record
  674.             // Note that the _factoryRecords hashtable is protected by the hierarchy lock.
  675.             if (factoryRecord != null || HasFactoryRecords) {
  676.                 EnsureFactories()[configKey] = factoryRecord;
  677.             }
  678.            
  679.             // Throw accumulated errors
  680.             ThrowIfParseErrors(errors);
  681.         }
  682.        
  683.         internal IInternalConfigHost Host {
  684.             get { return _configRoot.Host; }
  685.         }
  686.        
  687.         internal BaseConfigurationRecord Parent {
  688.             get { return _parent; }
  689.         }
  690.        
  691.         internal bool IsRootConfig {
  692.             get { return _parent == null; }
  693.         }
  694.        
  695.         internal bool IsMachineConfig {
  696.             get { return _parent == _configRoot.RootConfigRecord; }
  697.         }
  698.        
  699.        
  700.         internal string LocationSubPath {
  701.             get { return _locationSubPath; }
  702.         }
  703.        
  704.         internal bool IsLocationConfig {
  705.             get { return _locationSubPath != null; }
  706.         }
  707.        
  708.         protected ConfigRecordStreamInfo ConfigStreamInfo {
  709.             get {
  710.                 if (IsLocationConfig) {
  711.                     return _parent._configStreamInfo;
  712.                 }
  713.                 else {
  714.                     return _configStreamInfo;
  715.                 }
  716.             }
  717.         }
  718.        
  719.         private object GetSection(string configKey, bool getLkg, bool checkPermission)
  720.         {
  721.             object result;
  722.             object resultRuntimeObject;
  723.            
  724.             //
  725.             // Note that GetSectionRecursive may invalidate this record,
  726.             // so there should be no further references to 'this' after the call.
  727.             //
  728.                 /* getRuntimeObject */                /* requestIsHere */            GetSectionRecursive(configKey, getLkg, checkPermission, true, true, out result, out resultRuntimeObject);
  729.            
  730.             return resultRuntimeObject;
  731.         }
  732.        
  733.         private void GetSectionRecursive(string configKey, bool getLkg, bool checkPermission, bool getRuntimeObject, bool requestIsHere, out object result, out object resultRuntimeObject)
  734.         {
  735.            
  736.             result = null;
  737.             resultRuntimeObject = null;
  738.            
  739.             #if DBG
  740.             Debug.Assert(requestIsHere || !checkPermission, "requestIsHere || !checkPermission");
  741.             if (getLkg) {
  742.                 Debug.Assert(getRuntimeObject == true, "getRuntimeObject == true");
  743.                 Debug.Assert(requestIsHere == true, "requestIsHere == true");
  744.             }
  745.             #endif
  746.            
  747.             //
  748.             // Store results in temporary variables, because we don't want to return
  749.             // results if an exception is thrown by CheckPermissionAllowed.
  750.             //
  751.             object tmpResult = null;
  752.             object tmpResultRuntimeObject = null;
  753.             bool requirePermission = true;
  754.             bool isResultTrustedWithoutAptca = true;
  755.            
  756.             // Throw errors from initial parse, if any.
  757.             if (!getLkg) {
  758.                 ThrowIfInitErrors();
  759.             }
  760.            
  761.             //
  762.             // check for a cached result
  763.             //
  764.             bool hasResult = false;
  765.             SectionRecord sectionRecord = GetSectionRecord(configKey, getLkg);
  766.             if (sectionRecord != null && sectionRecord.HasResult) {
  767.                 // Results should never be stored if the section has errors.
  768.                 Debug.Assert(!sectionRecord.HasErrors, "!sectionRecord.HasErrors");
  769.                
  770.                 // Create the runtime object if requested and does not yet exist.
  771.                 if (getRuntimeObject && !sectionRecord.HasResultRuntimeObject) {
  772.                     try {
  773.                         sectionRecord.ResultRuntimeObject = GetRuntimeObject(sectionRecord.Result);
  774.                     }
  775.                     catch {
  776.                         //
  777.                         // Ignore the error if we are attempting to retreive
  778.                         // the last known good configuration.
  779.                         //
  780.                         if (!getLkg) {
  781.                             throw;
  782.                         }
  783.                     }
  784.                 }
  785.                
  786.                 // Get the cached result.
  787.                 if (!getRuntimeObject || sectionRecord.HasResultRuntimeObject) {
  788.                     requirePermission = sectionRecord.RequirePermission;
  789.                     isResultTrustedWithoutAptca = sectionRecord.IsResultTrustedWithoutAptca;
  790.                     tmpResult = sectionRecord.Result;
  791.                     if (getRuntimeObject) {
  792.                         tmpResultRuntimeObject = sectionRecord.ResultRuntimeObject;
  793.                     }
  794.                    
  795.                     hasResult = true;
  796.                 }
  797.             }
  798.            
  799.             //
  800.             // If there is no cached result, get the parent's section,
  801.             // then merge it with our own input if we have any.
  802.             //
  803.             if (!hasResult) {
  804.                 FactoryRecord factoryRecord = null;
  805.                 bool hasInput = (sectionRecord != null && sectionRecord.HasInput);
  806.                
  807.                 //
  808.                 // We want to cache results in a section record if:
  809.                 // - The request is made at this level, and so is likely to be
  810.                 // made here again.
  811.                 // OR
  812.                 // - The section has input, in which case we want to
  813.                 // avoid evaluating the same input multiple times.
  814.                 //
  815.                 bool cacheResults = (requestIsHere || hasInput);
  816.                
  817.                 bool isRootDeclaration;
  818.                 try {
  819.                     //
  820.                     // We need to get a factory record to:
  821.                     // - Check whether the caller has permission to access a section.
  822.                     // - Determine if this is the root declaration of a config section,
  823.                     // and thus the termination point for recursion.
  824.                     // - Get a factory that can create a configuration section.
  825.                     //
  826.                     // Since most factories will be declared in machine.config and not in
  827.                     // child config files, we do not optimize for checking whether a
  828.                     // factory record is the root declaration, as the calculation at
  829.                     // machine.config is trivial.
  830.                     //
  831.                     // It WILL be common in web scenarios for there to be
  832.                     // deep hierarchies of config files, most of which have
  833.                     // sparse input. Therefore we do not want to retreive a
  834.                     // factory record if it is not necessary to do so, as
  835.                     // it would always lead to an order N-squared operation,
  836.                     // where N is the depth of the config hierarchy.
  837.                     //
  838.                     // We can skip the reteival of a factory record if:
  839.                     // - This is the recursive call to GetSectionRecursive,
  840.                     // AND
  841.                     // - There is no section input at this level,
  842.                     // AND
  843.                     // - No factory is declared at this level.
  844.                     //
  845.                     // In this case, we'll simply continue the recursion to our parent.
  846.                     //
  847.                     if (requestIsHere) {
  848.                         //
  849.                         // Ensure that we have a valid factory record and a valid factory
  850.                         // for creating sections when a request for a section is first
  851.                         // made.
  852.                         //
  853.                         factoryRecord = FindAndEnsureFactoryRecord(configKey, out isRootDeclaration);
  854.                        
  855.                         //
  856.                         // If initialization is delayed, complete initialization if:
  857.                         // - We can't find the requested factory, and it therefore
  858.                         // may be in the file we haven't yet read,
  859.                         // OR
  860.                         // - The definition of that factory is allowed at
  861.                         // levels of the config hierarchy that have not
  862.                         // been initialized.
  863.                         //
  864.                         // This works for client config scenarios because the default
  865.                         // for AllowExeDefinition is MachineToApplication. It would not
  866.                         // be useful for Web scenarios, as most sections can be requested
  867.                         // Everywhere.
  868.                         //
  869.                         // Note that configuration errors that may be present in the
  870.                         // file where intialization is delayed will be ignored, and
  871.                         // thus the order in which configuration sections are requested
  872.                         // will affect results. This is considered OK as it is very
  873.                         // expensive to determine configuration paths to
  874.                         // client user configuration files, which aren't needed by
  875.                         // most applications.
  876.                         //
  877.                         if (IsInitDelayed && (factoryRecord == null || _initDelayedRoot.IsDefinitionAllowed(factoryRecord.AllowDefinition, factoryRecord.AllowExeDefinition))) {
  878.                            
  879.                             //
  880.                             // We are going to remove this record, so get any data we need
  881.                             // before the reference to 'this' becomes invalid.
  882.                             //
  883.                             string configPath = this._configPath;
  884.                             InternalConfigRoot configRoot = this._configRoot;
  885.                            
  886.                             // Tell the host to no longer permit delayed initialization.
  887.                             Host.RequireCompleteInit(_initDelayedRoot);
  888.                            
  889.                             // Removed config at the root of where initialization is delayed.
  890.                             _initDelayedRoot.Remove();
  891.                            
  892.                             // Get the config record for this config path
  893.                             BaseConfigurationRecord newRecord = (BaseConfigurationRecord)configRoot.GetConfigRecord(configPath);
  894.                            
  895.                             // Repeat the call to GetSectionRecursive
  896.                             newRecord.GetSectionRecursive(configKey, getLkg, checkPermission, getRuntimeObject, requestIsHere, out result, out resultRuntimeObject);
  897.                            
  898.                             // Return and make no more references to this record.
  899.                             return;
  900.                         }
  901.                        
  902.                         //
  903.                         // For compatibility with previous versions,
  904.                         // return null if the section is not found
  905.                         // or is a group.
  906.                         //
  907.                         if (factoryRecord == null || factoryRecord.IsGroup) {
  908.                             return;
  909.                         }
  910.                        
  911.                         //
  912.                         // Use the factory record's copy of the configKey,
  913.                         // so that we don't store more than one instance
  914.                         // of the same configKey.
  915.                         //
  916.                         configKey = factoryRecord.ConfigKey;
  917.                     }
  918.                     else if (hasInput) {
  919.                         //
  920.                         // We'll need a factory to evaluate the input.
  921.                         //
  922.                         factoryRecord = FindAndEnsureFactoryRecord(configKey, out isRootDeclaration);
  923.                         Debug.Assert(factoryRecord != null, "factoryRecord != null");
  924.                     }
  925.                     else {
  926.                         //
  927.                         // We don't need a factory record unless this is the root declaration.
  928.                         // We know it is not the root declaration if there is no factory
  929.                         // declared here. This is important to avoid a walk up the config
  930.                         // hierachy when there is no input in this record.
  931.                         //
  932.                         factoryRecord = GetFactoryRecord(configKey, false);
  933.                         if (factoryRecord == null) {
  934.                             isRootDeclaration = false;
  935.                         }
  936.                         else {
  937.                             factoryRecord = FindAndEnsureFactoryRecord(configKey, out isRootDeclaration);
  938.                             Debug.Assert(factoryRecord != null, "factoryRecord != null");
  939.                         }
  940.                     }
  941.                    
  942.                     // We need a factory record to check permission.
  943.                     Debug.Assert(!checkPermission || factoryRecord != null, "!checkPermission || factoryRecord != null");
  944.                    
  945.                     //
  946.                     // If this is the root declaration, then we always want to cache
  947.                     // the result, in order to prevent the section default from being
  948.                     // created multiple times.
  949.                     //
  950.                     if (isRootDeclaration) {
  951.                         cacheResults = true;
  952.                     }
  953.                    
  954.                     //
  955.                     // We'll need a section record to cache results,
  956.                     // and maybe to use in creating the section default.
  957.                     //
  958.                     if (sectionRecord == null && cacheResults) {
  959.                         sectionRecord = EnsureSectionRecord(configKey, true);
  960.                     }
  961.                    
  962.                     //
  963.                     // Retrieve the parent's runtime object if the runtimeObject
  964.                     // is requested, and we are not going to merge that input
  965.                     // with input in this section.
  966.                     //
  967.                     bool getParentRuntimeObject = (getRuntimeObject && !hasInput);
  968.                    
  969.                     object parentResult = null;
  970.                     object parentResultRuntimeObject = null;
  971.                     if (isRootDeclaration) {
  972.                         //
  973.                         // Create the default section.
  974.                         //
  975.                         // Use the existing section record to create it if there is no input,
  976.                         // so that the cached result is attached to the correct record.
  977.                         //
  978.                         SectionRecord sectionRecordForDefault = (hasInput) ? null : sectionRecord;
  979.                         CreateSectionDefault(configKey, getParentRuntimeObject, factoryRecord, sectionRecordForDefault, out parentResult, out parentResultRuntimeObject);
  980.                     }
  981.                     else {
  982.                         //
  983.                         // Get the parent section.
  984.                         //
  985.                             /* getLkg */                            /* checkPermission */                            /* requestIsHere */                        _parent.GetSectionRecursive(configKey, false, false, getParentRuntimeObject, false, out parentResult, out parentResultRuntimeObject);
  986.                     }
  987.                    
  988.                     if (hasInput) {
  989.                         //
  990.                         // Evaluate the input.
  991.                         //
  992.                         // If Evaluate() encounters an error, it may not throw an exception
  993.                         // when getLkg == true.
  994.                         //
  995.                         // The complete success of the evaluation is determined by the return value.
  996.                         //
  997.                         bool success = Evaluate(factoryRecord, sectionRecord, parentResult, getLkg, getRuntimeObject, out tmpResult, out tmpResultRuntimeObject);
  998.                        
  999.                         Debug.Assert(success || getLkg, "success || getLkg");
  1000.                        
  1001.                         if (!success) {
  1002.                             Debug.Assert(getLkg == true, "getLkg == true");
  1003.                             // Do not cache partial results if getLkg was specified.
  1004.                             cacheResults = false;
  1005.                         }
  1006.                     }
  1007.                     else {
  1008.                         //
  1009.                         // If we are going to cache results here, we will need
  1010.                         // to create a copy in the case of MgmtConfigurationRecord -
  1011.                         // otherwise we could inadvertently return the parent to the user,
  1012.                         // which could then be modified.
  1013.                         //
  1014.                         if (sectionRecord != null) {
  1015.                             tmpResult = UseParentResult(configKey, parentResult, sectionRecord);
  1016.                             if (getRuntimeObject) {
  1017.                                 //
  1018.                                 // If the parent result is the same as the parent runtime object,
  1019.                                 // then use the same copy of the parent result for our own runtime object.
  1020.                                 //
  1021.                                 if (object.ReferenceEquals(parentResult, parentResultRuntimeObject)) {
  1022.                                     tmpResultRuntimeObject = tmpResult;
  1023.                                 }
  1024.                                 else {
  1025.                                     tmpResultRuntimeObject = UseParentResult(configKey, parentResultRuntimeObject, sectionRecord);
  1026.                                 }
  1027.                             }
  1028.                         }
  1029.                         else {
  1030.                             Debug.Assert(!requestIsHere, "!requestIsHere");
  1031.                            
  1032.                             //
  1033.                             // We don't need to make a copy if we are not storing
  1034.                             // the result, and thus not returning the result to the
  1035.                             // caller of GetSection.
  1036.                             //
  1037.                             tmpResult = parentResult;
  1038.                             tmpResultRuntimeObject = parentResultRuntimeObject;
  1039.                         }
  1040.                     }
  1041.                    
  1042.                     //
  1043.                     // Determine which permissions are required of the caller.
  1044.                     //
  1045.                     if (cacheResults || checkPermission) {
  1046.                         requirePermission = factoryRecord.RequirePermission;
  1047.                         isResultTrustedWithoutAptca = factoryRecord.IsFactoryTrustedWithoutAptca;
  1048.                        
  1049.                         //
  1050.                         // Cache the results.
  1051.                         //
  1052.                         if (cacheResults) {
  1053.                             if (sectionRecord == null) {
  1054.                                 sectionRecord = EnsureSectionRecord(configKey, true);
  1055.                             }
  1056.                            
  1057.                             sectionRecord.Result = tmpResult;
  1058.                             if (getRuntimeObject) {
  1059.                                 sectionRecord.ResultRuntimeObject = tmpResultRuntimeObject;
  1060.                             }
  1061.                            
  1062.                             sectionRecord.RequirePermission = requirePermission;
  1063.                             sectionRecord.IsResultTrustedWithoutAptca = isResultTrustedWithoutAptca;
  1064.                         }
  1065.                     }
  1066.                    
  1067.                     hasResult = true;
  1068.                 }
  1069.                 catch {
  1070.                     //
  1071.                     // Ignore the error if we are attempting to retreive
  1072.                     // the last known good configuration.
  1073.                     //
  1074.                     if (!getLkg) {
  1075.                         throw;
  1076.                     }
  1077.                 }
  1078.                
  1079.                 //
  1080.                 // If we don't have a result, ask our parent for its
  1081.                 // last known good result.
  1082.                 //
  1083.                 if (!hasResult) {
  1084.                     Debug.Assert(getLkg == true, "getLkg == true");
  1085.                    
  1086.                         /* getLkg */                        /* getRuntimeObject */                        /* requestIsHere */                    _parent.GetSectionRecursive(configKey, true, checkPermission, true, true, out result, out resultRuntimeObject);
  1087.                    
  1088.                     return;
  1089.                 }
  1090.             }
  1091.            
  1092.             //
  1093.             // Check if permission to access the section is allowed.
  1094.             //
  1095.             if (checkPermission) {
  1096.                 CheckPermissionAllowed(configKey, requirePermission, isResultTrustedWithoutAptca);
  1097.             }
  1098.            
  1099.             //
  1100.             // Return the results.
  1101.             //
  1102.             result = tmpResult;
  1103.             if (getRuntimeObject) {
  1104.                 resultRuntimeObject = tmpResultRuntimeObject;
  1105.             }
  1106.         }
  1107.        
  1108.         protected void CreateSectionDefault(string configKey, bool getRuntimeObject, FactoryRecord factoryRecord, SectionRecord sectionRecord, out object result, out object resultRuntimeObject)
  1109.         {
  1110.            
  1111.             result = null;
  1112.             resultRuntimeObject = null;
  1113.            
  1114.             SectionRecord sectionRecordForDefault;
  1115.             if (sectionRecord != null) {
  1116.                 sectionRecordForDefault = sectionRecord;
  1117.             }
  1118.             else {
  1119.                 sectionRecordForDefault = new SectionRecord(configKey);
  1120.             }
  1121.            
  1122.             object tmpResult = CallCreateSection(true, factoryRecord, sectionRecordForDefault, null, null, null, -1);
  1123.             object tmpResultRuntimeObject;
  1124.             if (getRuntimeObject) {
  1125.                 tmpResultRuntimeObject = GetRuntimeObject(tmpResult);
  1126.             }
  1127.             else {
  1128.                 tmpResultRuntimeObject = null;
  1129.             }
  1130.            
  1131.             result = tmpResult;
  1132.             resultRuntimeObject = tmpResultRuntimeObject;
  1133.         }
  1134.        
  1135.        
  1136.         //
  1137.         // Check if an input should be skipped based on inheritInChildApplications setting.
  1138.         //
  1139.         // If skipInChildApps == true (it means inheritInChildApplications=="false" in the location tag):
  1140.         //
  1141.         // - If _flags[IsAboveApplication]==true, that means the app pointed to by _configPath is above of the
  1142.         // current running app. In another word, the running app is a child app of the app pointed to by _configPath.
  1143.         // In this case, we should skip the input.
  1144.         //
  1145.         // - If _flags[IsAboveApplication]==false, that means the app pointed to by _configPath == current running app.
  1146.         // In this case it's okay to use the input.
  1147.         //
  1148.         private bool ShouldSkipDueToInheritInChildApplications(bool skipInChildApps)
  1149.         {
  1150.             return (skipInChildApps && _flags[IsAboveApplication]);
  1151.         }
  1152.        
  1153.         //
  1154.         // Evaluate the input.
  1155.         //
  1156.         // If Evaluate() encounters an error, it may not throw an exception
  1157.         // when getLkg == true.
  1158.         //
  1159.         // The complete success of the evaluation is determined by the return value.
  1160.         //
  1161.         private bool Evaluate(FactoryRecord factoryRecord, SectionRecord sectionRecord, object parentResult, bool getLkg, bool getRuntimeObject, out object result, out object resultRuntimeObject)
  1162.         {
  1163.            
  1164.             result = null;
  1165.             resultRuntimeObject = null;
  1166.            
  1167.             //
  1168.             // Store results in temporary variables, because we don't want to return
  1169.             // results if an exception is thrown.
  1170.             //
  1171.             object tmpResult = null;
  1172.             object tmpResultRuntimeObject = null;
  1173.            
  1174.             // Factory record should be error-free.
  1175.             Debug.Assert(!factoryRecord.HasErrors, "!factoryRecord.HasErrors");
  1176.            
  1177.             // We should have some input
  1178.             Debug.Assert(sectionRecord.HasInput, "sectionRecord.HasInput");
  1179.            
  1180.             //
  1181.             // Grab inputs before checking result,
  1182.             // as inputs may be cleared once the result is set.
  1183.             //
  1184.             List<SectionInput> locationInputs = sectionRecord.LocationInputs;
  1185.             SectionInput fileInput = sectionRecord.FileInput;
  1186.            
  1187.             //
  1188.             // Now that we have our inputs, lets check if there
  1189.             // is a result, because if there is, our inputs might
  1190.             // have been invalidated.
  1191.             //
  1192.             bool success = false;
  1193.             if (sectionRecord.HasResult) {
  1194.                 // Results should never be stored if the section has errors.
  1195.                 Debug.Assert(!sectionRecord.HasErrors, "!sectionRecord.HasErrors");
  1196.                
  1197.                 // Create the runtime object if requested and it does not yet exist.
  1198.                 if (getRuntimeObject && !sectionRecord.HasResultRuntimeObject) {
  1199.                     try {
  1200.                         sectionRecord.ResultRuntimeObject = GetRuntimeObject(sectionRecord.Result);
  1201.                     }
  1202.                     catch {
  1203.                         //
  1204.                         // Ignore the error if we are attempting to retreive
  1205.                         // the last known good configuration.
  1206.                         //
  1207.                         if (!getLkg) {
  1208.                             throw;
  1209.                         }
  1210.                     }
  1211.                 }
  1212.                
  1213.                 // Get the cached result.
  1214.                 if (!getRuntimeObject || sectionRecord.HasResultRuntimeObject) {
  1215.                     tmpResult = sectionRecord.Result;
  1216.                     if (getRuntimeObject) {
  1217.                         tmpResultRuntimeObject = sectionRecord.ResultRuntimeObject;
  1218.                     }
  1219.                    
  1220.                     success = true;
  1221.                 }
  1222.             }
  1223.            
  1224.             if (!success) {
  1225.                 Exception savedException = null;
  1226.                 try {
  1227.                     string configKey = factoryRecord.ConfigKey;
  1228.                     string[] keys = configKey.Split(ConfigPathSeparatorParams);
  1229.                     object currentResult = parentResult;
  1230.                    
  1231.                     //
  1232.                     // Evaluate location inputs
  1233.                     //
  1234.                     if (locationInputs != null) {
  1235.                         foreach (SectionInput locationInput in locationInputs) {
  1236.                             if (!locationInput.HasResult) {
  1237.                                 locationInput.ThrowOnErrors();
  1238.                                 bool isTrusted = Host.IsTrustedConfigPath(locationInput.SectionXmlInfo.DefinitionConfigPath);
  1239.                                 locationInput.Result = EvaluateOne(keys, locationInput, isTrusted, factoryRecord, sectionRecord, currentResult);
  1240.                             }
  1241.                            
  1242.                             currentResult = locationInput.Result;
  1243.                         }
  1244.                     }
  1245.                    
  1246.                     //
  1247.                     // Evaluate file input
  1248.                     //
  1249.                     if (fileInput != null) {
  1250.                         if (!fileInput.HasResult) {
  1251.                             fileInput.ThrowOnErrors();
  1252.                             bool isTrusted = _flags[IsTrusted];
  1253.                             fileInput.Result = EvaluateOne(keys, fileInput, isTrusted, factoryRecord, sectionRecord, currentResult);
  1254.                         }
  1255.                        
  1256.                         currentResult = fileInput.Result;
  1257.                     }
  1258.                     else {
  1259.                         //
  1260.                         // The section needs its own copy of the result that is distinct
  1261.                         // from its location parent result.
  1262.                         //
  1263.                         Debug.Assert(locationInputs != null, "locationInputs != null");
  1264.                         currentResult = UseParentResult(configKey, currentResult, sectionRecord);
  1265.                     }
  1266.                    
  1267.                     if (getRuntimeObject) {
  1268.                         tmpResultRuntimeObject = GetRuntimeObject(currentResult);
  1269.                     }
  1270.                    
  1271.                     tmpResult = currentResult;
  1272.                     success = true;
  1273.                 }
  1274.                 catch (Exception e) {
  1275.                     //
  1276.                     // Catch the exception if LKG is requested and we have
  1277.                     // location input to fall back on.
  1278.                     //
  1279.                     if (getLkg && locationInputs != null) {
  1280.                         savedException = e;
  1281.                     }
  1282.                     else {
  1283.                         throw;
  1284.                     }
  1285.                    
  1286.                 }
  1287.                
  1288.                 //
  1289.                 // If getLkg, then return a result from the last valid location input.
  1290.                 //
  1291.                 if (!success) {
  1292.                     Debug.Assert(getLkg == true, "getLkg == true");
  1293.                    
  1294.                     int i = locationInputs.Count;
  1295.                     while (--i >= 0) {
  1296.                         SectionInput locationInput = locationInputs[i];
  1297.                         if (locationInput.HasResult) {
  1298.                             if (getRuntimeObject && !locationInput.HasResultRuntimeObject) {
  1299.                                 try {
  1300.                                     locationInput.ResultRuntimeObject = GetRuntimeObject(locationInput.Result);
  1301.                                 }
  1302.                                 catch {
  1303.                                 }
  1304.                             }
  1305.                            
  1306.                             if (!getRuntimeObject || locationInput.HasResultRuntimeObject) {
  1307.                                 tmpResult = locationInput.Result;
  1308.                                 if (getRuntimeObject) {
  1309.                                     tmpResultRuntimeObject = locationInput.ResultRuntimeObject;
  1310.                                 }
  1311.                                
  1312.                                 break;
  1313.                             }
  1314.                         }
  1315.                     }
  1316.                    
  1317.                     if (i < 0) {
  1318.                         throw savedException;
  1319.                     }
  1320.                 }
  1321.             }
  1322.            
  1323.             //
  1324.             // If evaluation was successful, we can remove any saved rawXml.
  1325.             //
  1326.             if (success && !_flags[SupportsKeepInputs]) {
  1327.                 sectionRecord.ClearRawXml();
  1328.             }
  1329.            
  1330.             result = tmpResult;
  1331.             if (getRuntimeObject) {
  1332.                 resultRuntimeObject = tmpResultRuntimeObject;
  1333.             }
  1334.            
  1335.             return success;
  1336.         }
  1337.        
  1338.         private object EvaluateOne(string[] keys, SectionInput input, bool isTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, object parentResult)
  1339.         {
  1340.            
  1341.             object result;
  1342.             try {
  1343.                 ConfigXmlReader reader = GetSectionXmlReader(keys, input);
  1344.                 if (reader == null) {
  1345.                     //
  1346.                     // If section is not found in a file, use the parent result
  1347.                     //
  1348.                     result = UseParentResult(factoryRecord.ConfigKey, parentResult, sectionRecord);
  1349.                 }
  1350.                 else {
  1351.                     result = CallCreateSection(isTrusted, factoryRecord, sectionRecord, parentResult, reader, input.SectionXmlInfo.Filename, input.SectionXmlInfo.LineNumber);
  1352.                 }
  1353.             }
  1354.             catch (Exception e) {
  1355.                 throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_exception_creating_section, factoryRecord.ConfigKey), e, input.SectionXmlInfo);
  1356.             }
  1357.             catch {
  1358.                 throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_exception_creating_section, factoryRecord.ConfigKey), null, input.SectionXmlInfo);
  1359.             }
  1360.            
  1361.             return result;
  1362.         }
  1363.        
  1364.         //
  1365.         // Create a single cached instance of UnrestrictedConfigPermission.
  1366.         //
  1367.         private static ConfigurationPermission UnrestrictedConfigPermission {
  1368.             get {
  1369.                 if (s_unrestrictedConfigPermission == null) {
  1370.                     s_unrestrictedConfigPermission = new ConfigurationPermission(PermissionState.Unrestricted);
  1371.                 }
  1372.                
  1373.                 return s_unrestrictedConfigPermission;
  1374.             }
  1375.         }
  1376.        
  1377.         //
  1378.         // Check whether permission to the section is allowed to the caller.
  1379.         //
  1380.         private void CheckPermissionAllowed(string configKey, bool requirePermission, bool isTrustedWithoutAptca)
  1381.         {
  1382.             //
  1383.             // Demand unrestricted ConfigurationPermission if the section requires it
  1384.             //
  1385.             if (requirePermission) {
  1386.                
  1387.                 try {
  1388.                     UnrestrictedConfigPermission.Demand();
  1389.                 }
  1390.                 catch (SecurityException e) {
  1391.                     //
  1392.                     // Add a nice error message that includes the sectionName and explains
  1393.                     // how to use the requirePermission attribute.
  1394.                     //
  1395.                     throw new SecurityException(SR.GetString(SR.ConfigurationPermission_Denied, configKey), e);
  1396.                 }
  1397.             }
  1398.            
  1399.             //
  1400.             // Ensure that the recepient isn't receiving an object they otherwise
  1401.             // wouldn't be able to create due to Aptca.
  1402.             //
  1403.             if (isTrustedWithoutAptca && !Host.IsFullTrustSectionWithoutAptcaAllowed(this)) {
  1404.                 throw new ConfigurationErrorsException(SR.GetString(SR.Section_from_untrusted_assembly, configKey));
  1405.             }
  1406.         }
  1407.        
  1408.        
  1409.         private ConfigXmlReader FindSection(string[] keys, SectionXmlInfo sectionXmlInfo, out int lineNumber)
  1410.         {
  1411.             lineNumber = 0;
  1412.             ConfigXmlReader section = null;
  1413.             try {
  1414.                 using (Impersonate()) {
  1415.                     using (Stream stream = Host.OpenStreamForRead(sectionXmlInfo.Filename)) {
  1416.                         if (!_flags[SupportsRefresh] && (stream == null || HasStreamChanged(sectionXmlInfo.Filename, sectionXmlInfo.StreamVersion))) {
  1417.                            
  1418.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_file_has_changed), sectionXmlInfo.Filename, 0);
  1419.                         }
  1420.                        
  1421.                         if (stream != null) {
  1422.                             using (XmlUtil xmlUtil = new XmlUtil(stream, sectionXmlInfo.Filename, true)) {
  1423.                                 if (sectionXmlInfo.SubPath == null) {
  1424.                                     section = FindSectionRecursive(keys, 0, xmlUtil, ref lineNumber);
  1425.                                 }
  1426.                                 else {
  1427.                                     // search children of <configuration> for <location>
  1428.                                     xmlUtil.ReadToNextElement();
  1429.                                     while (xmlUtil.Reader.Depth > 0) {
  1430.                                         if (xmlUtil.Reader.Name == KEYWORD_LOCATION) {
  1431.                                             bool locationValid = false;
  1432.                                             string locationSubPathAttribute = xmlUtil.Reader.GetAttribute(KEYWORD_LOCATION_PATH);
  1433.                                            
  1434.                                             try {
  1435.                                                 locationSubPathAttribute = NormalizeLocationSubPath(locationSubPathAttribute, xmlUtil);
  1436.                                                 locationValid = true;
  1437.                                             }
  1438.                                             catch (ConfigurationException ce) {
  1439.                                                 xmlUtil.SchemaErrors.AddError(ce, ExceptionAction.NonSpecific);
  1440.                                             }
  1441.                                            
  1442.                                             if (locationValid && StringUtil.EqualsIgnoreCase(sectionXmlInfo.SubPath, locationSubPathAttribute)) {
  1443.                                                
  1444.                                                 section = FindSectionRecursive(keys, 0, xmlUtil, ref lineNumber);
  1445.                                                 if (section != null)
  1446.                                                     break;
  1447.                                             }
  1448.                                         }
  1449.                                        
  1450.                                         xmlUtil.SkipToNextElement();
  1451.                                     }
  1452.                                 }
  1453.                                
  1454.                                 // Throw accumulated errors
  1455.                                 ThrowIfParseErrors(xmlUtil.SchemaErrors);
  1456.                             }
  1457.                         }
  1458.                     }
  1459.                 }
  1460.             }
  1461.             // Don't allow frames up the stack to run exception filters while impersonated.
  1462.             catch {
  1463.                 throw;
  1464.             }
  1465.            
  1466.            
  1467.             return section;
  1468.         }
  1469.        
  1470.         private ConfigXmlReader FindSectionRecursive(string[] keys, int iKey, XmlUtil xmlUtil, ref int lineNumber)
  1471.         {
  1472.             string name = keys[iKey];
  1473.             ConfigXmlReader section = null;
  1474.            
  1475.             int depth = xmlUtil.Reader.Depth;
  1476.             xmlUtil.ReadToNextElement();
  1477.            
  1478.             while (xmlUtil.Reader.Depth > depth) {
  1479.                 if (xmlUtil.Reader.Name == name) {
  1480.                     if (iKey < keys.Length - 1) {
  1481.                         //
  1482.                         // We haven't reached the section yet, so keep evaluating
  1483.                         //
  1484.                         section = FindSectionRecursive(keys, iKey + 1, xmlUtil, ref lineNumber);
  1485.                         if (section != null) {
  1486.                             break;
  1487.                         }
  1488.                        
  1489.                         continue;
  1490.                         // don't call "Skip" -- FindSectionRecursive forwards the reader
  1491.                     }
  1492.                     else {
  1493.                         //
  1494.                         // We've reached the section. Load the section into a string.
  1495.                         //
  1496.                         string filename = ((IConfigErrorInfo)xmlUtil).Filename;
  1497.                         int lineOffset = xmlUtil.Reader.LineNumber;
  1498.                         string rawXml = xmlUtil.CopySection();
  1499.                         section = new ConfigXmlReader(rawXml, filename, lineOffset);
  1500.                         break;
  1501.                     }
  1502.                 }
  1503.                 else if (iKey == 0 && xmlUtil.Reader.Name == KEYWORD_LOCATION) {
  1504.                     string locationSubPath = xmlUtil.Reader.GetAttribute(KEYWORD_LOCATION_PATH);
  1505.                     bool isValid = false;
  1506.                     try {
  1507.                         locationSubPath = NormalizeLocationSubPath(locationSubPath, xmlUtil);
  1508.                         isValid = true;
  1509.                     }
  1510.                     catch (ConfigurationException ce) {
  1511.                         xmlUtil.SchemaErrors.AddError(ce, ExceptionAction.NonSpecific);
  1512.                     }
  1513.                    
  1514.                     if (isValid && locationSubPath == null) {
  1515.                         //
  1516.                         // Location sections that don't have a subpath are treated
  1517.                         // as ordinary sections.
  1518.                         //
  1519.                         section = FindSectionRecursive(keys, iKey, xmlUtil, ref lineNumber);
  1520.                         if (section != null) {
  1521.                             break;
  1522.                         }
  1523.                        
  1524.                         continue;
  1525.                         // don't call "Skip" -- FindSectionRecursive forwards the reader
  1526.                     }
  1527.                 }
  1528.                
  1529.                 xmlUtil.SkipToNextElement();
  1530.             }
  1531.            
  1532.             return section;
  1533.         }
  1534.        
  1535.         private ConfigXmlReader LoadConfigSource(string name, SectionXmlInfo sectionXmlInfo)
  1536.         {
  1537.             string configSourceStreamName = sectionXmlInfo.ConfigSourceStreamName;
  1538.            
  1539.             try {
  1540.                 using (Impersonate()) {
  1541.                     using (Stream stream = Host.OpenStreamForRead(configSourceStreamName)) {
  1542.                         if (stream == null) {
  1543.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_cannot_open_config_source, sectionXmlInfo.ConfigSource), sectionXmlInfo);
  1544.                         }
  1545.                        
  1546.                         using (XmlUtil xmlUtil = new XmlUtil(stream, configSourceStreamName, true)) {
  1547.                             if (xmlUtil.Reader.Name != name) {
  1548.                                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_source_file_format), xmlUtil);
  1549.                             }
  1550.                            
  1551.                             // Check for protectionProvider
  1552.                             string protectionProviderAttribute = xmlUtil.Reader.GetAttribute(KEYWORD_PROTECTION_PROVIDER);
  1553.                             if (protectionProviderAttribute != null) {
  1554.                                 if (xmlUtil.Reader.AttributeCount != 1) {
  1555.                                     // Error: elements with protectionProvider should not have other attributes
  1556.                                     throw new ConfigurationErrorsException(SR.GetString(SR.Protection_provider_syntax_error), xmlUtil);
  1557.                                 }
  1558.                                
  1559.                                 sectionXmlInfo.ProtectionProviderName = ValidateProtectionProviderAttribute(protectionProviderAttribute, xmlUtil);
  1560.                             }
  1561.                            
  1562.                             int lineOffset = xmlUtil.Reader.LineNumber;
  1563.                             string rawXml = xmlUtil.CopySection();
  1564.                            
  1565.                             // Detect if there is any XML left over after the section
  1566.                             while (!xmlUtil.Reader.EOF) {
  1567.                                 XmlNodeType t = xmlUtil.Reader.NodeType;
  1568.                                 if (t != XmlNodeType.Comment) {
  1569.                                     throw new ConfigurationErrorsException(SR.GetString(SR.Config_source_file_format), xmlUtil);
  1570.                                 }
  1571.                                
  1572.                                 xmlUtil.Reader.Read();
  1573.                             }
  1574.                            
  1575.                             ConfigXmlReader section = new ConfigXmlReader(rawXml, configSourceStreamName, lineOffset);
  1576.                             return section;
  1577.                         }
  1578.                     }
  1579.                 }
  1580.             }
  1581.             catch {
  1582.                 // Don't allow frames up the stack to run exception filters while impersonated.
  1583.                 throw;
  1584.             }
  1585.         }
  1586.        
  1587.         protected ConfigXmlReader GetSectionXmlReader(string[] keys, SectionInput input)
  1588.         {
  1589.             ConfigXmlReader reader = null;
  1590.             string filename = input.SectionXmlInfo.Filename;
  1591.             int lineNumber = input.SectionXmlInfo.LineNumber;
  1592.            
  1593.             try {
  1594.                 string name = keys[keys.Length - 1];
  1595.                 string rawXml = input.SectionXmlInfo.RawXml;
  1596.                 if (rawXml != null) {
  1597.                     // Use the stored raw xml to provide the content of the section.
  1598.                     reader = new ConfigXmlReader(rawXml, input.SectionXmlInfo.Filename, input.SectionXmlInfo.LineNumber);
  1599.                 }
  1600.                 else if (!String.IsNullOrEmpty(input.SectionXmlInfo.ConfigSource)) {
  1601.                     // Load the config source to provide the content of the section.
  1602.                     filename = input.SectionXmlInfo.ConfigSourceStreamName;
  1603.                     lineNumber = 0;
  1604.                     reader = LoadConfigSource(name, input.SectionXmlInfo);
  1605.                 }
  1606.                 else {
  1607.                     // Find the content of the section in the config file.
  1608.                     lineNumber = 0;
  1609.                     reader = FindSection(keys, input.SectionXmlInfo, out lineNumber);
  1610.                 }
  1611.                
  1612.                 if (reader != null) {
  1613.                     if (!input.IsProtectionProviderDetermined) {
  1614.                         input.ProtectionProvider = GetProtectionProviderFromName(input.SectionXmlInfo.ProtectionProviderName, false);
  1615.                     }
  1616.                    
  1617.                     if (input.ProtectionProvider != null) {
  1618.                         reader = DecryptConfigSection(reader, input.ProtectionProvider);
  1619.                     }
  1620.                 }
  1621.             }
  1622.            
  1623.             //
  1624.             // Guarantee that exceptions contain the name of the stream and an approximate line number.
  1625.             //
  1626.             catch (Exception e) {
  1627.                 throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_error_loading_XML_file), e, filename, lineNumber);
  1628.             }
  1629.             catch {
  1630.                 throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_error_loading_XML_file), null, filename, lineNumber);
  1631.             }
  1632.            
  1633.             return reader;
  1634.         }
  1635.        
  1636.         internal string DefaultProviderName {
  1637.             get { return ProtectedConfig.DefaultProvider; }
  1638.         }
  1639.        
  1640.         internal ProtectedConfigurationProvider GetProtectionProviderFromName(string providerName, bool throwIfNotFound)
  1641.         {
  1642.             ProtectedConfigurationProvider provider = null;
  1643.            
  1644.             if (String.IsNullOrEmpty(providerName)) {
  1645.                 if (throwIfNotFound) {
  1646.                     throw new ConfigurationErrorsException(SR.GetString(SR.ProtectedConfigurationProvider_not_found, providerName));
  1647.                 }
  1648.                 else {
  1649.                     return null;
  1650.                 }
  1651.             }
  1652.            
  1653.             provider = ProtectedConfig.GetProviderFromName(providerName);
  1654.            
  1655.             return provider;
  1656.         }
  1657.        
  1658.         private ProtectedConfigurationSection ProtectedConfig {
  1659.             get {
  1660.                 if (!_flags[ProtectedDataInitialized]) {
  1661.                     InitProtectedConfigurationSection();
  1662.                 }
  1663.                
  1664.                 return _protectedConfig;
  1665.             }
  1666.         }
  1667.        
  1668.         internal void InitProtectedConfigurationSection()
  1669.         {
  1670.             if (!_flags[ProtectedDataInitialized]) {
  1671.                 _protectedConfig = GetSection(BaseConfigurationRecord.RESERVED_SECTION_PROTECTED_CONFIGURATION, false, false) as ProtectedConfigurationSection;
  1672.                
  1673.                 Debug.Assert(_protectedConfig != null, "<configProtectedData> section should always be available because it's a built-in section");
  1674.                
  1675.                 _flags[ProtectedDataInitialized] = true;
  1676.             }
  1677.         }
  1678.        
  1679.         protected object CallCreateSection(bool inputIsTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, object parentConfig, ConfigXmlReader reader, string filename, int line)
  1680.         {
  1681.             object config;
  1682.            
  1683.             // Call into config section while impersonating process or UNC identity
  1684.             // so that the section could read files from disk if needed
  1685.             try {
  1686.                 using (Impersonate()) {
  1687.                     config = CreateSection(inputIsTrusted, factoryRecord, sectionRecord, parentConfig, reader);
  1688.                     if (config == null && parentConfig != null) {
  1689.                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_object_is_null), filename, line);
  1690.                     }
  1691.                 }
  1692.             }
  1693.             catch (Exception e) {
  1694.                 throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_exception_creating_section_handler, factoryRecord.ConfigKey), e, filename, line);
  1695.             }
  1696.             catch {
  1697.                 throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_exception_creating_section_handler, factoryRecord.ConfigKey), null, filename, line);
  1698.             }
  1699.            
  1700.             return config;
  1701.         }
  1702.        
  1703.         //
  1704.         //
  1705.         //
  1706.         internal bool IsRootDeclaration(string configKey, bool implicitIsRooted)
  1707.         {
  1708.             if (!implicitIsRooted && IsImplicitSection(configKey)) {
  1709.                 return false;
  1710.             }
  1711.            
  1712.             return (_parent.IsRootConfig || _parent.FindFactoryRecord(configKey, true) == null);
  1713.         }
  1714.        
  1715.         // Search the config hierarchy for a FactoryRecord.
  1716.         // Note that callers should check whether the returned factory has errors.
  1717.         internal FactoryRecord FindFactoryRecord(string configKey, bool permitErrors, out BaseConfigurationRecord configRecord)
  1718.         {
  1719.             configRecord = null;
  1720.             BaseConfigurationRecord tConfigRecord = this;
  1721.            
  1722.             while (!tConfigRecord.IsRootConfig) {
  1723.                 FactoryRecord factoryRecord = tConfigRecord.GetFactoryRecord(configKey, permitErrors);
  1724.                 if (factoryRecord != null) {
  1725.                     #if DBG
  1726.                     if (IsImplicitSection(configKey) && !factoryRecord.HasErrors) {
  1727.                         Debug.Assert(tConfigRecord._parent.IsRootConfig, "Implicit section should be found only at the record beneath the root (e.g. machine.config)");
  1728.                     }
  1729.                     #endif
  1730.                    
  1731.                     configRecord = tConfigRecord;
  1732.                     return factoryRecord;
  1733.                 }
  1734.                
  1735.                 tConfigRecord = tConfigRecord._parent;
  1736.             }
  1737.            
  1738.             return null;
  1739.         }
  1740.        
  1741.        
  1742.         internal FactoryRecord FindFactoryRecord(string configKey, bool permitErrors)
  1743.         {
  1744.             BaseConfigurationRecord dummy;
  1745.             return FindFactoryRecord(configKey, permitErrors, out dummy);
  1746.         }
  1747.        
  1748.         //
  1749.         // FindAndEnsureFactoryRecord:
  1750.         //
  1751.         // - Find the nearest factory record
  1752.         // - Determine if it is the root
  1753.         // - Create the factory in the root if it doesn't exist.
  1754.         // - Determine if the factory type is from a global assembly without APTCA
  1755.         // - Copy the factory and IsFactoryTrustedWithoutAptca bit into the child record
  1756.         //
  1757.         private FactoryRecord FindAndEnsureFactoryRecord(string configKey, out bool isRootDeclaredHere)
  1758.         {
  1759.             isRootDeclaredHere = false;
  1760.            
  1761.             BaseConfigurationRecord configRecord;
  1762.             FactoryRecord factoryRecord = FindFactoryRecord(configKey, false, out configRecord);
  1763.             if (factoryRecord != null && !factoryRecord.IsGroup) {
  1764.                 //
  1765.                 // Find the root declaration
  1766.                 //
  1767.                 FactoryRecord rootFactoryRecord = factoryRecord;
  1768.                 BaseConfigurationRecord rootConfigRecord = configRecord;
  1769.                
  1770.                 BaseConfigurationRecord currentConfigRecord = configRecord._parent;
  1771.                 while (!currentConfigRecord.IsRootConfig) {
  1772.                     BaseConfigurationRecord tempConfigRecord;
  1773.                     FactoryRecord tempFactoryRecord = currentConfigRecord.FindFactoryRecord(configKey, false, out tempConfigRecord);
  1774.                     if (tempFactoryRecord == null)
  1775.                         break;
  1776.                    
  1777.                     rootFactoryRecord = tempFactoryRecord;
  1778.                     rootConfigRecord = tempConfigRecord;
  1779.                    
  1780.                     // continue the search from the parent of the configRecord we found
  1781.                     currentConfigRecord = tempConfigRecord.Parent;
  1782.                 }
  1783.                
  1784.                 //
  1785.                 // A child factory record must be equivalent to its parent,
  1786.                 // so if the child has no errors, the parent must also have no errors.
  1787.                 //
  1788.                 Debug.Assert(!rootFactoryRecord.HasErrors, "!rootFactoryRecord.HasErrors");
  1789.                 if (rootFactoryRecord.Factory == null) {
  1790.                     try {
  1791.                         //
  1792.                         // Create the factory from the type string, and cache it
  1793.                         //
  1794.                         object factory = rootConfigRecord.CreateSectionFactory(rootFactoryRecord);
  1795.                         bool isFactoryTrustedWithoutAptca = TypeUtil.IsTypeFromTrustedAssemblyWithoutAptca(factory.GetType());
  1796.                         rootFactoryRecord.Factory = factory;
  1797.                         rootFactoryRecord.IsFactoryTrustedWithoutAptca = isFactoryTrustedWithoutAptca;
  1798.                     }
  1799.                     catch (Exception e) {
  1800.                         throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_exception_creating_section_handler, factoryRecord.ConfigKey), e, factoryRecord);
  1801.                     }
  1802.                     catch {
  1803.                         throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_exception_creating_section_handler, factoryRecord.ConfigKey), null, factoryRecord);
  1804.                     }
  1805.                 }
  1806.                
  1807.                 if (factoryRecord.Factory == null) {
  1808.                     factoryRecord.Factory = rootFactoryRecord.Factory;
  1809.                     factoryRecord.IsFactoryTrustedWithoutAptca = rootFactoryRecord.IsFactoryTrustedWithoutAptca;
  1810.                 }
  1811.                
  1812.                 isRootDeclaredHere = Object.ReferenceEquals(this, rootConfigRecord);
  1813.             }
  1814.            
  1815.             return factoryRecord;
  1816.         }
  1817.        
  1818.         private Hashtable ScanFactories(XmlUtil xmlUtil)
  1819.         {
  1820.             Hashtable factoryList;
  1821.            
  1822.             factoryList = new Hashtable();
  1823.            
  1824.             if (xmlUtil.Reader.NodeType != XmlNodeType.Element || xmlUtil.Reader.Name != KEYWORD_CONFIGURATION) {
  1825.                 string safeFilename = ConfigurationErrorsException.AlwaysSafeFilename(((IConfigErrorInfo)xmlUtil).Filename);
  1826.                
  1827.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_file_doesnt_have_root_configuration, safeFilename), xmlUtil);
  1828.             }
  1829.            
  1830.             // Ignore xmlns attribute
  1831.             while (xmlUtil.Reader.MoveToNextAttribute()) {
  1832.                 switch (xmlUtil.Reader.Name) {
  1833.                     case KEYWORD_XMLNS:
  1834.                         if (xmlUtil.Reader.Value == KEYWORD_CONFIGURATION_NAMESPACE) {
  1835.                             _flags[NamespacePresentInFile] = true;
  1836.                             _flags[NamespacePresentCurrent] = true;
  1837.                         }
  1838.                         else {
  1839.                             ConfigurationErrorsException ce;
  1840.                            
  1841.                             ce = new ConfigurationErrorsException(SR.GetString(SR.Config_namespace_invalid, xmlUtil.Reader.Value, KEYWORD_CONFIGURATION_NAMESPACE), xmlUtil);
  1842.                            
  1843.                             xmlUtil.SchemaErrors.AddError(ce, ExceptionAction.Global);
  1844.                         }
  1845.                        
  1846.                         break;
  1847.                     default:
  1848.                        
  1849.                         xmlUtil.AddErrorUnrecognizedAttribute(ExceptionAction.NonSpecific);
  1850.                         break;
  1851.                 }
  1852.             }
  1853.            
  1854.             // move to first child of <configuration>
  1855.             xmlUtil.StrictReadToNextElement(ExceptionAction.NonSpecific);
  1856.             if (xmlUtil.Reader.Depth == 1 && xmlUtil.Reader.Name == KEYWORD_CONFIGSECTIONS) {
  1857.                 xmlUtil.VerifyNoUnrecognizedAttributes(ExceptionAction.NonSpecific);
  1858.                 ScanFactoriesRecursive(xmlUtil, string.Empty, factoryList);
  1859.             }
  1860.            
  1861.             return factoryList;
  1862.         }
  1863.        
  1864.        
  1865.         // Scans the <configSections> section of a configuration file. The function is recursive
  1866.         // to traverse arbitrarily nested config groups.
  1867.         //
  1868.         // <sectionGroup name="foo">
  1869.         // <sectionGroup name="bar">
  1870.         // <section name="fooBarSection" type="..." />
  1871.         // ...
  1872.         //
  1873.         // Note: This function valiates that the factory record has not been
  1874.         // declared before in a parent record. (it does not check
  1875.         // current record, which allows you to update list)
  1876.         //
  1877.         private void ScanFactoriesRecursive(XmlUtil xmlUtil, string parentConfigKey, Hashtable factoryList)
  1878.         {
  1879.            
  1880.             // discard any accumulated local errors
  1881.             xmlUtil.SchemaErrors.ResetLocalErrors();
  1882.            
  1883.             int depth = xmlUtil.Reader.Depth;
  1884.             xmlUtil.StrictReadToNextElement(ExceptionAction.NonSpecific);
  1885.            
  1886.             while (xmlUtil.Reader.Depth == depth + 1) {
  1887.                 bool positionedAtNextElement = false;
  1888.                
  1889.                 switch (xmlUtil.Reader.Name) {
  1890.                     case KEYWORD_SECTIONGROUP:
  1891.                         //
  1892.                         // Handle <sectionGroup name="groupName" [type="typename"] />
  1893.                         //
  1894.                        
  1895.                         {
  1896.                             string tagName = null;
  1897.                             string typeName = null;
  1898.                            
  1899.                             int lineNumber = xmlUtil.Reader.LineNumber;
  1900.                             while (xmlUtil.Reader.MoveToNextAttribute()) {
  1901.                                 switch (xmlUtil.Reader.Name) {
  1902.                                     case KEYWORD_SECTIONGROUP_NAME:
  1903.                                         tagName = xmlUtil.Reader.Value;
  1904.                                         VerifySectionName(tagName, xmlUtil, ExceptionAction.Local, false);
  1905.                                         break;
  1906.                                     case KEYWORD_SECTIONGROUP_TYPE:
  1907.                                        
  1908.                                         xmlUtil.VerifyAndGetNonEmptyStringAttribute(ExceptionAction.Local, out typeName);
  1909.                                         break;
  1910.                                     default:
  1911.                                        
  1912.                                         xmlUtil.AddErrorUnrecognizedAttribute(ExceptionAction.Local);
  1913.                                         break;
  1914.                                 }
  1915.                             }
  1916.                             xmlUtil.Reader.MoveToElement();
  1917.                             // if on an attribute move back to the element
  1918.                             if (!xmlUtil.VerifyRequiredAttribute(tagName, KEYWORD_SECTIONGROUP_NAME, ExceptionAction.NonSpecific)) {
  1919.                                
  1920.                                 //
  1921.                                 // Without a name, we cannot continue parsing the sections and groups within.
  1922.                                 // Skip the entire section.
  1923.                                 //
  1924.                                 xmlUtil.SchemaErrors.RetrieveAndResetLocalErrors(true);
  1925.                                 xmlUtil.StrictSkipToNextElement(ExceptionAction.NonSpecific);
  1926.                             }
  1927.                             else {
  1928.                                 string configKey = CombineConfigKey(parentConfigKey, tagName);
  1929.                                
  1930.                                 FactoryRecord factoryRecord = (FactoryRecord)factoryList[configKey];
  1931.                                 if (factoryRecord != null) {
  1932.                                     // Error: duplicate sectionGroup declaration
  1933.                                     xmlUtil.SchemaErrors.AddError(new ConfigurationErrorsException(SR.GetString(SR.Config_tag_name_already_defined_at_this_level, tagName), xmlUtil), ExceptionAction.Local);
  1934.                                    
  1935.                                 }
  1936.                                 else {
  1937.                                     FactoryRecord parentFactoryRecord = _parent.FindFactoryRecord(configKey, true);
  1938.                                     if (parentFactoryRecord != null) {
  1939.                                         configKey = parentFactoryRecord.ConfigKey;
  1940.                                        
  1941.                                        
  1942.                                         // make sure that an ancestor has not defined a section with the same name as the group
  1943.                                         if (!parentFactoryRecord.IsGroup || !parentFactoryRecord.IsEquivalentSectionGroupFactory(Host, typeName)) {
  1944.                                            
  1945.                                             xmlUtil.SchemaErrors.AddError(new ConfigurationErrorsException(SR.GetString(SR.Config_tag_name_already_defined, tagName), xmlUtil), ExceptionAction.Local);
  1946.                                            
  1947.                                             parentFactoryRecord = null;
  1948.                                         }
  1949.                                     }
  1950.                                    
  1951.                                     if (parentFactoryRecord != null) {
  1952.                                         factoryRecord = parentFactoryRecord.CloneSectionGroup(typeName, xmlUtil.Filename, lineNumber);
  1953.                                     }
  1954.                                     else {
  1955.                                         factoryRecord = new FactoryRecord(configKey, parentConfigKey, tagName, typeName, xmlUtil.Filename, lineNumber);
  1956.                                     }
  1957.                                    
  1958.                                     factoryList[configKey] = factoryRecord;
  1959.                                 }
  1960.                                
  1961.                                 // Add any errors we may have encountered
  1962.                                 factoryRecord.AddErrors(xmlUtil.SchemaErrors.RetrieveAndResetLocalErrors(true));
  1963.                                
  1964.                                 // continue recursive scan
  1965.                                 ScanFactoriesRecursive(xmlUtil, configKey, factoryList);
  1966.                             }
  1967.                            
  1968.                             continue;
  1969.                         }
  1970.                         break;
  1971.                     case KEYWORD_SECTION:
  1972.                        
  1973.                        
  1974.                         {
  1975.                             string tagName = null;
  1976.                             string typeName = null;
  1977.                             ConfigurationAllowDefinition allowDefinition = ConfigurationAllowDefinition.Everywhere;
  1978.                             ConfigurationAllowExeDefinition allowExeDefinition = ConfigurationAllowExeDefinition.MachineToApplication;
  1979.                             bool allowLocation = true;
  1980.                             bool restartOnExternalChanges = true;
  1981.                             bool requirePermission = true;
  1982.                             bool gotType = false;
  1983.                            
  1984.                             // parse section attributes
  1985.                             int lineNumber = xmlUtil.Reader.LineNumber;
  1986.                             while (xmlUtil.Reader.MoveToNextAttribute()) {
  1987.                                 switch (xmlUtil.Reader.Name) {
  1988.                                     case KEYWORD_SECTION_NAME:
  1989.                                         tagName = xmlUtil.Reader.Value;
  1990.                                         VerifySectionName(tagName, xmlUtil, ExceptionAction.Local, false);
  1991.                                         break;
  1992.                                     case KEYWORD_SECTION_TYPE:
  1993.                                        
  1994.                                         xmlUtil.VerifyAndGetNonEmptyStringAttribute(ExceptionAction.Local, out typeName);
  1995.                                         gotType = true;
  1996.                                         break;
  1997.                                     case KEYWORD_SECTION_ALLOWLOCATION:
  1998.                                        
  1999.                                         xmlUtil.VerifyAndGetBooleanAttribute(ExceptionAction.Local, true, out allowLocation);
  2000.                                         break;
  2001.                                     case KEYWORD_SECTION_ALLOWEXEDEFINITION:
  2002.                                        
  2003.                                         try {
  2004.                                             allowExeDefinition = AllowExeDefinitionToEnum(xmlUtil.Reader.Value, xmlUtil);
  2005.                                         }
  2006.                                         catch (ConfigurationException ce) {
  2007.                                             xmlUtil.SchemaErrors.AddError(ce, ExceptionAction.Local);
  2008.                                         }
  2009.                                        
  2010.                                         break;
  2011.                                     case KEYWORD_SECTION_ALLOWDEFINITION:
  2012.                                        
  2013.                                         try {
  2014.                                             allowDefinition = AllowDefinitionToEnum(xmlUtil.Reader.Value, xmlUtil);
  2015.                                         }
  2016.                                         catch (ConfigurationException ce) {
  2017.                                             xmlUtil.SchemaErrors.AddError(ce, ExceptionAction.Local);
  2018.                                         }
  2019.                                        
  2020.                                         break;
  2021.                                     case KEYWORD_SECTION_RESTARTONEXTERNALCHANGES:
  2022.                                        
  2023.                                         xmlUtil.VerifyAndGetBooleanAttribute(ExceptionAction.Local, true, out restartOnExternalChanges);
  2024.                                        
  2025.                                         break;
  2026.                                     case KEYWORD_SECTION_REQUIREPERMISSION:
  2027.                                        
  2028.                                         xmlUtil.VerifyAndGetBooleanAttribute(ExceptionAction.Local, true, out requirePermission);
  2029.                                        
  2030.                                         break;
  2031.                                     default:
  2032.                                        
  2033.                                         xmlUtil.AddErrorUnrecognizedAttribute(ExceptionAction.Local);
  2034.                                         break;
  2035.                                 }
  2036.                             }
  2037.                            
  2038.                             xmlUtil.Reader.MoveToElement();
  2039.                             // if on an attribute move back to the element
  2040.                             if (!xmlUtil.VerifyRequiredAttribute(tagName, KEYWORD_SECTION_NAME, ExceptionAction.NonSpecific)) {
  2041.                                
  2042.                                 //
  2043.                                 // Without a name, we cannot continue to create a factoryRecord.
  2044.                                 //
  2045.                                 xmlUtil.SchemaErrors.RetrieveAndResetLocalErrors(true);
  2046.                             }
  2047.                             else {
  2048.                                 // Verify that the Type attribute was present.
  2049.                                 // Note that 'typeName' will be null if the attribute was present
  2050.                                 // but specified as an empty string.
  2051.                                 if (!gotType) {
  2052.                                     xmlUtil.AddErrorRequiredAttribute(KEYWORD_SECTION_TYPE, ExceptionAction.Local);
  2053.                                 }
  2054.                                
  2055.                                 string configKey = CombineConfigKey(parentConfigKey, tagName);
  2056.                                
  2057.                                 FactoryRecord factoryRecord = (FactoryRecord)factoryList[configKey];
  2058.                                 if (factoryRecord != null) {
  2059.                                     // Error: duplicate section declaration
  2060.                                     xmlUtil.SchemaErrors.AddError(new ConfigurationErrorsException(SR.GetString(SR.Config_tag_name_already_defined_at_this_level, tagName), xmlUtil), ExceptionAction.Local);
  2061.                                 }
  2062.                                 else {
  2063.                                     FactoryRecord parentFactoryRecord = _parent.FindFactoryRecord(configKey, true);
  2064.                                     if (parentFactoryRecord != null) {
  2065.                                         configKey = parentFactoryRecord.ConfigKey;
  2066.                                        
  2067.                                         // make sure that an ancestor has not defined a section with the same name as the group
  2068.                                         if (parentFactoryRecord.IsGroup) {
  2069.                                             xmlUtil.SchemaErrors.AddError(new ConfigurationErrorsException(SR.GetString(SR.Config_tag_name_already_defined, tagName), xmlUtil), ExceptionAction.Local);
  2070.                                            
  2071.                                             parentFactoryRecord = null;
  2072.                                         }
  2073.                                         else if (!parentFactoryRecord.IsEquivalentSectionFactory(Host, typeName, allowLocation, allowDefinition, allowExeDefinition, restartOnExternalChanges, requirePermission)) {
  2074.                                             xmlUtil.SchemaErrors.AddError(new ConfigurationErrorsException(SR.GetString(SR.Config_tag_name_already_defined, tagName), xmlUtil), ExceptionAction.Local);
  2075.                                            
  2076.                                             parentFactoryRecord = null;
  2077.                                         }
  2078.                                     }
  2079.                                    
  2080.                                     if (parentFactoryRecord != null) {
  2081.                                         // Note - Clone will propagate the IsFromTrustedConfigRecord bit,
  2082.                                         // which is what we want - if this record is a duplicate of an ancestor,
  2083.                                         // the ancestor may be from a trusted config record.
  2084.                                         factoryRecord = parentFactoryRecord.CloneSection(xmlUtil.Filename, lineNumber);
  2085.                                     }
  2086.                                     else {
  2087.                                         factoryRecord = new FactoryRecord(configKey, parentConfigKey, tagName, typeName, allowLocation, allowDefinition, allowExeDefinition, restartOnExternalChanges, requirePermission, _flags[IsTrusted],
  2088.                                             // isUndeclared
  2089.                                         false, xmlUtil.Filename, lineNumber);
  2090.                                     }
  2091.                                    
  2092.                                     factoryList[configKey] = factoryRecord;
  2093.                                 }
  2094.                                
  2095.                                 // Add any errors we may have encountered
  2096.                                 factoryRecord.AddErrors(xmlUtil.SchemaErrors.RetrieveAndResetLocalErrors(true));
  2097.                             }
  2098.                         }
  2099.                         break;
  2100.                     case KEYWORD_REMOVE:
  2101.                        
  2102.                        
  2103.                         {
  2104.                             string name = null;
  2105.                             int lineNumber = -1;
  2106.                            
  2107.                             // parse attributes
  2108.                             while (xmlUtil.Reader.MoveToNextAttribute()) {
  2109.                                 if (xmlUtil.Reader.Name != KEYWORD_SECTION_NAME) {
  2110.                                     xmlUtil.AddErrorUnrecognizedAttribute(ExceptionAction.NonSpecific);
  2111.                                 }
  2112.                                
  2113.                                 name = xmlUtil.Reader.Value;
  2114.                                 lineNumber = xmlUtil.Reader.LineNumber;
  2115.                             }
  2116.                             xmlUtil.Reader.MoveToElement();
  2117.                            
  2118.                             if (xmlUtil.VerifyRequiredAttribute(name, KEYWORD_SECTION_NAME, ExceptionAction.NonSpecific)) {
  2119.                                
  2120.                                 VerifySectionName(name, xmlUtil, ExceptionAction.NonSpecific, false);
  2121.                             }
  2122.                         }
  2123.                         break;
  2124.                     case KEYWORD_CLEAR:
  2125.                        
  2126.                        
  2127.                         {
  2128.                             xmlUtil.VerifyNoUnrecognizedAttributes(ExceptionAction.NonSpecific);
  2129.                         }
  2130.                         break;
  2131.                     default:
  2132.                        
  2133.                         xmlUtil.AddErrorUnrecognizedElement(ExceptionAction.NonSpecific);
  2134.                         xmlUtil.StrictSkipToNextElement(ExceptionAction.NonSpecific);
  2135.                         positionedAtNextElement = true;
  2136.                         break;
  2137.                 }
  2138.                
  2139.                 if (!positionedAtNextElement) {
  2140.                     // Need to read to next element, and check if an unrecognized child
  2141.                     // element is found.
  2142.                     xmlUtil.StrictReadToNextElement(ExceptionAction.NonSpecific);
  2143.                    
  2144.                     // unrecognized children are not allowed in <configSections>
  2145.                     if (xmlUtil.Reader.Depth > depth + 1) {
  2146.                         xmlUtil.AddErrorUnrecognizedElement(ExceptionAction.NonSpecific);
  2147.                        
  2148.                         // Lets try to backup to where we are suppose to be
  2149.                         while (xmlUtil.Reader.Depth > (depth + 1)) {
  2150.                             xmlUtil.ReadToNextElement();
  2151.                         }
  2152.                     }
  2153.                 }
  2154.             }
  2155.         }
  2156.        
  2157.         // ExeDefinitionToEnum
  2158.         //
  2159.         // Translate an ExeDefinition string from the Declaration in a file
  2160.         // to the appropriate enumeration
  2161.         //
  2162.         // Parameters:
  2163.         // allowExeDefinition - string representation of value
  2164.         // xmlUtil [optional] - can provide better error
  2165.         //
  2166.         static internal ConfigurationAllowExeDefinition AllowExeDefinitionToEnum(string allowExeDefinition, XmlUtil xmlUtil)
  2167.         {
  2168.             switch (allowExeDefinition) {
  2169.                 case KEYWORD_SECTION_ALLOWDEFINITION_MACHINEONLY:
  2170.                     return ConfigurationAllowExeDefinition.MachineOnly;
  2171.                 case KEYWORD_SECTION_ALLOWDEFINITION_MACHINETOAPPLICATION:
  2172.                    
  2173.                     return ConfigurationAllowExeDefinition.MachineToApplication;
  2174.                 case KEYWORD_SECTION_ALLOWEXEDEFINITION_MACHTOROAMING:
  2175.                    
  2176.                     return ConfigurationAllowExeDefinition.MachineToRoamingUser;
  2177.                 case KEYWORD_SECTION_ALLOWEXEDEFINITION_MACHTOLOCAL:
  2178.                    
  2179.                     return ConfigurationAllowExeDefinition.MachineToLocalUser;
  2180.                 default:
  2181.                    
  2182.                     throw new ConfigurationErrorsException(SR.GetString(SR.Config_section_allow_exe_definition_attribute_invalid), xmlUtil);
  2183.                     break;
  2184.             }
  2185.         }
  2186.        
  2187.         static internal ConfigurationAllowDefinition AllowDefinitionToEnum(string allowDefinition, XmlUtil xmlUtil)
  2188.         {
  2189.             switch (xmlUtil.Reader.Value) {
  2190.                 case KEYWORD_SECTION_ALLOWDEFINITION_EVERYWHERE:
  2191.                     return ConfigurationAllowDefinition.Everywhere;
  2192.                 case KEYWORD_SECTION_ALLOWDEFINITION_MACHINEONLY:
  2193.                    
  2194.                     return ConfigurationAllowDefinition.MachineOnly;
  2195.                 case KEYWORD_SECTION_ALLOWDEFINITION_MACHINETOAPPLICATION:
  2196.                    
  2197.                     return ConfigurationAllowDefinition.MachineToApplication;
  2198.                 case KEYWORD_SECTION_ALLOWDEFINITION_MACHINETOWEBROOT:
  2199.                    
  2200.                     return ConfigurationAllowDefinition.MachineToWebRoot;
  2201.                 default:
  2202.                    
  2203.                     throw new ConfigurationErrorsException(SR.GetString(SR.Config_section_allow_definition_attribute_invalid), xmlUtil);
  2204.                     break;
  2205.             }
  2206.         }
  2207.        
  2208.         static internal string CombineConfigKey(string parentConfigKey, string tagName)
  2209.         {
  2210.             if (String.IsNullOrEmpty(parentConfigKey)) {
  2211.                 return tagName;
  2212.             }
  2213.            
  2214.             if (String.IsNullOrEmpty(tagName)) {
  2215.                 return parentConfigKey;
  2216.             }
  2217.            
  2218.             return parentConfigKey + "/" + tagName;
  2219.         }
  2220.        
  2221.         static internal void SplitConfigKey(string configKey, out string group, out string name)
  2222.         {
  2223.             int lastSlash = configKey.LastIndexOf('/');
  2224.             if (lastSlash == -1) {
  2225.                 group = string.Empty;
  2226.                 name = configKey;
  2227.             }
  2228.             else {
  2229.                 group = configKey.Substring(0, lastSlash);
  2230.                 name = configKey.Substring(lastSlash + 1);
  2231.             }
  2232.         }
  2233.        
  2234.         // Return true if a parent is locked or locks its children.
  2235.         private bool IsParentCausingLock(string configKey)
  2236.         {
  2237.             BaseConfigurationRecord parent = _parent;
  2238.             while (!parent.IsRootConfig) {
  2239.                 SectionRecord sectionRecord = parent.GetSectionRecord(configKey, true);
  2240.                 if (sectionRecord != null && (sectionRecord.LockChildren || sectionRecord.Locked)) {
  2241.                    
  2242.                     return true;
  2243.                 }
  2244.                
  2245.                 parent = parent._parent;
  2246.             }
  2247.            
  2248.             return false;
  2249.         }
  2250.        
  2251.         // Return true if a section is locked.
  2252.         protected bool IsSectionLocked(string configKey)
  2253.         {
  2254.             SectionRecord sectionRecord = GetSectionRecord(configKey, true);
  2255.            
  2256.             // If the section record exists, the locked bit will be set if it is locked.
  2257.             if (sectionRecord != null) {
  2258.                 if (sectionRecord.Locked) {
  2259.                     return true;
  2260.                 }
  2261.                
  2262.                 // Because we are so close to RTM, we cannot change the code to avoid
  2263.                 // the call below to IsParentCausingLock(). However, we can still verify
  2264.                 // that the parent isn't causing a lock.
  2265.                 Debug.Assert(!IsParentCausingLock(configKey), "!IsParentCausingLock(configKey)");
  2266.             }
  2267.            
  2268.             // Check if parent causes a lock.
  2269.             return IsParentCausingLock(configKey);
  2270.         }
  2271.        
  2272.         // VerifySectionUnlocked
  2273.         //
  2274.         // Verify the section we have defined is unlocked
  2275.         //
  2276.         protected void VerifySectionUnlocked(string configKey, IConfigErrorInfo configErrorInfo)
  2277.         {
  2278.             if (IsSectionLocked(configKey)) {
  2279.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_section_locked), configErrorInfo);
  2280.             }
  2281.         }
  2282.        
  2283.         private void ScanSections(XmlUtil xmlUtil)
  2284.         {
  2285.             ScanSectionsRecursive(xmlUtil, string.Empty, false, null, false, false);
  2286.         }
  2287.        
  2288.         private void ScanSectionsRecursive(XmlUtil xmlUtil, string parentConfigKey, bool inLocation, string locationSubPath, bool lockChildren, bool skipInChildApps)
  2289.         {
  2290.            
  2291.             // discard any accumulated local errors
  2292.             xmlUtil.SchemaErrors.ResetLocalErrors();
  2293.            
  2294.             int depth;
  2295.            
  2296.             // only move to child nodes when not on first level (we've already passed the first <configsections>)
  2297.             if (parentConfigKey.Length == 0 && !inLocation) {
  2298.                 depth = 0;
  2299.             }
  2300.             else {
  2301.                 depth = xmlUtil.Reader.Depth;
  2302.                 xmlUtil.StrictReadToNextElement(ExceptionAction.NonSpecific);
  2303.             }
  2304.            
  2305.             while (xmlUtil.Reader.Depth == depth + 1) {
  2306.                
  2307.                 string tagName = xmlUtil.Reader.Name;
  2308.                
  2309.                 //
  2310.                 // Check for reserved elements before looking up the factory,
  2311.                 // which may have the same name if it is in error.
  2312.                 //
  2313.                 if (tagName == KEYWORD_CONFIGSECTIONS) {
  2314.                     // Error: duplicate <configSections> tag, or <configSections> not the first tag under <configuration>
  2315.                     xmlUtil.SchemaErrors.AddError(new ConfigurationErrorsException(SR.GetString(SR.Config_client_config_too_many_configsections_elements, tagName), xmlUtil), ExceptionAction.NonSpecific);
  2316.                    
  2317.                     xmlUtil.StrictSkipToNextElement(ExceptionAction.NonSpecific);
  2318.                     continue;
  2319.                 }
  2320.                
  2321.                 if (tagName == KEYWORD_LOCATION) {
  2322.                     if (parentConfigKey.Length > 0 || inLocation) {
  2323.                         // Error: <location> section not at top level
  2324.                         xmlUtil.SchemaErrors.AddError(new ConfigurationErrorsException(SR.GetString(SR.Config_location_location_not_allowed), xmlUtil), ExceptionAction.Global);
  2325.                        
  2326.                         xmlUtil.StrictSkipToNextElement(ExceptionAction.NonSpecific);
  2327.                     }
  2328.                     else {
  2329.                         // Recurse into the location section
  2330.                         ScanLocationSection(xmlUtil);
  2331.                     }
  2332.                    
  2333.                     continue;
  2334.                 }
  2335.                
  2336.                 string configKey = CombineConfigKey(parentConfigKey, tagName);
  2337.                 FactoryRecord factoryRecord = FindFactoryRecord(configKey, true);
  2338.                
  2339.                
  2340.                 if (factoryRecord == null) {
  2341.                     //
  2342.                     //
  2343.                     if (!ClassFlags[ClassIgnoreLocalErrors]) {
  2344.                         xmlUtil.SchemaErrors.AddError(new ConfigurationErrorsException(SR.GetString(SR.Config_unrecognized_configuration_section, configKey), xmlUtil), ExceptionAction.Local);
  2345.                     }
  2346.                    
  2347.                     VerifySectionName(tagName, xmlUtil, ExceptionAction.Local, false);
  2348.                    
  2349.                     factoryRecord = new FactoryRecord(configKey, parentConfigKey, tagName, typeof(DefaultSection).AssemblyQualifiedName, true, ConfigurationAllowDefinition.Everywhere, ConfigurationAllowExeDefinition.MachineToRoamingUser, true, true, _flags[IsTrusted],
  2350.                         // allowLocation
  2351.                         // restartOnExternalChanges
  2352.                         // requirePermission
  2353.                         // isUndeclared
  2354.                     true, null, -1);
  2355.                    
  2356.                     // Add any errors we may have encountered to the factory record,
  2357.                     // so that child config that also refer to this unrecognized section
  2358.                     // get the error.
  2359.                     factoryRecord.AddErrors(xmlUtil.SchemaErrors.RetrieveAndResetLocalErrors(true));
  2360.                    
  2361.                     // Add the factory to the list of factories
  2362.                     EnsureFactories()[configKey] = factoryRecord;
  2363.                 }
  2364.                
  2365.                 if (factoryRecord.IsGroup) {
  2366.                     //
  2367.                     // Section Group
  2368.                     //
  2369.                     if (factoryRecord.HasErrors) {
  2370.                         xmlUtil.StrictSkipToNextElement(ExceptionAction.NonSpecific);
  2371.                     }
  2372.                     else {
  2373.                         if (xmlUtil.Reader.AttributeCount > 0) {
  2374.                             while (xmlUtil.Reader.MoveToNextAttribute()) {
  2375.                                 if (IsReservedAttributeName(xmlUtil.Reader.Name)) {
  2376.                                     xmlUtil.AddErrorReservedAttribute(ExceptionAction.NonSpecific);
  2377.                                 }
  2378.                             }
  2379.                            
  2380.                             xmlUtil.Reader.MoveToElement();
  2381.                             // if on an attribute move back to the element
  2382.                         }
  2383.                        
  2384.                         // Recurse into group definition
  2385.                         ScanSectionsRecursive(xmlUtil, configKey, inLocation, locationSubPath, lockChildren, skipInChildApps);
  2386.                     }
  2387.                 }
  2388.                 else {
  2389.                     //
  2390.                     // Section
  2391.                     //
  2392.                     configKey = factoryRecord.ConfigKey;
  2393.                     string fileName = xmlUtil.Filename;
  2394.                     int lineNumber = xmlUtil.LineNumber;
  2395.                     string rawXml = null;
  2396.                     string configSource = null;
  2397.                     string configSourceStreamName = null;
  2398.                     object configSourceStreamVersion = null;
  2399.                     string protectionProviderName = null;
  2400.                     bool isSectionLocked = false;
  2401.                     bool positionedAtNextElement = false;
  2402.                     bool isFileInput = (locationSubPath == null);
  2403.                    
  2404.                     if (!factoryRecord.HasErrors) {
  2405.                         // We have a valid factoryRecord for a section
  2406.                         if (inLocation && factoryRecord.AllowLocation == false) {
  2407.                             xmlUtil.SchemaErrors.AddError(new ConfigurationErrorsException(SR.GetString(SR.Config_section_cannot_be_used_in_location), xmlUtil), ExceptionAction.Local);
  2408.                         }
  2409.                        
  2410.                         // Verify correctness for file inputs.
  2411.                         if (isFileInput) {
  2412.                             // Verify that the section is unique
  2413.                             SectionRecord sectionRecord = GetSectionRecord(configKey, true);
  2414.                             if (sectionRecord != null && sectionRecord.HasFileInput) {
  2415.                                 xmlUtil.SchemaErrors.AddError(new ConfigurationErrorsException(SR.GetString(SR.Config_sections_must_be_unique), xmlUtil), ExceptionAction.Local);
  2416.                             }
  2417.                            
  2418.                             // Verify that the definition is allowed.
  2419.                             try {
  2420.                                 VerifyDefinitionAllowed(factoryRecord, _configPath, xmlUtil);
  2421.                             }
  2422.                             catch (ConfigurationException ce) {
  2423.                                 xmlUtil.SchemaErrors.AddError(ce, ExceptionAction.Local);
  2424.                             }
  2425.                         }
  2426.                        
  2427.                         // Verify that section is unlocked, both for file and location inputs.
  2428.                         try {
  2429.                             VerifySectionUnlocked(configKey, xmlUtil);
  2430.                         }
  2431.                         catch (ConfigurationException ce) {
  2432.                             isSectionLocked = true;
  2433.                             xmlUtil.SchemaErrors.AddError(ce, ExceptionAction.Local);
  2434.                         }
  2435.                        
  2436.                         // check for configSource or protectionProvider
  2437.                         if (xmlUtil.Reader.AttributeCount >= 1) {
  2438.                             // First do all the attributes reading without advancing the reader.
  2439.                            
  2440.                             string configSourceAttribute = xmlUtil.Reader.GetAttribute(KEYWORD_CONFIGSOURCE);
  2441.                             if (configSourceAttribute != null) {
  2442.                                 try {
  2443.                                     configSource = NormalizeConfigSource(configSourceAttribute, xmlUtil);
  2444.                                 }
  2445.                                 catch (ConfigurationException ce) {
  2446.                                     xmlUtil.SchemaErrors.AddError(ce, ExceptionAction.Local);
  2447.                                 }
  2448.                                
  2449.                                 if (xmlUtil.Reader.AttributeCount != 1) {
  2450.                                     // Error: elements with configSource should not have other attributes
  2451.                                     xmlUtil.SchemaErrors.AddError(new ConfigurationErrorsException(SR.GetString(SR.Config_source_syntax_error), xmlUtil), ExceptionAction.Local);
  2452.                                 }
  2453.                             }
  2454.                            
  2455.                             string protectionProviderAttribute = xmlUtil.Reader.GetAttribute(KEYWORD_PROTECTION_PROVIDER);
  2456.                             if (protectionProviderAttribute != null) {
  2457.                                 try {
  2458.                                     protectionProviderName = ValidateProtectionProviderAttribute(protectionProviderAttribute, xmlUtil);
  2459.                                 }
  2460.                                 catch (ConfigurationException ce) {
  2461.                                     xmlUtil.SchemaErrors.AddError(ce, ExceptionAction.Local);
  2462.                                 }
  2463.                                
  2464.                                 if (xmlUtil.Reader.AttributeCount != 1) {
  2465.                                     // Error: elements with protectionProvider should not have other attributes
  2466.                                     xmlUtil.SchemaErrors.AddError(new ConfigurationErrorsException(SR.GetString(SR.Protection_provider_syntax_error), xmlUtil), ExceptionAction.Local);
  2467.                                 }
  2468.                             }
  2469.                            
  2470.                             // The 2nd part of the configSource check requires advancing the reader.
  2471.                             // Please note that this part should be done only AFTER all other attributes
  2472.                             // checking are done.
  2473.                             if (configSourceAttribute != null) {
  2474.                                 if (!xmlUtil.Reader.IsEmptyElement) {
  2475.                                     while (xmlUtil.Reader.Read()) {
  2476.                                         XmlNodeType t = xmlUtil.Reader.NodeType;
  2477.                                         if (t == XmlNodeType.EndElement)
  2478.                                             break;
  2479.                                        
  2480.                                         if (t != XmlNodeType.Comment) {
  2481.                                             // Error: elements with configSource should not subelements other than comments
  2482.                                             xmlUtil.SchemaErrors.AddError(new ConfigurationErrorsException(SR.GetString(SR.Config_source_syntax_error), xmlUtil), ExceptionAction.Local);
  2483.                                            
  2484.                                             if (t == XmlNodeType.Element) {
  2485.                                                 xmlUtil.StrictSkipToOurParentsEndElement(ExceptionAction.NonSpecific);
  2486.                                             }
  2487.                                             else {
  2488.                                                 xmlUtil.StrictSkipToNextElement(ExceptionAction.NonSpecific);
  2489.                                             }
  2490.                                            
  2491.                                             positionedAtNextElement = true;
  2492.                                             break;
  2493.                                         }
  2494.                                     }
  2495.                                 }
  2496.                             }
  2497.                         }
  2498.                        
  2499.                         if (configSource != null) {
  2500.                             try {
  2501.                                 try {
  2502.                                     configSourceStreamName = Host.GetStreamNameForConfigSource(ConfigStreamInfo.StreamName, configSource);
  2503.                                 }
  2504.                                 catch (Exception e) {
  2505.                                     throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_source_invalid), e, xmlUtil);
  2506.                                 }
  2507.                                 ValidateUniqueConfigSource(configKey, configSourceStreamName, configSource, xmlUtil);
  2508.                                 configSourceStreamVersion = MonitorStream(configKey, configSource, configSourceStreamName);
  2509.                             }
  2510.                             catch (ConfigurationException ex) {
  2511.                                 xmlUtil.SchemaErrors.AddError(ex, ExceptionAction.Local);
  2512.                             }
  2513.                         }
  2514.                        
  2515.                         //
  2516.                         // prefetch the raw xml
  2517.                         //
  2518.                         if (!xmlUtil.SchemaErrors.HasLocalErrors) {
  2519.                             if (configSource == null && ShouldPrefetchRawXml(factoryRecord)) {
  2520.                                 Debug.Assert(!positionedAtNextElement, "!positionedAtNextElement");
  2521.                                
  2522.                                 rawXml = xmlUtil.CopySection();
  2523.                                 if (xmlUtil.Reader.NodeType != XmlNodeType.Element) {
  2524.                                     xmlUtil.VerifyIgnorableNodeType(ExceptionAction.NonSpecific);
  2525.                                     xmlUtil.StrictReadToNextElement(ExceptionAction.NonSpecific);
  2526.                                 }
  2527.                                
  2528.                                 positionedAtNextElement = true;
  2529.                             }
  2530.                         }
  2531.                     }
  2532.                    
  2533.                     // Get the list of errors before advancing the reader
  2534.                     List<ConfigurationException> localErrors = xmlUtil.SchemaErrors.RetrieveAndResetLocalErrors(isFileInput);
  2535.                    
  2536.                     // advance the reader to the next element
  2537.                     if (!positionedAtNextElement) {
  2538.                         xmlUtil.StrictSkipToNextElement(ExceptionAction.NonSpecific);
  2539.                     }
  2540.                    
  2541.                     // Add the input either to:
  2542.                     // 1. The file input at the current config level, or
  2543.                     // 2. LocationSections, where it will be used in sub paths
  2544.                     bool addInput = true;
  2545.                    
  2546.                     if (isFileInput) {
  2547.                         // If isFileInput==true, Input added will be used against this config level.
  2548.                         // Need to check if we need to skip it due to inheritInChildApplications.
  2549.                        
  2550.                         if (ShouldSkipDueToInheritInChildApplications(skipInChildApps)) {
  2551.                             addInput = false;
  2552.                         }
  2553.                     }
  2554.                     else {
  2555.                         if (!_flags[SupportsLocation]) {
  2556.                             // Skip if we have a location input but we don't support location tag.
  2557.                             addInput = false;
  2558.                         }
  2559.                     }
  2560.                    
  2561.                     if (addInput) {
  2562.                        
  2563.                         string targetConfigPath = (locationSubPath == null) ? _configPath : null;
  2564.                        
  2565.                         SectionXmlInfo sectionXmlInfo = new SectionXmlInfo(configKey, _configPath, targetConfigPath, locationSubPath, fileName, lineNumber, ConfigStreamInfo.StreamVersion, rawXml, configSource, configSourceStreamName,
  2566.                         configSourceStreamVersion, protectionProviderName, lockChildren, skipInChildApps);
  2567.                        
  2568.                         if (locationSubPath == null) {
  2569.                             //
  2570.                             // Add this file input to the section record
  2571.                             //
  2572.                            
  2573.                             // We've already checked for locked above, so use skip the second check
  2574.                             // and set the locked bit.
  2575.                             SectionRecord sectionRecord = EnsureSectionRecordUnsafe(configKey, true);
  2576.                            
  2577.                             Debug.Assert(!sectionRecord.Locked || isSectionLocked, "!sectionRecord.Locked || isSectionLocked");
  2578.                            
  2579.                             if (isSectionLocked) {
  2580.                                 sectionRecord.Locked = true;
  2581.                             }
  2582.                            
  2583.                             SectionInput fileInput = new SectionInput(sectionXmlInfo, localErrors);
  2584.                             sectionRecord.AddFileInput(fileInput);
  2585.                         }
  2586.                         else {
  2587.                             //
  2588.                             // Add this location input to this list of location sections
  2589.                             //
  2590.                             LocationSectionRecord locationSectionRecord = new LocationSectionRecord(sectionXmlInfo, localErrors);
  2591.                             EnsureLocationSections().Add(locationSectionRecord);
  2592.                         }
  2593.                     }
  2594.                 }
  2595.             }
  2596.         }
  2597.        
  2598.         private void ScanLocationSection(XmlUtil xmlUtil)
  2599.         {
  2600.             string locationSubPath = null;
  2601.             bool allowOverride = true;
  2602.             bool inheritInChildApp = true;
  2603.             int errorCountBeforeScan = xmlUtil.SchemaErrors.GlobalErrorCount;
  2604.            
  2605.             // Get the location section attributes
  2606.             while (xmlUtil.Reader.MoveToNextAttribute()) {
  2607.                 switch (xmlUtil.Reader.Name) {
  2608.                     case KEYWORD_LOCATION_PATH:
  2609.                         locationSubPath = xmlUtil.Reader.Value;
  2610.                         break;
  2611.                     case KEYWORD_LOCATION_ALLOWOVERRIDE:
  2612.                        
  2613.                         xmlUtil.VerifyAndGetBooleanAttribute(ExceptionAction.Global, true, out allowOverride);
  2614.                        
  2615.                         break;
  2616.                     case KEYWORD_LOCATION_INHERITINCHILDAPPLICATIONS:
  2617.                        
  2618.                         xmlUtil.VerifyAndGetBooleanAttribute(ExceptionAction.Global, true, out inheritInChildApp);
  2619.                        
  2620.                         break;
  2621.                     default:
  2622.                        
  2623.                         xmlUtil.AddErrorUnrecognizedAttribute(ExceptionAction.Global);
  2624.                         break;
  2625.                 }
  2626.             }
  2627.            
  2628.             xmlUtil.Reader.MoveToElement();
  2629.             // if on an attribute move back to the element
  2630.             try {
  2631.                 locationSubPath = NormalizeLocationSubPath(locationSubPath, xmlUtil);
  2632.                
  2633.                 //
  2634.                 //
  2635.                 if (locationSubPath == null && !inheritInChildApp && Host.IsDefinitionAllowed(_configPath, ConfigurationAllowDefinition.MachineToWebRoot, ConfigurationAllowExeDefinition.MachineOnly)) {
  2636.                     throw new ConfigurationErrorsException(SR.GetString(SR.Location_invalid_inheritInChildApplications_in_machine_or_root_web_config), xmlUtil);
  2637.                 }
  2638.             }
  2639.             catch (ConfigurationErrorsException ce) {
  2640.                 xmlUtil.SchemaErrors.AddError(ce, ExceptionAction.Global);
  2641.             }
  2642.            
  2643.             // Skip over this location section if there are errors
  2644.             if (xmlUtil.SchemaErrors.GlobalErrorCount > errorCountBeforeScan) {
  2645.                 xmlUtil.StrictSkipToNextElement(ExceptionAction.NonSpecific);
  2646.                 return;
  2647.             }
  2648.            
  2649.             // Scan elements of the location section if the path is the current path.
  2650.             // We do not add <location path="." /> to the _locationSections list.
  2651.             if (locationSubPath == null) {
  2652.                 ScanSectionsRecursive(xmlUtil, string.Empty, true, null, !allowOverride, !inheritInChildApp);
  2653.                 return;
  2654.             }
  2655.            
  2656.             // Skip over location sections for client config
  2657.             if (!_flags[SupportsLocation]) {
  2658.                 xmlUtil.StrictSkipToNextElement(ExceptionAction.NonSpecific);
  2659.                 return;
  2660.             }
  2661.            
  2662.             AddLocation(locationSubPath);
  2663.             ScanSectionsRecursive(xmlUtil, string.Empty, true, locationSubPath, !allowOverride, !inheritInChildApp);
  2664.         }
  2665.        
  2666.        
  2667.         // AddLocation
  2668.         //
  2669.         // If you wish to keep track of the Location Fields, then use this
  2670.         //
  2671.         protected virtual void AddLocation(string LocationSubPath)
  2672.         {
  2673.         }
  2674.        
  2675.         //
  2676.         // Resolve information about a location section at the time that the location section
  2677.         // is being used by child configuration records. This allows us to:
  2678.         // * Delay determining the configuration path for the location record until the sites section is available.
  2679.         // * Delay reporting bad location paths until the location record has to be used.
  2680.         //
  2681.         private void ResolveLocationSections()
  2682.         {
  2683.             if (!_flags[IsLocationListResolved]) {
  2684.                 // Resolve outside of any lock
  2685.                 if (!_parent.IsRootConfig) {
  2686.                     _parent.ResolveLocationSections();
  2687.                 }
  2688.                
  2689.                 lock (this) {
  2690.                     if (!_flags[IsLocationListResolved]) {
  2691.                         if (_locationSections != null) {
  2692.                             //
  2693.                             // Create dictionary that maps configPaths to (dictionary that maps sectionNames to locationSectionRecords)
  2694.                             //
  2695.                             HybridDictionary locationConfigPaths = new HybridDictionary(true);
  2696.                             foreach (LocationSectionRecord locationSectionRecord in _locationSections) {
  2697.                                 //
  2698.                                 // Resolve the target config path
  2699.                                 //
  2700.                                 string targetConfigPath = Host.GetConfigPathFromLocationSubPath(_configPath, locationSectionRecord.SectionXmlInfo.SubPath);
  2701.                                 locationSectionRecord.SectionXmlInfo.TargetConfigPath = targetConfigPath;
  2702.                                
  2703.                                 //
  2704.                                 // Check uniqueness
  2705.                                 //
  2706.                                 HybridDictionary locationSectionRecordDictionary = (HybridDictionary)locationConfigPaths[targetConfigPath];
  2707.                                 if (locationSectionRecordDictionary == null) {
  2708.                                     locationSectionRecordDictionary = new HybridDictionary(false);
  2709.                                     locationConfigPaths.Add(targetConfigPath, locationSectionRecordDictionary);
  2710.                                 }
  2711.                                
  2712.                                 LocationSectionRecord duplicateRecord = (LocationSectionRecord)locationSectionRecordDictionary[locationSectionRecord.ConfigKey];
  2713.                                 if (duplicateRecord == null) {
  2714.                                     locationSectionRecordDictionary.Add(locationSectionRecord.ConfigKey, locationSectionRecord);
  2715.                                 }
  2716.                                 else {
  2717.                                     if (!duplicateRecord.HasErrors) {
  2718.                                         duplicateRecord.AddError(new ConfigurationErrorsException(SR.GetString(SR.Config_sections_must_be_unique), duplicateRecord.SectionXmlInfo));
  2719.                                     }
  2720.                                    
  2721.                                     locationSectionRecord.AddError(new ConfigurationErrorsException(SR.GetString(SR.Config_sections_must_be_unique), locationSectionRecord.SectionXmlInfo));
  2722.                                 }
  2723.                                
  2724.                                 //
  2725.                                 // Check if the definition is allowed
  2726.                                 //
  2727.                                 FactoryRecord factoryRecord = FindFactoryRecord(locationSectionRecord.ConfigKey, true);
  2728.                                 if (!factoryRecord.HasErrors) {
  2729.                                     try {
  2730.                                         VerifyDefinitionAllowed(factoryRecord, targetConfigPath, locationSectionRecord.SectionXmlInfo);
  2731.                                     }
  2732.                                     catch (ConfigurationException e) {
  2733.                                         locationSectionRecord.AddError(e);
  2734.                                     }
  2735.                                 }
  2736.                             }
  2737.                            
  2738.                             //
  2739.                             // Check location section for being locked.
  2740.                             //
  2741.                             BaseConfigurationRecord parent = _parent;
  2742.                             while (!parent.IsRootConfig) {
  2743.                                 foreach (LocationSectionRecord locationSectionRecord in this._locationSections) {
  2744.                                     bool locked = false;
  2745.                                    
  2746.                                     //
  2747.                                     // It is an error if a parent section with the same configKey is locked.
  2748.                                     //
  2749.                                     SectionRecord sectionRecord = parent.GetSectionRecord(locationSectionRecord.ConfigKey, true);
  2750.                                     if (sectionRecord != null && (sectionRecord.LockChildren || sectionRecord.Locked)) {
  2751.                                        
  2752.                                         locked = true;
  2753.                                     }
  2754.                                     else {
  2755.                                         //
  2756.                                         // It is an error if a parent configuration file locks a section for the
  2757.                                         // locationConfigPath or any sub-path of the locationConfigPath.
  2758.                                         //
  2759.                                         if (parent._locationSections != null) {
  2760.                                             string targetConfigPath = locationSectionRecord.SectionXmlInfo.TargetConfigPath;
  2761.                                            
  2762.                                             foreach (LocationSectionRecord parentLocationSectionRecord in parent._locationSections) {
  2763.                                                 string parentTargetConfigPath = parentLocationSectionRecord.SectionXmlInfo.TargetConfigPath;
  2764.                                                
  2765.                                                 if (parentLocationSectionRecord.SectionXmlInfo.LockChildren && locationSectionRecord.ConfigKey == parentLocationSectionRecord.ConfigKey && UrlPath.IsEqualOrSubpath(targetConfigPath, parentTargetConfigPath)) {
  2766.                                                    
  2767.                                                     locked = true;
  2768.                                                     break;
  2769.                                                 }
  2770.                                             }
  2771.                                         }
  2772.                                     }
  2773.                                    
  2774.                                     if (locked) {
  2775.                                         locationSectionRecord.AddError(new ConfigurationErrorsException(SR.GetString(SR.Config_section_locked), locationSectionRecord.SectionXmlInfo));
  2776.                                     }
  2777.                                 }
  2778.                                
  2779.                                 parent = parent._parent;
  2780.                             }
  2781.                         }
  2782.                     }
  2783.                    
  2784.                     _flags[IsLocationListResolved] = true;
  2785.                 }
  2786.             }
  2787.         }
  2788.        
  2789.         // VerifyDefinitionAllowed
  2790.         //
  2791.         // Verify that the Definition is allowed at this
  2792.         // place.
  2793.         //
  2794.         // For example, if this config record is an application then
  2795.         // make sure the section say's it can be defined in an
  2796.         // application
  2797.         //
  2798.         private void VerifyDefinitionAllowed(FactoryRecord factoryRecord, string configPath, IConfigErrorInfo errorInfo)
  2799.         {
  2800.             Host.VerifyDefinitionAllowed(configPath, factoryRecord.AllowDefinition, factoryRecord.AllowExeDefinition, errorInfo);
  2801.         }
  2802.        
  2803.         internal bool IsDefinitionAllowed(ConfigurationAllowDefinition allowDefinition, ConfigurationAllowExeDefinition allowExeDefinition)
  2804.         {
  2805.             return Host.IsDefinitionAllowed(_configPath, allowDefinition, allowExeDefinition);
  2806.         }
  2807.        
  2808.         protected static void VerifySectionName(string name, XmlUtil xmlUtil, ExceptionAction action, bool allowImplicit)
  2809.         {
  2810.             try {
  2811.                 VerifySectionName(name, (IConfigErrorInfo)xmlUtil, allowImplicit);
  2812.             }
  2813.             catch (ConfigurationErrorsException ce) {
  2814.                 xmlUtil.SchemaErrors.AddError(ce, action);
  2815.             }
  2816.         }
  2817.        
  2818.         // Check if the section name contains reserved words from the config system,
  2819.         // and is a valid name for an XML Element.
  2820.         protected static void VerifySectionName(string name, IConfigErrorInfo errorInfo, bool allowImplicit)
  2821.         {
  2822.             if (String.IsNullOrEmpty(name)) {
  2823.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_tag_name_invalid), errorInfo);
  2824.             }
  2825.            
  2826.             // must be a valid name in xml, so that it can be used as an element
  2827.             // n.b. - it also excludes forward slash '/'
  2828.             try {
  2829.                 XmlConvert.VerifyName(name);
  2830.             }
  2831.             // Do not let the exception propagate as an XML exception,
  2832.             // for we want errors in the section name to be treated as local errors,
  2833.             // not global ones.
  2834.             catch (Exception e) {
  2835.                 throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_tag_name_invalid), e, errorInfo);
  2836.             }
  2837.             catch {
  2838.                 throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_tag_name_invalid), null, errorInfo);
  2839.             }
  2840.            
  2841.             if (IsImplicitSection(name)) {
  2842.                 if (allowImplicit) {
  2843.                     // avoid test below for strings starting with "config"
  2844.                     return;
  2845.                 }
  2846.                 else {
  2847.                     throw new ConfigurationErrorsException(SR.GetString(SR.Cannot_declare_or_remove_implicit_section, name), errorInfo);
  2848.                 }
  2849.             }
  2850.            
  2851.             if (StringUtil.StartsWith(name, "config")) {
  2852.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_tag_name_cannot_begin_with_config), errorInfo);
  2853.             }
  2854.            
  2855.             if (name == KEYWORD_LOCATION) {
  2856.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_tag_name_cannot_be_location), errorInfo);
  2857.             }
  2858.         }
  2859.        
  2860. /*
  2861.         From http://www.w3.org/Addressing/
  2862.           reserved    = ';' | '/' | '?' | ':' | '@' | '&' | '=' | '+' | '$' | ','
  2863.         From Platform SDK
  2864.           reserved    = '\' |  '/' | '|' | ':' |  '"' |  '<' | '>'
  2865.         */       
  2866.        
  2867.         // NOTE: If you change these strings, you must change the associated error message
  2868.         const string invalidFirstSubPathCharacters = "\\./";
  2869.         const string invalidLastSubPathCharacters = "\\./";
  2870.         const string invalidSubPathCharactersString = "\\;?:@&=+$,*\"<>|";
  2871.         static char[] s_invalidSubPathCharactersArray = invalidSubPathCharactersString.ToCharArray();
  2872.        
  2873.         // Return null if the subPath represents the current directory, for example:
  2874.         // path=""
  2875.         // path=" "
  2876.         // path="."
  2877.         // path="./"
  2878.         static internal string NormalizeLocationSubPath(string subPath, IConfigErrorInfo errorInfo)
  2879.         {
  2880.             // if subPath is null or empty, it is the current dir
  2881.             if (String.IsNullOrEmpty(subPath))
  2882.                 return null;
  2883.            
  2884.             // if subPath=".", it is the current dir
  2885.             if (subPath == ".")
  2886.                 return null;
  2887.            
  2888.             // do not allow whitespace in front of subPath, as the OS
  2889.             // handles beginning and trailing whitespace inconsistently
  2890.             string trimmedSubPath = subPath.TrimStart();
  2891.             if (trimmedSubPath.Length != subPath.Length) {
  2892.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_location_path_invalid_first_character), errorInfo);
  2893.             }
  2894.            
  2895.             // do not allow problematic starting characters
  2896.             if (invalidFirstSubPathCharacters.IndexOf(subPath[0]) != -1) {
  2897.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_location_path_invalid_first_character), errorInfo);
  2898.             }
  2899.            
  2900.             // do not allow whitespace at end of subPath, as the OS
  2901.             // handles beginning and trailing whitespace inconsistently
  2902.             trimmedSubPath = subPath.TrimEnd();
  2903.             if (trimmedSubPath.Length != subPath.Length) {
  2904.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_location_path_invalid_last_character), errorInfo);
  2905.             }
  2906.            
  2907.             // the file system ignores trailing '.', '\', or '/', so do not allow it in a location subpath specification
  2908.             if (invalidLastSubPathCharacters.IndexOf(subPath[subPath.Length - 1]) != -1) {
  2909.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_location_path_invalid_last_character), errorInfo);
  2910.             }
  2911.            
  2912.             // combination of URI reserved characters and OS invalid filename characters, minus / (allowed reserved character)
  2913.             if (subPath.IndexOfAny(s_invalidSubPathCharactersArray) != -1) {
  2914.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_location_path_invalid_character), errorInfo);
  2915.             }
  2916.            
  2917.             return subPath;
  2918.         }
  2919.        
  2920.        
  2921.         //
  2922.         // Return the SectionRecord for a section.
  2923.         // If the record does not exist, return null.
  2924.         // Throw cached errors if the section is in error and permitErrors == false.
  2925.         //
  2926.         protected SectionRecord GetSectionRecord(string configKey, bool permitErrors)
  2927.         {
  2928.             SectionRecord sectionRecord;
  2929.            
  2930.             if (_sectionRecords != null) {
  2931.                 sectionRecord = (SectionRecord)_sectionRecords[configKey];
  2932.             }
  2933.             else {
  2934.                 sectionRecord = null;
  2935.             }
  2936.            
  2937.             if (sectionRecord != null && !permitErrors) {
  2938.                 sectionRecord.ThrowOnErrors();
  2939.             }
  2940.            
  2941.             return sectionRecord;
  2942.         }
  2943.        
  2944.         // Return an existing SectionRecord, or create one if one does not exist.
  2945.         // Propagate the Locked bit from parent
  2946.         protected SectionRecord EnsureSectionRecord(string configKey, bool permitErrors)
  2947.         {
  2948.             return EnsureSectionRecordImpl(configKey, permitErrors, true);
  2949.         }
  2950.        
  2951.         // Return an existing SectionRecord, or create one if one does not exist.
  2952.         // Do not propagate the Locked bit from parent, because caller will check
  2953.         // himself later.
  2954.         protected SectionRecord EnsureSectionRecordUnsafe(string configKey, bool permitErrors)
  2955.         {
  2956.             return EnsureSectionRecordImpl(configKey, permitErrors, false);
  2957.         }
  2958.        
  2959.         // Return an existing SectionRecord, or create one if one does not exist.
  2960.         // If desired, set the locked bit if locked by a parent.
  2961.         private SectionRecord EnsureSectionRecordImpl(string configKey, bool permitErrors, bool checkIfLocked)
  2962.         {
  2963.             SectionRecord sectionRecord = GetSectionRecord(configKey, permitErrors);
  2964.             if (sectionRecord == null) {
  2965.                 bool sectionAdded = false;
  2966.                 lock (this) {
  2967.                     if (_sectionRecords == null) {
  2968.                         _sectionRecords = new Hashtable();
  2969.                     }
  2970.                     else {
  2971.                         sectionRecord = GetSectionRecord(configKey, permitErrors);
  2972.                     }
  2973.                    
  2974.                     if (sectionRecord == null) {
  2975.                         sectionRecord = new SectionRecord(configKey);
  2976.                         _sectionRecords.Add(configKey, sectionRecord);
  2977.                         sectionAdded = true;
  2978.                     }
  2979.                 }
  2980.                
  2981.                 if (checkIfLocked && sectionAdded) {
  2982.                     sectionRecord.Locked = IsParentCausingLock(configKey);
  2983.                 }
  2984.             }
  2985.            
  2986.             return sectionRecord;
  2987.         }
  2988.        
  2989.         private bool HasFactoryRecords {
  2990.             get { return _factoryRecords != null; }
  2991.         }
  2992.        
  2993.         internal FactoryRecord GetFactoryRecord(string configKey, bool permitErrors)
  2994.         {
  2995.             FactoryRecord factoryRecord;
  2996.            
  2997.             if (_factoryRecords == null) {
  2998.                 return null;
  2999.             }
  3000.            
  3001.             factoryRecord = (FactoryRecord)_factoryRecords[configKey];
  3002.             if (factoryRecord != null && !permitErrors) {
  3003.                 factoryRecord.ThrowOnErrors();
  3004.             }
  3005.            
  3006.             return factoryRecord;
  3007.         }
  3008.        
  3009.         // Only create a _factories hashtable when necessary.
  3010.         // Most config records won't have factories, so we can save 120 bytes
  3011.         // per record by creating the table on demand.
  3012.         protected Hashtable EnsureFactories()
  3013.         {
  3014.             if (_factoryRecords == null) {
  3015.                 _factoryRecords = new Hashtable();
  3016.             }
  3017.            
  3018.             return _factoryRecords;
  3019.         }
  3020.        
  3021.         private ArrayList EnsureLocationSections()
  3022.         {
  3023.             if (_locationSections == null) {
  3024.                 _locationSections = new ArrayList();
  3025.             }
  3026.            
  3027.             return _locationSections;
  3028.         }
  3029.        
  3030.         // Return true if there is no unique configuration information in this record.
  3031.         internal bool IsEmpty {
  3032.             get { return _parent != null && !_initErrors.HasErrors(false) && (_sectionRecords == null || _sectionRecords.Count == 0) && (_factoryRecords == null || _factoryRecords.Count == 0) && (_locationSections == null || _locationSections.Count == 0); }
  3033.         }
  3034.        
  3035.         static internal string NormalizeConfigSource(string configSource, IConfigErrorInfo errorInfo)
  3036.         {
  3037.             if (String.IsNullOrEmpty(configSource)) {
  3038.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_source_invalid_format), errorInfo);
  3039.             }
  3040.            
  3041.             string trimmedConfigSource = configSource.Trim();
  3042.             if (trimmedConfigSource.Length != configSource.Length) {
  3043.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_source_invalid_format), errorInfo);
  3044.             }
  3045.            
  3046.             if (configSource.IndexOf('/') != -1) {
  3047.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_source_invalid_chars), errorInfo);
  3048.             }
  3049.            
  3050.             if (String.IsNullOrEmpty(configSource) || System.IO.Path.IsPathRooted(configSource)) {
  3051.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_source_invalid_format), errorInfo);
  3052.             }
  3053.            
  3054.             return configSource;
  3055.         }
  3056.        
  3057.         protected object MonitorStream(string configKey, string configSource, string streamname)
  3058.         {
  3059.             lock (this) {
  3060.                 if (_flags[Closed]) {
  3061.                     return null;
  3062.                 }
  3063.                
  3064.                 StreamInfo streamInfo = (StreamInfo)ConfigStreamInfo.StreamInfos[streamname];
  3065.                 if (streamInfo != null) {
  3066.                     if (streamInfo.SectionName != configKey) {
  3067.                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_source_cannot_be_shared, streamname));
  3068.                     }
  3069.                    
  3070.                     if (streamInfo.IsMonitored) {
  3071.                         return streamInfo.Version;
  3072.                     }
  3073.                 }
  3074.                 else {
  3075.                     streamInfo = new StreamInfo(configKey, configSource, streamname);
  3076.                     ConfigStreamInfo.StreamInfos.Add(streamname, streamInfo);
  3077.                 }
  3078.             }
  3079.            
  3080.             //
  3081.             // Call the host outside the lock to avoid deadlock.
  3082.             //
  3083.             object version = Host.GetStreamVersion(streamname);
  3084.            
  3085.             StreamChangeCallback callbackDelegate = null;
  3086.            
  3087.             lock (this) {
  3088.                 if (_flags[Closed]) {
  3089.                     return null;
  3090.                 }
  3091.                
  3092.                 StreamInfo streamInfo = (StreamInfo)ConfigStreamInfo.StreamInfos[streamname];
  3093.                 if (streamInfo.IsMonitored) {
  3094.                     return streamInfo.Version;
  3095.                 }
  3096.                
  3097.                 streamInfo.IsMonitored = true;
  3098.                 streamInfo.Version = version;
  3099.                
  3100.                 if (_flags[SupportsChangeNotifications]) {
  3101.                     if (ConfigStreamInfo.CallbackDelegate == null) {
  3102.                         ConfigStreamInfo.CallbackDelegate = new StreamChangeCallback(this.OnStreamChanged);
  3103.                     }
  3104.                    
  3105.                     callbackDelegate = ConfigStreamInfo.CallbackDelegate;
  3106.                 }
  3107.             }
  3108.            
  3109.             if (_flags[SupportsChangeNotifications]) {
  3110.                 Host.StartMonitoringStreamForChanges(streamname, callbackDelegate);
  3111.             }
  3112.            
  3113.             return version;
  3114.         }
  3115.        
  3116.         private void OnStreamChanged(string streamname)
  3117.         {
  3118.             bool notifyChanged;
  3119.             StreamInfo streamInfo;
  3120.             string sectionName;
  3121.            
  3122.             lock (this) {
  3123.                 if (_flags[Closed])
  3124.                     return;
  3125.                
  3126.                 streamInfo = (StreamInfo)ConfigStreamInfo.StreamInfos[streamname];
  3127.                 if (streamInfo == null || !streamInfo.IsMonitored)
  3128.                     return;
  3129.                
  3130.                 sectionName = streamInfo.SectionName;
  3131.             }
  3132.            
  3133.             if (sectionName == null) {
  3134.                 notifyChanged = true;
  3135.             }
  3136.             else {
  3137.                 FactoryRecord factoryRecord = FindFactoryRecord(sectionName, false);
  3138.                 notifyChanged = factoryRecord.RestartOnExternalChanges;
  3139.             }
  3140.            
  3141.             if (notifyChanged) {
  3142.                 _configRoot.FireConfigChanged(_configPath);
  3143.             }
  3144.             else {
  3145.                 _configRoot.ClearResult(this, sectionName, false);
  3146.             }
  3147.         }
  3148.        
  3149.         //
  3150.         //
  3151.         private void ValidateUniqueConfigSource(string configKey, string configSourceStreamName, string configSourceArg, IConfigErrorInfo errorInfo)
  3152.         {
  3153.            
  3154.             //
  3155.             // Detect if another section in this file is using the same configSource
  3156.             // with has a different section name.
  3157.             //
  3158.             lock (this) {
  3159.                 if (ConfigStreamInfo.HasStreamInfos) {
  3160.                     StreamInfo streamInfo = (StreamInfo)ConfigStreamInfo.StreamInfos[configSourceStreamName];
  3161.                     if (streamInfo != null && streamInfo.SectionName != configKey) {
  3162.                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_source_cannot_be_shared, configSourceArg), errorInfo);
  3163.                     }
  3164.                 }
  3165.             }
  3166.            
  3167.             ValidateUniqueChildConfigSource(configKey, configSourceStreamName, configSourceArg, errorInfo);
  3168.         }
  3169.        
  3170.         protected void ValidateUniqueChildConfigSource(string configKey, string configSourceStreamName, string configSourceArg, IConfigErrorInfo errorInfo)
  3171.         {
  3172.            
  3173.             //
  3174.             // Detect if a parent config file is using the same config source stream.
  3175.             //
  3176.             BaseConfigurationRecord current;
  3177.             if (IsLocationConfig) {
  3178.                 current = _parent._parent;
  3179.             }
  3180.             else {
  3181.                 current = _parent;
  3182.             }
  3183.            
  3184.             while (!current.IsRootConfig) {
  3185.                 lock (current) {
  3186.                     if (current.ConfigStreamInfo.HasStreamInfos) {
  3187.                         StreamInfo streamInfo = (StreamInfo)current.ConfigStreamInfo.StreamInfos[configSourceStreamName];
  3188.                         if (streamInfo != null) {
  3189.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_source_parent_conflict, configSourceArg), errorInfo);
  3190.                         }
  3191.                     }
  3192.                 }
  3193.                
  3194.                 current = current.Parent;
  3195.             }
  3196.         }
  3197.        
  3198.         // Recursively clear the result.
  3199.         // If forceEvaluation == true, force a rescan of the config file to find
  3200.         // the section.
  3201.         // Requires the hierarchy lock to be acquired (hl)
  3202.         internal void hlClearResultRecursive(string configKey, bool forceEvaluatation)
  3203.         {
  3204.             SectionRecord sectionRecord;
  3205.            
  3206.             // Refresh it's factory Record
  3207.             RefreshFactoryRecord(configKey);
  3208.            
  3209.             // Clear any stored result in the section
  3210.             sectionRecord = GetSectionRecord(configKey, false);
  3211.             if (sectionRecord != null) {
  3212.                 sectionRecord.ClearResult();
  3213.                
  3214.                 sectionRecord.ClearRawXml();
  3215.             }
  3216.            
  3217.             //
  3218.             // If we need to reevaluate, add a dummy file input so
  3219.             // that we open the file on the next evaluation
  3220.             //
  3221.             if (forceEvaluatation && !IsInitDelayed && !String.IsNullOrEmpty(ConfigStreamInfo.StreamName)) {
  3222.                 if (_flags[SupportsPath]) {
  3223.                     throw ExceptionUtil.UnexpectedError("BaseConfigurationRecord::hlClearResultRecursive");
  3224.                 }
  3225.                
  3226.                 FactoryRecord factoryRecord = FindFactoryRecord(configKey, false);
  3227.                 if (factoryRecord != null && !factoryRecord.IsGroup) {
  3228.                     configKey = factoryRecord.ConfigKey;
  3229.                     sectionRecord = EnsureSectionRecord(configKey, false);
  3230.                     if (!sectionRecord.HasFileInput) {
  3231.                         SectionXmlInfo sectionXmlInfo = new SectionXmlInfo(configKey, _configPath, _configPath, null, ConfigStreamInfo.StreamName, 0, null, null, null, null,
  3232.                         null, null, false, false);
  3233.                        
  3234.                         SectionInput fileInput = new SectionInput(sectionXmlInfo, null);
  3235.                         sectionRecord.AddFileInput(fileInput);
  3236.                     }
  3237.                 }
  3238.             }
  3239.            
  3240.             // Recurse
  3241.             if (_children != null) {
  3242.                 IEnumerable children = _children.Values;
  3243.                 foreach (BaseConfigurationRecord child in children) {
  3244.                     child.hlClearResultRecursive(configKey, forceEvaluatation);
  3245.                 }
  3246.             }
  3247.         }
  3248.        
  3249.         // Returns a child record.
  3250.         // Requires the hierarchy lock to be acquired (hl)
  3251.         internal BaseConfigurationRecord hlGetChild(string configName)
  3252.         {
  3253.             if (_children == null)
  3254.                 return null;
  3255.            
  3256.             return (BaseConfigurationRecord)_children[configName];
  3257.         }
  3258.        
  3259.         // Adds a child record.
  3260.         // Requires the hierarchy lock to be acquired (hl)
  3261.         internal void hlAddChild(string configName, BaseConfigurationRecord child)
  3262.         {
  3263.             if (_children == null) {
  3264.                 _children = new Hashtable(StringComparer.OrdinalIgnoreCase);
  3265.             }
  3266.            
  3267.             _children.Add(configName, child);
  3268.         }
  3269.        
  3270.         // Removes a child record.
  3271.         // Requires the hierarchy lock to be acquired (hl)
  3272.         internal void hlRemoveChild(string configName)
  3273.         {
  3274.             if (_children != null) {
  3275.                 _children.Remove(configName);
  3276.             }
  3277.         }
  3278.        
  3279.         // Removes true if a child record is needed for a
  3280.         // child config path.
  3281.         // Requires the hierarchy lock to be acquired (hl)
  3282.         internal bool hlNeedsChildFor(string configName)
  3283.         {
  3284.             // Always return true for root config record
  3285.             if (IsRootConfig)
  3286.                 return true;
  3287.            
  3288.             // Never create a child record when the parent has an exception.
  3289.             if (HasInitErrors) {
  3290.                 return false;
  3291.             }
  3292.            
  3293.             string childConfigPath = ConfigPathUtility.Combine(_configPath, configName);
  3294.            
  3295.             try {
  3296.                 using (Impersonate()) {
  3297.                     // check host if required
  3298.                     if (Host.IsConfigRecordRequired(childConfigPath)) {
  3299.                         return true;
  3300.                     }
  3301.                 }
  3302.             }
  3303.             catch {
  3304.                 // Don't allow frames up the stack to run exception filters while impersonated.
  3305.                 throw;
  3306.             }
  3307.            
  3308.             // see if there's a location
  3309.             if (_flags[SupportsLocation]) {
  3310.                 BaseConfigurationRecord configRecord = this;
  3311.                
  3312.                 while (!configRecord.IsRootConfig) {
  3313.                     if (configRecord._locationSections != null) {
  3314.                         configRecord.ResolveLocationSections();
  3315.                         foreach (LocationSectionRecord locationSectionRecord in configRecord._locationSections) {
  3316.                             if (UrlPath.IsEqualOrSubpath(locationSectionRecord.SectionXmlInfo.TargetConfigPath, childConfigPath)) {
  3317.                                 return true;
  3318.                             }
  3319.                         }
  3320.                     }
  3321.                    
  3322.                     configRecord = configRecord._parent;
  3323.                 }
  3324.             }
  3325.            
  3326.             return false;
  3327.         }
  3328.        
  3329.         // Close the record. An explicit close is needed
  3330.         // in order to stop monitoring streams used by
  3331.         // this record. Stream monitors cause this record
  3332.         // to be rooted in the GC heap.
  3333.         //
  3334.         // Note that we purposely do not cleanup the child/parent
  3335.         // hierarchy. This is so that a config system which has
  3336.         // a pointer to this record can still call GetSection on
  3337.         // it while another thread closes it.
  3338.         internal void CloseRecursive()
  3339.         {
  3340.             if (!_flags[Closed]) {
  3341.                 bool doClose = false;
  3342.                 HybridDictionary streamInfos = null;
  3343.                 StreamChangeCallback callbackDelegate = null;
  3344.                
  3345.                 lock (this) {
  3346.                     if (!_flags[Closed]) {
  3347.                         _flags[Closed] = true;
  3348.                         doClose = true;
  3349.                        
  3350.                         if (!IsLocationConfig && ConfigStreamInfo.HasStreamInfos) {
  3351.                             callbackDelegate = ConfigStreamInfo.CallbackDelegate;
  3352.                             streamInfos = ConfigStreamInfo.StreamInfos;
  3353.                            
  3354.                             ConfigStreamInfo.CallbackDelegate = null;
  3355.                             ConfigStreamInfo.ClearStreamInfos();
  3356.                         }
  3357.                     }
  3358.                 }
  3359.                
  3360.                 if (doClose) {
  3361.                     // no hierarchy lock is needed to access _children here,
  3362.                     // as it has already been detached from the hierarchy tree
  3363.                     if (_children != null) {
  3364.                         foreach (BaseConfigurationRecord child in _children.Values) {
  3365.                             child.CloseRecursive();
  3366.                         }
  3367.                     }
  3368.                    
  3369.                     if (streamInfos != null) {
  3370.                         foreach (StreamInfo streamInfo in streamInfos.Values) {
  3371.                             if (streamInfo.IsMonitored) {
  3372.                                 Host.StopMonitoringStreamForChanges(streamInfo.StreamName, callbackDelegate);
  3373.                                 streamInfo.IsMonitored = false;
  3374.                             }
  3375.                         }
  3376.                     }
  3377.                 }
  3378.             }
  3379.         }
  3380.        
  3381.         internal string FindChangedConfigurationStream()
  3382.         {
  3383.             BaseConfigurationRecord configRecord = this;
  3384.             while (!configRecord.IsRootConfig) {
  3385.                 lock (configRecord) {
  3386.                     if (configRecord.ConfigStreamInfo.HasStreamInfos) {
  3387.                         foreach (StreamInfo streamInfo in configRecord.ConfigStreamInfo.StreamInfos.Values) {
  3388.                             if (streamInfo.IsMonitored && HasStreamChanged(streamInfo.StreamName, streamInfo.Version)) {
  3389.                                 return streamInfo.StreamName;
  3390.                             }
  3391.                         }
  3392.                     }
  3393.                 }
  3394.                
  3395.                 configRecord = configRecord._parent;
  3396.             }
  3397.            
  3398.             return null;
  3399.         }
  3400.        
  3401.         private bool HasStreamChanged(string streamname, object lastVersion)
  3402.         {
  3403.             object currentVersion = Host.GetStreamVersion(streamname);
  3404.            
  3405.             if (lastVersion != null) {
  3406.                 return (currentVersion == null || !lastVersion.Equals(currentVersion));
  3407.             }
  3408.             else {
  3409.                 return currentVersion != null;
  3410.             }
  3411.         }
  3412.        
  3413.         protected virtual string CallHostDecryptSection(string encryptedXml, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedConfig)
  3414.         {
  3415.             return Host.DecryptSection(encryptedXml, protectionProvider, protectedConfig);
  3416.         }
  3417.        
  3418.         static internal string ValidateProtectionProviderAttribute(string protectionProvider, IConfigErrorInfo errorInfo)
  3419.         {
  3420.             if (String.IsNullOrEmpty(protectionProvider)) {
  3421.                 throw new ConfigurationErrorsException(SR.GetString(SR.Protection_provider_invalid_format), errorInfo);
  3422.             }
  3423.            
  3424.             return protectionProvider;
  3425.         }
  3426.        
  3427.         private ConfigXmlReader DecryptConfigSection(ConfigXmlReader reader, ProtectedConfigurationProvider protectionProvider)
  3428.         {
  3429.             ConfigXmlReader clone = reader.Clone();
  3430.             IConfigErrorInfo err = (IConfigErrorInfo)clone;
  3431.             string encryptedXml = null;
  3432.             string clearTextXml = null;
  3433.             XmlNodeType nodeType;
  3434.            
  3435.             clone.Read();
  3436.            
  3437.             // Save the file and line at the top of the section
  3438.            
  3439.             string filename = err.Filename;
  3440.             int lineNumber = err.LineNumber;
  3441.             int sectionLineNumber = lineNumber;
  3442.            
  3443.             if (clone.IsEmptyElement) {
  3444.                 throw new ConfigurationErrorsException(SR.GetString(SR.EncryptedNode_not_found), filename, lineNumber);
  3445.             }
  3446.            
  3447.             //////////////////////////////////////////////////////////
  3448.             // Find the <EncryptedData> node
  3449.             for (;;) {
  3450.                 clone.Read();
  3451.                 // Keep reading till we find a relavant node
  3452.                 nodeType = clone.NodeType;
  3453.                
  3454.                 if (nodeType == XmlNodeType.Element && clone.Name == "EncryptedData") {
  3455.                     // Found it!
  3456.                     break;
  3457.                 }
  3458.                
  3459.                 if (nodeType == XmlNodeType.EndElement) {
  3460.                     throw new ConfigurationErrorsException(SR.GetString(SR.EncryptedNode_not_found), filename, lineNumber);
  3461.                 }
  3462.                 else if (nodeType != XmlNodeType.Comment && nodeType != XmlNodeType.Whitespace) {
  3463.                     // some other unexpected content
  3464.                     throw new ConfigurationErrorsException(SR.GetString(SR.EncryptedNode_is_in_invalid_format), filename, lineNumber);
  3465.                 }
  3466.             }
  3467.            
  3468.             //////////////////////////////////////////////////////////
  3469.             // Do the decryption
  3470.            
  3471.             // Save the line at the top of the <EncryptedData> node
  3472.             lineNumber = err.LineNumber;
  3473.            
  3474.             encryptedXml = clone.ReadOuterXml();
  3475.             try {
  3476.                 clearTextXml = CallHostDecryptSection(encryptedXml, protectionProvider, ProtectedConfig);
  3477.             }
  3478.             catch (Exception e) {
  3479.                 throw new ConfigurationErrorsException(SR.GetString(SR.Decryption_failed, protectionProvider.Name, e.Message), e, filename, lineNumber);
  3480.             }
  3481.             catch {
  3482.                 throw new ConfigurationErrorsException(SR.GetString(SR.Decryption_failed, protectionProvider.Name, ExceptionUtil.NoExceptionInformation), filename, lineNumber);
  3483.             }
  3484.            
  3485.             // Detect if there is any XML left over after <EncryptedData>
  3486.             do {
  3487.                 nodeType = clone.NodeType;
  3488.                
  3489.                 if (nodeType == XmlNodeType.EndElement) {
  3490.                     break;
  3491.                 }
  3492.                 else if (nodeType != XmlNodeType.Comment && nodeType != XmlNodeType.Whitespace) {
  3493.                     // Got other unexpected content
  3494.                     throw new ConfigurationErrorsException(SR.GetString(SR.EncryptedNode_is_in_invalid_format), filename, lineNumber);
  3495.                 }
  3496.             }
  3497.             while (clone.Read());
  3498.            
  3499.             // Create a new reader, using the position of the original reader
  3500.             return new ConfigXmlReader(clearTextXml, filename, sectionLineNumber, true);
  3501.         }
  3502.        
  3503.         // ConfigContext
  3504.         //
  3505.         // Retrieve the context for the config
  3506.         //
  3507.         internal object ConfigContext {
  3508.             get {
  3509.                 if (!_flags[ContextEvaluated]) {
  3510.                     // Retrieve context for Path
  3511.                     _configContext = Host.CreateConfigurationContext(ConfigPath, LocationSubPath);
  3512.                     _flags[ContextEvaluated] = true;
  3513.                 }
  3514.                
  3515.                 return _configContext;
  3516.             }
  3517.         }
  3518.        
  3519.         // ThrowIfParseErrors
  3520.         //
  3521.         // Throw if there were parse errors detected
  3522.         //
  3523.         private void ThrowIfParseErrors(ConfigurationSchemaErrors schemaErrors)
  3524.         {
  3525.             schemaErrors.ThrowIfErrors(ClassFlags[ClassIgnoreLocalErrors]);
  3526.         }
  3527.        
  3528.        
  3529.         // RecordSupportsLocation
  3530.         //
  3531.         // Does it make sense to put use location tags in this file?
  3532.         // In the web case this is true at any level. In the exe case
  3533.         // this is only true for machine.config (since machine.config
  3534.         // can really be used for any scenario)
  3535.         //
  3536.         internal bool RecordSupportsLocation {
  3537.             get { return (_flags[SupportsLocation] || IsMachineConfig); }
  3538.         }
  3539.        
  3540.         //
  3541.         // Note: Some of the per-attribute encryption stuff is moved to the end of the file to minimize
  3542.         // FI merging conflicts
  3543.         //
  3544.         const string ProtectedConfigurationSectionTypeName = "System.Configuration.ProtectedConfigurationSection, " + AssemblyRef.SystemConfiguration;
  3545.         internal const string RESERVED_SECTION_PROTECTED_CONFIGURATION = "configProtectedData";
  3546.        
  3547.         static internal bool IsImplicitSection(string configKey)
  3548.         {
  3549.             if (configKey == RESERVED_SECTION_PROTECTED_CONFIGURATION) {
  3550.                 return true;
  3551.             }
  3552.             else {
  3553.                 return false;
  3554.             }
  3555.         }
  3556.        
  3557.         //
  3558.         // Add implicit sections to the factory list.
  3559.         // If factoryList == null, then add to the config record's factory list.
  3560.         //
  3561.         private void AddImplicitSections(Hashtable factoryList)
  3562.         {
  3563.             // Add implicit sections to the factoryList if we're under the root
  3564.             // (e.g. if we're in machine.config)
  3565.             if (_parent.IsRootConfig) {
  3566.                
  3567.                 if (factoryList == null) {
  3568.                     factoryList = EnsureFactories();
  3569.                 }
  3570.                
  3571.                 FactoryRecord factoryRecord = (FactoryRecord)factoryList[RESERVED_SECTION_PROTECTED_CONFIGURATION];
  3572.                
  3573.                 // If the user has mistakenly declared an implicit section, we should leave the factoryRecord
  3574.                 // alone because it contains the error and the error will be thrown later.
  3575.                 if (factoryRecord != null) {
  3576.                     Debug.Assert(factoryRecord.HasErrors, "If the user has mistakenly declared an implicit section, we should have recorded an error.");
  3577.                 }
  3578.                 else {
  3579.                     factoryList[RESERVED_SECTION_PROTECTED_CONFIGURATION] = new FactoryRecord(RESERVED_SECTION_PROTECTED_CONFIGURATION, string.Empty, RESERVED_SECTION_PROTECTED_CONFIGURATION, ProtectedConfigurationSectionTypeName, true, ConfigurationAllowDefinition.Everywhere, ConfigurationAllowExeDefinition.MachineToApplication, true, true, true,
  3580.                         // configKey
  3581.                         // group
  3582.                         // name
  3583.                         // factoryTypeName
  3584.                         // allowLocation
  3585.                         // allowDefinition
  3586.                         // allowExeDefinition
  3587.                         // restartOnExternalChanges
  3588.                         // requirePermission
  3589.                         // isFromTrustedConfig
  3590.                         // isUndeclared
  3591.                         // filename
  3592.                     true, null, -1);
  3593.                     // lineNumber
  3594.                 }
  3595.             }
  3596.         }
  3597.        
  3598.         // We reserve all attribute names starting with config or lock
  3599.         static internal bool IsReservedAttributeName(string name)
  3600.         {
  3601.             if (StringUtil.StartsWith(name, "config") || StringUtil.StartsWith(name, "lock")) {
  3602.                 return true;
  3603.             }
  3604.             else {
  3605.                 return false;
  3606.             }
  3607.         }
  3608.        
  3609.         protected class ConfigRecordStreamInfo
  3610.         {
  3611.             private bool _hasStream;
  3612.             // does the stream exist?
  3613.             private string _streamname;
  3614.             // name of the stream of this record
  3615.             private object _streamVersion;
  3616.             // version of the stream
  3617.             private Encoding _encoding;
  3618.             // encoding of the stream
  3619.             private StreamChangeCallback _callbackDelegate;
  3620.             // host delegate to callback to when stream has changed
  3621.             private HybridDictionary _streamInfos;
  3622.             // streamname -> StreamInfo. It'll also contain the main stream pointed to by _streamname
  3623.             internal ConfigRecordStreamInfo()
  3624.             {
  3625.                 // default encoding
  3626.                 _encoding = Encoding.UTF8;
  3627.             }
  3628.            
  3629.             internal bool HasStream {
  3630.                 get { return _hasStream; }
  3631.                 set { _hasStream = value; }
  3632.             }
  3633.            
  3634.             internal string StreamName {
  3635.                 get { return _streamname; }
  3636.                 set { _streamname = value; }
  3637.             }
  3638.            
  3639.             internal object StreamVersion {
  3640.                 get { return _streamVersion; }
  3641.                 set { _streamVersion = value; }
  3642.             }
  3643.            
  3644.             internal Encoding StreamEncoding {
  3645.                 get { return _encoding; }
  3646.                 set { _encoding = value; }
  3647.             }
  3648.            
  3649.             internal StreamChangeCallback CallbackDelegate {
  3650.                 get { return _callbackDelegate; }
  3651.                 set { _callbackDelegate = value; }
  3652.             }
  3653.            
  3654.             internal HybridDictionary StreamInfos {
  3655.                 get {
  3656.                     if (_streamInfos == null) {
  3657.                         _streamInfos = new HybridDictionary(true);
  3658.                     }
  3659.                    
  3660.                     return _streamInfos;
  3661.                 }
  3662.             }
  3663.            
  3664.             internal bool HasStreamInfos {
  3665.                 get { return _streamInfos != null; }
  3666.             }
  3667.            
  3668.             internal void ClearStreamInfos()
  3669.             {
  3670.                 _streamInfos = null;
  3671.             }
  3672.            
  3673.             #if DBG
  3674.             // For Debugging only
  3675.             internal string[] Keys {
  3676.                 get {
  3677.                     string[] keys = new string[StreamInfos.Count];
  3678.                     StreamInfos.Keys.CopyTo(keys, 0);
  3679.                     return keys;
  3680.                 }
  3681.             }
  3682.             #endif
  3683.         }
  3684.     }
  3685. }

Developer Fusion