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