File: Configuration\RemoteWebConfigurationHost.cs
Project: ndp\fx\src\xsp\system\Web\System.Web.csproj (System.Web)
//------------------------------------------------------------------------------
// <copyright file="RemoteWebConfigurationHost.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
 
namespace System.Web.Configuration {
    using System.Collections;
    using System.Configuration;
    using System.Configuration.Internal;
    using System.Web;
    using System.Web.Util;
    using System.Security;
    using System.IO;
    using System.Web.Hosting;
    using System.Runtime.InteropServices;
    using System.Reflection;
    using System.Collections.Specialized;
    using System.Xml;
    using System.Security.Principal;
    using System.Threading;
    using System.Globalization;
    using System.Security.Permissions;
 
    [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
    internal sealed class RemoteWebConfigurationHost : DelegatingConfigHost
    {
        private const string        KEY_MACHINE = "MACHINE";
 
        private static object       s_version = new object();
 
        private string              _Server;
        private string              _Username;
        private string              _Domain;
        private string              _Password;
        private WindowsIdentity     _Identity;
 
        private Hashtable           _PathMap;   // configPath -> configFile
        private string              _ConfigPath;
 
        /////////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////////
        internal RemoteWebConfigurationHost() {}
 
        public override void Init(IInternalConfigRoot configRoot, params object[] hostInitParams) {
            throw ExceptionUtil.UnexpectedError("RemoteWebConfigurationHost::Init");
        }
 
        public override void InitForConfiguration(ref string locationSubPath, out string configPath, out string locationConfigPath,
                        IInternalConfigRoot root, params object[] hostInitConfigurationParams) {
 
 
            WebLevel                webLevel = (WebLevel)               hostInitConfigurationParams[0];
            // ConfigurationFileMap    fileMap = (ConfigurationFileMap)    hostInitConfigurationParams[1];
            string                  path = (string)                     hostInitConfigurationParams[2];
            string                  site = (string)                     hostInitConfigurationParams[3];
 
            if (locationSubPath == null) {
                locationSubPath = (string)                              hostInitConfigurationParams[4];
            }
 
            string                  server = (string)                   hostInitConfigurationParams[5];
            string                  userName = (string)                 hostInitConfigurationParams[6];
            string                  password = (string)                 hostInitConfigurationParams[7];
            IntPtr                  tokenHandle = (IntPtr)              hostInitConfigurationParams[8];
 
            configPath = null;
            locationConfigPath = null;
 
            _Server = server;
            _Username = GetUserNameFromFullName(userName);
            _Domain = GetDomainFromFullName(userName);
            _Password = password;
            _Identity = (tokenHandle == IntPtr.Zero) ? null : new WindowsIdentity(tokenHandle); //CreateWindowsIdentity(username, domain, password, tokenHandle);
 
            _PathMap = new Hashtable(StringComparer.OrdinalIgnoreCase);
 
#if !FEATURE_PAL // FEATURE_PAL does not have WindowsImpersonationContext, COM objects
            //
            // Send the path arguments to the server for parsing,
            // and retreive the normalized paths and path mapping
            // from config paths to file paths.
            //
            string filePaths;
            try {
                WindowsImpersonationContext wiContext = (_Identity != null) ? _Identity.Impersonate() : null;
                try {
                    IRemoteWebConfigurationHostServer remoteSrv = RemoteWebConfigurationHost.CreateRemoteObject(server, _Username, _Domain, password); //(IRemoteWebConfigurationHostServer) Activator.CreateInstance(type);
                    try {
                        filePaths = remoteSrv.GetFilePaths((int) webLevel, path, site, locationSubPath);
                    } finally {
                        // Release COM objects
                        while (Marshal.ReleaseComObject(remoteSrv) > 0) {
                        }
                    }
                } finally {
                    if (wiContext != null)
                        wiContext.Undo();
                }
            }
            catch {
                // Wrap finally clause with a try to avoid exception clauses being run
                // while the thread is impersonated.
                throw;
            }
 
            if (filePaths == null) {
                throw ExceptionUtil.UnexpectedError("RemoteWebConfigurationHost::InitForConfiguration");
            }
 
            //
            // Format of filePaths:
            //      appPath < appSiteName < appSiteID < configPath < locationConfigPath [< configPath < fileName]+
            //
            string[] parts = filePaths.Split(RemoteWebConfigurationHostServer.FilePathsSeparatorParams);
 
            if (parts.Length < 7 || (parts.Length - 5) % 2 != 0) {
                throw ExceptionUtil.UnexpectedError("RemoteWebConfigurationHost::InitForConfiguration");
            }
 
            // convert empty strings to nulls
            for (int i = 0; i < parts.Length; i++) {
                if (parts[i].Length == 0) {
                    parts[i] = null;
                }
            }
 
            // get config paths
            string appPath = parts[0];
            string appSiteName = parts[1];
            string appSiteID = parts[2];
            configPath = parts[3];
            locationConfigPath = parts[4];
            _ConfigPath = configPath;
 
            // Create a WebConfigurationFileMap to be used when we later initialize our delegating WebConfigurationHost
            WebConfigurationFileMap configFileMap = new WebConfigurationFileMap();
            VirtualPath             appPathVirtualPath = VirtualPath.CreateAbsoluteAllowNull(appPath);
 
            configFileMap.Site = appSiteID;
            
            // populate the configpath->physical path mapping
            for (int i = 5; i < parts.Length; i += 2) {
                string      configPathTemp = parts[i];
                string      physicalFilePath = parts[i+1];
                
                _PathMap.Add(configPathTemp, physicalFilePath);
 
                // Update the WebConfigurationFileMap
                if (WebConfigurationHost.IsMachineConfigPath(configPathTemp)) {
                    configFileMap.MachineConfigFilename = physicalFilePath;
                }
                else {
                    string      vPathString;
                    bool        isRootApp;
 
                    if (WebConfigurationHost.IsRootWebConfigPath(configPathTemp)) {
                        vPathString = null;
                        isRootApp = false;
                    }
                    else {
                        VirtualPath vPath;
                        string      dummy;
                        
                        WebConfigurationHost.GetSiteIDAndVPathFromConfigPath(configPathTemp, out dummy, out vPath);
                        vPathString = VirtualPath.GetVirtualPathString(vPath);
                        isRootApp = (vPath == appPathVirtualPath);
                    }
 
                    configFileMap.VirtualDirectories.Add(vPathString, 
                        new VirtualDirectoryMapping(Path.GetDirectoryName(physicalFilePath), isRootApp));
                }
            }
 
#else // !FEATURE_PAL: set dummy config path
            string appPath = null;
            _ConfigPath = configPath;
#endif // !FEATURE_PAL
 
            // Delegate to a WebConfigurationHost for unhandled methods.
            WebConfigurationHost webConfigurationHost = new WebConfigurationHost();
            webConfigurationHost.Init(root, true, new UserMapPath(configFileMap, /*pathsAreLocal*/ false), null, appPath, appSiteName, appSiteID);
            Host = webConfigurationHost;
        }
 
        // config path support
        public override bool IsConfigRecordRequired(string configPath) {
            // a record is required for every part of the config path
            return configPath.Length <= _ConfigPath.Length;
        }
 
        /////////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////////
        public override string GetStreamName(string configPath)
        {
            return (string) _PathMap[configPath];
        }
 
        /////////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////////
        public override object GetStreamVersion(string streamName) {
#if FEATURE_PAL // FEATURE_PAL: singelton version
	return s_version;
#else 
            // for now, assume it is the same
            // return s_version;
            bool exists;
            long size, createDate, lastWriteDate;
            WindowsImpersonationContext wiContext = null;
 
            try {
                if (_Identity != null) {
                    wiContext = _Identity.Impersonate();
                }
 
                try {
                    //////////////////////////////////////////////////////////////////
                    // Step 3: Get the type and create the object on the remote server
                    IRemoteWebConfigurationHostServer remoteSrv = CreateRemoteObject(_Server, _Username, _Domain, _Password);
                    try {
                        //////////////////////////////////////////////////////////////////
                        // Step 4: Call the API
                        remoteSrv.GetFileDetails(streamName, out exists, out size, out createDate, out lastWriteDate);
                    }
                    finally {
                        while (Marshal.ReleaseComObject(remoteSrv) > 0) { } // release the COM object
                    }
                }
                finally {
                    if (wiContext != null) {
                        wiContext.Undo(); // revert impersonation
                    }
                }
            }
            catch {
                // Wrap finally clause with a try to avoid exception clauses being run
                // while the thread is impersonated.
                throw;
            }
 
            return new FileDetails(exists, size, DateTime.FromFileTimeUtc(createDate), DateTime.FromFileTimeUtc(lastWriteDate));
#endif // FEATURE_PAL
        }
 
        /////////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////////
        public override Stream OpenStreamForRead(string streamName) {
            RemoteWebConfigurationHostStream rcs = new RemoteWebConfigurationHostStream(false, _Server, streamName, null, _Username, _Domain, _Password, _Identity);
            if (rcs == null || rcs.Length < 1)
                return null;
            return rcs;
        }
 
        /////////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////////
        public override Stream OpenStreamForWrite(string streamName, string templateStreamName, ref object writeContext) {
            RemoteWebConfigurationHostStream rcs = new RemoteWebConfigurationHostStream(true, _Server, streamName, templateStreamName, _Username, _Domain, _Password, _Identity);
            writeContext = rcs;
            return rcs;
        }
 
        /////////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////////
        public override void DeleteStream(string StreamName)
        {
            // 
        }
 
        /////////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////////
        public override void WriteCompleted(string streamName, bool success, object writeContext)
        {
            if (success) {
                RemoteWebConfigurationHostStream rcs = (RemoteWebConfigurationHostStream)writeContext;
                rcs.FlushForWriteCompleted();
            }
        }
 
        /////////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////////
        public override bool IsFile(string StreamName)
        {
            return false;
        }
 
        /////////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////////
        public override bool PrefetchAll(string configPath, string StreamName)
        {
            return true;
        }
 
        /////////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////////
        public override bool PrefetchSection(string sectionGroupName, string sectionName)
        {
            return true;
        }
 
        /////////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////////
        public override void GetRestrictedPermissions(IInternalConfigRecord configRecord, out PermissionSet permissionSet, out bool isHostReady) {
            WebConfigurationHost.StaticGetRestrictedPermissions(configRecord, out permissionSet, out isHostReady);
        }
 
        /////////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////////
        public override bool IsRemote {
            get { return true; }
        }
        
        /////////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////////
        // Encrypt/decrypt support
        public override string DecryptSection(string encryptedXmlString, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedConfigSection) {
            return CallEncryptOrDecrypt(false, encryptedXmlString, protectionProvider, protectedConfigSection);
        }
        public override string EncryptSection(string clearTextXmlString, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedConfigSection) {
            return CallEncryptOrDecrypt(true, clearTextXmlString, protectionProvider, protectedConfigSection);
        }
 
        private string CallEncryptOrDecrypt(bool doEncrypt, string xmlString, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedConfigSection)
        {
#if !FEATURE_PAL // FEATURE_PAL has no COM objects => no encryption
            // ROTORTODO: COM Objects are not implemented.
            // CORIOLISTODO: COM Objects are not implemented.
            ProviderSettings                   ps;
            NameValueCollection                nvc;
            string  []                         paramKeys;
            string  []                         paramValues;
            string                             returnString = null;
            string                             typeName;
            WindowsImpersonationContext        wiContext = null;
 
            ////////////////////////////////////////////////////////////
            // Step 1: Create list of parameters for the protection provider
            typeName = protectionProvider.GetType().AssemblyQualifiedName;
            ps = protectedConfigSection.Providers[protectionProvider.Name];
            if (ps == null)
                throw ExceptionUtil.ParameterInvalid("protectionProvider");
 
            nvc = ps.Parameters;
            if (nvc == null)
                nvc = new NameValueCollection();
 
            paramKeys = nvc.AllKeys;
            paramValues = new string[paramKeys.Length];
            for(int iter = 0; iter<paramKeys.Length; iter++)
                paramValues[iter] = nvc[paramKeys[iter]];
 
            ////////////////////////////////////////////////////////////
            // Step 2: Set the impersonation if required
            if (_Identity != null)
                wiContext = _Identity.Impersonate();
 
            try {
                try {
                    //////////////////////////////////////////////////////////////////
                    // Step 3: Get the type and create the object on the remote server
                    IRemoteWebConfigurationHostServer remoteSrv = CreateRemoteObject(_Server, _Username, _Domain, _Password);
                    try {
                        //////////////////////////////////////////////////////////////////
                        // Step 4: Call the API
                        returnString = remoteSrv.DoEncryptOrDecrypt(doEncrypt, xmlString, protectionProvider.Name, typeName, paramKeys, paramValues);
                    } finally {
                        while (Marshal.ReleaseComObject(remoteSrv) > 0) { } // release the COM object
                    }
                } finally {
                    if (wiContext != null)
                        wiContext.Undo(); // revert impersonation
                }
            }
            catch {
            }
 
            return returnString;
#else       // !FEATURE_PAL
            throw new NotImplementedException("ROTORTODO");
#endif      // !FEATURE_PAL
        }
 
        ///////////////////////////////////////////////////////////////////////////////////////
        ///////////////////////////////////////////////////////////////////////////////////////
        private static string GetUserNameFromFullName(string fullUserName) {
            if (string.IsNullOrEmpty(fullUserName))
                return null;
            if (fullUserName.Contains("@")) {
                return fullUserName;
            }
            string[] splitted = fullUserName.Split(new char[] { '\\' });
            if (splitted.Length == 1)
                return fullUserName;
            else
                return splitted[1];
        }
        private static string GetDomainFromFullName(string fullUserName) {
            if (string.IsNullOrEmpty(fullUserName))
                return null;
            if (fullUserName.Contains("@"))
                return null;
            string[] splitted = fullUserName.Split(new char[] { '\\' });
            if (splitted.Length == 1)
                return ".";
            return splitted[0];
        }
 
        // impersonation support: create an identity from credentials
#if OLD_WAY
        private static WindowsIdentity CreateWindowsIdentity(string userName, string password, IntPtr tokenHandle) {
 
            //////////////////////////////////////////////////////////////////
            // Step 0: Most common case: check if no credentials are supplied
            if (string.IsNullOrEmpty(userName) && tokenHandle == IntPtr.Zero && string.IsNullOrEmpty(password))
                return null;
 
            //////////////////////////////////////////////////////////////////
            // Step 1: Make sure that either username & password OR token is supplied
            if ((string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password)) || (!string.IsNullOrEmpty(userName) && string.IsNullOrEmpty(password)))
                throw ExceptionUtil.ParameterNullOrEmpty("password");
 
            if (!string.IsNullOrEmpty(userName) && tokenHandle != IntPtr.Zero)
                throw ExceptionUtil.ParameterInvalid("tokenHandle");
 
            //////////////////////////////////////////////////////////////////
            // Step 2: Create token if not supplied
            if (!string.IsNullOrEmpty(userName))
                tokenHandle = CreateUserToken(userName, password);
 
            //////////////////////////////////////////////////////////////////
            // Step 3: Create a windows identity from the token
            WindowsIdentity wi = new WindowsIdentity(tokenHandle);
 
            if (!string.IsNullOrEmpty(userName) && tokenHandle != IntPtr.Zero) // Close the handle if we created it.
                UnsafeNativeMethods.CloseHandle(tokenHandle);
            return wi;
        }
 
        private static IntPtr CreateUserToken(string fullUserName, string password) {
            string userName, domain;
            if (fullUserName.Contains("@")) {
                userName = fullUserName;
                domain = null;
            } else {
                string[] splitted = fullUserName.Split(new char[] { '\\' });
                if (splitted.Length == 1) {
                    userName = fullUserName;
                    domain = ".";
                } else {
                    userName = splitted[1];
                    domain = splitted[0];
                }
            }
            //This parameter causes LogonUser to create a primary token.
            const int LOGON32_PROVIDER_DEFAULT        = 0;
            const int LOGON32_LOGON_INTERACTIVE       = 2;
            const int LOGON32_LOGON_NETWORK           = 3;
            const int LOGON32_LOGON_BATCH             = 4;
            const int LOGON32_LOGON_SERVICE           = 5;
            const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
 
            int[] Logon32Values = new int[] { LOGON32_LOGON_INTERACTIVE, LOGON32_LOGON_BATCH, LOGON32_LOGON_SERVICE, LOGON32_LOGON_NETWORK_CLEARTEXT, LOGON32_LOGON_NETWORK};
 
            IntPtr tokenHandle = IntPtr.Zero;
            int lastError = 0;
            if (UnsafeNativeMethods.LogonUser(userName, domain, password, Logon32Values[0], LOGON32_PROVIDER_DEFAULT, ref tokenHandle) != 0)
                return tokenHandle;
            lastError = Marshal.GetHRForLastWin32Error();
            for (int iter = 1; iter < Logon32Values.Length; iter++)
                if (UnsafeNativeMethods.LogonUser(userName, domain, password, Logon32Values[iter], LOGON32_PROVIDER_DEFAULT, ref tokenHandle) != 0)
                    return tokenHandle;
            Marshal.ThrowExceptionForHR(lastError);
            return IntPtr.Zero;
        }
#endif
        internal static IRemoteWebConfigurationHostServer CreateRemoteObject(string server, string username, string domain, string password) {
 
#if !FEATURE_PAL // FEATURE_PAL has no COM objects
            try {
                if (string.IsNullOrEmpty(username))
                    return CreateRemoteObjectUsingGetTypeFromCLSID(server);
                if (IntPtr.Size == 8)
                    return CreateRemoteObjectOn64BitPlatform(server, username, domain, password);
                return CreateRemoteObjectOn32BitPlatform(server, username, domain, password);
            } catch (COMException ex) {
                if ((uint)ex.ErrorCode == 0x80040154)
                    throw new Exception(SR.GetString(SR.Make_sure_remote_server_is_enabled_for_config_access));
                throw;
            }
        }
        private static IRemoteWebConfigurationHostServer CreateRemoteObjectUsingGetTypeFromCLSID(string server) {
            Type type = Type.GetTypeFromCLSID(typeof(RemoteWebConfigurationHostServer).GUID, server, true);
            return (IRemoteWebConfigurationHostServer)Activator.CreateInstance(type);
        }
 
        private static IRemoteWebConfigurationHostServer CreateRemoteObjectOn32BitPlatform(string server, string username, string domain, string password)
        {
            MULTI_QI []     amqi            = new MULTI_QI[1];
            IntPtr          guidbuf         = IntPtr.Zero;
            COAUTHINFO      ca              = null;
            IntPtr          captr           = IntPtr.Zero;
            COSERVERINFO    cs              = null;
            Guid            clsid           = typeof(RemoteWebConfigurationHostServer).GUID;
            int             hr              = 0;
            COAUTHIDENTITY  ci              = null;
            IntPtr          ciptr           = IntPtr.Zero;
 
            try {
                guidbuf = Marshal.AllocCoTaskMem(16);
                Marshal.StructureToPtr(typeof(IRemoteWebConfigurationHostServer).GUID, guidbuf, false);
                amqi[0] = new MULTI_QI(guidbuf);
 
                ci = new COAUTHIDENTITY(username, domain, password);
                ciptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(ci));
                Marshal.StructureToPtr(ci, ciptr, false);
 
                ca = new COAUTHINFO(RpcAuthent.WinNT, RpcAuthor.None, null, /*RpcLevel.Connect*/ RpcLevel.Default, RpcImpers.Impersonate, ciptr);
                captr = Marshal.AllocCoTaskMem(Marshal.SizeOf(ca));
                Marshal.StructureToPtr(ca, captr, false);
 
                cs = new COSERVERINFO(server, captr);
                hr = UnsafeNativeMethods.CoCreateInstanceEx(ref clsid, IntPtr.Zero, (int)ClsCtx.RemoteServer, cs, 1, amqi);
                if ((uint)hr == 0x80040154)
                        throw new Exception(SR.GetString(SR.Make_sure_remote_server_is_enabled_for_config_access));
                if (hr < 0)
                    Marshal.ThrowExceptionForHR(hr);
                if (amqi[0].hr < 0)
                    Marshal.ThrowExceptionForHR(amqi[0].hr);
                hr = UnsafeNativeMethods.CoSetProxyBlanket(amqi[0].pItf, RpcAuthent.WinNT, RpcAuthor.None, null, /*RpcLevel.Connect*/ RpcLevel.Default, RpcImpers.Impersonate, ciptr, 0);
                if (hr < 0)
                    Marshal.ThrowExceptionForHR(hr);
                return (IRemoteWebConfigurationHostServer)Marshal.GetObjectForIUnknown(amqi[0].pItf);
            } finally {
                if (amqi[0].pItf != IntPtr.Zero)
                {
                    Marshal.Release(amqi[0].pItf);
                    amqi[0].pItf = IntPtr.Zero;
                }
                amqi[0].piid = IntPtr.Zero;
                if (captr != IntPtr.Zero) {
                    Marshal.DestroyStructure(captr, typeof(COAUTHINFO));
                    Marshal.FreeCoTaskMem(captr);
                }
                if (ciptr != IntPtr.Zero) {
                    Marshal.DestroyStructure(ciptr, typeof(COAUTHIDENTITY));
                    Marshal.FreeCoTaskMem(ciptr);
                }
                if (guidbuf != IntPtr.Zero)
                    Marshal.FreeCoTaskMem(guidbuf);
            }
#else // !FEATURE_PAL
            throw new NotSupportedException();
#endif // !FEATURE_PAL
        }
 
        private static IRemoteWebConfigurationHostServer CreateRemoteObjectOn64BitPlatform(string server, string username, string domain, string password)
        {
            MULTI_QI_X64[]      amqi            = new MULTI_QI_X64[1];
            IntPtr              guidbuf         = IntPtr.Zero;
            COAUTHINFO_X64      ca              = null;
            IntPtr              captr           = IntPtr.Zero;
            COSERVERINFO_X64    cs              = null;
            Guid                clsid           = typeof(RemoteWebConfigurationHostServer).GUID;
            int                 hr              = 0;
            COAUTHIDENTITY_X64  ci              = null;
            IntPtr              ciptr           = IntPtr.Zero;
 
            try {
                guidbuf = Marshal.AllocCoTaskMem(16);
                Marshal.StructureToPtr(typeof(IRemoteWebConfigurationHostServer).GUID, guidbuf, false);
                amqi[0] = new MULTI_QI_X64(guidbuf);
 
                ci = new COAUTHIDENTITY_X64(username, domain, password);
                ciptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(ci));
                Marshal.StructureToPtr(ci, ciptr, false);
 
                ca = new COAUTHINFO_X64(RpcAuthent.WinNT, RpcAuthor.None, null, /*RpcLevel.Connect*/ RpcLevel.Default, RpcImpers.Impersonate, ciptr);
                captr = Marshal.AllocCoTaskMem(Marshal.SizeOf(ca));
                Marshal.StructureToPtr(ca, captr, false);
 
                cs = new COSERVERINFO_X64(server, captr);
                hr = UnsafeNativeMethods.CoCreateInstanceEx(ref clsid, IntPtr.Zero, (int)ClsCtx.RemoteServer, cs, 1, amqi);
                if ((uint)hr == 0x80040154)
                    throw new Exception(SR.GetString(SR.Make_sure_remote_server_is_enabled_for_config_access));
                if (hr < 0)
                    Marshal.ThrowExceptionForHR(hr);
                if (amqi[0].hr < 0)
                    Marshal.ThrowExceptionForHR(amqi[0].hr);
                hr = UnsafeNativeMethods.CoSetProxyBlanket(amqi[0].pItf, RpcAuthent.WinNT, RpcAuthor.None, null, /*RpcLevel.Connect*/ RpcLevel.Default, RpcImpers.Impersonate, ciptr, 0);
                if (hr < 0)
                    Marshal.ThrowExceptionForHR(hr);
                return (IRemoteWebConfigurationHostServer)Marshal.GetObjectForIUnknown(amqi[0].pItf);
            } finally {
                if (amqi[0].pItf != IntPtr.Zero) {
                    Marshal.Release(amqi[0].pItf);
                    amqi[0].pItf = IntPtr.Zero;
                }
                amqi[0].piid = IntPtr.Zero;
                if (captr != IntPtr.Zero) {
                    Marshal.DestroyStructure(captr, typeof(COAUTHINFO_X64));
                    Marshal.FreeCoTaskMem(captr);
                }
                if (ciptr != IntPtr.Zero) {
                    Marshal.DestroyStructure(ciptr, typeof(COAUTHIDENTITY_X64));
                    Marshal.FreeCoTaskMem(ciptr);
                }
                if (guidbuf != IntPtr.Zero)
                    Marshal.FreeCoTaskMem(guidbuf);
            }
        }
    }
}