windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/w3/server/filtinit.cxx
2020-09-26 16:20:57 +08:00

1380 lines
34 KiB
C++

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