2025-04-27 07:49:33 -04:00

537 lines
13 KiB
C++

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name :
sitebinding.cxx
Abstract:
Given a ip-address/port, determine the site ID
Author:
Bilal Alam (BAlam) 29-March-2000
Environment:
Win32 - User Mode
Project:
Stream Filter Worker Process
--*/
#include "precomp.hxx"
SITE_BINDING_HASH * SITE_BINDING::sm_pSiteBindingHash;
BOOL SITE_BINDING::sm_fAllWildcardBindings;
//static
HRESULT
SITE_BINDING::ParseSiteBinding(
WCHAR * pszBinding,
DWORD * pLocalAddress,
USHORT * pLocalPort
)
/*++
Routine Description:
Parse a metabase site binding into an address/port
Arguments:
pszBinding - Binding in metabase (in form ip:port)
pLocalAddress - Filled with ip address of binding on success
pLocalPort - Filled with port of binding on success
Return Value:
HRESULT
--*/
{
LPWSTR pszPort;
LPWSTR pszEnd;
HRESULT hr = NO_ERROR;
ULONG LocalPort;
STACK_STRA( strIpAddress, 64 );
if ( pszBinding == NULL ||
pLocalAddress == NULL ||
pLocalPort == NULL )
{
DBG_ASSERT( FALSE );
return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
}
//
// Binding is of form "IP-Address:Port:Host"
//
// For our purposes (SSL), we'll ignore the Host
// For wildcard IP addresss, the parameter is empty (example :443:)
//
pszEnd = wcschr( pszBinding, L':' );
if ( pszEnd == NULL )
{
hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
goto Finished;
}
//
// Handle the IP address
//
if ( pszBinding[ 0 ] == L'\0' )
{
*pLocalAddress = WILDCARD_ADDRESS;
}
else
{
hr = strIpAddress.CopyW( pszBinding,
DIFF( pszEnd - pszBinding ) );
if ( FAILED( hr ) )
{
goto Finished;
}
*pLocalAddress = inet_addr( strIpAddress.QueryStr() );
}
//
// Handle the port
//
pszBinding = pszEnd + 1;
if ( *pszBinding == L'\0' )
{
goto Finished;
}
LocalPort = wcstoul( pszBinding, NULL, 10 );
if ( LocalPort > 0xFFFF ||
LocalPort == 0 )
{
goto Finished;
}
*pLocalPort = (USHORT) LocalPort;
Finished:
return hr;
}
//static
HRESULT
SITE_BINDING::Initialize(
VOID
)
/*++
Routine Description:
Read all the site bindings and insert them into hash table
Arguments:
None
Return Value:
HRESULT
--*/
{
MB mb( g_pStreamFilter->QueryMDObject() );
BOOL fRet;
HRESULT hr = NO_ERROR;
DWORD dwIndex;
DWORD dwSiteId;
WCHAR achSitePath[ METADATA_MAX_NAME_LEN ];
DWORD LocalAddress;
USHORT LocalPort;
LPWSTR pszBinding;
MULTISZ mszBindings;
LK_RETCODE lkRet;
SITE_BINDING * pSiteBinding;
DBG_ASSERT( sm_pSiteBindingHash == NULL );
sm_fAllWildcardBindings = TRUE;
//
// First create a hash table to store all site bindings
//
sm_pSiteBindingHash = new SITE_BINDING_HASH();
if ( sm_pSiteBindingHash == NULL )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
goto Finished;
}
//
// Iterate all sites in metabase and populate the table
//
fRet = mb.Open( L"/LM/W3SVC",
METADATA_PERMISSION_READ );
if ( !fRet )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
goto Finished;
}
dwIndex = 0;
while ( mb.EnumObjects( L"",
achSitePath,
dwIndex++ ) )
{
//
// We only want the sites (w3svc/<number>)
//
dwSiteId = wcstoul( achSitePath, NULL, 10 );
if ( dwSiteId == 0 )
{
continue;
}
fRet = mb.GetMultisz( achSitePath,
MD_SECURE_BINDINGS,
IIS_MD_UT_SERVER,
&mszBindings,
0 );
if ( fRet )
{
//
// We have a secure binding (and thus a SSL site)
// Iterate thru the site bindings and make an entry (and add
// to hash table) to each one
//
pszBinding = (LPWSTR) mszBindings.First();
do
{
if ( pszBinding == NULL )
{
//
// An empty site binding was set. Just bail
//
break;
}
hr = SITE_BINDING::ParseSiteBinding( pszBinding,
&LocalAddress,
&LocalPort );
if ( FAILED( hr ) )
{
break;
}
//
// Keep track if we have encountered a non-wildcard bound
// site. This will speed up our lookup of site bindings
// at "run-time"
//
if ( sm_fAllWildcardBindings &&
LocalAddress != WILDCARD_ADDRESS )
{
sm_fAllWildcardBindings = FALSE;
}
//
// Add to hash table
//
pSiteBinding = new SITE_BINDING( LocalAddress,
LocalPort,
dwSiteId );
if ( pSiteBinding == NULL )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
goto Finished;
}
lkRet = sm_pSiteBindingHash->InsertRecord( pSiteBinding );
if ( lkRet != LK_SUCCESS )
{
//
// ISSUE: What to do
//
}
else
{
//
// The hash table owns the reference
//
pSiteBinding->DereferenceSiteBinding();
}
}
while ( pszBinding = (LPWSTR) mszBindings.Next( pszBinding ) );
}
}
Finished:
if ( FAILED( hr ) )
{
if ( sm_pSiteBindingHash != NULL )
{
delete sm_pSiteBindingHash;
sm_pSiteBindingHash = NULL;
}
}
return hr;
}
//static
VOID
SITE_BINDING::Terminate(
VOID
)
/*++
Routine Description:
Cleanup global binding table
Arguments:
None
Return Value:
None
--*/
{
if ( sm_pSiteBindingHash != NULL )
{
delete sm_pSiteBindingHash;
sm_pSiteBindingHash = NULL;
}
}
//static
HRESULT
SITE_BINDING::HandleSiteBindingChange(
DWORD dwSiteId,
WCHAR * pszSitePath
)
/*++
Routine Description:
Handle site binding change by updating our table accordingly
Arguments:
dwSiteId - Site ID whose binding has changed
pszSitePath - Metabase path for site
Return Value:
HRESULT
--*/
{
BOOL fRet;
LPWSTR pszBinding;
MULTISZ mszBindings;
HRESULT hr = NO_ERROR;
DWORD LocalAddress;
USHORT LocalPort;
SITE_BINDING_KEY bindingKey;
SITE_BINDING * pSiteBinding = NULL;
LK_RETCODE lkRet;
MB mb( g_pStreamFilter->QueryMDObject() );
fRet = mb.Open( pszSitePath,
METADATA_PERMISSION_READ );
if ( !fRet )
{
return HRESULT_FROM_WIN32( GetLastError() );
}
fRet = mb.GetMultisz( NULL,
MD_SECURE_BINDINGS,
IIS_MD_UT_SERVER,
&mszBindings,
0 );
if ( fRet )
{
//
// With the secure binding, find any existing sites with this binding
// and remove them.
//
pszBinding = (LPWSTR) mszBindings.First();
do
{
if ( pszBinding == NULL )
{
//
// An empty site binding was set. Just bail
//
break;
}
hr = SITE_BINDING::ParseSiteBinding( pszBinding,
&LocalAddress,
&LocalPort );
if ( FAILED( hr ) )
{
break;
}
//
// Keep track if we have encountered a non-wildcard bound
// site. This will speed up our lookup of site bindings
// at "run-time"
//
if ( sm_fAllWildcardBindings &&
LocalAddress != WILDCARD_ADDRESS )
{
sm_fAllWildcardBindings = FALSE;
}
//
// Delete the site for the given binding
//
bindingKey = GenerateBindingKey( LocalAddress, LocalPort );
sm_pSiteBindingHash->DeleteKey( bindingKey );
//
// Now insert a new entry
//
pSiteBinding = new SITE_BINDING( LocalAddress,
LocalPort,
dwSiteId );
if ( pSiteBinding == NULL )
{
return HRESULT_FROM_WIN32( GetLastError() );
}
lkRet = sm_pSiteBindingHash->InsertRecord( pSiteBinding );
if ( lkRet != LK_SUCCESS )
{
//
// ISSUE: What to do
//
}
else
{
//
// The hash table owns the reference
//
pSiteBinding->DereferenceSiteBinding();
}
}
while ( pszBinding = (LPWSTR) mszBindings.Next( pszBinding ) );
}
return NO_ERROR;
}
//static
HRESULT
SITE_BINDING::GetSiteId(
DWORD LocalAddress,
USHORT LocalPort,
DWORD * pdwSiteId
)
/*++
Routine Description:
Given an ip-address/port, determine the matching site id
Arguments:
LocalAddress - Local IP address
LocalPort - Local Port
pdwSiteId - Filled with site id on success
Return Value:
HRESULT
--*/
{
SITE_BINDING_KEY bindingKey;
LK_RETCODE lkrc;
SITE_BINDING * pSiteBinding = NULL;
if ( pdwSiteId == NULL )
{
DBG_ASSERT( FALSE );
return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
}
*pdwSiteId = 0;
DBG_ASSERT( sm_pSiteBindingHash != NULL );
//
// Do we have an non-wildcard bindings in the table? If so start by
// looking up the specific ip-address/port pair
//
if ( !sm_fAllWildcardBindings )
{
bindingKey = GenerateBindingKey( LocalAddress, LocalPort );
lkrc = sm_pSiteBindingHash->FindKey( bindingKey, &pSiteBinding );
if ( lkrc == LK_SUCCESS )
{
//
// We're done!
//
DBG_ASSERT( pSiteBinding != NULL );
*pdwSiteId = pSiteBinding->QuerySiteId();
pSiteBinding->DereferenceSiteBinding();
return NO_ERROR;
}
}
//
// Now we try to find a wildcard binding
//
bindingKey = GenerateBindingKey( WILDCARD_ADDRESS, LocalPort );
lkrc = sm_pSiteBindingHash->FindKey( bindingKey, &pSiteBinding );
if ( lkrc == LK_SUCCESS )
{
//
// We're done!
//
DBG_ASSERT( pSiteBinding != NULL );
*pdwSiteId = pSiteBinding->QuerySiteId();
pSiteBinding->DereferenceSiteBinding();
return NO_ERROR;
}
//
// Could not find a binding.
//
return HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
}