|
|
/*++
Copyright (c) 2001-2002 Microsoft Corporation
Module Name:
ServerConfig.c
Abstract:
Code for handling server configuration APIs.
Author:
Rajesh Sundaram (rajeshsu) 1-Nov-2001
Revision History:
Eric Stenson (ericsten) **-***-**** -- Add IP Listen support. Rajesh Sundaram (rajeshsu) 16-Apr-2002 -- Add URL ACL support.
--*/
#include "precomp.h"
#include <stdio.h>
#include <search.h>
#include <Shlwapi.h>
#include <sddl.h>
#define HTTP_PARAM_KEY \
L"System\\CurrentControlSet\\Services\\HTTP\\Parameters" #define URLACL_REGISTRY_KEY HTTP_PARAM_KEY L"\\UrlAclInfo"
//
// Keys for synchronizing registry access.
//
#define HTTP_SYNCHRONIZE_KEY HTTP_PARAM_KEY L"\\Synchronize"
#define SSL_REGISTRY_KEY_SYNCHRONIZE L"SSL"
#define IP_REGISTRY_KEY_SYNCHRONIZE L"IPListen"
HKEY g_SynchronizeRegistryHandle;
//
// SSL Config
//
#define SSL_REGISTRY_KEY HTTP_PARAM_KEY L"\\SslBindingInfo"
#define SSL_CERT_HASH L"SslCertHash"
#define SSL_APPID L"AppId"
#define SSL_CERT_STORE_NAME L"SslCertStoreName"
#define SSL_CERT_CHECK_MODE L"DefaultSslCertCheckMode"
#define SSL_REVOCATION_FRESHNESS_TIME L"DefaultSslRevocationFreshnessTime"
#define SSL_REVOCATION_URL_RETRIEVAL_TIMEOUT \
L"DefaultSslRevocationUrlRetrievalTimeout" #define SSL_CTL_IDENTIFIER L"DefaultSslCtlIdentifier"
#define SSL_CTL_STORENAME L"DefaultSslCtlStoreName"
#define SSL_FLAGS L"DefaultFlags"
HKEY g_SslRegistryHandle;
HANDLE g_ServiceControlChannelHandle; HKEY g_UrlAclRegistryHandle;
//
// IP Listen Only Config
//
#define IP_LISTEN_ONLY_VALUE L"ListenOnlyList"
//
// Macros.
//
// NOTE: REG_QUERY_VALUE will not raise an exception for ERROR_FILE_NOT_FOUND
// because not all parameters are mandatory (e.g. SslCtlIdentifier).
#define REG_QUERY_VALUE(Status, Handle, Value, pBuffer, BytesAvail) \
{ \ (Status) = RegQueryValueEx( \ (Handle), \ (Value), \ 0, \ NULL, \ (PVOID)(pBuffer), \ &(BytesAvail) \ ); \ \ if((Status) != NO_ERROR && (Status) != ERROR_FILE_NOT_FOUND) \ { \ __leave; \ } \ }
#define ADVANCE_BUFFER(Status, pSrc, lSrc, pBuffer, BytesAvail, pWritten) \
{ \ if((Status) == NO_ERROR) \ { \ (pSrc) = (PVOID)(pBuffer); \ (lSrc) = (BytesAvail); \ *(pWritten) += ALIGN_UP((BytesAvail), PVOID); \ (pBuffer) += ALIGN_UP((BytesAvail), PVOID); \ } \ }
#define REG_SET_VALUE(Status, Handle, Value, Type, pBuffer, Length) \
{ \ (Status) = RegSetValueEx((Handle), \ (Value), \ 0, \ (Type), \ (PVOID)(pBuffer), \ (Length) \ ); \ if((Status) != ERROR_SUCCESS) \ { \ __leave; \ } \ }
#define REG_SET_SZ(Status, Handle, Value, pBuffer) \
{ \ if((pBuffer)) \ { \ REG_SET_VALUE((Status), \ (Handle), \ (Value), \ REG_SZ, \ (pBuffer), \ (ULONG)(wcslen((pBuffer)) + 1) * sizeof(WCHAR) \ ); \ } \ }
//
// Internal Functions.
//
DWORD ComputeSockAddrLength( IN PSOCKADDR pSockAddr ) { DWORD dwLength;
switch(pSockAddr->sa_family) { case AF_INET: dwLength = sizeof(SOCKADDR_IN); break;
case AF_INET6: dwLength = sizeof(SOCKADDR_IN6); break;
default: dwLength = 0; break; }
return dwLength; }
/***************************************************************************++
Routine Description:
Performs initialization of the configuration globals.
Arguments:
None.
Return Value:
Success/Failure.
--***************************************************************************/
ULONG InitializeConfigurationGlobals() { ULONG Status, Disposition; WORD wVersionRequested; WSADATA wsaData;
//
// Init to NULL
//
g_SynchronizeRegistryHandle = NULL; g_SslRegistryHandle = NULL;
wVersionRequested = MAKEWORD( 2, 2 );
if(WSAStartup( wVersionRequested, &wsaData ) != 0) { return GetLastError(); }
//
// Create the SSL registry key.
//
Status = RegCreateKeyEx( HKEY_LOCAL_MACHINE, SSL_REGISTRY_KEY, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &g_SslRegistryHandle, &Disposition );
if(NO_ERROR != Status) { TerminateConfigurationGlobals(); return Status; }
//
// Create the Synchronize registry key.
//
Status = RegCreateKeyEx( HKEY_LOCAL_MACHINE, HTTP_SYNCHRONIZE_KEY, 0, NULL, REG_OPTION_VOLATILE, KEY_READ | KEY_WRITE, NULL, &g_SynchronizeRegistryHandle, &Disposition );
if(NO_ERROR != Status) { TerminateConfigurationGlobals(); return Status; }
//
// URL ACL registry key.
//
Status = RegCreateKeyEx( HKEY_LOCAL_MACHINE, URLACL_REGISTRY_KEY, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &g_UrlAclRegistryHandle, &Disposition );
if(NO_ERROR != Status) { TerminateConfigurationGlobals(); return Status; }
//
// Control channel for URL ACL.
//
Status = OpenAndEnableControlChannel(&g_ServiceControlChannelHandle);
if(NO_ERROR != Status) { TerminateConfigurationGlobals(); return Status; }
return Status; }
/***************************************************************************++
Routine Description:
Performs termination of the configuration globals.
Arguments:
None.
Return Value:
None. --***************************************************************************/
VOID TerminateConfigurationGlobals(VOID) { WSACleanup();
if(g_SynchronizeRegistryHandle) { RegCloseKey(g_SynchronizeRegistryHandle); g_SynchronizeRegistryHandle = NULL; }
if(g_SslRegistryHandle) { RegCloseKey(g_SslRegistryHandle); g_SslRegistryHandle = NULL; }
if(g_UrlAclRegistryHandle) { RegCloseKey(g_UrlAclRegistryHandle); g_UrlAclRegistryHandle = NULL; }
if(g_ServiceControlChannelHandle) { CloseHandle(g_ServiceControlChannelHandle); g_ServiceControlChannelHandle = NULL; } }
/***************************************************************************++
Routine Description:
Acquires a process wide mutex (for interprocess synchronization). We could make this into a MRSW lock, but that's not going to help us a whole lot since Set/Delete are rare operations & there is only one reader.
Arguments:
None.
Return Value:
None. --***************************************************************************/
_inline DWORD AcquireHttpRegistryMutex( PWCHAR pKey ) { DWORD Status; DWORD Disposition; HKEY SubKeyHandle; HANDLE hEvent = NULL;
for(;;) { Status = RegCreateKeyEx( g_SynchronizeRegistryHandle, pKey, 0, NULL, REG_OPTION_VOLATILE, KEY_READ | KEY_WRITE, NULL, &SubKeyHandle, &Disposition );
if(Status != ERROR_SUCCESS) { return Status; }
RegCloseKey(SubKeyHandle);
if(Disposition == REG_OPENED_EXISTING_KEY) { // Some other thread has acquired the lock. We'll wait till we
// own the lock. In order to do this, we register for change
// notification for g_SynchronizeRegistryHandle (i.e the owner
// thread deletes the HTTP_SYNCHRONIZE_KEY key).
//
// Now, there are two issues here. There could be a race where
// the key gets deleted just before we call RegNotifyChangeKeyValue
// In order to protect from this, we add a timeout to the Wait
// routine.
//
// Secondly, we could get woken when the app changes other parts
// of the registry under g_SynchronizeRegistryHandle. However,
// since Sets & deletes are not common operations, this is OK.
//
// We don't care about the return value of RegNotifyChangeKeyValue
// If it fails, we'll just wait till the timeout expires.
//
if(!hEvent) { hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if(!hEvent) { return GetLastError(); } }
RegNotifyChangeKeyValue( g_SynchronizeRegistryHandle, TRUE, REG_NOTIFY_CHANGE_NAME, hEvent, TRUE );
if(WaitForSingleObject( hEvent, 10000 // 10 seconds.
) == WAIT_FAILED) { CloseHandle(hEvent); return GetLastError(); } } else { // We've acquired the lock.
break; } }
if(hEvent) { CloseHandle(hEvent); }
return ERROR_SUCCESS; }
/***************************************************************************++
Routine Description:
Releases a process wide mutex (for interprocess synchronization)
Arguments:
None.
Return Value:
None. --***************************************************************************/ _inline VOID ReleaseHttpRegistryMutex( IN PWCHAR pKey ) { RegDeleteKey(g_SynchronizeRegistryHandle, pKey); }
/***************************************************************************++
Routine Description:
Internal function that sets SSL configuration.
Arguments: pConfigInformation - pointer to HTTP_SERVICE_CONFIG_SSL_SET ConfigInformationLength - length of input buffer.
Return Value:
Win32 error code. --***************************************************************************/ ULONG SetSslServiceConfiguration( IN PVOID pConfigInformation, IN ULONG ConfigInformationLength ) { ULONG Status = NO_ERROR; HKEY SubKeyHandle = NULL; PHTTP_SERVICE_CONFIG_SSL_SET pSslConfig; WCHAR IpAddrBuff[MAX_PATH]; DWORD dwIpAddrLength, Disposition; DWORD dwSockAddrLength; BOOLEAN bDeleteCreatedKey = FALSE;
//
// Parameter validation.
//
pSslConfig = (PHTTP_SERVICE_CONFIG_SSL_SET) pConfigInformation; if(!pSslConfig || ConfigInformationLength != sizeof(HTTP_SERVICE_CONFIG_SSL_SET)) { return ERROR_INVALID_PARAMETER; }
// acquire the mutex to prevent other processes from reading this
// since we are acquiring a machine wide mutex, we need to ensure
// that we release the mutex if the app passes bad parameters.
// Acquire the mutex.
__try { if((Status = AcquireHttpRegistryMutex(SSL_REGISTRY_KEY_SYNCHRONIZE)) != NO_ERROR) { __leave; }
// Convert the address into a string.
//
dwIpAddrLength = MAX_PATH;
dwSockAddrLength = ComputeSockAddrLength(pSslConfig->KeyDesc.pIpPort);
if(dwSockAddrLength == 0) { Status = ERROR_NOT_SUPPORTED; __leave; }
Status = WSAAddressToString( pSslConfig->KeyDesc.pIpPort, dwSockAddrLength, NULL, IpAddrBuff, &dwIpAddrLength );
if(Status != NO_ERROR) { __leave; }
// First, we try to create the IP:port. If this already exists,
// we'll bail.
Status = RegCreateKeyEx( g_SslRegistryHandle, IpAddrBuff, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &SubKeyHandle, &Disposition );
if(Status != ERROR_SUCCESS) { __leave; }
if(Disposition == REG_OPENED_EXISTING_KEY) { Status = ERROR_ALREADY_EXISTS; __leave; }
//
// Any errors from now onwards should delete the key.
//
bDeleteCreatedKey = TRUE;
//
// REG_BINARY: Cert Hash
//
REG_SET_VALUE(Status, SubKeyHandle, SSL_CERT_HASH, REG_BINARY, pSslConfig->ParamDesc.pSslHash, pSslConfig->ParamDesc.SslHashLength );
//
// REG_BINARY: AppID
//
REG_SET_VALUE(Status, SubKeyHandle, SSL_APPID, REG_BINARY, &pSslConfig->ParamDesc.AppId, sizeof(pSslConfig->ParamDesc.AppId) );
//
// REG_DWORD: The Cert Check Mode.
//
REG_SET_VALUE(Status, SubKeyHandle, SSL_CERT_CHECK_MODE, REG_DWORD, &pSslConfig->ParamDesc.DefaultCertCheckMode, sizeof(pSslConfig->ParamDesc.DefaultCertCheckMode) );
//
// REG_DWORD: The revocation freshness time
//
REG_SET_VALUE( Status, SubKeyHandle, SSL_REVOCATION_FRESHNESS_TIME, REG_DWORD, &pSslConfig->ParamDesc.DefaultRevocationFreshnessTime, sizeof(pSslConfig->ParamDesc.DefaultRevocationFreshnessTime) );
//
// REG_DWORD: The URL Retrieval Timeout
//
REG_SET_VALUE( Status, SubKeyHandle, SSL_REVOCATION_URL_RETRIEVAL_TIMEOUT, REG_DWORD, &pSslConfig->ParamDesc.DefaultRevocationUrlRetrievalTimeout, sizeof(pSslConfig->ParamDesc.DefaultRevocationUrlRetrievalTimeout) );
//
// REG_DWORD: SSL Flags
//
REG_SET_VALUE(Status, SubKeyHandle, SSL_FLAGS, REG_DWORD, &pSslConfig->ParamDesc.DefaultFlags, sizeof(pSslConfig->ParamDesc.DefaultFlags) );
//
// REG_SZ: The Cert Store name.
//
REG_SET_SZ(Status, SubKeyHandle, SSL_CERT_STORE_NAME, pSslConfig->ParamDesc.pSslCertStoreName );
//
// REG_SZ: The CTL Identifier
//
REG_SET_SZ(Status, SubKeyHandle, SSL_CTL_IDENTIFIER, pSslConfig->ParamDesc.pDefaultSslCtlIdentifier );
//
// REG_SZ: The CTL Store name.
//
REG_SET_SZ(Status, SubKeyHandle, SSL_CTL_STORENAME, pSslConfig->ParamDesc.pDefaultSslCtlStoreName );
} __finally {
if(SubKeyHandle) { RegCloseKey(SubKeyHandle); SubKeyHandle = NULL; }
if(Status != NO_ERROR && bDeleteCreatedKey) { // Recursively delete subkeys & all descendents.
SHDeleteKey(g_SslRegistryHandle, IpAddrBuff); }
// Free the mutex.
//
ReleaseHttpRegistryMutex(SSL_REGISTRY_KEY_SYNCHRONIZE); }
return Status; }
/***************************************************************************++
Routine Description:
Internal function that deletes SSL configuration.
Arguments: pConfigInformation - pointer to HTTP_SERVICE_CONFIG_SSL_SET ConfigInformationLength - length of input buffer.
Return Value:
Win32 error code. --***************************************************************************/ ULONG DeleteSslServiceConfiguration( IN PVOID pConfigInformation, IN ULONG ConfigInformationLength ) { ULONG Status = NO_ERROR; PHTTP_SERVICE_CONFIG_SSL_SET pSslConfig; WCHAR IpAddrBuff[MAX_PATH]; DWORD dwIpAddrLength; DWORD dwSockAddrLength;
//
// Parameter validation.
//
pSslConfig = (PHTTP_SERVICE_CONFIG_SSL_SET) pConfigInformation; if(!pSslConfig || ConfigInformationLength != sizeof(HTTP_SERVICE_CONFIG_SSL_SET)) { return ERROR_INVALID_PARAMETER; }
// acquire the mutex to prevent other processes from reading this
// since we are acquiring a machine wide mutex, we need to ensure
// that we release the mutex if the app passes bad parameters.
__try { if((Status = AcquireHttpRegistryMutex(SSL_REGISTRY_KEY_SYNCHRONIZE)) != NO_ERROR) { __leave; }
// Convert the address into a string.
//
dwIpAddrLength = MAX_PATH; dwSockAddrLength = ComputeSockAddrLength(pSslConfig->KeyDesc.pIpPort);
if(dwSockAddrLength == 0) { Status = ERROR_NOT_SUPPORTED; __leave; }
Status = WSAAddressToString( pSslConfig->KeyDesc.pIpPort, dwSockAddrLength, NULL, IpAddrBuff, &dwIpAddrLength );
if(Status != NO_ERROR) { __leave; }
//
// Recursively delete all subkeys under this.
//
Status = SHDeleteKey(g_SslRegistryHandle, IpAddrBuff);
} __finally { // Free the mutex.
//
ReleaseHttpRegistryMutex(SSL_REGISTRY_KEY_SYNCHRONIZE); }
return Status; }
/***************************************************************************++
Routine Description:
Internal function that queries SSL configuration for a exact match. This routine is called with the SSL Mutex acquired.
Arguments: pInput - pointer to HTTP_SERVICE_CONFIG_SSL_QUERY InputLength - length of input buffer. pOutput - pointer to output buffer OutputLength - sizeof output buffer pReturnLength - Bytes written/needed.
Return Value:
Win32 error code. --***************************************************************************/ ULONG QuerySslServiceConfigurationExact( IN PWCHAR lpszIpAddrBuff, IN PCHAR pBuffer, OUT PULONG pReturnLength, IN ULONG BytesAvailable ) { DWORD Status = NO_ERROR; HKEY SubKeyHandle = NULL; DWORD dwSockAddrLength = sizeof(SOCKADDR_STORAGE); DWORD BytesRequired, ValueCount, MaxValueLength; PHTTP_SERVICE_CONFIG_SSL_SET pSslSet;
//
// Validate output parameters.
//
pSslSet = (PHTTP_SERVICE_CONFIG_SSL_SET) pBuffer;
Status = RegOpenKeyEx( g_SslRegistryHandle, lpszIpAddrBuff, 0, KEY_READ | KEY_WRITE, &SubKeyHandle );
if(Status != ERROR_SUCCESS) { return Status; }
__try { Status = RegQueryInfoKey( SubKeyHandle, NULL, // class buffer
0, // sizeof class buffer
NULL, // reserved
NULL, // # of subkeys
NULL, // longest subkey name
NULL, // longest class string
&ValueCount, // # of value entries.
NULL, // longest value name
&MaxValueLength, // longest value data
NULL, // security descriptor length
NULL // last write time
); if(Status != ERROR_SUCCESS) { __leave; }
//
// MaxValueLength does not include the size of the NULL terminator,
// so let's compensate for that.
//
MaxValueLength += sizeof(WCHAR);
//
// We'll assume that all the Value's under SubKey are of MaxValueLength
// that keeps things a lot simpler.
//
BytesRequired = dwSockAddrLength + sizeof(HTTP_SERVICE_CONFIG_SSL_SET) + (ValueCount * ALIGN_UP(MaxValueLength, PVOID));
if(pBuffer == NULL || BytesAvailable < BytesRequired) { *pReturnLength = BytesRequired; Status = ERROR_INSUFFICIENT_BUFFER; __leave; }
ZeroMemory(pSslSet, sizeof(HTTP_SERVICE_CONFIG_SSL_SET)); pBuffer += sizeof(HTTP_SERVICE_CONFIG_SSL_SET); *pReturnLength = sizeof(HTTP_SERVICE_CONFIG_SSL_SET);
//
// Set up SOCKET_ADDRESS.
//
pSslSet->KeyDesc.pIpPort = (LPSOCKADDR)pBuffer;
// Convert the IP address into SOCKADDR
//
// First, we try v4
Status = WSAStringToAddress( lpszIpAddrBuff, AF_INET, NULL, pSslSet->KeyDesc.pIpPort, (LPINT) &dwSockAddrLength );
if(Status != NO_ERROR) { dwSockAddrLength = sizeof(SOCKADDR_STORAGE);
Status = WSAStringToAddress( lpszIpAddrBuff, AF_INET6, NULL, pSslSet->KeyDesc.pIpPort, (LPINT)&dwSockAddrLength );
if(Status != NO_ERROR) { Status = GetLastError(); __leave; } }
pBuffer += sizeof(SOCKADDR_STORAGE); *pReturnLength += sizeof(SOCKADDR_STORAGE);
//
// Query SSL HASH.
//
BytesAvailable = MaxValueLength;
REG_QUERY_VALUE(Status, SubKeyHandle, SSL_CERT_HASH, pBuffer, BytesAvailable );
ADVANCE_BUFFER(Status, pSslSet->ParamDesc.pSslHash, pSslSet->ParamDesc.SslHashLength, pBuffer, BytesAvailable, pReturnLength );
//
// Query pSslCertStoreName
//
BytesAvailable = MaxValueLength;
REG_QUERY_VALUE(Status, SubKeyHandle, SSL_CERT_STORE_NAME, pBuffer, BytesAvailable );
ADVANCE_BUFFER(Status, pSslSet->ParamDesc.pSslCertStoreName, BytesAvailable, pBuffer, BytesAvailable, pReturnLength );
//
// Query pDefaultSslCtlIdentifier
//
BytesAvailable = MaxValueLength;
REG_QUERY_VALUE(Status, SubKeyHandle, SSL_CTL_IDENTIFIER, pBuffer, BytesAvailable );
ADVANCE_BUFFER(Status, pSslSet->ParamDesc.pDefaultSslCtlIdentifier, BytesAvailable, pBuffer, BytesAvailable, pReturnLength ); //
// Query pDefaultSslCtlStoreName
//
BytesAvailable = MaxValueLength; REG_QUERY_VALUE(Status, SubKeyHandle, SSL_CTL_STORENAME, pBuffer, BytesAvailable );
ADVANCE_BUFFER(Status, pSslSet->ParamDesc.pDefaultSslCtlStoreName, BytesAvailable, pBuffer, BytesAvailable, pReturnLength );
//
// NOTE: when querying DWORDs, we don't have to call ADVANCE_BUFFER
// as we use the space provided in the structure itself.
//
//
// Query DefaultCertCheckMode
//
BytesAvailable = sizeof(pSslSet->ParamDesc.DefaultCertCheckMode);
REG_QUERY_VALUE(Status, SubKeyHandle, SSL_CERT_CHECK_MODE, &pSslSet->ParamDesc.DefaultCertCheckMode, BytesAvailable );
//
// Query RevocationFreshnessTime
//
BytesAvailable = sizeof(pSslSet->ParamDesc.DefaultRevocationFreshnessTime); REG_QUERY_VALUE(Status, SubKeyHandle, SSL_REVOCATION_FRESHNESS_TIME, &pSslSet->ParamDesc.DefaultRevocationFreshnessTime, BytesAvailable );
//
// Query RevocationUrlRetrievalTimeout
//
BytesAvailable = sizeof(pSslSet->ParamDesc.DefaultRevocationUrlRetrievalTimeout); REG_QUERY_VALUE( Status, SubKeyHandle, SSL_REVOCATION_URL_RETRIEVAL_TIMEOUT, &pSslSet->ParamDesc.DefaultRevocationUrlRetrievalTimeout, BytesAvailable );
//
// Query DefaultFlags
//
BytesAvailable = sizeof(pSslSet->ParamDesc.DefaultFlags); REG_QUERY_VALUE(Status, SubKeyHandle, SSL_FLAGS, &pSslSet->ParamDesc.DefaultFlags, BytesAvailable );
//
// Query the AppId.
//
BytesAvailable = sizeof(GUID); REG_QUERY_VALUE(Status, SubKeyHandle, SSL_APPID, &pSslSet->ParamDesc.AppId, BytesAvailable );
//
// If the last REG_QUERY_VALUE returned an error, we'll consume it.
// Some of these registry parameters are optional so we don't want to
// fail the API with FILE_NOT_FOUND.
//
Status = NO_ERROR; } __finally { if(SubKeyHandle) { RegCloseKey(SubKeyHandle); } }
return Status; }
/***************************************************************************++
Routine Description:
Internal function that queries SSL configuration.
Arguments: pInput - pointer to HTTP_SERVICE_CONFIG_SSL_QUERY InputLength - length of input buffer. pOutput - pointer to output buffer OutputLength - sizeof output buffer pReturnLength - Bytes written/needed.
Return Value:
Win32 error code. --***************************************************************************/ ULONG QuerySslServiceConfiguration( IN PVOID pInputConfigInfo, IN ULONG InputLength, IN PVOID pOutput, IN ULONG OutputLength, OUT PULONG pReturnLength ) { ULONG Status = NO_ERROR; PHTTP_SERVICE_CONFIG_SSL_QUERY pSslQuery; WCHAR IpAddrBuff[MAX_PATH]; DWORD dwSize, dwIndex; FILETIME FileTime; DWORD dwIpAddrLength; DWORD dwSockAddrLength;
pSslQuery = (PHTTP_SERVICE_CONFIG_SSL_QUERY) pInputConfigInfo;
//
// Validate input parameters.
//
if(pSslQuery == NULL || InputLength != sizeof(HTTP_SERVICE_CONFIG_SSL_QUERY)) { return ERROR_INVALID_PARAMETER; }
__try { if((Status = AcquireHttpRegistryMutex(SSL_REGISTRY_KEY_SYNCHRONIZE)) != NO_ERROR) { __leave; }
switch(pSslQuery->QueryDesc) { case HttpServiceConfigQueryExact: { //
// Convert the address into a string.
//
dwIpAddrLength = MAX_PATH;
dwSockAddrLength = ComputeSockAddrLength( pSslQuery->KeyDesc.pIpPort );
if(dwSockAddrLength == 0) { Status = ERROR_NOT_SUPPORTED; __leave; }
Status = WSAAddressToString( pSslQuery->KeyDesc.pIpPort, dwSockAddrLength, NULL, IpAddrBuff, &dwIpAddrLength ); if(Status != NO_ERROR) { break; }
Status = QuerySslServiceConfigurationExact( IpAddrBuff, pOutput, pReturnLength, OutputLength );
break; }
case HttpServiceConfigQueryNext: { dwIndex = pSslQuery->dwToken; dwSize = MAX_PATH;
Status = RegEnumKeyEx( g_SslRegistryHandle, dwIndex, IpAddrBuff, &dwSize, NULL, NULL, NULL, &FileTime );
if(Status != NO_ERROR) { break; }
Status = QuerySslServiceConfigurationExact( IpAddrBuff, pOutput, pReturnLength, OutputLength );
if(Status != NO_ERROR) { break; }
break; }
default: { Status = ERROR_INVALID_PARAMETER; break; } }
} __finally { // Free the mutex.
//
ReleaseHttpRegistryMutex(SSL_REGISTRY_KEY_SYNCHRONIZE); }
return Status; }
//
// IP Listen-Only List
//
/***************************************************************************++
Routine Description:
Internal function that adds an address to the IP Listen-Only list.
Arguments: pConfigInformation - pointer to HTTP_SERVICE_CONFIG_IP_LISTEN_PARAM ConfigInformationLength - length of input buffer.
Return Value:
Win32 error code. --***************************************************************************/ ULONG SetIpListenServiceConfiguration( IN PVOID pConfigInformation, IN ULONG ConfigInformationLength ) { DWORD Status = NO_ERROR; HKEY SubKeyHandle = NULL; WCHAR IpAddrBuff[MAX_PATH+1]; DWORD dwIpAddrLength; DWORD dwValueSize; DWORD dwType; PWSTR pNewValue = NULL; DWORD dwNewValueSize; DWORD AddrCount; DWORD i; PWSTR pTmp; PWSTR pTempBuffer = NULL; PWSTR *AddrArray = NULL; PHTTP_SERVICE_CONFIG_IP_LISTEN_PARAM pIpListenParam;
//
// Validate params.
//
if ( !pConfigInformation || ConfigInformationLength != sizeof(HTTP_SERVICE_CONFIG_IP_LISTEN_PARAM) ) { return ERROR_INVALID_PARAMETER; }
pIpListenParam = (PHTTP_SERVICE_CONFIG_IP_LISTEN_PARAM) pConfigInformation;
if ( !pIpListenParam->AddrLength || !pIpListenParam->pAddress ) { return ERROR_INVALID_PARAMETER; }
__try { if((Status = AcquireHttpRegistryMutex(IP_REGISTRY_KEY_SYNCHRONIZE)) != NO_ERROR) { __leave; }
//
// Convert the address into a string.
//
dwIpAddrLength = MAX_PATH; Status = WSAAddressToString( pIpListenParam->pAddress, pIpListenParam->AddrLength, NULL, IpAddrBuff, &dwIpAddrLength // in chars, including NULL.
); if ( SOCKET_ERROR == Status ) { Status = WSAGetLastError(); __leave; } // finesse: add double null now
IpAddrBuff[dwIpAddrLength] = L'\0'; //
// open HTTP parameters reg key
//
Status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, HTTP_PARAM_KEY, 0, KEY_READ | KEY_WRITE, &SubKeyHandle ); if ( Status != ERROR_SUCCESS ) { // CODEWORK: add tracing.
__leave; } ASSERT(SubKeyHandle); //
// query existing value
//
dwValueSize = 0; Status = RegQueryValueEx( SubKeyHandle, // handle to key
IP_LISTEN_ONLY_VALUE, // value name
NULL, // reserved
&dwType, // type buffer
NULL, // data buffer
&dwValueSize // size of data buffer (bytes)
); if ( ERROR_SUCCESS == Status ) { // There's an existing value!
if (REG_MULTI_SZ != dwType) { // type mismatch. fail.
Status = ERROR_DATATYPE_MISMATCH; __leave; } // alloc local buffer to hold existing value plus new
// address (and its NULL)
dwNewValueSize = dwValueSize + (sizeof(WCHAR) * dwIpAddrLength); pNewValue = ALLOC_MEM(dwNewValueSize); if (!pNewValue) { Status = ERROR_NOT_ENOUGH_MEMORY; __leave; } // zero-out the block (so we don't have to worry about the
// double-null at the end)
ZeroMemory(pNewValue, dwNewValueSize); // read existing value into local buffer
Status = RegQueryValueEx( SubKeyHandle, // handle to key
IP_LISTEN_ONLY_VALUE, // value name
NULL, // reserved
&dwType, // type buffer
(LPBYTE)pNewValue, // data buffer
&dwValueSize // size of data buffer (bytes)
); if ( ERROR_SUCCESS != Status ) { __leave; } if (REG_MULTI_SZ != dwType) { // type mismatch. fail.
Status = ERROR_DATATYPE_MISMATCH; __leave; } // count how many strings there are
pTmp = pNewValue; AddrCount = 0; while ( *pTmp ) { // check if the new addr is a dup
if ( (wcslen(pTmp) == (dwIpAddrLength - 1)) && (0 == wcsncmp(pTmp, IpAddrBuff, dwIpAddrLength-1)) ) { // Dup found; bail out
Status = ERROR_ALREADY_EXISTS; __leave; } // advance to next multi-sz string
pTmp += ( wcslen(pTmp) + 1 ); AddrCount ++; } // Add new address to end of the list
// finesse: leverage the fact that the buffer is big enough, and
// we've already double-nulled the end of the new address (hence
// the dwIpAddrLength+1)
memcpy( pTmp, IpAddrBuff, (sizeof(WCHAR) * (dwIpAddrLength+1)) ); AddrCount++; // alloc array of pointers for quicksort
AddrArray = ALLOC_MEM( AddrCount * sizeof(PWSTR) ); if ( !AddrArray ) { Status = ERROR_NOT_ENOUGH_MEMORY; __leave; } // Init array of addresses
pTmp = pNewValue; i = 0; while( *pTmp ) { AddrArray[i] = pTmp; pTmp += ( wcslen(pTmp) + 1 ); i++; } // Sort Array of PWSTR pointers
// NOTE: this does not sort the array!
qsort( AddrArray, AddrCount, sizeof(PWSTR), wcscmp ); // Alloc a temp buffer (because an in-place rearrangement is painful)
pTempBuffer = ALLOC_MEM(dwNewValueSize); if (!pTempBuffer) { Status = ERROR_NOT_ENOUGH_MEMORY; __leave; } pTmp = pTempBuffer; for ( i = 0; i < AddrCount; i++ ) { // CODEWORK: add an heuristic for checking for duplicates.
wcscpy( pTmp, AddrArray[i] ); pTmp += wcslen(AddrArray[i]) + 1; } // add double-null
ASSERT( (DWORD)(pTmp - pTempBuffer) < dwNewValueSize ); *pTmp = L'\0'; // set sorted value
REG_SET_VALUE(Status, SubKeyHandle, IP_LISTEN_ONLY_VALUE, REG_MULTI_SZ, pTempBuffer, dwNewValueSize ); FREE_MEM( pTempBuffer ); } else { // No value exists!
// calc the buffer size in bytes (including the double-null)
dwValueSize = sizeof(WCHAR) * (dwIpAddrLength + 1); // set value
// finesse: the value has already been double-null'd above.
REG_SET_VALUE(Status, SubKeyHandle, IP_LISTEN_ONLY_VALUE, REG_MULTI_SZ, IpAddrBuff, dwValueSize ); } } __finally { //
// close reg key
//
if ( SubKeyHandle ) { RegCloseKey(SubKeyHandle); }
//
// release alloc'd values
//
if ( pNewValue ) { FREE_MEM( pNewValue ); }
if ( AddrArray ) { FREE_MEM( AddrArray ); }
ReleaseHttpRegistryMutex(IP_REGISTRY_KEY_SYNCHRONIZE); }
return Status; }
/***************************************************************************++
Routine Description:
Internal function that deletes an address from the IP Listen-Only list.
Arguments: pConfigInformation - pointer to HTTP_SERVICE_CONFIG_IP_LISTEN_PARAM ConfigInformationLength - length of input buffer.
Return Value:
Win32 error code. --***************************************************************************/ ULONG DeleteIpListenServiceConfiguration( IN PVOID pConfigInformation, IN ULONG ConfigInformationLength ) { DWORD Status = NO_ERROR; HKEY SubKeyHandle = NULL; WCHAR IpAddrBuff[MAX_PATH]; DWORD dwIpAddrLength; DWORD dwValueSize; DWORD dwRemainder; PWSTR pNewValue = NULL; DWORD dwType; PWSTR pTmp; PWSTR pNext; PHTTP_SERVICE_CONFIG_IP_LISTEN_PARAM pIpListenParam;
//
// Validate params.
//
if ( !pConfigInformation || ConfigInformationLength != sizeof(HTTP_SERVICE_CONFIG_IP_LISTEN_PARAM) ) { return ERROR_INVALID_PARAMETER; }
pIpListenParam = (PHTTP_SERVICE_CONFIG_IP_LISTEN_PARAM) pConfigInformation;
if ( !pIpListenParam->AddrLength || !pIpListenParam->pAddress ) { return ERROR_INVALID_PARAMETER; }
__try { if((Status = AcquireHttpRegistryMutex(IP_REGISTRY_KEY_SYNCHRONIZE)) != NO_ERROR) { __leave; }
//
// Convert the address into a string.
//
dwIpAddrLength = MAX_PATH; Status = WSAAddressToString( pIpListenParam->pAddress, pIpListenParam->AddrLength, NULL, IpAddrBuff, &dwIpAddrLength // in chars, including NULL.
); if ( SOCKET_ERROR == Status ) { Status = WSAGetLastError(); __leave; } //
// open HTTP parameters reg key
//
Status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, HTTP_PARAM_KEY, 0, KEY_READ | KEY_WRITE, &SubKeyHandle ); if ( Status != ERROR_SUCCESS ) { // CODEWORK: add tracing.
__leave; } ASSERT(SubKeyHandle); //
// query existing value
//
dwValueSize = 0; Status = RegQueryValueEx( SubKeyHandle, // handle to key
IP_LISTEN_ONLY_VALUE, // value name
NULL, // reserved
&dwType, // type buffer
NULL, // data buffer
&dwValueSize // size of data buffer (bytes)
); if ( ERROR_SUCCESS == Status ) { // There's an existing value!
if (REG_MULTI_SZ != dwType) { // type mismatch. fail.
Status = ERROR_DATATYPE_MISMATCH; __leave; } pNewValue = ALLOC_MEM(dwValueSize); if (!pNewValue) { Status = ERROR_NOT_ENOUGH_MEMORY; __leave; } // read existing value into local buffer
Status = RegQueryValueEx( SubKeyHandle, // handle to key
IP_LISTEN_ONLY_VALUE, // value name
NULL, // reserved
&dwType, // type buffer
(LPBYTE)pNewValue, // data buffer
&dwValueSize // size of data buffer (bytes)
); if ( ERROR_SUCCESS != Status ) { __leave; } if (REG_MULTI_SZ != dwType) { // type mismatch. fail.
Status = ERROR_DATATYPE_MISMATCH; __leave; } // walk value, looking for match as we go
Status = ERROR_NOT_FOUND; pTmp = pNewValue; while ( *pTmp ) { // check if the new addr is a dup
if ( (wcslen(pTmp) == (dwIpAddrLength - 1)) && (0 == wcsncmp(pTmp, IpAddrBuff, dwIpAddrLength-1)) ) { // Found: move suffix of values up.
pNext = pTmp + dwIpAddrLength; dwRemainder = dwValueSize - (DWORD)((PUCHAR)pNext - (PUCHAR)pNewValue); dwValueSize -= (dwIpAddrLength * sizeof(WCHAR)); if (dwRemainder) { MoveMemory(pTmp, pNext, dwRemainder ); } else { // removing last element on list;
// must insert trailing double-null
*pTmp = L'\0'; } if (dwValueSize > sizeof(WCHAR)) { // write updated value to key
REG_SET_VALUE(Status, SubKeyHandle, IP_LISTEN_ONLY_VALUE, REG_MULTI_SZ, pNewValue, dwValueSize ); } else { // no more IPs left on list; remove the value
Status = RegDeleteValue( SubKeyHandle, IP_LISTEN_ONLY_VALUE ); }
__leave; } // advance to next multi-sz string
pTmp += ( wcslen(pTmp) + 1 ); } } else { // No existing value, so therefore we can't delete.
Status = ERROR_NOT_FOUND; } } __finally { ReleaseHttpRegistryMutex(IP_REGISTRY_KEY_SYNCHRONIZE);
if ( pNewValue ) { FREE_MEM( pNewValue ); } if (SubKeyHandle) { RegCloseKey(SubKeyHandle); } } return Status; }
/***************************************************************************++
Routine Description:
Internal function that queries the IP Listen-Only configuration. This function grabs the entire list and returns it in one chunk.
Arguments: pOutput - pointer to output buffer (point to caller provided HTTP_SERVICE_CONFIG_IP_LISTEN_QUERY structure) [OPTIONAL] OutputLength - sizeof output buffer. Must be zero if pOutput is NULL. pReturnLength - Bytes written/needed.
Return Value:
Win32 error code. ERROR_INSUFFICIENT_BUFFER - if OutputLength cannot hold entire list. pReturnLength will contain the required bytes. ERROR_NOT_ENOUGH_MEMORY - Can't alloc enough memory to complete operation. --***************************************************************************/ ULONG QueryIpListenServiceConfiguration( IN PVOID pOutput, IN ULONG OutputLength, OUT PULONG pReturnLength ) { DWORD Status = NO_ERROR; HKEY SubKeyHandle = NULL; DWORD dwValueSize; DWORD dwSockAddrLength; DWORD AddrCount; DWORD BytesNeeded = 0; PWSTR pValue = NULL; PWSTR pTmp; PHTTP_SERVICE_CONFIG_IP_LISTEN_QUERY pIpListenQuery; PSOCKADDR_STORAGE pHttpAddr;
//
// Validate parameters
//
if ( pOutput && OutputLength < sizeof(HTTP_SERVICE_CONFIG_IP_LISTEN_QUERY) ) { return ERROR_INVALID_PARAMETER; }
if ( !pReturnLength ) { return ERROR_INVALID_PARAMETER; }
__try { if((Status = AcquireHttpRegistryMutex(IP_REGISTRY_KEY_SYNCHRONIZE)) != NO_ERROR) { __leave; }
//
// open HTTP parameters reg key
//
Status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, HTTP_PARAM_KEY, 0, KEY_READ | KEY_WRITE, &SubKeyHandle ); if ( Status != ERROR_SUCCESS ) { // CODEWORK: add tracing.
__leave; } ASSERT(SubKeyHandle); //
// query existing value
//
dwValueSize = 0; Status = RegQueryValueEx( SubKeyHandle, // handle to key
IP_LISTEN_ONLY_VALUE, // value name
NULL, // reserved
NULL, // type buffer
NULL, // data buffer
&dwValueSize // size of data buffer (bytes)
); if ( ERROR_SUCCESS == Status ) { // There's an existing value!
pValue = ALLOC_MEM(dwValueSize); if (!pValue) { Status = ERROR_NOT_ENOUGH_MEMORY; __leave; } // read existing value into local buffer
Status = RegQueryValueEx( SubKeyHandle, // handle to key
IP_LISTEN_ONLY_VALUE, // value name
NULL, // reserved
NULL, // type buffer
(LPBYTE)pValue, // data buffer
&dwValueSize // size of data buffer (bytes)
); if ( ERROR_SUCCESS != Status ) { __leave; } // first pass: count the number of addresses & see if we
// have enough buffer.
pTmp = pValue; AddrCount = 0; while ( *pTmp ) { AddrCount++; // advance to next multi-sz string
pTmp += ( wcslen(pTmp) + 1 ); } if ( 0 == AddrCount ) { // invalid. bail out.
Status = ERROR_REGISTRY_CORRUPT; __leave; } // calculate bytes needed
BytesNeeded = sizeof(HTTP_SERVICE_CONFIG_IP_LISTEN_QUERY) + (sizeof(SOCKADDR_STORAGE) * (AddrCount - 1)); // see if we have enough buffer to write out the whole mess
if ( (NULL == pOutput) || (OutputLength < BytesNeeded) ) { Status = ERROR_INSUFFICIENT_BUFFER; __leave; } // second pass: walk value, converting into buffer as we go
pIpListenQuery = (PHTTP_SERVICE_CONFIG_IP_LISTEN_QUERY) pOutput; pHttpAddr = (PSOCKADDR_STORAGE) &(pIpListenQuery->AddrList[0]); pIpListenQuery->AddrCount = AddrCount; pTmp = pValue; while ( *pTmp ) { //
// Convert the IP addresses into SOCKADDRs
//
// First, we try v4
dwSockAddrLength = sizeof(SOCKADDR_STORAGE); Status = WSAStringToAddress( pTmp, AF_INET, NULL, (LPSOCKADDR)pHttpAddr, (LPINT)&dwSockAddrLength ); if ( Status != NO_ERROR ) { // Second, we try v6
dwSockAddrLength = sizeof(SOCKADDR_STORAGE); Status = WSAStringToAddress( pTmp, AF_INET6, NULL, (LPSOCKADDR)pHttpAddr, (LPINT)&dwSockAddrLength ); if ( Status != NO_ERROR ) { // if that fails, bail out; corrupt value.
Status = ERROR_REGISTRY_CORRUPT; __leave; } } // advance to next multi-sz string
pTmp += ( wcslen(pTmp) + 1 ); pHttpAddr++; } } else { // No existing value, so therefore we can't query.
Status = ERROR_NOT_FOUND; } } __finally { // free memory
if (pValue) { FREE_MEM(pValue); } // close reg key
if (SubKeyHandle) { RegCloseKey(SubKeyHandle); }
ReleaseHttpRegistryMutex(IP_REGISTRY_KEY_SYNCHRONIZE);
// tell caller how many bytes are need
*pReturnLength = BytesNeeded; }
return Status; }
//
// URL ACL functions.
//
/***************************************************************************++
Routine Description:
Internal function that adds an URL ACL entry
Arguments: pConfigInformation - pointer to HTTP_SERVICE_CONFIG_URL_ACL ConfigInformationLength - length of input buffer.
Return Value:
Win32 error code.
--***************************************************************************/ ULONG SetUrlAclInfo( IN PVOID pConfigInformation, IN ULONG ConfigInformationLength ) { DWORD Status; PHTTP_SERVICE_CONFIG_URLACL_SET pUrlAcl; PSECURITY_DESCRIPTOR pSecurityDescriptor; ULONG SecurityDescriptorLength;
//
// Validate arguments.
//
if (pConfigInformation == NULL || ConfigInformationLength != sizeof(HTTP_SERVICE_CONFIG_URLACL_SET)) { return ERROR_INVALID_PARAMETER; }
pUrlAcl = (PHTTP_SERVICE_CONFIG_URLACL_SET) pConfigInformation;
if(FALSE == ConvertStringSecurityDescriptorToSecurityDescriptor( pUrlAcl->ParamDesc.pStringSecurityDescriptor, SDDL_REVISION_1, &pSecurityDescriptor, &SecurityDescriptorLength )) { return GetLastError(); }
//
// Now, make the IOCTL call
//
Status = AddUrlToConfigGroup( HttpUrlOperatorTypeReservation, g_ServiceControlChannelHandle, HTTP_NULL_ID, pUrlAcl->KeyDesc.pUrlPrefix, HTTP_NULL_ID, pSecurityDescriptor, SecurityDescriptorLength );
LocalFree(pSecurityDescriptor);
return Status; }
/***************************************************************************++
Routine Description:
Internal function that queries URL ACL configuration
Arguments: pInputConfigInfo - pointer to HTTP_SERVICE_CONFIG_URLACL_QUERY InputLength - length of input buffer. pBuffer - Output Buffer pReturnLength - Bytes written/needed. BytesAvailable - sizeof output buffer Return Value:
Win32 error code. --***************************************************************************/ ULONG QueryUrlAclInfo( IN PVOID pInputConfigInfo, IN ULONG InputLength, IN PVOID pOutput, IN ULONG OutputLength, OUT PULONG pReturnLength ) { ULONG Status; PHTTP_SERVICE_CONFIG_URLACL_QUERY pUrlAclQuery; PHTTP_SERVICE_CONFIG_URLACL_SET pUrlAclSet; DWORD dwIndex; PVOID pData; PUCHAR pBuffer; DWORD Type; DWORD DataSize; DWORD NameSize; PWSTR pFullyQualifiedUrl = NULL; PSECURITY_DESCRIPTOR pSecurityDescriptor; PWSTR pStringSecurityDescriptor; BOOLEAN bAllocatedUrl = FALSE;
pData = NULL; pStringSecurityDescriptor = NULL; Status = NO_ERROR;
pUrlAclQuery = (PHTTP_SERVICE_CONFIG_URLACL_QUERY) pInputConfigInfo;
//
// Validate input parameters.
//
if(pUrlAclQuery == NULL || InputLength != sizeof(HTTP_SERVICE_CONFIG_URLACL_QUERY)) { return ERROR_INVALID_PARAMETER; }
switch(pUrlAclQuery->QueryDesc) { case HttpServiceConfigQueryNext: { dwIndex = pUrlAclQuery->dwToken; DataSize = 0;
//
// RegEnumValue wants ValueName to be MAXUSHORT characters.
//
NameSize = (MAXUSHORT + 1) * sizeof(WCHAR); pFullyQualifiedUrl = LocalAlloc(LMEM_FIXED, NameSize);
if(!pFullyQualifiedUrl) { return ERROR_NOT_ENOUGH_MEMORY; } else { RtlZeroMemory(pFullyQualifiedUrl, NameSize); bAllocatedUrl = TRUE; }
//
// Set NameSize to WCHARs & exclude the NULL.
//
NameSize = MAXUSHORT;
//
// Get the Size.
//
Status = RegEnumValue( g_UrlAclRegistryHandle, dwIndex, pFullyQualifiedUrl, &NameSize, NULL, // Reserved
&Type, // Type
NULL, // Data
&DataSize // DataSize
);
// On return, NameSize contains size in WCHARs
// excluding NULL. Account for the NULL. The buffer is already
// zero'd out.
//
// At this time, NameSize is in WCHARs, including NULL
//
NameSize ++; } break;
case HttpServiceConfigQueryExact: { pFullyQualifiedUrl = pUrlAclQuery->KeyDesc.pUrlPrefix,
//
// NameSize must be in WCHARs including NULL.
//
NameSize = (DWORD)((wcslen(pFullyQualifiedUrl) + 1));
Status = RegQueryValueEx( g_UrlAclRegistryHandle, pFullyQualifiedUrl, 0, &Type, NULL, // Buffer
&DataSize ); } break;
default: Status = ERROR_INVALID_PARAMETER; goto Cleanup;
} // switch
if(Status != NO_ERROR) { goto Cleanup; }
if(Type != REG_BINARY || DataSize == 0) { Status = ERROR_REGISTRY_CORRUPT; goto Cleanup; }
//
// Allocate space for data
//
pData = LocalAlloc(LMEM_FIXED, DataSize);
if(!pData) { Status = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } Status = RegQueryValueEx( g_UrlAclRegistryHandle, pFullyQualifiedUrl, 0, &Type, pData, // Buffer
&DataSize );
if(Status != NO_ERROR) { goto Cleanup; }
if(Type != REG_BINARY) { Status = ERROR_REGISTRY_CORRUPT; goto Cleanup; }
pSecurityDescriptor = (PSECURITY_DESCRIPTOR) pData;
//
// If we are here, we have to convert the binary to a SDDL.
//
if(FALSE == ConvertSecurityDescriptorToStringSecurityDescriptor( pSecurityDescriptor, SDDL_REVISION_1, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, &pStringSecurityDescriptor, &DataSize )) { Status = GetLastError(); goto Cleanup; }
//
// Convert WCHAR to length.
//
DataSize *= sizeof(WCHAR); NameSize *= sizeof(WCHAR);
*pReturnLength = DataSize + NameSize + sizeof(HTTP_SERVICE_CONFIG_URLACL_SET);
if(OutputLength >= *pReturnLength) { pBuffer = pOutput; pUrlAclSet = (PHTTP_SERVICE_CONFIG_URLACL_SET) pBuffer; pBuffer += sizeof(HTTP_SERVICE_CONFIG_URLACL_SET);
RtlZeroMemory(pUrlAclSet, sizeof(HTTP_SERVICE_CONFIG_URLACL_SET));
pUrlAclSet->KeyDesc.pUrlPrefix = (PWSTR) pBuffer; pBuffer += NameSize;
// Includes NULL.
RtlCopyMemory( pUrlAclSet->KeyDesc.pUrlPrefix, pFullyQualifiedUrl, NameSize );
pUrlAclSet->ParamDesc.pStringSecurityDescriptor = (PWSTR)pBuffer;
RtlCopyMemory( pUrlAclSet->ParamDesc.pStringSecurityDescriptor, pStringSecurityDescriptor, DataSize );
Status = NO_ERROR; } else { Status = ERROR_INSUFFICIENT_BUFFER; }
Cleanup:
if(bAllocatedUrl) { LocalFree(pFullyQualifiedUrl); }
if(pStringSecurityDescriptor) { LocalFree(pStringSecurityDescriptor); }
if(pData) { LocalFree(pData); }
return Status; }
/***************************************************************************++
Routine Description:
Internal function that deletes an URL ACL entry
Arguments: pConfigInformation - pointer to HTTP_SERVICE_CONFIG_URL_ACL ConfigInformationLength - length of input buffer.
Return Value:
Win32 error code. --***************************************************************************/ ULONG DeleteUrlAclInfo( IN PVOID pConfigInformation, IN ULONG ConfigInformationLength ) { DWORD Status; PHTTP_SERVICE_CONFIG_URLACL_SET pUrlAcl;
//
// Validate arguments.
//
if (pConfigInformation == NULL || ConfigInformationLength != sizeof(HTTP_SERVICE_CONFIG_URLACL_SET)) { return ERROR_INVALID_PARAMETER; }
pUrlAcl = (PHTTP_SERVICE_CONFIG_URLACL_SET) pConfigInformation;
//
// Now, make the IOCTL call
//
Status = RemoveUrlFromConfigGroup( HttpUrlOperatorTypeReservation, g_ServiceControlChannelHandle, HTTP_NULL_ID, pUrlAcl->KeyDesc.pUrlPrefix );
return Status; }
//
// Public Functions.
//
/***************************************************************************++
Routine Description:
Sets a service configuration parameter.
Arguments:
ConfigId - ID of the parameter that we are setting. pConfigInformation - pointer to the object that is being set. ConfigInformationLength - Length of the object.
Return Value:
ULONG - Completion status.
--***************************************************************************/ ULONG WINAPI HttpSetServiceConfiguration( IN HANDLE pHandle, IN HTTP_SERVICE_CONFIG_ID ConfigId, IN PVOID pConfigInformation, IN ULONG ConfigInformationLength, IN LPOVERLAPPED pOverlapped ) { ULONG Status = NO_ERROR;
if(pOverlapped != NULL || pHandle != NULL) { return ERROR_INVALID_PARAMETER; }
switch(ConfigId) { case HttpServiceConfigSSLCertInfo: { Status = SetSslServiceConfiguration(pConfigInformation, ConfigInformationLength ); break; }
case HttpServiceConfigIPListenList: { Status = SetIpListenServiceConfiguration( pConfigInformation, ConfigInformationLength ); break; }
case HttpServiceConfigUrlAclInfo: { Status = SetUrlAclInfo( pConfigInformation, ConfigInformationLength ); break; }
default: Status = ERROR_INVALID_PARAMETER; break; }
return Status; }
/***************************************************************************++
Routine Description:
Deletes a service configuration parameter.
Arguments:
ConfigId - ID of the parameter that we are setting. pConfigInformation - pointer to the object that is being set. ConfigInformationLength - Length of the object.
Return Value:
ULONG - Completion status.
--***************************************************************************/ ULONG WINAPI HttpDeleteServiceConfiguration( IN HANDLE pHandle, IN HTTP_SERVICE_CONFIG_ID ConfigId, IN PVOID pConfigInformation, IN ULONG ConfigInformationLength, IN LPOVERLAPPED pOverlapped ) { ULONG Status = NO_ERROR;
if(pOverlapped != NULL || pHandle != NULL) { return ERROR_INVALID_PARAMETER; }
switch(ConfigId) { case HttpServiceConfigSSLCertInfo: Status = DeleteSslServiceConfiguration(pConfigInformation, ConfigInformationLength ); break;
case HttpServiceConfigIPListenList: { Status = DeleteIpListenServiceConfiguration( pConfigInformation, ConfigInformationLength ); break; }
case HttpServiceConfigUrlAclInfo: { Status = DeleteUrlAclInfo( pConfigInformation, ConfigInformationLength ); break; }
default: Status = ERROR_INVALID_PARAMETER; break; }
return Status; }
/***************************************************************************++
Routine Description:
Queries a service configuration parameter.
Arguments:
ConfigId - ID of the parameter that we are setting. pConfigInformation - pointer to the object that is being set. ConfigInformationLength - Length of the object.
Return Value:
ULONG - Completion status.
--***************************************************************************/ ULONG WINAPI HttpQueryServiceConfiguration( IN HANDLE pHandle, IN HTTP_SERVICE_CONFIG_ID ConfigId, IN PVOID pInput, IN ULONG InputLength, IN OUT PVOID pOutput, IN ULONG OutputLength, OUT PULONG pReturnLength, IN LPOVERLAPPED pOverlapped ) { ULONG Status = NO_ERROR;
if(pOverlapped != NULL || pHandle != NULL) { return ERROR_INVALID_PARAMETER; }
switch(ConfigId) { case HttpServiceConfigSSLCertInfo: { Status = QuerySslServiceConfiguration( pInput, InputLength, pOutput, OutputLength, pReturnLength );
break;
}
case HttpServiceConfigIPListenList: { Status = QueryIpListenServiceConfiguration( pOutput, OutputLength, pReturnLength ); break; }
case HttpServiceConfigUrlAclInfo: { Status = QueryUrlAclInfo( pInput, InputLength, pOutput, OutputLength, pReturnLength ); break; }
default: Status = ERROR_INVALID_PARAMETER; break; }
return Status; }
|