The Labs \ Source Viewer \ SSCLI \ System.Configuration.Internal \ InternalConfigHost

  1. //------------------------------------------------------------------------------
  2. // <copyright file="InternalConfigHost.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.Internal
  16. {
  17.     using Microsoft.Win32;
  18.     using System.Diagnostics.CodeAnalysis;
  19.     using System.CodeDom.Compiler;
  20.     using System.Configuration;
  21.     using System.IO;
  22.     using System.Reflection;
  23.     using System.Security;
  24.     using System.Security.Permissions;
  25.     using System.Security.Policy;
  26.     using System.Threading;
  27.    
  28.     //
  29.     // An IInternalConfigHost with common implementations of some file functions.
  30.     //
  31.     internal sealed class InternalConfigHost : IInternalConfigHost
  32.     {
  33.         private IInternalConfigRoot _configRoot;
  34.        
  35.         internal InternalConfigHost()
  36.         {
  37.         }
  38.        
  39.         void IInternalConfigHost.Init(IInternalConfigRoot configRoot, params object[] hostInitParams)
  40.         {
  41.             _configRoot = configRoot;
  42.         }
  43.        
  44.         void IInternalConfigHost.InitForConfiguration(ref string locationSubPath, out string configPath, out string locationConfigPath, IInternalConfigRoot configRoot, params object[] hostInitConfigurationParams)
  45.         {
  46.            
  47.             _configRoot = configRoot;
  48.             configPath = null;
  49.             locationConfigPath = null;
  50.         }
  51.        
  52.         // config path support
  53.         bool IInternalConfigHost.IsConfigRecordRequired(string configPath)
  54.         {
  55.             return true;
  56.         }
  57.        
  58.         bool IInternalConfigHost.IsInitDelayed(IInternalConfigRecord configRecord)
  59.         {
  60.             return false;
  61.         }
  62.        
  63.         void IInternalConfigHost.RequireCompleteInit(IInternalConfigRecord configRecord)
  64.         {
  65.         }
  66.        
  67.         // IsSecondaryRoot
  68.         //
  69.         // In the default there are no secondary root's
  70.         //
  71.         public bool IsSecondaryRoot(string configPath)
  72.         {
  73.             return false;
  74.         }
  75.        
  76.         // stream support
  77.         string IInternalConfigHost.GetStreamName(string configPath)
  78.         {
  79.             throw ExceptionUtil.UnexpectedError("IInternalConfigHost.GetStreamName");
  80.         }
  81.        
  82.         [FileIOPermission(SecurityAction.Assert, AllFiles = FileIOPermissionAccess.PathDiscovery)]
  83.         static internal string StaticGetStreamNameForConfigSource(string streamName, string configSource)
  84.         {
  85.             //
  86.            
  87.             if (!Path.IsPathRooted(streamName)) {
  88.                 throw ExceptionUtil.ParameterInvalid("streamName");
  89.             }
  90.            
  91.             // get the path part of the original stream
  92.             streamName = Path.GetFullPath(streamName);
  93.             string dirStream = UrlPath.GetDirectoryOrRootName(streamName);
  94.            
  95.             // combine with the new config source
  96.             string result = Path.Combine(dirStream, configSource);
  97.             result = Path.GetFullPath(result);
  98.            
  99.             // ensure the result is in or under the directory of the original source
  100.             string dirResult = UrlPath.GetDirectoryOrRootName(result);
  101.             if (!UrlPath.IsEqualOrSubdirectory(dirStream, dirResult)) {
  102.                 throw new ArgumentException(SR.GetString(SR.Config_source_not_under_config_dir, configSource));
  103.             }
  104.            
  105.             return result;
  106.         }
  107.        
  108.         string IInternalConfigHost.GetStreamNameForConfigSource(string streamName, string configSource)
  109.         {
  110.             return StaticGetStreamNameForConfigSource(streamName, configSource);
  111.         }
  112.        
  113.         static internal object StaticGetStreamVersion(string streamName)
  114.         {
  115.             bool exists = false;
  116.             long fileSize = 0;
  117.             DateTime utcCreationTime = DateTime.MinValue;
  118.             DateTime utcLastWriteTime = DateTime.MinValue;
  119.            
  120.             UnsafeNativeMethods.WIN32_FILE_ATTRIBUTE_DATA data;
  121.             if (UnsafeNativeMethods.GetFileAttributesEx(streamName, UnsafeNativeMethods.GetFileExInfoStandard, out data) && (data.fileAttributes & (int)FileAttributes.Directory) == 0) {
  122.                 exists = true;
  123.                 fileSize = (long)(uint)data.fileSizeHigh << 32 | (long)(uint)data.fileSizeLow;
  124.                 utcCreationTime = DateTime.FromFileTimeUtc(((long)data.ftCreationTimeHigh) << 32 | (long)data.ftCreationTimeLow);
  125.                 utcLastWriteTime = DateTime.FromFileTimeUtc(((long)data.ftLastWriteTimeHigh) << 32 | (long)data.ftLastWriteTimeLow);
  126.             }
  127.            
  128.             return new FileVersion(exists, fileSize, utcCreationTime, utcLastWriteTime);
  129.         }
  130.        
  131.         object IInternalConfigHost.GetStreamVersion(string streamName)
  132.         {
  133.             return StaticGetStreamVersion(streamName);
  134.         }
  135.        
  136.         // default impl treats name as a file name
  137.         // null means stream doesn't exist for this name
  138.         static internal Stream StaticOpenStreamForRead(string streamName)
  139.         {
  140.             if (string.IsNullOrEmpty(streamName)) {
  141.                 throw ExceptionUtil.UnexpectedError("InternalConfigHost::StaticOpenStreamForRead");
  142.             }
  143.            
  144.             if (!FileUtil.FileExists(streamName, true))
  145.                 return null;
  146.            
  147.             return new FileStream(streamName, FileMode.Open, FileAccess.Read, FileShare.Read);
  148.         }
  149.        
  150.         Stream IInternalConfigHost.OpenStreamForRead(string streamName)
  151.         {
  152.             return ((IInternalConfigHost)this).OpenStreamForRead(streamName, false);
  153.         }
  154.        
  155.         // Okay to suppress, since this is callable only through internal interfaces.
  156.         [SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")]
  157.         Stream IInternalConfigHost.OpenStreamForRead(string streamName, bool assertPermissions)
  158.         {
  159.             Stream stream = null;
  160.             bool revertAssert = false;
  161.            
  162.             //
  163.             // Runtime config: assert access to the file
  164.             // Designtime config: require caller to have all required permissions
  165.             //
  166.             // assertPermissions: if true, we'll assert permission. Used by ClientSettingsConfigurationHost.
  167.             //
  168.             if (assertPermissions || !_configRoot.IsDesignTime) {
  169.                 new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, streamName).Assert();
  170.                 revertAssert = true;
  171.             }
  172.            
  173.             try {
  174.                 stream = StaticOpenStreamForRead(streamName);
  175.             }
  176.             finally {
  177.                 if (revertAssert) {
  178.                     CodeAccessPermission.RevertAssert();
  179.                 }
  180.             }
  181.            
  182.             return stream;
  183.         }
  184.        
  185.         const FileAttributes InvalidAttributesForWrite = (FileAttributes.ReadOnly | FileAttributes.Hidden);
  186.        
  187.         // This method doesn't really open the streamName for write. Instead, using WriteFileContext
  188.         // it opens a stream on a temporary file created in the same directory as streamName.
  189.         //
  190.         // Parameters:
  191.         // assertPermissions - If true, then we'll assert all required permissions. Used by ClientSettingsConfigurationHost.
  192.         // to allow low-trust apps to use ClientSettingsStore.
  193.         static internal Stream StaticOpenStreamForWrite(string streamName, string templateStreamName, ref object writeContext, bool assertPermissions)
  194.         {
  195.             bool revertAssert = false;
  196.            
  197.             if (string.IsNullOrEmpty(streamName)) {
  198.                 throw new ConfigurationException(SR.GetString(SR.Config_no_stream_to_write));
  199.             }
  200.            
  201.             // Create directory if it does not exist.
  202.             // Ignore errors, allow any failure to come when trying to open the file.
  203.             string dir = Path.GetDirectoryName(streamName);
  204.             try {
  205.                 if (!Directory.Exists(dir)) {
  206.                     if (assertPermissions) {
  207.                         new FileIOPermission(PermissionState.Unrestricted).Assert();
  208.                         revertAssert = true;
  209.                     }
  210.                    
  211.                     Directory.CreateDirectory(dir);
  212.                 }
  213.             }
  214.             catch {
  215.             }
  216.             finally {
  217.                 if (revertAssert) {
  218.                     CodeAccessPermission.RevertAssert();
  219.                 }
  220.             }
  221.            
  222.             Stream stream;
  223.             WriteFileContext writeFileContext = null;
  224.             revertAssert = false;
  225.            
  226.             if (assertPermissions) {
  227.                 // If we're asked to assert permission, we will assert allAccess on the directory (instead of just the file).
  228.                 // We need to assert for the whole directory because WriteFileContext will call TempFileCollection.AddExtension,
  229.                 // which will generate a temporary file and make a AllAccess Demand on that file.
  230.                 // Since we don't know the name of the temporary file right now, we need to assert for the whole dir.
  231.                 new FileIOPermission(FileIOPermissionAccess.AllAccess, dir).Assert();
  232.                 revertAssert = true;
  233.             }
  234.            
  235.             try {
  236.                 writeFileContext = new WriteFileContext(streamName, templateStreamName);
  237.                
  238.                 if (File.Exists(streamName)) {
  239.                     FileInfo fi = new FileInfo(streamName);
  240.                     FileAttributes attrs = fi.Attributes;
  241.                     if ((int)(attrs & InvalidAttributesForWrite) != 0) {
  242.                         throw new IOException(SR.GetString(SR.Config_invalid_attributes_for_write, streamName));
  243.                     }
  244.                 }
  245.                
  246.                 try {
  247.                     stream = new FileStream(writeFileContext.TempNewFilename, FileMode.Create, FileAccess.Write, FileShare.Read);
  248.                 }
  249.                 // Wrap all exceptions so that we provide a meaningful filename - otherwise the end user
  250.                 // will just see the temporary file name, which is meaningless.
  251.                 catch (Exception e) {
  252.                     throw new ConfigurationException(SR.GetString(SR.Config_write_failed, streamName), e);
  253.                 }
  254.                 catch {
  255.                     throw new ConfigurationException(SR.GetString(SR.Config_write_failed, streamName));
  256.                 }
  257.             }
  258.             catch {
  259.                 if (writeFileContext != null) {
  260.                     writeFileContext.Complete(streamName, false);
  261.                 }
  262.                 throw;
  263.             }
  264.             finally {
  265.                 if (revertAssert) {
  266.                     CodeAccessPermission.RevertAssert();
  267.                 }
  268.             }
  269.            
  270.             writeContext = writeFileContext;
  271.             return stream;
  272.         }
  273.        
  274.        
  275.         Stream IInternalConfigHost.OpenStreamForWrite(string streamName, string templateStreamName, ref object writeContext)
  276.         {
  277.             return ((IInternalConfigHost)this).OpenStreamForWrite(streamName, templateStreamName, ref writeContext, false);
  278.         }
  279.        
  280.        
  281.         Stream IInternalConfigHost.OpenStreamForWrite(string streamName, string templateStreamName, ref object writeContext, bool assertPermissions)
  282.         {
  283.             return StaticOpenStreamForWrite(streamName, templateStreamName, ref writeContext, assertPermissions);
  284.         }
  285.        
  286.         // Parameters:
  287.         // assertPermissions - If true, then we'll assert all required permissions. Used by ClientSettingsConfigurationHost.
  288.         // to allow low-trust apps to use ClientSettingsStore.
  289.         static internal void StaticWriteCompleted(string streamName, bool success, object writeContext, bool assertPermissions)
  290.         {
  291.             WriteFileContext writeFileContext = (WriteFileContext)writeContext;
  292.             bool revertAssert = false;
  293.            
  294.             if (assertPermissions) {
  295.                 // If asked to assert permissions, we will assert allAccess on the streamName, the temporary file
  296.                 // created by WriteContext, and also the directory itself. The last one is needed because
  297.                 // WriteFileContext will call TempFileCollection.Dispose, which will remove a .tmp file it created.
  298.                 string dir = Path.GetDirectoryName(streamName);
  299.                 string[] filePaths = new string[] {streamName, writeFileContext.TempNewFilename, dir};
  300.                 FileIOPermission fileIOPerm = new FileIOPermission(FileIOPermissionAccess.AllAccess, filePaths);
  301.                 fileIOPerm.Assert();
  302.                 revertAssert = true;
  303.             }
  304.            
  305.             try {
  306.                 writeFileContext.Complete(streamName, success);
  307.             }
  308.             finally {
  309.                 if (revertAssert) {
  310.                     CodeAccessPermission.RevertAssert();
  311.                 }
  312.             }
  313.         }
  314.        
  315.         void IInternalConfigHost.WriteCompleted(string streamName, bool success, object writeContext)
  316.         {
  317.             ((IInternalConfigHost)this).WriteCompleted(streamName, success, writeContext, false);
  318.         }
  319.        
  320.         void IInternalConfigHost.WriteCompleted(string streamName, bool success, object writeContext, bool assertPermissions)
  321.         {
  322.             StaticWriteCompleted(streamName, success, writeContext, assertPermissions);
  323.         }
  324.        
  325.         static internal void StaticDeleteStream(string streamName)
  326.         {
  327.             File.Delete(streamName);
  328.         }
  329.        
  330.         void IInternalConfigHost.DeleteStream(string streamName)
  331.         {
  332.             StaticDeleteStream(streamName);
  333.         }
  334.        
  335.         // ConfigurationErrorsException support
  336.         static internal bool StaticIsFile(string streamName)
  337.         {
  338.             // We want to avoid loading configuration before machine.config
  339.             // is instantiated. Referencing the Uri class will cause config
  340.             // to be loaded, so we use Path.IsPathRooted.
  341.             return Path.IsPathRooted(streamName);
  342.         }
  343.        
  344.         bool IInternalConfigHost.IsFile(string streamName)
  345.         {
  346.             return StaticIsFile(streamName);
  347.         }
  348.        
  349.         // change notification support - runtime only
  350.         bool IInternalConfigHost.SupportsChangeNotifications {
  351.             get { return false; }
  352.         }
  353.        
  354.         object IInternalConfigHost.StartMonitoringStreamForChanges(string streamName, StreamChangeCallback callback)
  355.         {
  356.             throw ExceptionUtil.UnexpectedError("IInternalConfigHost.StartMonitoringStreamForChanges");
  357.         }
  358.        
  359.         void IInternalConfigHost.StopMonitoringStreamForChanges(string streamName, StreamChangeCallback callback)
  360.         {
  361.             throw ExceptionUtil.UnexpectedError("IInternalConfigHost.StopMonitoringStreamForChanges");
  362.         }
  363.        
  364.         // RefreshConfig support - runtime only
  365.         bool IInternalConfigHost.SupportsRefresh {
  366.             get { return false; }
  367.         }
  368.        
  369.         // path support
  370.         bool IInternalConfigHost.SupportsPath {
  371.             get { return false; }
  372.         }
  373.        
  374.         bool IInternalConfigHost.IsDefinitionAllowed(string configPath, ConfigurationAllowDefinition allowDefinition, ConfigurationAllowExeDefinition allowExeDefinition)
  375.         {
  376.             return true;
  377.         }
  378.        
  379.         void IInternalConfigHost.VerifyDefinitionAllowed(string configPath, ConfigurationAllowDefinition allowDefinition, ConfigurationAllowExeDefinition allowExeDefinition, IConfigErrorInfo errorInfo)
  380.         {
  381.         }
  382.        
  383.         // Do we support location tags?
  384.         bool IInternalConfigHost.SupportsLocation {
  385.             get { return false; }
  386.         }
  387.        
  388.         bool IInternalConfigHost.IsAboveApplication(string configPath)
  389.         {
  390.             throw ExceptionUtil.UnexpectedError("IInternalConfigHost.IsAboveApplication");
  391.         }
  392.        
  393.         string IInternalConfigHost.GetConfigPathFromLocationSubPath(string configPath, string locationSubPath)
  394.         {
  395.             throw ExceptionUtil.UnexpectedError("IInternalConfigHost.GetConfigPathFromLocationSubPath");
  396.         }
  397.        
  398.         bool IInternalConfigHost.IsLocationApplicable(string configPath)
  399.         {
  400.             throw ExceptionUtil.UnexpectedError("IInternalConfigHost.IsLocationApplicable");
  401.         }
  402.        
  403.         bool IInternalConfigHost.IsTrustedConfigPath(string configPath)
  404.         {
  405.             throw ExceptionUtil.UnexpectedError("IInternalConfigHost.IsTrustedConfigPath");
  406.         }
  407.        
  408.         // Default implementation: ensure that the caller has full trust.
  409.         bool IInternalConfigHost.IsFullTrustSectionWithoutAptcaAllowed(IInternalConfigRecord configRecord)
  410.         {
  411.             return TypeUtil.IsCallerFullTrust;
  412.         }
  413.        
  414.         // security support
  415.         void IInternalConfigHost.GetRestrictedPermissions(IInternalConfigRecord configRecord, out PermissionSet permissionSet, out bool isHostReady)
  416.         {
  417.             permissionSet = null;
  418.             isHostReady = true;
  419.         }
  420.        
  421.         IDisposable IInternalConfigHost.Impersonate()
  422.         {
  423.             return null;
  424.         }
  425.        
  426.         // prefetch support
  427.         bool IInternalConfigHost.PrefetchAll(string configPath, string streamName)
  428.         {
  429.             return false;
  430.         }
  431.        
  432.         bool IInternalConfigHost.PrefetchSection(string sectionGroupName, string sectionName)
  433.         {
  434.             return false;
  435.         }
  436.        
  437.         // context support
  438.         object IInternalConfigHost.CreateDeprecatedConfigContext(string configPath)
  439.         {
  440.             throw ExceptionUtil.UnexpectedError("IInternalConfigHost.CreateDeprecatedConfigContext");
  441.         }
  442.        
  443.         // New Context
  444.         //
  445.         object IInternalConfigHost.CreateConfigurationContext(string configPath, string locationSubPath)
  446.         {
  447.             throw ExceptionUtil.UnexpectedError("IInternalConfigHost.CreateConfigurationContext");
  448.         }
  449.        
  450.         // Encrypt/decrypt support
  451.         string IInternalConfigHost.DecryptSection(string encryptedXml, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedConfigSection)
  452.         {
  453.             return ProtectedConfigurationSection.DecryptSection(encryptedXml, protectionProvider);
  454.         }
  455.        
  456.         string IInternalConfigHost.EncryptSection(string clearTextXml, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedConfigSection)
  457.         {
  458.             return ProtectedConfigurationSection.EncryptSection(clearTextXml, protectionProvider);
  459.         }
  460.        
  461.         // Type name support
  462.         Type IInternalConfigHost.GetConfigType(string typeName, bool throwOnError)
  463.         {
  464.             return Type.GetType(typeName, throwOnError);
  465.         }
  466.        
  467.         string IInternalConfigHost.GetConfigTypeName(Type t)
  468.         {
  469.             return t.AssemblyQualifiedName;
  470.         }
  471.        
  472.         bool IInternalConfigHost.IsRemote {
  473.             get { return false; }
  474.         }
  475.        
  476.     }
  477. }

Developer Fusion