/// <summary> /// Adds/updates or deletes an http(s) URL namespace reservation for a specified Windows user or group. /// </summary> /// <param name="url">The http(s) URL to modify the reservation for.</param> /// <param name="windowsAccountName">The Windows account name (user or group) to modify the reservation for.</param> /// <param name="configurationAction">The configuration action to perform (e.g. add/update or delete).</param> /// <remarks> /// This method must be called under a user context with local administrative privledges. See /// <a href="http://msdn.microsoft.com/en-us/magazine/cc163531.aspx">http://msdn.microsoft.com/en-us/magazine/cc163531.aspx</a> about why this is necessary. /// </remarks> public static void ModifyNamespaceReservation(Uri url, string windowsAccountName, HttpServerApiConfigurationAction configurationAction) { if ((false == url.Scheme.Equals(Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase)) && (false == url.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase))) { throw new ArgumentException("Invalid scheme. Only http and https are supported.", "url"); } uint retVal = NativeMethods.HttpInitialize(NativeMethods.HTTPAPI_VERSION_1, (uint)NativeMethods.HTTP_INITIALIZE_FLAG.HTTP_INITIALIZE_CONFIG, IntPtr.Zero); if ((uint)NativeMethods.HTTP_API_ErrorCode.NO_ERROR == retVal) { string urlPrefix = BuildStrongWildcardUrlPrefixFromUrl(url); var keyDesc = new NativeMethods.HTTP_SERVICE_CONFIG_URLACL_KEY(urlPrefix); string securityDescriptor = BuildGenericExecuteSecurityDescriptorFromWindowsAccount(windowsAccountName); var paramDesc = new NativeMethods.HTTP_SERVICE_CONFIG_URLACL_PARAM(securityDescriptor); var inputConfigInfoSet = new NativeMethods.HTTP_SERVICE_CONFIG_URLACL_SET { KeyDesc = keyDesc, ParamDesc = paramDesc }; IntPtr unmanagedConfigInformation = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(NativeMethods.HTTP_SERVICE_CONFIG_URLACL_SET))); Marshal.StructureToPtr(inputConfigInfoSet, unmanagedConfigInformation, false); if (configurationAction == HttpServerApiConfigurationAction.Delete) { retVal = NativeMethods.HttpDeleteServiceConfiguration( IntPtr.Zero, NativeMethods.HTTP_SERVICE_CONFIG_ID.HttpServiceConfigUrlAclInfo, unmanagedConfigInformation, Marshal.SizeOf(inputConfigInfoSet), IntPtr.Zero); if ((uint)NativeMethods.HTTP_API_ErrorCode.ERROR_FILE_NOT_FOUND == retVal) { // OK -- nothing to delete... retVal = (uint)NativeMethods.HTTP_API_ErrorCode.NO_ERROR; } } else { retVal = NativeMethods.HttpSetServiceConfiguration( IntPtr.Zero, NativeMethods.HTTP_SERVICE_CONFIG_ID.HttpServiceConfigUrlAclInfo, unmanagedConfigInformation, Marshal.SizeOf(inputConfigInfoSet), IntPtr.Zero); if ((uint)NativeMethods.HTTP_API_ErrorCode.ERROR_ALREADY_EXISTS == retVal) { retVal = NativeMethods.HttpDeleteServiceConfiguration( IntPtr.Zero, NativeMethods.HTTP_SERVICE_CONFIG_ID.HttpServiceConfigUrlAclInfo, unmanagedConfigInformation, Marshal.SizeOf(inputConfigInfoSet), IntPtr.Zero); if ((uint)NativeMethods.HTTP_API_ErrorCode.NO_ERROR == retVal) { retVal = NativeMethods.HttpSetServiceConfiguration( IntPtr.Zero, NativeMethods.HTTP_SERVICE_CONFIG_ID.HttpServiceConfigUrlAclInfo, unmanagedConfigInformation, Marshal.SizeOf(inputConfigInfoSet), IntPtr.Zero); } } } Marshal.FreeCoTaskMem(unmanagedConfigInformation); NativeMethods.HttpTerminate((uint)NativeMethods.HTTP_INITIALIZE_FLAG.HTTP_INITIALIZE_CONFIG, IntPtr.Zero); } if ((uint)NativeMethods.HTTP_API_ErrorCode.NO_ERROR != retVal) { throw Marshal.GetExceptionForHR(HResultFromWin32(retVal)); } }
/// <summary>Add/updates or deletes an SSL certificate binding for a specified IP address/port.</summary> /// <remarks> /// The provided SSL certificate data in <paramref name="sslHash"/> is added/updated/deleted in the certificate /// store specified by <paramref name="targetSslCertStoreName"/>. /// </remarks> /// <param name="address">The IP address to bind the SSL certificate to.</param> /// <param name="port">The port to bind the SSL certificate to.</param> /// <param name="sslHash">The hash of the SSL certificate to bind.</param> /// <param name="targetSslCertStoreName">The target certificate store for the SSL certificate.</param> /// <param name="configurationAction">The configuration action to perform (e.g. add/update or delete).</param> public static void ModifySslCertificateToAddressBinding(string address, int port, byte[] sslHash, StoreName targetSslCertStoreName, HttpServerApiConfigurationAction configurationAction) { uint retVal = NativeMethods.HttpInitialize(NativeMethods.HTTPAPI_VERSION_1, (uint)NativeMethods.HTTP_INITIALIZE_FLAG.HTTP_INITIALIZE_CONFIG, IntPtr.Zero); if ((uint)NativeMethods.HTTP_API_ErrorCode.NO_ERROR == retVal) { var configSslSet = new NativeMethods.HTTP_SERVICE_CONFIG_SSL_SET(); var httpServiceConfigSslKey = new NativeMethods.HTTP_SERVICE_CONFIG_SSL_KEY(); var configSslParam = new NativeMethods.HTTP_SERVICE_CONFIG_SSL_PARAM(); IPAddress ip = IPAddress.Parse(address); var addressEndPoint = new IPEndPoint(ip, port); // serialize the endpoint to a SocketAddress and create an array to hold the values. Pin the array. SocketAddress socketAddress = addressEndPoint.Serialize(); var socketBytes = new byte[socketAddress.Size]; GCHandle handleSocketAddress = GCHandle.Alloc(socketBytes, GCHandleType.Pinned); // Should copy the first 16 bytes (the SocketAddress has a 32 byte buffer, the size will only be 16, // which is what the SOCKADDR accepts for (int i = 0; i < socketAddress.Size; ++i) { socketBytes[i] = socketAddress[i]; } httpServiceConfigSslKey.pIpPort = handleSocketAddress.AddrOfPinnedObject(); GCHandle handleHash = GCHandle.Alloc(sslHash, GCHandleType.Pinned); configSslParam.AppId = Guid.NewGuid(); configSslParam.DefaultCertCheckMode = 0; configSslParam.DefaultFlags = (uint)NativeMethods.HTTP_SERVICE_CONFIG_SSL_FLAG.HTTP_SERVICE_CONFIG_SSL_FLAG_NEGOTIATE_CLIENT_CERT; configSslParam.DefaultRevocationFreshnessTime = 0; configSslParam.DefaultRevocationUrlRetrievalTimeout = 0; configSslParam.pSslCertStoreName = targetSslCertStoreName.ToString(); configSslParam.pSslHash = handleHash.AddrOfPinnedObject(); configSslParam.SslHashLength = sslHash.Length; configSslSet.ParamDesc = configSslParam; configSslSet.KeyDesc = httpServiceConfigSslKey; IntPtr unmanagedConfigInformation = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(NativeMethods.HTTP_SERVICE_CONFIG_SSL_SET))); Marshal.StructureToPtr(configSslSet, unmanagedConfigInformation, false); if (configurationAction == HttpServerApiConfigurationAction.Delete) { retVal = NativeMethods.HttpDeleteServiceConfiguration( IntPtr.Zero, NativeMethods.HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo, unmanagedConfigInformation, Marshal.SizeOf(configSslSet), IntPtr.Zero); if ((uint)NativeMethods.HTTP_API_ErrorCode.ERROR_FILE_NOT_FOUND == retVal) { // OK -- nothing to delete... retVal = (uint)NativeMethods.HTTP_API_ErrorCode.NO_ERROR; } } else { retVal = NativeMethods.HttpSetServiceConfiguration( IntPtr.Zero, NativeMethods.HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo, unmanagedConfigInformation, Marshal.SizeOf(configSslSet), IntPtr.Zero); if ((uint)NativeMethods.HTTP_API_ErrorCode.ERROR_ALREADY_EXISTS == retVal) { retVal = NativeMethods.HttpDeleteServiceConfiguration( IntPtr.Zero, NativeMethods.HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo, unmanagedConfigInformation, Marshal.SizeOf(configSslSet), IntPtr.Zero); if ((uint)NativeMethods.HTTP_API_ErrorCode.NO_ERROR == retVal) { retVal = NativeMethods.HttpSetServiceConfiguration( IntPtr.Zero, NativeMethods.HTTP_SERVICE_CONFIG_ID.HttpServiceConfigSSLCertInfo, unmanagedConfigInformation, Marshal.SizeOf(configSslSet), IntPtr.Zero); } } } Marshal.FreeCoTaskMem(unmanagedConfigInformation); NativeMethods.HttpTerminate((uint)NativeMethods.HTTP_INITIALIZE_FLAG.HTTP_INITIALIZE_CONFIG, IntPtr.Zero); } if ((uint)NativeMethods.HTTP_API_ErrorCode.NO_ERROR != retVal) { throw Marshal.GetExceptionForHR(HResultFromWin32(retVal)); } }