Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2654 lines
74 KiB

/*++
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;
}