[bcl] Updates referencesource to 4.7.1
[mono-project.git] / mcs / class / referencesource / System.Configuration / System / Configuration / Internal / InternalConfigHost.cs
blob27af61e3d97de515175b2a895cdd49e7fd3cb88f
1 //------------------------------------------------------------------------------
2 // <copyright file="InternalConfigHost.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
7 namespace System.Configuration.Internal {
8 using Microsoft.Win32;
9 using System.Diagnostics.CodeAnalysis;
10 using System.CodeDom.Compiler;
11 using System.Configuration;
12 using System.IO;
13 using System.Reflection;
14 using System.Security;
15 #if !FEATURE_PAL
16 using System.Security.AccessControl;
17 #endif
18 using System.Security.Permissions;
19 using System.Security.Policy;
20 using System.Threading;
21 using System.Xml;
24 // An IInternalConfigHost with common implementations of some file functions.
26 internal sealed class InternalConfigHost : IInternalConfigHost, IInternalConfigurationBuilderHost {
27 private IInternalConfigRoot _configRoot;
29 internal InternalConfigHost() {
32 void IInternalConfigHost.Init(IInternalConfigRoot configRoot, params object[] hostInitParams) {
33 _configRoot = configRoot;
36 void IInternalConfigHost.InitForConfiguration(ref string locationSubPath, out string configPath, out string locationConfigPath,
37 IInternalConfigRoot configRoot, params object[] hostInitConfigurationParams) {
39 _configRoot = configRoot;
40 configPath = null;
41 locationConfigPath = null;
44 // config path support
45 bool IInternalConfigHost.IsConfigRecordRequired(string configPath) {
46 return true;
49 bool IInternalConfigHost.IsInitDelayed(IInternalConfigRecord configRecord) {
50 return false;
53 void IInternalConfigHost.RequireCompleteInit(IInternalConfigRecord configRecord) {
56 // IsSecondaryRoot
58 // In the default there are no secondary root's
60 public bool IsSecondaryRoot(string configPath) {
61 return false;
64 // stream support
65 string IInternalConfigHost.GetStreamName(string configPath) {
66 throw ExceptionUtil.UnexpectedError("IInternalConfigHost.GetStreamName");
69 [FileIOPermission(SecurityAction.Assert, AllFiles = FileIOPermissionAccess.PathDiscovery)]
70 [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts", Justification = "The callers don't leak this information.")]
71 static internal string StaticGetStreamNameForConfigSource(string streamName, string configSource) {
73 // Note (Microsoft 7/08/05):
74 // RemoteWebConfigurationHost also redirects GetStreamNameForConfigSource to this
75 // method, and that means streamName is referring to a path that's on the remote
76 // machine. The problem is that Path.GetFullPath will demand FileIOPermission on
77 // that file and *assume* the file is referring to one on the local machine.
78 // This can be a potential problem for RemoteWebConfigurationHost. However, since
79 // we Assert the PathDiscovery permission at this method, so this problem is handled
80 // and we're okay. But in the future if we modify this method to handle anything
81 // that assumes streamName is a local path, then RemoteWebConfigurationHost has to
82 // override GetStreamNameForConfigSource.
85 // don't allow relative paths for stream name
86 if (!Path.IsPathRooted(streamName)) {
87 throw ExceptionUtil.ParameterInvalid("streamName");
90 // get the path part of the original stream
91 streamName = Path.GetFullPath(streamName);
92 string dirStream = UrlPath.GetDirectoryOrRootName(streamName);
94 // combine with the new config source
95 string result = Path.Combine(dirStream, configSource);
96 result = Path.GetFullPath(result);
98 // ensure the result is in or under the directory of the original source
99 string dirResult = UrlPath.GetDirectoryOrRootName(result);
100 if (!UrlPath.IsEqualOrSubdirectory(dirStream, dirResult)) {
101 throw new ArgumentException(SR.GetString(SR.Config_source_not_under_config_dir, configSource));
104 return result;
107 string IInternalConfigHost.GetStreamNameForConfigSource(string streamName, string configSource) {
108 return StaticGetStreamNameForConfigSource(streamName, configSource);
111 static internal object StaticGetStreamVersion(string streamName) {
112 bool exists = false;
113 long fileSize = 0;
114 DateTime utcCreationTime = DateTime.MinValue;
115 DateTime utcLastWriteTime = DateTime.MinValue;
117 UnsafeNativeMethods.WIN32_FILE_ATTRIBUTE_DATA data;
118 if ( UnsafeNativeMethods.GetFileAttributesEx(streamName, UnsafeNativeMethods.GetFileExInfoStandard, out data) &&
119 (data.fileAttributes & (int) FileAttributes.Directory) == 0) {
120 exists = true;
121 fileSize = (long)(uint)data.fileSizeHigh << 32 | (long)(uint)data.fileSizeLow;
122 utcCreationTime = DateTime.FromFileTimeUtc(((long)data.ftCreationTimeHigh) << 32 | (long)data.ftCreationTimeLow);
123 utcLastWriteTime = DateTime.FromFileTimeUtc(((long)data.ftLastWriteTimeHigh) << 32 | (long)data.ftLastWriteTimeLow);
126 return new FileVersion(exists, fileSize, utcCreationTime, utcLastWriteTime);
129 object IInternalConfigHost.GetStreamVersion(string streamName) {
130 return StaticGetStreamVersion(streamName);
133 // default impl treats name as a file name
134 // null means stream doesn't exist for this name
135 static internal Stream StaticOpenStreamForRead(string streamName) {
136 if (string.IsNullOrEmpty(streamName)) {
137 throw ExceptionUtil.UnexpectedError("InternalConfigHost::StaticOpenStreamForRead");
140 if (!FileUtil.FileExists(streamName, true))
141 return null;
143 // consider: FileShare.Delete is not exposed by FileShare enumeration
144 return new FileStream(streamName, FileMode.Open, FileAccess.Read, FileShare.Read);
147 Stream IInternalConfigHost.OpenStreamForRead(string streamName) {
148 return ((IInternalConfigHost)this).OpenStreamForRead(streamName, false);
151 // Okay to suppress, since this is callable only through internal interfaces.
152 [SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")]
153 Stream IInternalConfigHost.OpenStreamForRead(string streamName, bool assertPermissions) {
154 Stream stream = null;
155 bool revertAssert = false;
158 // Runtime config: assert access to the file
159 // Designtime config: require caller to have all required permissions
161 // assertPermissions: if true, we'll assert permission. Used by ClientSettingsConfigurationHost.
163 if (assertPermissions || !_configRoot.IsDesignTime) {
164 new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, streamName).Assert();
165 revertAssert = true;
168 try {
169 stream = StaticOpenStreamForRead(streamName);
171 finally {
172 if (revertAssert) {
173 CodeAccessPermission.RevertAssert();
177 return stream;
180 const FileAttributes InvalidAttributesForWrite = (FileAttributes.ReadOnly | FileAttributes.Hidden);
182 // This method doesn't really open the streamName for write. Instead, using WriteFileContext
183 // it opens a stream on a temporary file created in the same directory as streamName.
185 // Parameters:
186 // assertPermissions - If true, then we'll assert all required permissions. Used by ClientSettingsConfigurationHost.
187 // to allow low-trust apps to use ClientSettingsStore.
188 static internal Stream StaticOpenStreamForWrite(string streamName, string templateStreamName, ref object writeContext, bool assertPermissions) {
189 bool revertAssert = false;
191 if (string.IsNullOrEmpty(streamName)) {
192 throw new ConfigurationErrorsException(SR.GetString(SR.Config_no_stream_to_write));
195 // Create directory if it does not exist.
196 // Ignore errors, allow any failure to come when trying to open the file.
197 string dir = Path.GetDirectoryName(streamName);
198 try {
199 if (!Directory.Exists(dir)) {
206 if (assertPermissions) {
207 new FileIOPermission(PermissionState.Unrestricted).Assert();
208 revertAssert = true;
211 Directory.CreateDirectory(dir);
214 catch {
216 finally {
217 if (revertAssert) {
218 CodeAccessPermission.RevertAssert();
222 Stream stream;
223 WriteFileContext writeFileContext = null;
224 revertAssert = false;
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;
235 try {
236 writeFileContext = new WriteFileContext(streamName, templateStreamName);
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));
246 try {
247 stream = new FileStream(writeFileContext.TempNewFilename, FileMode.Create, FileAccess.Write, FileShare.Read);
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 ConfigurationErrorsException(SR.GetString(SR.Config_write_failed, streamName), e);
255 catch {
256 if (writeFileContext != null) {
257 writeFileContext.Complete(streamName, false);
259 throw;
261 finally {
262 if (revertAssert) {
263 CodeAccessPermission.RevertAssert();
267 writeContext = writeFileContext;
268 return stream;
272 Stream IInternalConfigHost.OpenStreamForWrite(string streamName, string templateStreamName, ref object writeContext) {
273 return ((IInternalConfigHost)this).OpenStreamForWrite(streamName, templateStreamName, ref writeContext, false);
277 Stream IInternalConfigHost.OpenStreamForWrite(string streamName, string templateStreamName, ref object writeContext, bool assertPermissions) {
278 return StaticOpenStreamForWrite(streamName, templateStreamName, ref writeContext, assertPermissions);
281 // Parameters:
282 // assertPermissions - If true, then we'll assert all required permissions. Used by ClientSettingsConfigurationHost.
283 // to allow low-trust apps to use ClientSettingsStore.
284 static internal void StaticWriteCompleted(string streamName, bool success, object writeContext, bool assertPermissions) {
285 WriteFileContext writeFileContext = (WriteFileContext) writeContext;
286 bool revertAssert = false;
288 if (assertPermissions) {
289 // If asked to assert permissions, we will assert allAccess on the streamName, the temporary file
290 // created by WriteContext, and also the directory itself. The last one is needed because
291 // WriteFileContext will call TempFileCollection.Dispose, which will remove a .tmp file it created.
292 string dir = Path.GetDirectoryName(streamName);
293 string[] filePaths = new string[] {streamName, writeFileContext.TempNewFilename, dir};
294 FileIOPermission fileIOPerm = new FileIOPermission(FileIOPermissionAccess.AllAccess, AccessControlActions.View | AccessControlActions.Change, filePaths);
295 fileIOPerm.Assert();
296 revertAssert = true;
299 try {
300 writeFileContext.Complete(streamName, success);
302 finally {
303 if (revertAssert) {
304 CodeAccessPermission.RevertAssert();
309 void IInternalConfigHost.WriteCompleted(string streamName, bool success, object writeContext) {
310 ((IInternalConfigHost)this).WriteCompleted(streamName, success, writeContext, false);
313 void IInternalConfigHost.WriteCompleted(string streamName, bool success, object writeContext, bool assertPermissions) {
314 StaticWriteCompleted(streamName, success, writeContext, assertPermissions);
317 static internal void StaticDeleteStream(string streamName) {
318 File.Delete(streamName);
321 void IInternalConfigHost.DeleteStream(string streamName) {
322 StaticDeleteStream(streamName);
325 // ConfigurationErrorsException support
326 static internal bool StaticIsFile(string streamName) {
327 // We want to avoid loading configuration before machine.config
328 // is instantiated. Referencing the Uri class will cause config
329 // to be loaded, so we use Path.IsPathRooted.
330 return Path.IsPathRooted(streamName);
333 bool IInternalConfigHost.IsFile(string streamName) {
334 return StaticIsFile(streamName);
337 // change notification support - runtime only
338 bool IInternalConfigHost.SupportsChangeNotifications {
339 get {return false;}
342 object IInternalConfigHost.StartMonitoringStreamForChanges(string streamName, StreamChangeCallback callback) {
343 throw ExceptionUtil.UnexpectedError("IInternalConfigHost.StartMonitoringStreamForChanges");
346 void IInternalConfigHost.StopMonitoringStreamForChanges(string streamName, StreamChangeCallback callback) {
347 throw ExceptionUtil.UnexpectedError("IInternalConfigHost.StopMonitoringStreamForChanges");
350 // RefreshConfig support - runtime only
351 bool IInternalConfigHost.SupportsRefresh {
352 get {return false;}
355 // path support
356 bool IInternalConfigHost.SupportsPath {
357 get {return false;}
360 bool IInternalConfigHost.IsDefinitionAllowed(string configPath, ConfigurationAllowDefinition allowDefinition, ConfigurationAllowExeDefinition allowExeDefinition) {
361 return true;
364 void IInternalConfigHost.VerifyDefinitionAllowed(string configPath, ConfigurationAllowDefinition allowDefinition, ConfigurationAllowExeDefinition allowExeDefinition, IConfigErrorInfo errorInfo) {
367 // Do we support location tags?
368 bool IInternalConfigHost.SupportsLocation {
369 get {return false;}
372 bool IInternalConfigHost.IsAboveApplication(string configPath) {
373 throw ExceptionUtil.UnexpectedError("IInternalConfigHost.IsAboveApplication");
376 string IInternalConfigHost.GetConfigPathFromLocationSubPath(string configPath, string locationSubPath) {
377 throw ExceptionUtil.UnexpectedError("IInternalConfigHost.GetConfigPathFromLocationSubPath");
380 bool IInternalConfigHost.IsLocationApplicable(string configPath) {
381 throw ExceptionUtil.UnexpectedError("IInternalConfigHost.IsLocationApplicable");
384 bool IInternalConfigHost.IsTrustedConfigPath(string configPath) {
385 throw ExceptionUtil.UnexpectedError("IInternalConfigHost.IsTrustedConfigPath");
388 // Default implementation: ensure that the caller has full trust.
389 bool IInternalConfigHost.IsFullTrustSectionWithoutAptcaAllowed(IInternalConfigRecord configRecord) {
390 return TypeUtil.IsCallerFullTrust;
393 // security support
394 void IInternalConfigHost.GetRestrictedPermissions(IInternalConfigRecord configRecord, out PermissionSet permissionSet, out bool isHostReady) {
395 permissionSet = null;
396 isHostReady = true;
399 IDisposable IInternalConfigHost.Impersonate() {
400 return null;
403 // prefetch support
404 bool IInternalConfigHost.PrefetchAll(string configPath, string streamName) {
405 return false;
408 bool IInternalConfigHost.PrefetchSection(string sectionGroupName, string sectionName) {
409 return false;
412 // context support
413 object IInternalConfigHost.CreateDeprecatedConfigContext(string configPath) {
414 throw ExceptionUtil.UnexpectedError("IInternalConfigHost.CreateDeprecatedConfigContext");
417 // New Context
419 object
420 IInternalConfigHost.CreateConfigurationContext( string configPath,
421 string locationSubPath )
423 throw ExceptionUtil.UnexpectedError("IInternalConfigHost.CreateConfigurationContext");
426 // Encrypt/decrypt support
427 string IInternalConfigHost.DecryptSection(string encryptedXml, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedConfigSection) {
428 return ProtectedConfigurationSection.DecryptSection(encryptedXml, protectionProvider);
431 string IInternalConfigHost.EncryptSection(string clearTextXml, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedConfigSection) {
432 return ProtectedConfigurationSection.EncryptSection(clearTextXml, protectionProvider);
435 // Type name support
436 Type IInternalConfigHost.GetConfigType(string typeName, bool throwOnError) {
437 return Type.GetType(typeName, throwOnError);
440 string IInternalConfigHost.GetConfigTypeName(Type t) {
441 return t.AssemblyQualifiedName;
444 bool IInternalConfigHost.IsRemote {
445 get {
446 return false;
450 XmlNode IInternalConfigurationBuilderHost.ProcessRawXml(XmlNode rawXml, ConfigurationBuilder builder) {
451 if (builder != null) {
452 return builder.ProcessRawXml(rawXml);
455 return rawXml;
458 ConfigurationSection IInternalConfigurationBuilderHost.ProcessConfigurationSection(ConfigurationSection configSection, ConfigurationBuilder builder) {
459 if (builder != null) {
460 return builder.ProcessConfigurationSection(configSection);
463 return configSection;