|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
filtinit.cxx
Abstract:
This module contains the Microsoft HTTP server filter module for stuff that has to do with filter initialization, loading and unloading.
Author:
John Ludeman (johnl) 06-Aug-1996
Revision History:
--*/
#include "w3p.hxx"
//
// If the request doesn't specify an entry point, default to using
// this
//
#define SF_DEFAULT_ENTRY "HttpFilterProc"
#define SF_VERSION_ENTRY "GetFilterVersion"
#define SF_TERM_ENTRY "TerminateFilter"
//
// Name of the value under the parameters key containing the list of
// filter dlls. This was the value for IIS 1.0 and 2.0. Global filters
// can still be specified under this key.
//
#define HTTP_FILTER_DLLS "Filter DLLs"
//
// Globals
//
static BOOL g_fInitialized = FALSE; LIST_ENTRY g_FilterHead; // List of filter DLLs
CRITICAL_SECTION g_csFilterDlls;
//
// Prototypes
//
BOOL UpdateInstanceFilters( IN const CHAR * pszNewDll, IN const CHAR * pszOldDll, IN W3_SERVER_INSTANCE * pInst );
BOOL AdjustInstanceFilterListFlags( IN PVOID pvContext1, IN PVOID pvContext2, IN IIS_SERVER_INSTANCE *pInstance );
FILTER_LIST * InitializeFilters( BOOL * pfAnySecureFilters, W3_IIS_SERVICE * pSvc ) /*++
Routine Description:
Loads the global filter DLLs and their corresponding entry point. Note the global filter list does not allow unloads.
g_fInitialized should only be set after all of the global filters are loaded.
Arguments:
pfAnySecureFilters - Set to TRUE if there are any secure filters pSvc - Pointer to service global. The global service pointer isn't initialized yet so we pass it in for global filter initialization. Only used for logging events.
Return Value:
Global filter list or NULL if an error occurred
--*/ { CHAR szFilterKey[MAX_PATH+1]; FILTER_LIST * pfl; DWORD cb; CHAR szLoadOrder[1024]; CHAR szDllName[MAX_PATH+1]; CHAR * pchFilter; CHAR * pchComma; MB mb( (IMDCOM*) pSvc->QueryMDObject() ); DWORD fEnabled; DWORD cFilters; HKEY hkeyParam = NULL; DWORD err = NO_ERROR; BOOL fOpened;
INITIALIZE_CRITICAL_SECTION( &g_csFilterDlls ); InitializeListHead( &g_FilterHead );
strcpy( szFilterKey, IIS_MD_LOCAL_MACHINE_PATH "/" W3_SERVICE_NAME_A ); strcat( szFilterKey, IIS_MD_ISAPI_FILTERS ); DBG_ASSERT( strlen( szFilterKey ) + 1 < sizeof( szFilterKey ));
pfl = new FILTER_LIST();
if ( !pfl ) {
return NULL; }
//
// Loop through filter keys, if we can't access the metabase, we assume
// success and continue
//
if ( !mb.Open( szFilterKey, METADATA_PERMISSION_READ )) { DBGPRINTF(( DBG_CONTEXT, "[InitializeFilterList] Cannot open path %s, error %lu\n", szFilterKey, GetLastError() )); return pfl; } fOpened = TRUE;
//
// Get the filter load order
//
cb = sizeof( szLoadOrder ); *szLoadOrder = '\0';
if ( !mb.GetString( "", MD_FILTER_LOAD_ORDER, IIS_MD_UT_SERVER, szLoadOrder, &cb, 0 )) { DBGPRINTF(( DBG_CONTEXT, "[InitializeFilterList] Cannot load filter load order, error %lu\n", szFilterKey, GetLastError() )); delete pfl; return NULL; }
pchFilter = szLoadOrder;
while ( *pchFilter ) { if ( !fOpened && !mb.Open( szFilterKey, METADATA_PERMISSION_READ )) { DBGPRINTF(( DBG_CONTEXT, "[InitializeFilterList] Cannot open path %s, error %lu\n", szFilterKey, GetLastError() )); break; } fOpened = TRUE;
pchComma = strchr( pchFilter, ',' );
if ( pchComma ) { *pchComma = '\0'; }
while ( ISWHITEA( *pchFilter )) { pchFilter++; }
fEnabled = TRUE; mb.GetDword( pchFilter, MD_FILTER_ENABLED, IIS_MD_UT_SERVER, &fEnabled );
if ( fEnabled ) { cb = sizeof(szDllName); if ( mb.GetString( pchFilter, MD_FILTER_IMAGE_PATH, IIS_MD_UT_SERVER, szDllName, &cb, 0 )) { mb.Close(); fOpened = FALSE;
if ( pfl->LoadFilter( &mb, szFilterKey, &fOpened, pchFilter, szDllName, TRUE, pSvc )) { DBGPRINTF(( DBG_CONTEXT, "[InitializeFilterList] Loaded %s\n", szDllName )); } } } if ( pchComma ) { pchFilter = pchComma + 1; } else { break; } }
//
// Now load any filters that have been added in the registry for
// downlevel compatibility
//
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, W3_PARAMETERS_KEY, 0, KEY_READ, &hkeyParam );
if( err == NO_ERROR ) { TCHAR * psz; TCHAR * pszFilterList = NULL;
if ( ReadRegString( hkeyParam, &pszFilterList, HTTP_FILTER_DLLS, "" )) { RegCloseKey( hkeyParam );
psz = pszFilterList;
//
// Parse the comma separated list of dlls
//
INET_PARSER Parser( pszFilterList ); Parser.SetListMode( TRUE );
while ( *(psz = Parser.QueryToken()) ) { if ( pfl->LoadFilter( NULL, NULL, &fOpened, psz, psz, TRUE, pSvc )) { const CHAR * apszSubString[1];
DBGPRINTF(( DBG_CONTEXT, "[InitializeFilterList] Loaded %s\n", psz ));
apszSubString[0] = psz;
//
// Log a warning here if we picked up a filter from the
// registry
//
pSvc->LogEvent( W3_MSG_LOADED_FILTER_FROM_REG, 1, apszSubString, NO_ERROR ); }
Parser.NextItem(); }
Parser.RestoreBuffer();
TCP_FREE( pszFilterList ); } else { RegCloseKey( hkeyParam ); } }
*pfAnySecureFilters = CheckForSecurityFilter( pfl );
g_fInitialized = TRUE;
return pfl; }
VOID TerminateFilters( VOID ) /*++
Routine Description:
Unloads any filter DLLs and their corresponding entry point
--*/ { LIST_ENTRY * pEntry; HTTP_FILTER_DLL * pFilterDll;
if ( g_fInitialized ) { EnterCriticalSection( &g_csFilterDlls );
for ( pEntry = g_FilterHead.Flink; pEntry != &g_FilterHead; pEntry = g_FilterHead.Flink) { pFilterDll = CONTAINING_RECORD( pEntry, HTTP_FILTER_DLL, ListEntry );
RemoveEntryList( pEntry );
//
// This should delete the filter dll
//
DBGPRINTF(( DBG_CONTEXT, "[TerminateFilters] Filter %s, ref count %d\n", pFilterDll->QueryName(), pFilterDll->QueryRef() ));
// DBG_ASSERT( pFilterDll->QueryRef() == 1 );
HTTP_FILTER_DLL::Dereference( pFilterDll ); }
LeaveCriticalSection( &g_csFilterDlls ); DeleteCriticalSection( &g_csFilterDlls ); } }
HTTP_FILTER_DLL * CheckoutFilterDll( IN const CHAR * pszFilterDll ) /*++
Routine Description:
Checks to see if an existing filter dll is already loaded and ups the ref count if it is
NOTE: THE FILTER LIST LOCK MUST BE TAKEN PRIOR TO CALLING THIS FUNCTION
Arguments:
pszFilterDLL - Fully qualified path to filter dll to load
Return Value:
Pointer to the filter if it's already loaded, NULL if the filter isn't loaded
--*/ { LIST_ENTRY * pEntry; HTTP_FILTER_DLL * pFilterDll;
for ( pEntry = g_FilterHead.Flink; pEntry != &g_FilterHead; pEntry = pEntry->Flink ) { pFilterDll = CONTAINING_RECORD( pEntry, HTTP_FILTER_DLL, ListEntry );
DBG_ASSERT( pFilterDll->CheckSignature() );
if ( !lstrcmpi( pFilterDll->QueryName(), pszFilterDll )) { pFilterDll->Reference(); return pFilterDll; } }
return NULL; }
BOOL HTTP_FILTER_DLL::LoadDll( MB * pmb OPTIONAL, const CHAR * pszKeyName, LPBOOL pfOpened, const CHAR * pszRelFilterPath, const CHAR * pszFilterDll ) /*++
Routine Description:
Loads the specified dll
Arguments:
pmb - Open metabase to /filters key pszKeyName - metabase filters key name pfOpened - updated with TRUE if pmb opened on return pszFilterDll - Fully qualified name of filter to load
THE GLOBAL FILTER LIST LOCK MUST BE TAKEN PRIOR TO CALLING THIS METHOD
Return Value:
TRUE on success, FALSE on failure (call GetLastError)
--*/ { HTTP_FILTER_VERSION ver;
if ( !m_strName.Copy( pszFilterDll )) { return FALSE; }
//
// Load it and put it in the list, note the filter list lock
// is still taken
//
m_hmod = LoadLibraryEx( pszFilterDll, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
if ( g_fIsWindows95 && (m_hmod == NULL) && (GetLastError() == ERROR_FILE_NOT_FOUND) ) {
//
// According to vlads: the behaviour of flags used in loadlibraryex
// is different between chicago and NT. This caused a problem
// loading frontpage filters.
//
m_hmod = LoadLibrary( pszFilterDll); }
if ( !m_hmod ) { DBGPRINTF(( DBG_CONTEXT, "[LoadDll] LoadLibrary failed with error %d\n", GetLastError()));
goto ErrorExit; }
//
// Retrieve the entry point
//
m_pfnSFVer = (PFN_SF_VER_PROC) GetProcAddress( m_hmod, SF_VERSION_ENTRY ); m_pfnSFProc = (PFN_SF_DLL_PROC) GetProcAddress( m_hmod, SF_DEFAULT_ENTRY ); m_pfnSFTerm = (PFN_SF_TERM_PROC) GetProcAddress( m_hmod, SF_TERM_ENTRY );
if ( !m_pfnSFProc || !m_pfnSFVer ) { //
// Don't call the terminator if we didn't call the initializer
//
m_pfnSFTerm = NULL; goto ErrorExit; }
ver.dwServerFilterVersion = HTTP_FILTER_REVISION;
//
// Call the version entry point and get the filter capabilities
//
if ( !m_pfnSFVer( &ver ) ) { goto ErrorExit; }
if ( pmb && (*pfOpened || pmb->Open( pszKeyName, METADATA_PERMISSION_READ|METADATA_PERMISSION_WRITE )) ) { *pfOpened = TRUE;
if ( !pmb->SetString( pszRelFilterPath, MD_FILTER_DESCRIPTION, IIS_MD_UT_SERVER, ver.lpszFilterDesc, 0 ) || !pmb->SetDword( pszRelFilterPath, MD_FILTER_FLAGS, IIS_MD_UT_SERVER, ver.dwFlags, 0 )) { goto ErrorExit; } }
//
// If the client didn't specify any of the secure port notifications,
// supply them with the default of both
//
if ( !(ver.dwFlags & (SF_NOTIFY_SECURE_PORT | SF_NOTIFY_NONSECURE_PORT))) { ver.dwFlags |= (SF_NOTIFY_SECURE_PORT | SF_NOTIFY_NONSECURE_PORT); }
m_dwVersion = ver.dwFilterVersion; m_dwFlags = (ver.dwFlags & SF_NOTIFY_NONSECURE_PORT) ? ver.dwFlags : 0; m_dwSecureFlags = (ver.dwFlags & SF_NOTIFY_SECURE_PORT) ? ver.dwFlags : 0;
//
// Put the new dll on the filter dll list
//
InsertHeadList( &g_FilterHead, &ListEntry );
return TRUE;
ErrorExit:
return FALSE; }
BOOL HTTP_FILTER_DLL::Unload( const CHAR * pszDll ) /*++
Routine Description:
Finds the existing DLL and sets it up to be unloaded
Arguments:
pszDLL - Fully qualified path to filter dll to load
Return Value:
TRUE if the filter DLL was found, FALSE if it wasn't found or it's already marked for deletion
--*/ { LIST_ENTRY * pEntry; HTTP_FILTER_DLL * pFilterDll;
EnterCriticalSection( &g_csFilterDlls );
for ( pEntry = g_FilterHead.Flink; pEntry != &g_FilterHead; pEntry = pEntry->Flink ) { pFilterDll = CONTAINING_RECORD( pEntry, HTTP_FILTER_DLL, ListEntry );
DBG_ASSERT( pFilterDll->CheckSignature() );
if ( !lstrcmpi( pFilterDll->QueryName(), pszDll )) { RemoveEntryList( pEntry );
LeaveCriticalSection( &g_csFilterDlls ); return TRUE; } }
LeaveCriticalSection( &g_csFilterDlls );
return FALSE; }
BOOL FILTER_LIST::LoadFilter( MB * pmb, LPSTR pszKeyName, LPBOOL pfOpened, const CHAR * pszRelativeMBPath, const CHAR * pszFilterDll, BOOL fAllowRawRead, W3_IIS_SERVICE * pSvc ) /*++
Routine Description:
Loads the specified filter into this filter list. Note the filter dll's ref count starts at one for being on the g_FilterHead list. Thus if the refcount drops to one, no filter list is using the filter dll and it can be deleted.
Arguments:
pmb - metabase open at the filter root, opened for Read/Write pszKeyName - Metabase open path for filters key pfOpened - TRUE if pmb currently opened, otherwise FALSE must be set before calling this function, which will update it. pszRelativeMBPath - Metabase path to this filter dll pszFilterDll - Fully qualified name of filter to load fAllowRawRead - Set to TRUE if raw read filters are allowed pSvc - Optional service pointer for logging
Return Value:
TRUE on success, FALSE on failure (call GetLastError)
--*/ { HTTP_FILTER_VERSION ver; HTTP_FILTER_DLL * pFilterDll; DWORD i;
//
// pSvc will only be passed during InitializeFilters
//
if ( !pSvc ) { pSvc = (W3_IIS_SERVICE *) g_pInetSvc; }
//
// Make sure there's a free entry in the filter list array, and
// the secure/non-secure notification arrays (the latter two are used
// in conjunction with filters disabling themselves per request
//
if ( (m_cFilters+1) > (m_buffFilterArray.QuerySize() / sizeof(PVOID))) { if ( !m_buffFilterArray.Resize( (m_cFilters + 5) * sizeof(PVOID)) ) { return FALSE; }
if ( !m_buffSecureArray.Resize( (m_cFilters + 5) * sizeof(DWORD)) ) { return FALSE; }
if ( !m_buffNonSecureArray.Resize( (m_cFilters + 5) * sizeof(DWORD)) ) { return FALSE; } }
//
// Load the filter DLL
//
EnterCriticalSection( &g_csFilterDlls );
if ( !(pFilterDll = CheckoutFilterDll( pszFilterDll ))) { pFilterDll = new HTTP_FILTER_DLL;
if ( !pFilterDll || !pFilterDll->LoadDll( pmb, pszKeyName, pfOpened, pszRelativeMBPath, pszFilterDll ) ) { const CHAR * apszSubString[1]; DWORD err = GetLastError();
LeaveCriticalSection( &g_csFilterDlls ); delete pFilterDll;
apszSubString[0] = pszFilterDll;
if ( err ) { //
// Log a warning here if the filter supplied an error code
//
pSvc->LogEvent( W3_EVENT_FILTER_DLL_LOAD_FAILED, 1, apszSubString, err ); }
DBGPRINTF(( DBG_CONTEXT, "Cannot load filter dll (err = %d)\n", err));
if ( pmb && (*pfOpened || pmb->Open( pszKeyName, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE )) ) { *pfOpened = TRUE;
pmb->SetDword( pszRelativeMBPath, MD_WIN32_ERROR, IIS_MD_UT_SERVER, err, 0 ); pmb->SetDword( pszRelativeMBPath, MD_FILTER_STATE, IIS_MD_UT_SERVER, MD_FILTER_STATE_UNLOADED, 0 ); }
return FALSE; }
//
// This filter list now officially owns a reference to this filter dll
//
pFilterDll->Reference(); }
//
// Not a fatal error if the status doesn't get updated
//
DBG_ASSERT( pFilterDll != NULL ); if ( pmb && (*pfOpened || pmb->Open( pszKeyName, METADATA_PERMISSION_READ|METADATA_PERMISSION_WRITE )) ) { *pfOpened = TRUE;
if ( !pmb->SetDword( pszRelativeMBPath, MD_WIN32_ERROR, IIS_MD_UT_SERVER, NO_ERROR, 0 ) || !pmb->SetDword( pszRelativeMBPath, MD_FILTER_STATE, IIS_MD_UT_SERVER, MD_FILTER_STATE_LOADED, 0 )) { DBGPRINTF(( DBG_CONTEXT, "Error %d setting filter status\n", GetLastError() )); } }
//
// Disallow any per-instance read raw filters
//
if ( !fAllowRawRead && (pFilterDll->QueryNotificationFlags() & SF_NOTIFY_READ_RAW_DATA) ) { const CHAR * apszSubString[1];
apszSubString[0] = pszFilterDll;
pSvc->LogEvent( W3_MSG_READ_RAW_MUST_BE_GLOBAL, 1, apszSubString, 0 );
DBGPRINTF(( DBG_CONTEXT, "Refusing READ_RAW filter on server instance (%s)\n", pszFilterDll));
if ( pmb && (*pfOpened || pmb->Open( pszKeyName, METADATA_PERMISSION_READ|METADATA_PERMISSION_WRITE )) ) { *pfOpened = TRUE;
if ( !pmb->SetDword( pszRelativeMBPath, MD_WIN32_ERROR, IIS_MD_UT_SERVER, ERROR_INVALID_PARAMETER, 0 ) || !pmb->SetDword( pszRelativeMBPath, MD_FILTER_STATE, IIS_MD_UT_SERVER, MD_FILTER_STATE_UNLOADED, 0 )) { DBGPRINTF(( DBG_CONTEXT, "Error %d setting filter status\n", GetLastError() )); } }
//
// Undo the ref for being on this filter list
//
HTTP_FILTER_DLL::Dereference( pFilterDll );
//
// If nobody else is using this filter dll, then go ahead and force
// an unload. The filter dll can't be checked out with the filter
// critical section held so this is a safe operation.
//
if ( pFilterDll->QueryRef() == 1 ) { RemoveEntryList( &pFilterDll->ListEntry ); HTTP_FILTER_DLL::Dereference( pFilterDll ); }
LeaveCriticalSection( &g_csFilterDlls );
return FALSE;
}
//
// Find where pFilterDll goes in the list
//
for ( i = 0; i < m_cFilters; i++ ) { if ( (QueryDll(i)->QueryNotificationFlags() & SF_NOTIFY_ORDER_MASK) < (pFilterDll->QueryNotificationFlags() & SF_NOTIFY_ORDER_MASK) ) { break; } }
//
// And insert it into the array
//
memmove( (PVOID *) m_buffFilterArray.QueryPtr() + i + 1, (PVOID *) m_buffFilterArray.QueryPtr() + i, (m_cFilters - i) * sizeof(PVOID) );
(((HTTP_FILTER_DLL * *) (m_buffFilterArray.QueryPtr())))[i] = pFilterDll;
//
// Add notification DWORDS to secure/non-secure arrays
//
memmove( (DWORD *) m_buffSecureArray.QueryPtr() + i + 1, (DWORD *) m_buffSecureArray.QueryPtr() + i, (m_cFilters - i) * sizeof(DWORD) );
((DWORD*) m_buffSecureArray.QueryPtr())[i] = pFilterDll->QuerySecureFlags();
memmove( (DWORD *) m_buffNonSecureArray.QueryPtr() + i + 1, (DWORD *) m_buffNonSecureArray.QueryPtr() + i, (m_cFilters - i) * sizeof(DWORD) );
((DWORD*) m_buffNonSecureArray.QueryPtr())[i] = pFilterDll->QueryNonsecureFlags();
m_cFilters++;
//
// Segregate the secure and non-secure port notifications
//
m_SecureNotifications |= pFilterDll->QuerySecureFlags(); m_NonSecureNotifications |= pFilterDll->QueryNonsecureFlags();
LeaveCriticalSection( &g_csFilterDlls ); return TRUE; }
#if 0
BOOL FILTER_LIST::Copy( IN FILTER_LIST * pClone ) /*++
Routine Description:
Clones the passed filter list
Return Value:
TRUE on success, FALSE on failure (call GetLastError)
--*/ { DWORD i;
DBG_ASSERT( pClone->CheckSignature() ); DBG_ASSERT( CheckSignature() );
//
// Walk the list to be cloned and load all of the dlls
//
EnterCriticalSection( &g_csFilterDlls );
for ( i = 0; i < pClone->QueryFilterCount(); i++ ) { if ( !LoadFilter( pClone->QueryDll( i )->QueryName(), FALSE )) { DBGPRINTF(( DBG_CONTEXT, "[FILTER_LIST::Copy] Failed loading %s, error %d\n", pClone->QueryDll( i )->QueryName(), GetLastError() )); } }
LeaveCriticalSection( &g_csFilterDlls );
return TRUE; }
BOOL ReplaceFilterDll( IN const CHAR * pszNewDll, IN const CHAR * pszOldDll ) /*++
Routine Description:
Given a new filter and an old filter, this function renames the old filter dll to a temporary name, copies the new .dll into place then walks the instance list and replaces all occurrences of the old .dll with the new .dll.
Arguments:
pszNewDll - New filter dll pszOldDll - Existing filter dll that should be replaced
Return Value:
TRUE on success, FALSE on failure (call GetLastError)
--*/ { CHAR achTmp[MAX_PATH + 1]; CHAR * pszTmp; DWORD cVer = 1; CHAR achVer[32]; const CHAR * apsz[3];
apsz[0] = pszOldDll; apsz[1] = pszNewDll;
g_pInetSvc->LogEvent( W3_MSG_REP_FILTER, 2, apsz, 0 );
//
// Find a back up name - this just appends a number onto the dll
//
strcpy( achTmp, pszOldDll ); pszTmp = achTmp + strlen( pszOldDll );
while ( TRUE ) { _itoa( cVer, achVer, 10 ); strcpy( pszTmp, achVer );
if ( GetFileAttributes( achTmp ) != 0xffffffff || GetLastError() != ERROR_FILE_NOT_FOUND ) { cVer++;
//
// If we've tried a reasonable number of backups and we couldn't
// find a candidate then get out
//
if ( cVer > 8192 ) { SetLastError( ERROR_FILE_NOT_FOUND ); return FALSE; }
continue; }
//
// Rename the old DLL to the new dll name
//
if ( !MoveFileEx( pszOldDll, achTmp, MOVEFILE_WRITE_THROUGH | MOVEFILE_COPY_ALLOWED )) { DBGPRINTF(( DBG_CONTEXT, "[ReplaceFilterDll] Move old file failed, %s -> %s, error %d\n", pszOldDll, achTmp, GetLastError() ));
if ( GetLastError() == ERROR_FILE_EXISTS ) { cVer++; continue; }
apsz[0] = pszOldDll; apsz[1] = pszNewDll;
g_pInetSvc->LogEvent( W3_MSG_REP_FILTER, 2, apsz, GetLastError() );
return FALSE; }
break; }
//
// Rename the new DLL name to the old dll
//
if ( !MoveFileEx( pszNewDll, pszOldDll, MOVEFILE_WRITE_THROUGH | MOVEFILE_COPY_ALLOWED )) { DBGPRINTF(( DBG_CONTEXT, "[ReplaceFilterDll] Move new file failed, %s -> %s, error %d\n", pszNewDll, pszOldDll, GetLastError() ));
apsz[0] = pszNewDll; apsz[1] = pszOldDll;
g_pInetSvc->LogEvent( W3_MSG_REP_FILTER_FAILED, 2, apsz, 0 );
if ( !MoveFileEx( achTmp, pszOldDll, MOVEFILE_WRITE_THROUGH | MOVEFILE_COPY_ALLOWED )) { DBGPRINTF(( DBG_CONTEXT, "[ReplaceFilterDll] Move tmp to old file failed, %s -> %s, error %d\n", achTmp, pszOldDll, GetLastError() ));
apsz[0] = achTmp; apsz[1] = pszOldDll;
g_pInetSvc->LogEvent( W3_MSG_REP_FILTER_FAILED, 2, apsz, 0 ); }
return FALSE; }
//
// Update all of the instance filters
//
if ( !g_pInetSvc->EnumServiceInstances( (PVOID) pszNewDll, (PVOID) pszOldDll, (PFN_INSTANCE_ENUM) UpdateInstanceFilters )) { return FALSE; }
return TRUE; }
BOOL UpdateInstanceFilters( IN const CHAR * pszNewDll, IN const CHAR * pszOldDll, IN W3_SERVER_INSTANCE * pInst ) /*++
Routine Description:
This is a simple utility function that handles the instance callbacks
Arguments:
pszNewDll - New filter dll pszOldDll - Existing filter dll that should be replaced pInst - The instance the change is being applied to
Return Value:
TRUE on success, FALSE on failure (call GetLastError)
--*/ { #if 0
if ( !pInst->UpdateFilterList( pszNewDll, pszOldDll )) { DBGPRINTF(( DBG_CONTEXT, "[UpdateInstanceFilters] Failed with error %d\n", GetLastError() )); return FALSE; } #endif
return TRUE; } #endif
BOOL FILTER_LIST::InsertGlobalFilters( VOID ) /*++
Routine Description:
Transfers all of the global filters to the per-instance filter list
Note: This method assumes the server filter list is not dynamic
Return Value:
TRUE on success, FALSE on failure (call GetLastError)
--*/ { DWORD i; HTTP_FILTER_DLL * pFilterDll; BOOL fOpened;
for ( i = 0; i < GLOBAL_FILTER_LIST()->QueryFilterCount(); i++ ) { //
// Ignore the return code, an event gets logged in LoadFilter()
// We allow raw read filters here as we're just duplicating the
// global filter list
//
LoadFilter( NULL, NULL, &fOpened, "", GLOBAL_FILTER_LIST()->QueryDll( i )->QueryName(), TRUE ); }
return TRUE; }
BOOL CheckForSecurityFilter( FILTER_LIST * pFilterList ) /*++
Routine Description:
Checks to see if there are any global filters that are encryption filters
Return Value:
TRUE if an encryption filter was found, FALSE otherwise
--*/ { DWORD i; HTTP_FILTER_DLL * pFilterDll; BOOL fRet = FALSE;
for ( i = 0; i < pFilterList->QueryFilterCount(); i++ ) { pFilterDll = pFilterList->QueryDll( i );
//
// port notification, assume he's an encryption filter
//
#define SECURE_FILTER (SF_NOTIFY_SECURE_PORT | \
SF_NOTIFY_READ_RAW_DATA | \ SF_NOTIFY_SEND_RAW_DATA | \ SF_NOTIFY_ORDER_HIGH)
if ( (pFilterDll->QueryNotificationFlags() & SECURE_FILTER) == SECURE_FILTER) { fRet = TRUE; break; } }
return fRet; }
BOOL AdjustFilterFlags( PVOID pfnSFProc, DWORD dwNewFlags ) /*++
Routine Description:
Private exported routine that allows a filter to dynamically adjust its notification flags. This can only be done for global filters.
Return Value:
TRUE on success, FALSE on failure --*/ { W3_IIS_SERVICE * pSvc = (W3_IIS_SERVICE *) g_pInetSvc; FILTER_LIST * pFilterList; HTTP_FILTER_DLL * pFilterDll; DWORD i; BOOL fFoundSvcDLL = FALSE; BOOL fFoundInstanceDLL = FALSE;
//
// Can't adjust priority, just notification flags
//
if ( dwNewFlags & SF_NOTIFY_ORDER_MASK ) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; }
pFilterList = pSvc->QueryGlobalFilterList();
if ( !pFilterList ) { //
// Shouldn't happen but you never know
//
return TRUE; } //
// Try to find the appropriate DLL in the single global per-service filter list
//
for ( i = 0; i < pFilterList->QueryFilterCount(); i++ ) { DBG_ASSERT( pFilterList->QueryDll(i)->CheckSignature() ); if ( pFilterList->QueryDll(i)->QueryEntryPoint() == pfnSFProc ) { pFilterDll = pFilterList->QueryDll(i); //
// We've found the matching filter dll, adjust the flags in the
// filter dll object then adjust the flags in the filter list
//
pFilterDll->SetNotificationFlags( dwNewFlags ); pFilterList->SetNotificationFlags( i, pFilterDll );
fFoundSvcDLL = TRUE; } }
if ( fFoundSvcDLL ) { //
// Try to update the flags in each of the per-instance filter lists
//
if ( pSvc ) { if ( pSvc->EnumServiceInstances( (PVOID) &dwNewFlags, (PVOID) pfnSFProc, AdjustInstanceFilterListFlags ) ) { fFoundInstanceDLL = TRUE; } } }
if ( !( fFoundInstanceDLL && fFoundSvcDLL ) ) { SetLastError( ERROR_FILE_NOT_FOUND ); return FALSE; } return TRUE; }
BOOL AdjustInstanceFilterListFlags( IN PVOID pdwNewFlags, IN PVOID pfnSFProc, IN IIS_SERVER_INSTANCE *pInstance ) /*++
Routine Description:
This is the callback function called when we need to adjust the notification flags of a particular filter dll for the filter list associated with a server instance. Note that this filter list consists of the -global- [ie service-wide] filter dlls.
Arguments : pdwNewFlags - pointer to DWORD containing new notification flags pfnSFProc - pointer to filter entry point function pInstance - pointer to W3_SERVER_INSTANCE whose filter list is to be updated
Return Value:
TRUE if the DLL was found and the flags adjusted, FALSE otherwise --*/ { HTTP_FILTER_DLL *pFilterDll = NULL; W3_SERVER_INSTANCE *pW3Instance = (W3_SERVER_INSTANCE *) pInstance; BOOL fFound = FALSE;
if ( !pInstance ) { DBGPRINTF((DBG_CONTEXT, "NULL instance passed to AdjustInstanceFilterFlags !\n")); return FALSE; }
pInstance->LockThisForRead(); FILTER_LIST *pFilterList = ((W3_SERVER_INSTANCE *) pInstance)->QueryFilterList(); pInstance->UnlockThis();
if ( !pFilterList ) { DBGPRINTF((DBG_CONTEXT, "Very odd - instance 0x%p has no filter list associated with it !\n", pInstance)); return TRUE; }
pInstance->LockThisForWrite();
//
// Try to find the appropriate DLL in the filter list for this instance
//
for ( DWORD i = 0; i < pFilterList->QueryFilterCount(); i++ ) { DBG_ASSERT( pFilterList->QueryDll(i)->CheckSignature() ); if ( pFilterList->QueryDll(i)->QueryEntryPoint() == pfnSFProc ) { pFilterDll = pFilterList->QueryDll(i); //
// We've found the matching filter dll, adjust the flags in the
// filter dll object then adjust the flags in the filter list
//
pFilterDll->SetNotificationFlags( *((DWORD *) pdwNewFlags) ); pFilterList->SetNotificationFlags( i, pFilterDll );
fFound = TRUE; break; } }
pInstance->UnlockThis();
return fFound; }
|