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.
1119 lines
29 KiB
1119 lines
29 KiB
/*++
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name :
|
|
siteconfig.cxx
|
|
|
|
Abstract:
|
|
SSL configuration for a given site
|
|
|
|
Author:
|
|
Bilal Alam (BAlam) 29-March-2000
|
|
|
|
Environment:
|
|
Win32 - User Mode
|
|
|
|
Project:
|
|
Stream Filter Worker Process
|
|
--*/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
ENDPOINT_CONFIG_HASH * ENDPOINT_CONFIG::sm_pEndpointConfigHash;
|
|
ENDPOINT_CONFIG::INIT_STATE ENDPOINT_CONFIG::sm_InitState = INIT_NONE;
|
|
HANDLE ENDPOINT_CONFIG::sm_hHttpApiConfigChangeEvent = NULL;
|
|
HKEY ENDPOINT_CONFIG::sm_hHttpApiConfigKey = NULL;
|
|
HANDLE ENDPOINT_CONFIG::sm_hWaitHandle = NULL;
|
|
|
|
|
|
|
|
//static
|
|
HRESULT
|
|
ENDPOINT_CONFIG::Initialize(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize site configuration globals
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
DWORD dwError = NO_ERROR;
|
|
HTTPAPI_VERSION HttpApiVersion = HTTPAPI_VERSION_1;
|
|
|
|
//
|
|
// Initialize HttpApi to be able to retrieve SSL config
|
|
//
|
|
dwError = HttpInitialize( HttpApiVersion, HTTP_INITIALIZE_CONFIG, NULL );
|
|
|
|
if ( dwError != NO_ERROR )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( dwError );
|
|
goto Failed;
|
|
}
|
|
|
|
sm_InitState = INIT_HTTPAPI;
|
|
|
|
sm_pEndpointConfigHash = new ENDPOINT_CONFIG_HASH();
|
|
if ( sm_pEndpointConfigHash == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
|
goto Failed;
|
|
}
|
|
sm_InitState = INIT_HASH;
|
|
|
|
//
|
|
// Create event for HttpApi config store change notifications
|
|
//
|
|
|
|
sm_hHttpApiConfigChangeEvent = CreateEvent( NULL, // SD
|
|
FALSE, // fManualReset
|
|
FALSE, //fInitialState
|
|
NULL ); // name*/
|
|
if( sm_hHttpApiConfigChangeEvent == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"CreateEvent() failed. hr = 0x%x\n",
|
|
hr ));
|
|
|
|
goto Failed;
|
|
}
|
|
|
|
dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
L"System\\CurrentControlSet\\Services\\HTTP\\Parameters\\SslBindingInfo",
|
|
0,
|
|
KEY_READ,
|
|
&sm_hHttpApiConfigKey );
|
|
if ( dwError != ERROR_SUCCESS )
|
|
{
|
|
// backup plan
|
|
// if SslBindingInfo doesn't extst yet, simply listen on
|
|
// parent node. HTTP\Parameters is guaranteed to exist on valid install
|
|
//
|
|
dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
L"System\\CurrentControlSet\\Services\\HTTP\\Parameters",
|
|
0,
|
|
KEY_READ,
|
|
&sm_hHttpApiConfigKey );
|
|
if ( dwError != ERROR_SUCCESS )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( dwError );
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"Failed to open registry. hr = 0x%x\n",
|
|
hr ));
|
|
|
|
CloseHandle( sm_hHttpApiConfigChangeEvent );
|
|
sm_hHttpApiConfigChangeEvent = NULL;
|
|
goto Failed;
|
|
}
|
|
}
|
|
DBG_ASSERT( sm_hHttpApiConfigKey != NULL );
|
|
|
|
|
|
//
|
|
// Watch the registry key for a change
|
|
//
|
|
|
|
|
|
dwError = RegNotifyChangeKeyValue( sm_hHttpApiConfigKey,
|
|
TRUE,
|
|
REG_NOTIFY_CHANGE_LAST_SET |
|
|
REG_NOTIFY_CHANGE_NAME,
|
|
sm_hHttpApiConfigChangeEvent,
|
|
TRUE );
|
|
|
|
if( dwError != ERROR_SUCCESS )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( dwError );
|
|
|
|
RegCloseKey( sm_hHttpApiConfigKey );
|
|
sm_hHttpApiConfigKey = NULL;
|
|
CloseHandle( sm_hHttpApiConfigChangeEvent );
|
|
sm_hHttpApiConfigChangeEvent = NULL;
|
|
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"RegNotifyChangeKeyValue failed. hr = 0x%x\n",
|
|
hr ));
|
|
|
|
goto Failed;
|
|
}
|
|
|
|
//
|
|
// Register a callback function to wait on the event
|
|
//
|
|
|
|
|
|
if( !RegisterWaitForSingleObject(
|
|
&sm_hWaitHandle,
|
|
sm_hHttpApiConfigChangeEvent,
|
|
( WAITORTIMERCALLBACK )ENDPOINT_CONFIG::ConfigStoreChangeCallback,
|
|
NULL,
|
|
INFINITE,
|
|
WT_EXECUTEDEFAULT ) )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
|
|
RegCloseKey( sm_hHttpApiConfigKey );
|
|
sm_hHttpApiConfigKey = NULL;
|
|
CloseHandle( sm_hHttpApiConfigChangeEvent );
|
|
sm_hHttpApiConfigChangeEvent = NULL;
|
|
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"RegisterWaitForSingleObject failed. hr = 0x%x\n",
|
|
hr ));
|
|
|
|
goto Failed;
|
|
}
|
|
sm_InitState = INIT_CHANGE_NOTIF;
|
|
return NO_ERROR;
|
|
|
|
Failed:
|
|
Terminate();
|
|
return hr;
|
|
}
|
|
|
|
//static
|
|
VOID
|
|
ENDPOINT_CONFIG::Terminate(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cleanup site configuration globals
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
switch( sm_InitState )
|
|
{
|
|
case INIT_CHANGE_NOTIF:
|
|
|
|
|
|
if ( sm_hWaitHandle != NULL )
|
|
{
|
|
UnregisterWaitEx( sm_hWaitHandle,
|
|
INVALID_HANDLE_VALUE );
|
|
sm_hWaitHandle = NULL;
|
|
}
|
|
|
|
//
|
|
// NOTE:
|
|
// registry key must be closed before event is destroyed
|
|
// because closing handle will assure that sm_hHttpApiConfigChangeEvent event
|
|
// will not be used any more
|
|
//
|
|
|
|
if ( sm_hHttpApiConfigKey != NULL )
|
|
{
|
|
CloseHandle( sm_hHttpApiConfigKey );
|
|
sm_hHttpApiConfigKey = NULL;
|
|
}
|
|
|
|
if ( sm_hHttpApiConfigChangeEvent != NULL )
|
|
{
|
|
CloseHandle( sm_hHttpApiConfigChangeEvent );
|
|
sm_hHttpApiConfigChangeEvent = NULL;
|
|
}
|
|
case INIT_HASH:
|
|
if ( sm_pEndpointConfigHash != NULL )
|
|
{
|
|
//
|
|
// Clear hash table before deleting it
|
|
//
|
|
sm_pEndpointConfigHash->Clear();
|
|
delete sm_pEndpointConfigHash;
|
|
sm_pEndpointConfigHash = NULL;
|
|
}
|
|
case INIT_HTTPAPI:
|
|
HttpTerminate( HTTP_INITIALIZE_CONFIG, NULL );
|
|
case INIT_NONE:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//private
|
|
//static
|
|
HRESULT
|
|
ENDPOINT_CONFIG::GetEndpointConfigData(
|
|
IN DWORD LocalAddress,
|
|
IN USHORT LocalPort,
|
|
OUT PHTTP_SERVICE_CONFIG_SSL_SET * ppEndpointConfigData,
|
|
OUT BOOL * pfWildcardMatch
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
lookup SSL configuration
|
|
|
|
Arguments:
|
|
|
|
LocalAddress - IP address in network order
|
|
LocalPort - Port in network order
|
|
ppEndpointConfigData - allocated within this function - delete[] must be used to free it
|
|
pfWildcardMatch - was wildcard IP address match used?
|
|
)
|
|
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwError;
|
|
DWORD ReturnLength = 0;
|
|
HTTP_SERVICE_CONFIG_SSL_QUERY QueryParam;
|
|
PHTTP_SERVICE_CONFIG_SSL_SET pSetParam = NULL;
|
|
HRESULT hr = NO_ERROR;
|
|
SOCKADDR_IN SockAddr;
|
|
|
|
|
|
if ( ppEndpointConfigData == NULL ||
|
|
pfWildcardMatch == NULL )
|
|
{
|
|
return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
|
}
|
|
|
|
ZeroMemory( &SockAddr, sizeof(SockAddr) );
|
|
ZeroMemory( &QueryParam, sizeof(QueryParam) );
|
|
|
|
*pfWildcardMatch = FALSE;
|
|
|
|
QueryParam.QueryDesc = HttpServiceConfigQueryExact;
|
|
|
|
//
|
|
// build sock addr for HTTPAPI lookup
|
|
//
|
|
|
|
SockAddr.sin_family = AF_INET;
|
|
SockAddr.sin_port = LocalPort;
|
|
SockAddr.sin_addr.s_addr = LocalAddress;
|
|
|
|
QueryParam.KeyDesc.pIpPort = (PSOCKADDR) &SockAddr;
|
|
|
|
// Loop - check nonwildcard info first, if it fails then try wildcard
|
|
//
|
|
|
|
for(;;)
|
|
{
|
|
|
|
dwError = HttpQueryServiceConfiguration(
|
|
NULL,
|
|
HttpServiceConfigSSLCertInfo,
|
|
&QueryParam,
|
|
sizeof(QueryParam),
|
|
NULL,
|
|
0,
|
|
&ReturnLength,
|
|
NULL
|
|
);
|
|
|
|
if ( dwError == ERROR_INSUFFICIENT_BUFFER )
|
|
{
|
|
pSetParam = (PHTTP_SERVICE_CONFIG_SSL_SET) new BYTE[ReturnLength];
|
|
|
|
if ( pSetParam == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
|
|
goto Finished;
|
|
}
|
|
|
|
dwError = HttpQueryServiceConfiguration(
|
|
NULL,
|
|
HttpServiceConfigSSLCertInfo,
|
|
&QueryParam,
|
|
sizeof(QueryParam),
|
|
pSetParam,
|
|
ReturnLength,
|
|
&ReturnLength,
|
|
NULL
|
|
);
|
|
//
|
|
// It is possible that the size returned on the first call may
|
|
// have changed between first and second call.
|
|
// It would be caused by configuration change.
|
|
// Probability of it happening is very low.
|
|
// If it happens then one connection attempt will fail and it is
|
|
// acceptable
|
|
//
|
|
}
|
|
|
|
// If not found (and other error will mean end of trying)
|
|
// or if wildcard lookup already executed
|
|
// then leave the loop
|
|
//
|
|
if ( dwError != ERROR_FILE_NOT_FOUND || SockAddr.sin_addr.s_addr == INADDR_ANY )
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// continue loop for wildcard lookup
|
|
//
|
|
SockAddr.sin_addr.s_addr = INADDR_ANY;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if ( dwError != NO_ERROR )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( dwError );
|
|
goto Finished;
|
|
}
|
|
|
|
if ( SockAddr.sin_addr.s_addr == INADDR_ANY )
|
|
{
|
|
*pfWildcardMatch = TRUE;
|
|
}
|
|
|
|
*ppEndpointConfigData = pSetParam;
|
|
|
|
hr = S_OK;
|
|
|
|
Finished:
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//static
|
|
HRESULT
|
|
ENDPOINT_CONFIG::GetEndpointConfig(
|
|
CONNECTION_INFO * pConnectionInfo,
|
|
ENDPOINT_CONFIG ** ppEndpointConfig,
|
|
BOOL fCreateEmptyIfNotFound
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Lookup site configuration in hash table. If not there then create it
|
|
and add it to table
|
|
|
|
Arguments:
|
|
|
|
dwSiteId - Site ID to lookup
|
|
ppEndpointConfig - Filled with pointer to site config on success
|
|
fCreateEmptyIfNotFound - if endpoint config was not located
|
|
in the persistent store, create empty
|
|
endpoint config and stick it to cache
|
|
That will optimize lookup for EnableRawFilter
|
|
checks
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) when endpoint config not found
|
|
|
|
--*/
|
|
{
|
|
LK_RETCODE lkrc;
|
|
ENDPOINT_CONFIG * pEndpointConfig = NULL;
|
|
SERVER_CERT * pServerCert = NULL;
|
|
IIS_CTL * pIisCtl = NULL;
|
|
HRESULT hr = NO_ERROR;
|
|
STACK_STRU( strMBPath, 64 );
|
|
DWORD LocalAddress = 0;
|
|
USHORT LocalPort = 0;
|
|
BOOL fWildcardMatch = FALSE;
|
|
PHTTP_SERVICE_CONFIG_SSL_SET pEndpointConfigData = NULL;
|
|
|
|
if ( ppEndpointConfig == NULL ||
|
|
pConnectionInfo == NULL )
|
|
{
|
|
DBG_ASSERT( FALSE );
|
|
return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
|
}
|
|
|
|
*ppEndpointConfig = NULL;
|
|
|
|
//
|
|
// Figure out Ip Address and Port
|
|
//
|
|
|
|
//
|
|
// Pass Port and IP address in network order
|
|
// (HTTP service will return them in network order so no changes are needed)
|
|
//
|
|
|
|
if( pConnectionInfo->LocalAddressType == TDI_ADDRESS_TYPE_IP )
|
|
{
|
|
LocalAddress = pConnectionInfo->SockLocalAddress.ipv4SockAddress.sin_addr.s_addr;
|
|
LocalPort = pConnectionInfo->SockLocalAddress.ipv4SockAddress.sin_port;
|
|
}
|
|
else if ( pConnectionInfo->LocalAddressType == TDI_ADDRESS_TYPE_IP6 )
|
|
{
|
|
//
|
|
// IPv6 connections will be able to handle SSL connections only
|
|
// in the case when all IP addresses on the machine are configured to
|
|
// listen on secure port (IPv4 wildcard binding must be configured).
|
|
// CODEWORK: Once in the future there may be a need to implement
|
|
// for IPv6 support.
|
|
//
|
|
LocalAddress = INADDR_ANY; // Wildcard IP
|
|
LocalPort = pConnectionInfo->SockLocalAddress.ipv6SockAddress.sin6_port;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We support only IPv4 and IPv6. Any other value means error
|
|
//
|
|
DBG_ASSERT( FALSE );
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
|
goto ExitPoint;
|
|
|
|
}
|
|
|
|
//
|
|
// First lookup in the cache
|
|
// Because we don't preread all the endpoint configuration stored in HttpAPI Config
|
|
// store in out hash table, it is not straightforward to handle wildcard endpoint
|
|
// configuration
|
|
// If endpoint configuration lookup returned data based on wildcard endpoint config
|
|
// we will still store it in the hash table for the specific endpoint we looked up
|
|
// Otherwise there is is risk that wildcard endpoint config stored in the hash table
|
|
// could override individual endpoint settings that exist in the HttpAPI config store
|
|
// but were not yet read and stored in our hash table
|
|
//
|
|
|
|
DBG_ASSERT( sm_pEndpointConfigHash != NULL );
|
|
|
|
ENDPOINT_KEY EndpointKey = GenerateEndpointKey( LocalAddress, LocalPort );
|
|
|
|
lkrc = sm_pEndpointConfigHash->FindKey(
|
|
&EndpointKey,
|
|
&pEndpointConfig );
|
|
if ( lkrc == LK_SUCCESS )
|
|
{
|
|
DBG_ASSERT( pEndpointConfig != NULL );
|
|
*ppEndpointConfig = pEndpointConfig;
|
|
hr = S_OK;
|
|
goto ExitPoint;
|
|
}
|
|
|
|
//
|
|
// Ok, nothing cached. We will have to make a lookup in the persistent store
|
|
//
|
|
|
|
|
|
//
|
|
// Try to lookup config info through HTTPAPI
|
|
// fWildcardMatch is currently ignored we will store retrieved config data
|
|
// for the specific endpoint
|
|
//
|
|
hr = GetEndpointConfigData(
|
|
LocalAddress,
|
|
LocalPort,
|
|
&pEndpointConfigData,
|
|
&fWildcardMatch );
|
|
|
|
|
|
if ( hr == HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) && fCreateEmptyIfNotFound )
|
|
{
|
|
//
|
|
// Create empty endpoint info
|
|
// This will optimize the EnableRawFilter lookups
|
|
// because without cached entry for each new raw Filter connection
|
|
// we would need to make HttpApi config lookup
|
|
// (empty endpoint indicates that it is OK to do Raw Filter handling)
|
|
//
|
|
|
|
pEndpointConfigData = NULL;
|
|
|
|
pEndpointConfig = new ENDPOINT_CONFIG( LocalAddress,
|
|
LocalPort,
|
|
NULL, // no Server Cert info
|
|
NULL, // No Ctl info
|
|
pEndpointConfigData );
|
|
if ( pEndpointConfig == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
|
goto ExitPoint;
|
|
}
|
|
else
|
|
{
|
|
// ENDPOINT_CONFIG took ownership of pEndpointConfigData
|
|
pEndpointConfigData = NULL;
|
|
}
|
|
}
|
|
else if ( FAILED( hr ) )
|
|
{
|
|
//
|
|
// Not finding the site just means this is not an SSL site
|
|
//
|
|
|
|
goto ExitPoint;
|
|
}
|
|
else if ( pEndpointConfigData != NULL &&
|
|
pEndpointConfigData->ParamDesc.SslHashLength == 0 )
|
|
{
|
|
//
|
|
// Store endpoint config for nonsecure Endpoint
|
|
// to flag if Raw Filters are enabled or disabled
|
|
//
|
|
|
|
pEndpointConfig = new ENDPOINT_CONFIG( LocalAddress,
|
|
LocalPort,
|
|
NULL,
|
|
NULL,
|
|
pEndpointConfigData );
|
|
if ( pEndpointConfig == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
|
goto ExitPoint;
|
|
}
|
|
else
|
|
{
|
|
// ENDPOINT_CONFIG took ownership of pEndpointConfigData
|
|
pEndpointConfigData = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// To get this far means that we expect correct SSL endpoint info
|
|
// to be available
|
|
//
|
|
|
|
//
|
|
// We have enough to lookup in SERVER_CERT cache
|
|
//
|
|
|
|
hr = SERVER_CERT::GetServerCertificate( (PBYTE) pEndpointConfigData->ParamDesc.pSslHash,
|
|
pEndpointConfigData->ParamDesc.SslHashLength,
|
|
pEndpointConfigData->ParamDesc.pSslCertStoreName,
|
|
&pServerCert );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
//
|
|
// If we couldn't get a server cert, SSL will
|
|
// not be enablable for this site
|
|
//
|
|
|
|
goto ExitPoint;
|
|
}
|
|
|
|
DBG_ASSERT( pServerCert != NULL );
|
|
|
|
|
|
hr = IIS_CTL::GetIisCtl( pEndpointConfigData->ParamDesc.pDefaultSslCtlIdentifier,
|
|
pEndpointConfigData->ParamDesc.pDefaultSslCtlStoreName,
|
|
&pIisCtl );
|
|
//
|
|
// if CTL context creation failed, we must not fail site config creation
|
|
// because CTLs are not mandatory for all scenarios (only client certificate
|
|
// scenarios require them, so we have to make sure that those would be failing )
|
|
//
|
|
if ( FAILED( hr ) )
|
|
{
|
|
pIisCtl = NULL;
|
|
//
|
|
// BUGBUG: Error loading CTL should be logged into event log
|
|
//
|
|
hr = S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// OK. Create the config and attempt to add it to the cache
|
|
//
|
|
|
|
pEndpointConfig = new ENDPOINT_CONFIG( ( LocalAddress ),
|
|
LocalPort,
|
|
pServerCert,
|
|
pIisCtl,
|
|
pEndpointConfigData );
|
|
|
|
if ( pEndpointConfig == NULL )
|
|
{
|
|
if ( pServerCert != NULL )
|
|
{
|
|
pServerCert->DereferenceServerCert();
|
|
pServerCert = NULL;
|
|
}
|
|
if ( pIisCtl != NULL )
|
|
{
|
|
pIisCtl->DereferenceIisCtl();
|
|
pIisCtl = NULL;
|
|
}
|
|
hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
|
goto ExitPoint;
|
|
}
|
|
else
|
|
{
|
|
// ENDPOINT_CONFIG took ownership of pEndpointConfigData
|
|
pEndpointConfigData = NULL;
|
|
}
|
|
|
|
//
|
|
// Acquire credentials
|
|
//
|
|
|
|
hr = pEndpointConfig->AcquireCredentials();
|
|
if ( FAILED( hr ) )
|
|
{
|
|
delete pEndpointConfig;
|
|
pEndpointConfig = NULL;
|
|
goto ExitPoint;
|
|
}
|
|
}
|
|
//
|
|
// We don't care what the success of the insertion was. If it failed,
|
|
// then the pEndpointConfig will not be extra referenced and the caller
|
|
// will clean it up when it derefs
|
|
//
|
|
|
|
sm_pEndpointConfigHash->InsertRecord( pEndpointConfig );
|
|
|
|
*ppEndpointConfig = pEndpointConfig;
|
|
hr = S_OK;
|
|
|
|
ExitPoint:
|
|
if ( pEndpointConfigData != NULL )
|
|
{
|
|
delete [] pEndpointConfigData;
|
|
pEndpointConfigData = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//static
|
|
LK_PREDICATE
|
|
ENDPOINT_CONFIG::ServerCertPredicate(
|
|
ENDPOINT_CONFIG * pEndpointConfig,
|
|
void * pvState
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
DeleteIf() predicate used to find items which reference the
|
|
SERVER_CERT pointed to by pvState
|
|
|
|
Arguments:
|
|
|
|
pEndpointConfig - SSL endpoint config
|
|
pvState - SERVER_CERT to check for
|
|
|
|
Returns:
|
|
|
|
LK_PREDICATE - LKP_PERFORM indicates removing the current
|
|
token from token cache
|
|
|
|
LKP_NO_ACTION indicates doing nothing.
|
|
|
|
--*/
|
|
{
|
|
LK_PREDICATE lkpAction;
|
|
SERVER_CERT * pServerCert;
|
|
|
|
DBG_ASSERT( pEndpointConfig != NULL );
|
|
|
|
pServerCert = (SERVER_CERT*) pvState;
|
|
DBG_ASSERT( pServerCert != NULL );
|
|
DBG_ASSERT( pServerCert->CheckSignature() );
|
|
|
|
|
|
if ( pEndpointConfig->QueryServerCert() == pServerCert )
|
|
{
|
|
lkpAction = LKP_PERFORM;
|
|
}
|
|
else
|
|
{
|
|
lkpAction = LKP_NO_ACTION;
|
|
}
|
|
|
|
return lkpAction;
|
|
}
|
|
|
|
//static
|
|
HRESULT
|
|
ENDPOINT_CONFIG::FlushByServerCert(
|
|
SERVER_CERT * pServerCert
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Flush the ENDPOINT_CONFIG cache of anything referecing the given server
|
|
certificate
|
|
|
|
Arguments:
|
|
|
|
pServerCert - Server certificate to reference
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT( sm_pEndpointConfigHash != NULL );
|
|
|
|
sm_pEndpointConfigHash->DeleteIf( ENDPOINT_CONFIG::ServerCertPredicate,
|
|
pServerCert );
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//static
|
|
LK_PREDICATE
|
|
ENDPOINT_CONFIG::IisCtlPredicate(
|
|
ENDPOINT_CONFIG * pEndpointConfig,
|
|
void * pvState
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
DeleteIf() predicate used to find items which reference the
|
|
SERVER_CERT pointed to by pvState
|
|
|
|
Arguments:
|
|
|
|
pEndpointConfig - SSL endpoint config
|
|
pvState - IIS_CTL to check for
|
|
|
|
Returns:
|
|
|
|
LK_PREDICATE - LKP_PERFORM indicates removing the current
|
|
token from token cache
|
|
|
|
LKP_NO_ACTION indicates doing nothing.
|
|
|
|
--*/
|
|
{
|
|
LK_PREDICATE lkpAction;
|
|
IIS_CTL * pIisCtl;
|
|
|
|
DBG_ASSERT( pEndpointConfig != NULL );
|
|
|
|
pIisCtl = (IIS_CTL*) pvState;
|
|
DBG_ASSERT( pIisCtl != NULL );
|
|
DBG_ASSERT( pIisCtl->CheckSignature() );
|
|
|
|
if ( pEndpointConfig->QueryIisCtl() == pIisCtl )
|
|
{
|
|
lkpAction = LKP_PERFORM;
|
|
}
|
|
else
|
|
{
|
|
lkpAction = LKP_NO_ACTION;
|
|
}
|
|
|
|
return lkpAction;
|
|
}
|
|
|
|
//static
|
|
HRESULT
|
|
ENDPOINT_CONFIG::FlushByIisCtl(
|
|
IIS_CTL * pIisCtl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Flush the ENDPOINT_CONFIG cache of anything referecing the given CTL
|
|
|
|
Arguments:
|
|
|
|
pIisCtl -
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT( sm_pEndpointConfigHash != NULL );
|
|
|
|
sm_pEndpointConfigHash->DeleteIf( ENDPOINT_CONFIG::IisCtlPredicate,
|
|
pIisCtl );
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//static
|
|
LK_PREDICATE
|
|
ENDPOINT_CONFIG::SiteIdPredicate(
|
|
ENDPOINT_CONFIG * /*pEndpointConfig*/,
|
|
void * pvState
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
DeleteIf() predicate to delete config specified by site id (pvState)
|
|
|
|
Arguments:
|
|
|
|
pEndpointConfig - SSL Endpoint config
|
|
pvState - Site ID
|
|
|
|
Returns:
|
|
|
|
LK_PREDICATE - LKP_PERFORM indicates removing the current
|
|
token from token cache
|
|
|
|
LKP_NO_ACTION indicates doing nothing.
|
|
|
|
--*/
|
|
{
|
|
LK_PREDICATE lkpAction;
|
|
DWORD dwSiteId;
|
|
|
|
|
|
dwSiteId = PtrToUlong(pvState);
|
|
|
|
//
|
|
// Site Id is legacy value - all endpoints will be deleted
|
|
// upon change because we don't internally track site ID any more
|
|
// CODEWORK: Site concept should be completely removed from the code
|
|
// Remove before RC1
|
|
|
|
lkpAction = LKP_PERFORM;
|
|
return lkpAction;
|
|
}
|
|
|
|
|
|
//static
|
|
LK_PREDICATE
|
|
ENDPOINT_CONFIG::EndpointPredicate(
|
|
ENDPOINT_CONFIG * pEndpointConfig,
|
|
void * pvState
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
DeleteIf() predicate to delete config specified by site id (pvState)
|
|
|
|
Arguments:
|
|
|
|
pEndpointConfig - SSL Endpoint config
|
|
pvState - Endpoint key
|
|
|
|
Returns:
|
|
|
|
LK_PREDICATE - LKP_PERFORM indicates removing the current
|
|
token from token cache
|
|
|
|
LKP_NO_ACTION indicates doing nothing.
|
|
|
|
--*/
|
|
{
|
|
LK_PREDICATE lkpAction;
|
|
ENDPOINT_KEY * pEndpointKey;
|
|
|
|
DBG_ASSERT( pEndpointConfig != NULL );
|
|
|
|
pEndpointKey = (ENDPOINT_KEY *) (pvState);
|
|
|
|
if ( *( pEndpointConfig->QueryEndpointKey() ) == *pEndpointKey ||
|
|
*pEndpointKey == GenerateEndpointKey( INADDR_ANY, 0 ) )
|
|
{
|
|
// 0 means to delete all the endpoint info
|
|
lkpAction = LKP_PERFORM;
|
|
}
|
|
else
|
|
{
|
|
lkpAction = LKP_NO_ACTION;
|
|
}
|
|
|
|
return lkpAction;
|
|
}
|
|
|
|
//static
|
|
HRESULT
|
|
ENDPOINT_CONFIG::FlushByEndpoint(
|
|
DWORD LocalAddress,
|
|
USHORT LocalPort
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Flush specified site configuration. If dwSiteId is 0, then flush all
|
|
|
|
Arguments:
|
|
|
|
LocalAddress - IP Address
|
|
LocalPort - Port
|
|
if LocalAddress=INADDR_ANY and LocalPort=0 then all endpoints will be flushed
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT( sm_pEndpointConfigHash != NULL );
|
|
|
|
ENDPOINT_KEY EndpointKey = GenerateEndpointKey( LocalAddress, LocalPort );
|
|
|
|
sm_pEndpointConfigHash->DeleteIf( ENDPOINT_CONFIG::EndpointPredicate,
|
|
(PVOID) &EndpointKey );
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
ENDPOINT_CONFIG::~ENDPOINT_CONFIG()
|
|
{
|
|
if ( _pServerCert != NULL )
|
|
{
|
|
_pServerCert->DereferenceServerCert();
|
|
_pServerCert = NULL;
|
|
}
|
|
|
|
if ( _pIisCtl != NULL )
|
|
{
|
|
_pIisCtl->DereferenceIisCtl();
|
|
_pIisCtl = NULL;
|
|
}
|
|
|
|
if ( _pEndpointConfigData != NULL )
|
|
{
|
|
delete [] _pEndpointConfigData;
|
|
_pEndpointConfigData = NULL;
|
|
}
|
|
|
|
_dwSignature = ENDPOINT_CONFIG_SIGNATURE_FREE;
|
|
}
|
|
|
|
HRESULT
|
|
ENDPOINT_CONFIG::AcquireCredentials(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Do the Schannel thing to get credentials handle representing the
|
|
server cert/mapping configuration of this site
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT( _pServerCert != NULL );
|
|
|
|
return _SiteCreds.AcquireCredentials( _pServerCert,
|
|
QueryUseDSMapper() );
|
|
|
|
}
|
|
|
|
|
|
// static
|
|
VOID
|
|
WINAPI
|
|
ENDPOINT_CONFIG::ConfigStoreChangeCallback(
|
|
PVOID /*pParam*/,
|
|
BOOL /*fWaitFired*/
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback when HttpApi config store change occurs
|
|
|
|
Note: Currently we listen directly on registry changes
|
|
CODEWORK: once httpapi provides change notification mechanism
|
|
we have to use that one
|
|
|
|
|
|
Arguments:
|
|
|
|
not used
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// If we fail to re-register for change notifications
|
|
// we will ignore it. This will unfortunately stop all
|
|
// the future change notifications
|
|
// CODEWORK: consider if there is anything else we can do
|
|
//
|
|
|
|
RegNotifyChangeKeyValue( sm_hHttpApiConfigKey,
|
|
TRUE,
|
|
REG_NOTIFY_CHANGE_LAST_SET |
|
|
REG_NOTIFY_CHANGE_NAME,
|
|
sm_hHttpApiConfigChangeEvent,
|
|
TRUE );
|
|
|
|
//
|
|
// There is no straightforward mechanism to figure out individual change
|
|
// that happened. That's why we will flush all endpoints config
|
|
// ( Changes in the endpoint config are not frequent so this should not be
|
|
// a performance problem at all )
|
|
//
|
|
|
|
FlushByEndpoint( INADDR_ANY, 0 );
|
|
|
|
|
|
}
|
|
|
|
//static
|
|
VOID
|
|
ENDPOINT_CONFIG::Cleanup(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cleanup must be called before Terminate
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
sm_pEndpointConfigHash->Clear();
|
|
}
|