mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-14 13:56:01 +03:00
641 lines
15 KiB
C++
641 lines
15 KiB
C++
#define WIN32_LEAN_AND_MEAN
|
|
|
|
#undef inline
|
|
#define inline inline
|
|
|
|
// IIS7 Server API header file
|
|
#include "httpserv.h"
|
|
|
|
// Project header files
|
|
#include "mymodule.h"
|
|
#include "mymodulefactory.h"
|
|
#include "moduleconfig.h"
|
|
|
|
HRESULT
|
|
MODSECURITY_STORED_CONTEXT::Initialize(
|
|
IHttpContext * pW3Context,
|
|
IAppHostConfigException ** ppException
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IAppHostAdminManager *pAdminManager = NULL;
|
|
IAppHostElement *pSessionTrackingElement = NULL;
|
|
IAppHostPropertyException *pPropertyException = NULL;
|
|
|
|
PCWSTR pszConfigPath = pW3Context->GetMetadata()->GetMetaPath();
|
|
BSTR bstrUrlPath = SysAllocString( pszConfigPath );
|
|
|
|
pAdminManager = g_pHttpServer->GetAdminManager();
|
|
|
|
if ( ( FAILED( hr ) ) || ( pAdminManager == NULL ) )
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
goto Failure;
|
|
}
|
|
|
|
// Get a handle to the section:
|
|
hr = pAdminManager->GetAdminSection(
|
|
MODSECURITY_SECTION,
|
|
bstrUrlPath,
|
|
&pSessionTrackingElement );
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
if ( pSessionTrackingElement == NULL )
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
goto Failure;
|
|
}
|
|
|
|
// Get the property object for the 'enabled' attribute:
|
|
hr = GetBooleanPropertyValue(
|
|
pSessionTrackingElement,
|
|
MODSECURITY_SECTION_ENABLED,
|
|
&pPropertyException,
|
|
&m_bIsEnabled);
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
// If there is a config failure, we cannot continue execution:
|
|
if ( pPropertyException != NULL )
|
|
{
|
|
|
|
ppException = ( IAppHostConfigException** ) &pPropertyException;
|
|
goto Failure;
|
|
}
|
|
|
|
if ( m_bIsEnabled == FALSE )
|
|
{
|
|
// There is no point in reading any more of the config associated with the session
|
|
// tracking section, since this feature is not enabled for the current URL
|
|
goto Failure;
|
|
}
|
|
|
|
// Get the property object for the 'configfile' attribute:
|
|
hr = GetStringPropertyValue(
|
|
pSessionTrackingElement,
|
|
MODSECURITY_SECTION_CONFIGFILE,
|
|
&pPropertyException,
|
|
&m_pszPath);
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
// If there is a config failure, we cannot continue execution:
|
|
if ( pPropertyException != NULL )
|
|
{
|
|
|
|
ppException = ( IAppHostConfigException** ) &pPropertyException;
|
|
goto Failure;
|
|
}
|
|
|
|
Failure:
|
|
SysFreeString( bstrUrlPath );
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
MODSECURITY_STORED_CONTEXT::GetBooleanPropertyValue(
|
|
IAppHostElement* pElement,
|
|
WCHAR* pszPropertyName,
|
|
IAppHostPropertyException** pException,
|
|
BOOL* pBoolValue )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IAppHostProperty *pProperty = NULL;
|
|
VARIANT vPropertyValue;
|
|
|
|
if (
|
|
( pElement == NULL ) ||
|
|
( pszPropertyName == NULL ) ||
|
|
( pException == NULL ) ||
|
|
( pBoolValue == NULL )
|
|
)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Failure;
|
|
}
|
|
|
|
// Get the property object for the BOOLEAN attribute:
|
|
hr = pElement->GetPropertyByName(
|
|
pszPropertyName,
|
|
&pProperty );
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
if ( pProperty == NULL )
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
goto Failure;
|
|
}
|
|
|
|
// Get the attribute value:
|
|
VariantInit( &vPropertyValue );
|
|
|
|
hr = pProperty->get_Value( &vPropertyValue );
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
// See it there is an exception that might be due to the actual value in the
|
|
// config not meeting validation criteria
|
|
*pException = NULL;
|
|
|
|
hr = pProperty->get_Exception( pException );
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
// No need to continue if we got an exception...
|
|
if ( ( *pException ) != NULL )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
// Finally, get the value:
|
|
*pBoolValue = ( vPropertyValue.boolVal == VARIANT_TRUE ) ? TRUE : FALSE;
|
|
|
|
|
|
Failure:
|
|
VariantClear( &vPropertyValue );
|
|
|
|
if ( pProperty != NULL )
|
|
{
|
|
pProperty->Release();
|
|
pProperty = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
MODSECURITY_STORED_CONTEXT::GetDWORDPropertyValue(
|
|
IAppHostElement* pElement,
|
|
WCHAR* pszPropertyName,
|
|
IAppHostPropertyException** pException,
|
|
DWORD* pnValue )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IAppHostProperty *pProperty = NULL;
|
|
VARIANT vPropertyValue;
|
|
|
|
if (
|
|
( pElement == NULL ) ||
|
|
( pszPropertyName == NULL ) ||
|
|
( pException == NULL ) ||
|
|
( pnValue == NULL )
|
|
)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Failure;
|
|
}
|
|
|
|
// Get the property object for the INT attribute:
|
|
hr = pElement->GetPropertyByName(
|
|
pszPropertyName,
|
|
&pProperty );
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
if ( pProperty == NULL )
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
goto Failure;
|
|
}
|
|
|
|
// Get the attribute value:
|
|
VariantInit( &vPropertyValue );
|
|
|
|
hr = pProperty->get_Value( &vPropertyValue );
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
// See it there is an exception that might be due to the actual value in the
|
|
// config not meeting validation criteria
|
|
*pException = NULL;
|
|
|
|
hr = pProperty->get_Exception( pException );
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
// No need to continue if we got an exception...
|
|
if ( ( *pException ) != NULL )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
// Finally, get the value:
|
|
*pnValue = vPropertyValue.ulVal;
|
|
|
|
Failure:
|
|
VariantClear( &vPropertyValue );
|
|
|
|
if ( pProperty != NULL )
|
|
{
|
|
pProperty->Release();
|
|
pProperty = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
MODSECURITY_STORED_CONTEXT::GetTimeSpanPropertyValue(
|
|
IAppHostElement* pElement,
|
|
WCHAR* pszPropertyName,
|
|
IAppHostPropertyException** pException,
|
|
ULONGLONG* pnValue )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IAppHostProperty *pProperty = NULL;
|
|
VARIANT vPropertyValue;
|
|
|
|
if (
|
|
( pElement == NULL ) ||
|
|
( pszPropertyName == NULL ) ||
|
|
( pException == NULL ) ||
|
|
( pnValue == NULL )
|
|
)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Failure;
|
|
}
|
|
|
|
// Get the property object for the INT attribute:
|
|
hr = pElement->GetPropertyByName(
|
|
pszPropertyName,
|
|
&pProperty );
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
if ( pProperty == NULL )
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
goto Failure;
|
|
}
|
|
|
|
// Get the attribute value:
|
|
VariantInit( &vPropertyValue );
|
|
|
|
hr = pProperty->get_Value( &vPropertyValue );
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
// See it there is an exception that might be due to the actual value in the
|
|
// config not meeting validation criteria
|
|
*pException = NULL;
|
|
|
|
hr = pProperty->get_Exception( pException );
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
// No need to continue if we got an exception...
|
|
if ( ( *pException ) != NULL )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
// Finally, get the value:
|
|
*pnValue = vPropertyValue.ullVal;
|
|
|
|
Failure:
|
|
VariantClear( &vPropertyValue );
|
|
|
|
if ( pProperty != NULL )
|
|
{
|
|
pProperty->Release();
|
|
pProperty = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
MODSECURITY_STORED_CONTEXT::GetStringPropertyValue(
|
|
IAppHostElement* pElement,
|
|
WCHAR* pszPropertyName,
|
|
IAppHostPropertyException** pException,
|
|
WCHAR** ppszValue )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IAppHostProperty *pProperty = NULL;
|
|
DWORD dwLength;
|
|
VARIANT vPropertyValue;
|
|
|
|
if (
|
|
( pElement == NULL ) ||
|
|
( pszPropertyName == NULL ) ||
|
|
( pException == NULL ) ||
|
|
( ppszValue == NULL )
|
|
)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Failure;
|
|
}
|
|
|
|
*ppszValue = NULL;
|
|
|
|
// Get the property object for the string attribute:
|
|
hr = pElement->GetPropertyByName(
|
|
pszPropertyName,
|
|
&pProperty );
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
if ( pProperty == NULL )
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
goto Failure;
|
|
}
|
|
|
|
// Get the attribute value:
|
|
VariantInit( &vPropertyValue );
|
|
|
|
hr = pProperty->get_Value( &vPropertyValue );
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
// See it there is an exception that might be due to the actual value in the
|
|
// config not meeting validation criteria
|
|
*pException = NULL;
|
|
|
|
hr = pProperty->get_Exception( pException );
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
// No need to continue if we got an exception...
|
|
if ( ( *pException ) != NULL )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
// Finally, get the value:
|
|
dwLength = SysStringLen( vPropertyValue.bstrVal );
|
|
*ppszValue = new WCHAR[ dwLength + 1 ];
|
|
|
|
if ( (*ppszValue) == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
wcsncpy(
|
|
*ppszValue,
|
|
vPropertyValue.bstrVal,
|
|
dwLength );
|
|
|
|
(*ppszValue)[ dwLength ] = L'\0';
|
|
|
|
Failure:
|
|
VariantClear( &vPropertyValue );
|
|
|
|
if ( pProperty != NULL )
|
|
{
|
|
pProperty->Release();
|
|
pProperty = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
MODSECURITY_STORED_CONTEXT::~MODSECURITY_STORED_CONTEXT()
|
|
{
|
|
if ( m_pszPath != NULL )
|
|
{
|
|
delete [] m_pszPath;
|
|
m_pszPath = NULL;
|
|
}
|
|
}
|
|
|
|
MODSECURITY_STORED_CONTEXT::MODSECURITY_STORED_CONTEXT():
|
|
m_bIsEnabled ( FALSE ),
|
|
m_pszPath( NULL ),
|
|
m_Config( NULL ),
|
|
m_dwLastCheck( 0 )
|
|
{
|
|
m_LastChange.dwLowDateTime = 0;
|
|
m_LastChange.dwHighDateTime = 0;
|
|
}
|
|
|
|
DWORD
|
|
MODSECURITY_STORED_CONTEXT::GlobalWideCharToMultiByte(
|
|
WCHAR* pSource,
|
|
DWORD dwLengthSource,
|
|
CHAR** ppszDestination,
|
|
USHORT* pdwLengthDestination )
|
|
{
|
|
DWORD dwResult = NULL;
|
|
DWORD dwCount = 0;
|
|
|
|
if (
|
|
( pSource == NULL ) ||
|
|
( ppszDestination == NULL ) ||
|
|
( pdwLengthDestination == NULL )
|
|
)
|
|
{
|
|
dwResult = ERROR_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
// Initialize result length
|
|
*pdwLengthDestination = 0;
|
|
*ppszDestination = NULL;
|
|
|
|
dwCount = WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
pSource,
|
|
dwLengthSource + 1,
|
|
*ppszDestination,
|
|
0,
|
|
NULL,
|
|
NULL );
|
|
|
|
if ( 0 == dwCount )
|
|
{
|
|
dwResult = GetLastError ();
|
|
|
|
if ( dwResult == 0 )
|
|
{
|
|
dwResult = ERROR_INVALID_DATA;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
*ppszDestination = new CHAR[ dwCount + 1 ];
|
|
|
|
if ( NULL == ( *ppszDestination ) )
|
|
{
|
|
dwResult = ERROR_OUTOFMEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the memory is 'clean':
|
|
SecureZeroMemory(
|
|
( *ppszDestination ),
|
|
( dwCount + 1 ) * sizeof ( CHAR ) );
|
|
|
|
if (
|
|
0 == WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
pSource,
|
|
dwLengthSource + 1,
|
|
*ppszDestination,
|
|
dwCount,
|
|
NULL,
|
|
NULL )
|
|
)
|
|
{
|
|
dwResult = GetLastError();
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
*pdwLengthDestination = ( USHORT )dwCount;
|
|
|
|
Exit:
|
|
if ( dwResult != 0 )
|
|
{
|
|
// Make sure we do the proper cleanup in the error case:
|
|
if ( pdwLengthDestination != NULL )
|
|
{
|
|
*pdwLengthDestination = 0;
|
|
}
|
|
|
|
if ( ppszDestination != NULL )
|
|
{
|
|
if ( ( *ppszDestination ) != NULL )
|
|
{
|
|
delete [] ( *ppszDestination );
|
|
( *ppszDestination ) = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
HRESULT
|
|
MODSECURITY_STORED_CONTEXT::GetConfig(
|
|
IHttpContext * pContext,
|
|
MODSECURITY_STORED_CONTEXT ** ppModuleConfig
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
MODSECURITY_STORED_CONTEXT * pModuleConfig = NULL;
|
|
IHttpModuleContextContainer * pMetadataContainer = NULL;
|
|
IAppHostConfigException * pException = NULL;
|
|
|
|
pMetadataContainer = pContext->GetMetadata()->GetModuleContextContainer();
|
|
|
|
if ( pMetadataContainer == NULL )
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
return hr;
|
|
}
|
|
|
|
pModuleConfig = (MODSECURITY_STORED_CONTEXT *)pMetadataContainer->GetModuleContext( g_pModuleContext );
|
|
if ( pModuleConfig != NULL )
|
|
{
|
|
//
|
|
// We found stored data for this module for the metadata
|
|
// object which is different for unique configuration path
|
|
//
|
|
*ppModuleConfig = pModuleConfig;
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// If we reach here, that means this is first request or first
|
|
// request after a configuration change IIS core will throw stored context away
|
|
// if a change notification arrives for this metadata path
|
|
//
|
|
pModuleConfig = new MODSECURITY_STORED_CONTEXT();
|
|
if ( pModuleConfig == NULL )
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Read module configuration data and store in MODSECURITY_STORED_CONTEXT
|
|
//
|
|
hr = pModuleConfig->Initialize( pContext, &pException );
|
|
if ( FAILED( hr ) || pException != NULL )
|
|
{
|
|
pModuleConfig->CleanupStoredContext();
|
|
|
|
pModuleConfig = NULL;
|
|
hr = E_UNEXPECTED;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Store MODSECURITY_STORED_CONTEXT data as metadata stored context
|
|
//
|
|
hr = pMetadataContainer->SetModuleContext( pModuleConfig,
|
|
g_pModuleContext );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
pModuleConfig->CleanupStoredContext();
|
|
pModuleConfig = NULL;
|
|
|
|
//
|
|
// It is possible that some other thread stored context before this thread
|
|
// could do. Check returned hr and return context stored by other thread
|
|
//
|
|
if ( hr == HRESULT_FROM_WIN32( ERROR_ALREADY_ASSIGNED ) )
|
|
{
|
|
*ppModuleConfig = (MODSECURITY_STORED_CONTEXT *)pMetadataContainer->GetModuleContext( g_pModuleContext );
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
*ppModuleConfig = pModuleConfig;
|
|
return hr;
|
|
}
|