/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*/
#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;
}