Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1379 lines
34 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. filtinit.cxx
  5. Abstract:
  6. This module contains the Microsoft HTTP server filter module for stuff that
  7. has to do with filter initialization, loading and unloading.
  8. Author:
  9. John Ludeman (johnl) 06-Aug-1996
  10. Revision History:
  11. --*/
  12. #include "w3p.hxx"
  13. //
  14. // If the request doesn't specify an entry point, default to using
  15. // this
  16. //
  17. #define SF_DEFAULT_ENTRY "HttpFilterProc"
  18. #define SF_VERSION_ENTRY "GetFilterVersion"
  19. #define SF_TERM_ENTRY "TerminateFilter"
  20. //
  21. // Name of the value under the parameters key containing the list of
  22. // filter dlls. This was the value for IIS 1.0 and 2.0. Global filters
  23. // can still be specified under this key.
  24. //
  25. #define HTTP_FILTER_DLLS "Filter DLLs"
  26. //
  27. // Globals
  28. //
  29. static BOOL g_fInitialized = FALSE;
  30. LIST_ENTRY g_FilterHead; // List of filter DLLs
  31. CRITICAL_SECTION g_csFilterDlls;
  32. //
  33. // Prototypes
  34. //
  35. BOOL
  36. UpdateInstanceFilters(
  37. IN const CHAR * pszNewDll,
  38. IN const CHAR * pszOldDll,
  39. IN W3_SERVER_INSTANCE * pInst
  40. );
  41. BOOL
  42. AdjustInstanceFilterListFlags( IN PVOID pvContext1,
  43. IN PVOID pvContext2,
  44. IN IIS_SERVER_INSTANCE *pInstance );
  45. FILTER_LIST *
  46. InitializeFilters(
  47. BOOL * pfAnySecureFilters,
  48. W3_IIS_SERVICE * pSvc
  49. )
  50. /*++
  51. Routine Description:
  52. Loads the global filter DLLs and their corresponding entry point. Note the
  53. global filter list does not allow unloads.
  54. g_fInitialized should only be set after all of the global filters are
  55. loaded.
  56. Arguments:
  57. pfAnySecureFilters - Set to TRUE if there are any secure filters
  58. pSvc - Pointer to service global. The global service pointer isn't
  59. initialized yet so we pass it in for global filter initialization.
  60. Only used for logging events.
  61. Return Value:
  62. Global filter list or NULL if an error occurred
  63. --*/
  64. {
  65. CHAR szFilterKey[MAX_PATH+1];
  66. FILTER_LIST * pfl;
  67. DWORD cb;
  68. CHAR szLoadOrder[1024];
  69. CHAR szDllName[MAX_PATH+1];
  70. CHAR * pchFilter;
  71. CHAR * pchComma;
  72. MB mb( (IMDCOM*) pSvc->QueryMDObject() );
  73. DWORD fEnabled;
  74. DWORD cFilters;
  75. HKEY hkeyParam = NULL;
  76. DWORD err = NO_ERROR;
  77. BOOL fOpened;
  78. INITIALIZE_CRITICAL_SECTION( &g_csFilterDlls );
  79. InitializeListHead( &g_FilterHead );
  80. strcpy( szFilterKey, IIS_MD_LOCAL_MACHINE_PATH "/" W3_SERVICE_NAME_A );
  81. strcat( szFilterKey, IIS_MD_ISAPI_FILTERS );
  82. DBG_ASSERT( strlen( szFilterKey ) + 1 < sizeof( szFilterKey ));
  83. pfl = new FILTER_LIST();
  84. if ( !pfl ) {
  85. return NULL;
  86. }
  87. //
  88. // Loop through filter keys, if we can't access the metabase, we assume
  89. // success and continue
  90. //
  91. if ( !mb.Open( szFilterKey,
  92. METADATA_PERMISSION_READ ))
  93. {
  94. DBGPRINTF(( DBG_CONTEXT,
  95. "[InitializeFilterList] Cannot open path %s, error %lu\n",
  96. szFilterKey, GetLastError() ));
  97. return pfl;
  98. }
  99. fOpened = TRUE;
  100. //
  101. // Get the filter load order
  102. //
  103. cb = sizeof( szLoadOrder );
  104. *szLoadOrder = '\0';
  105. if ( !mb.GetString( "",
  106. MD_FILTER_LOAD_ORDER,
  107. IIS_MD_UT_SERVER,
  108. szLoadOrder,
  109. &cb,
  110. 0 ))
  111. {
  112. DBGPRINTF(( DBG_CONTEXT,
  113. "[InitializeFilterList] Cannot load filter load order, error %lu\n",
  114. szFilterKey, GetLastError() ));
  115. delete pfl;
  116. return NULL;
  117. }
  118. pchFilter = szLoadOrder;
  119. while ( *pchFilter )
  120. {
  121. if ( !fOpened &&
  122. !mb.Open( szFilterKey,
  123. METADATA_PERMISSION_READ ))
  124. {
  125. DBGPRINTF(( DBG_CONTEXT,
  126. "[InitializeFilterList] Cannot open path %s, error %lu\n",
  127. szFilterKey, GetLastError() ));
  128. break;
  129. }
  130. fOpened = TRUE;
  131. pchComma = strchr( pchFilter, ',' );
  132. if ( pchComma )
  133. {
  134. *pchComma = '\0';
  135. }
  136. while ( ISWHITEA( *pchFilter ))
  137. {
  138. pchFilter++;
  139. }
  140. fEnabled = TRUE;
  141. mb.GetDword( pchFilter,
  142. MD_FILTER_ENABLED,
  143. IIS_MD_UT_SERVER,
  144. &fEnabled );
  145. if ( fEnabled )
  146. {
  147. cb = sizeof(szDllName);
  148. if ( mb.GetString( pchFilter,
  149. MD_FILTER_IMAGE_PATH,
  150. IIS_MD_UT_SERVER,
  151. szDllName,
  152. &cb,
  153. 0 ))
  154. {
  155. mb.Close();
  156. fOpened = FALSE;
  157. if ( pfl->LoadFilter( &mb, szFilterKey, &fOpened, pchFilter, szDllName, TRUE, pSvc ))
  158. {
  159. DBGPRINTF(( DBG_CONTEXT,
  160. "[InitializeFilterList] Loaded %s\n",
  161. szDllName ));
  162. }
  163. }
  164. }
  165. if ( pchComma )
  166. {
  167. pchFilter = pchComma + 1;
  168. }
  169. else
  170. {
  171. break;
  172. }
  173. }
  174. //
  175. // Now load any filters that have been added in the registry for
  176. // downlevel compatibility
  177. //
  178. err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  179. W3_PARAMETERS_KEY,
  180. 0,
  181. KEY_READ,
  182. &hkeyParam );
  183. if( err == NO_ERROR )
  184. {
  185. TCHAR * psz;
  186. TCHAR * pszFilterList = NULL;
  187. if ( ReadRegString( hkeyParam,
  188. &pszFilterList,
  189. HTTP_FILTER_DLLS,
  190. "" ))
  191. {
  192. RegCloseKey( hkeyParam );
  193. psz = pszFilterList;
  194. //
  195. // Parse the comma separated list of dlls
  196. //
  197. INET_PARSER Parser( pszFilterList );
  198. Parser.SetListMode( TRUE );
  199. while ( *(psz = Parser.QueryToken()) )
  200. {
  201. if ( pfl->LoadFilter( NULL, NULL, &fOpened, psz, psz, TRUE, pSvc ))
  202. {
  203. const CHAR * apszSubString[1];
  204. DBGPRINTF(( DBG_CONTEXT,
  205. "[InitializeFilterList] Loaded %s\n",
  206. psz ));
  207. apszSubString[0] = psz;
  208. //
  209. // Log a warning here if we picked up a filter from the
  210. // registry
  211. //
  212. pSvc->LogEvent( W3_MSG_LOADED_FILTER_FROM_REG,
  213. 1,
  214. apszSubString,
  215. NO_ERROR );
  216. }
  217. Parser.NextItem();
  218. }
  219. Parser.RestoreBuffer();
  220. TCP_FREE( pszFilterList );
  221. }
  222. else
  223. {
  224. RegCloseKey( hkeyParam );
  225. }
  226. }
  227. *pfAnySecureFilters = CheckForSecurityFilter( pfl );
  228. g_fInitialized = TRUE;
  229. return pfl;
  230. }
  231. VOID
  232. TerminateFilters(
  233. VOID
  234. )
  235. /*++
  236. Routine Description:
  237. Unloads any filter DLLs and their corresponding entry point
  238. --*/
  239. {
  240. LIST_ENTRY * pEntry;
  241. HTTP_FILTER_DLL * pFilterDll;
  242. if ( g_fInitialized )
  243. {
  244. EnterCriticalSection( &g_csFilterDlls );
  245. for ( pEntry = g_FilterHead.Flink;
  246. pEntry != &g_FilterHead;
  247. pEntry = g_FilterHead.Flink)
  248. {
  249. pFilterDll = CONTAINING_RECORD( pEntry, HTTP_FILTER_DLL, ListEntry );
  250. RemoveEntryList( pEntry );
  251. //
  252. // This should delete the filter dll
  253. //
  254. DBGPRINTF(( DBG_CONTEXT,
  255. "[TerminateFilters] Filter %s, ref count %d\n",
  256. pFilterDll->QueryName(),
  257. pFilterDll->QueryRef() ));
  258. // DBG_ASSERT( pFilterDll->QueryRef() == 1 );
  259. HTTP_FILTER_DLL::Dereference( pFilterDll );
  260. }
  261. LeaveCriticalSection( &g_csFilterDlls );
  262. DeleteCriticalSection( &g_csFilterDlls );
  263. }
  264. }
  265. HTTP_FILTER_DLL *
  266. CheckoutFilterDll(
  267. IN const CHAR * pszFilterDll
  268. )
  269. /*++
  270. Routine Description:
  271. Checks to see if an existing filter dll is already loaded and ups the ref
  272. count if it is
  273. NOTE: THE FILTER LIST LOCK MUST BE TAKEN PRIOR TO CALLING THIS FUNCTION
  274. Arguments:
  275. pszFilterDLL - Fully qualified path to filter dll to load
  276. Return Value:
  277. Pointer to the filter if it's already loaded, NULL if the filter isn't
  278. loaded
  279. --*/
  280. {
  281. LIST_ENTRY * pEntry;
  282. HTTP_FILTER_DLL * pFilterDll;
  283. for ( pEntry = g_FilterHead.Flink;
  284. pEntry != &g_FilterHead;
  285. pEntry = pEntry->Flink )
  286. {
  287. pFilterDll = CONTAINING_RECORD( pEntry, HTTP_FILTER_DLL, ListEntry );
  288. DBG_ASSERT( pFilterDll->CheckSignature() );
  289. if ( !lstrcmpi( pFilterDll->QueryName(), pszFilterDll ))
  290. {
  291. pFilterDll->Reference();
  292. return pFilterDll;
  293. }
  294. }
  295. return NULL;
  296. }
  297. BOOL
  298. HTTP_FILTER_DLL::LoadDll(
  299. MB * pmb OPTIONAL,
  300. const CHAR * pszKeyName,
  301. LPBOOL pfOpened,
  302. const CHAR * pszRelFilterPath,
  303. const CHAR * pszFilterDll
  304. )
  305. /*++
  306. Routine Description:
  307. Loads the specified dll
  308. Arguments:
  309. pmb - Open metabase to /filters key
  310. pszKeyName - metabase filters key name
  311. pfOpened - updated with TRUE if pmb opened on return
  312. pszFilterDll - Fully qualified name of filter to load
  313. THE GLOBAL FILTER LIST LOCK MUST BE TAKEN PRIOR TO CALLING THIS METHOD
  314. Return Value:
  315. TRUE on success, FALSE on failure (call GetLastError)
  316. --*/
  317. {
  318. HTTP_FILTER_VERSION ver;
  319. if ( !m_strName.Copy( pszFilterDll ))
  320. {
  321. return FALSE;
  322. }
  323. //
  324. // Load it and put it in the list, note the filter list lock
  325. // is still taken
  326. //
  327. m_hmod = LoadLibraryEx( pszFilterDll,
  328. NULL,
  329. LOAD_WITH_ALTERED_SEARCH_PATH );
  330. if ( g_fIsWindows95 &&
  331. (m_hmod == NULL) &&
  332. (GetLastError() == ERROR_FILE_NOT_FOUND) ) {
  333. //
  334. // According to vlads: the behaviour of flags used in loadlibraryex
  335. // is different between chicago and NT. This caused a problem
  336. // loading frontpage filters.
  337. //
  338. m_hmod = LoadLibrary( pszFilterDll);
  339. }
  340. if ( !m_hmod )
  341. {
  342. DBGPRINTF(( DBG_CONTEXT,
  343. "[LoadDll] LoadLibrary failed with error %d\n",
  344. GetLastError()));
  345. goto ErrorExit;
  346. }
  347. //
  348. // Retrieve the entry point
  349. //
  350. m_pfnSFVer = (PFN_SF_VER_PROC) GetProcAddress( m_hmod,
  351. SF_VERSION_ENTRY );
  352. m_pfnSFProc = (PFN_SF_DLL_PROC) GetProcAddress( m_hmod,
  353. SF_DEFAULT_ENTRY );
  354. m_pfnSFTerm = (PFN_SF_TERM_PROC) GetProcAddress( m_hmod,
  355. SF_TERM_ENTRY );
  356. if ( !m_pfnSFProc || !m_pfnSFVer )
  357. {
  358. //
  359. // Don't call the terminator if we didn't call the initializer
  360. //
  361. m_pfnSFTerm = NULL;
  362. goto ErrorExit;
  363. }
  364. ver.dwServerFilterVersion = HTTP_FILTER_REVISION;
  365. //
  366. // Call the version entry point and get the filter capabilities
  367. //
  368. if ( !m_pfnSFVer( &ver ) )
  369. {
  370. goto ErrorExit;
  371. }
  372. if ( pmb &&
  373. (*pfOpened ||
  374. pmb->Open( pszKeyName, METADATA_PERMISSION_READ|METADATA_PERMISSION_WRITE )) )
  375. {
  376. *pfOpened = TRUE;
  377. if ( !pmb->SetString( pszRelFilterPath,
  378. MD_FILTER_DESCRIPTION,
  379. IIS_MD_UT_SERVER,
  380. ver.lpszFilterDesc,
  381. 0 ) ||
  382. !pmb->SetDword( pszRelFilterPath,
  383. MD_FILTER_FLAGS,
  384. IIS_MD_UT_SERVER,
  385. ver.dwFlags,
  386. 0 ))
  387. {
  388. goto ErrorExit;
  389. }
  390. }
  391. //
  392. // If the client didn't specify any of the secure port notifications,
  393. // supply them with the default of both
  394. //
  395. if ( !(ver.dwFlags & (SF_NOTIFY_SECURE_PORT | SF_NOTIFY_NONSECURE_PORT)))
  396. {
  397. ver.dwFlags |= (SF_NOTIFY_SECURE_PORT | SF_NOTIFY_NONSECURE_PORT);
  398. }
  399. m_dwVersion = ver.dwFilterVersion;
  400. m_dwFlags = (ver.dwFlags & SF_NOTIFY_NONSECURE_PORT) ? ver.dwFlags : 0;
  401. m_dwSecureFlags = (ver.dwFlags & SF_NOTIFY_SECURE_PORT) ? ver.dwFlags : 0;
  402. //
  403. // Put the new dll on the filter dll list
  404. //
  405. InsertHeadList( &g_FilterHead, &ListEntry );
  406. return TRUE;
  407. ErrorExit:
  408. return FALSE;
  409. }
  410. BOOL
  411. HTTP_FILTER_DLL::Unload(
  412. const CHAR * pszDll
  413. )
  414. /*++
  415. Routine Description:
  416. Finds the existing DLL and sets it up to be unloaded
  417. Arguments:
  418. pszDLL - Fully qualified path to filter dll to load
  419. Return Value:
  420. TRUE if the filter DLL was found, FALSE if it wasn't found or it's already
  421. marked for deletion
  422. --*/
  423. {
  424. LIST_ENTRY * pEntry;
  425. HTTP_FILTER_DLL * pFilterDll;
  426. EnterCriticalSection( &g_csFilterDlls );
  427. for ( pEntry = g_FilterHead.Flink;
  428. pEntry != &g_FilterHead;
  429. pEntry = pEntry->Flink )
  430. {
  431. pFilterDll = CONTAINING_RECORD( pEntry, HTTP_FILTER_DLL, ListEntry );
  432. DBG_ASSERT( pFilterDll->CheckSignature() );
  433. if ( !lstrcmpi( pFilterDll->QueryName(), pszDll ))
  434. {
  435. RemoveEntryList( pEntry );
  436. LeaveCriticalSection( &g_csFilterDlls );
  437. return TRUE;
  438. }
  439. }
  440. LeaveCriticalSection( &g_csFilterDlls );
  441. return FALSE;
  442. }
  443. BOOL
  444. FILTER_LIST::LoadFilter(
  445. MB * pmb,
  446. LPSTR pszKeyName,
  447. LPBOOL pfOpened,
  448. const CHAR * pszRelativeMBPath,
  449. const CHAR * pszFilterDll,
  450. BOOL fAllowRawRead,
  451. W3_IIS_SERVICE * pSvc
  452. )
  453. /*++
  454. Routine Description:
  455. Loads the specified filter into this filter list. Note the filter dll's
  456. ref count starts at one for being on the g_FilterHead list. Thus if the
  457. refcount drops to one, no filter list is using the filter dll and it can
  458. be deleted.
  459. Arguments:
  460. pmb - metabase open at the filter root, opened for Read/Write
  461. pszKeyName - Metabase open path for filters key
  462. pfOpened - TRUE if pmb currently opened, otherwise FALSE
  463. must be set before calling this function, which will
  464. update it.
  465. pszRelativeMBPath - Metabase path to this filter dll
  466. pszFilterDll - Fully qualified name of filter to load
  467. fAllowRawRead - Set to TRUE if raw read filters are allowed
  468. pSvc - Optional service pointer for logging
  469. Return Value:
  470. TRUE on success, FALSE on failure (call GetLastError)
  471. --*/
  472. {
  473. HTTP_FILTER_VERSION ver;
  474. HTTP_FILTER_DLL * pFilterDll;
  475. DWORD i;
  476. //
  477. // pSvc will only be passed during InitializeFilters
  478. //
  479. if ( !pSvc )
  480. {
  481. pSvc = (W3_IIS_SERVICE *) g_pInetSvc;
  482. }
  483. //
  484. // Make sure there's a free entry in the filter list array, and
  485. // the secure/non-secure notification arrays (the latter two are used
  486. // in conjunction with filters disabling themselves per request
  487. //
  488. if ( (m_cFilters+1) > (m_buffFilterArray.QuerySize() / sizeof(PVOID)))
  489. {
  490. if ( !m_buffFilterArray.Resize( (m_cFilters + 5) * sizeof(PVOID)) )
  491. {
  492. return FALSE;
  493. }
  494. if ( !m_buffSecureArray.Resize( (m_cFilters + 5) * sizeof(DWORD)) )
  495. {
  496. return FALSE;
  497. }
  498. if ( !m_buffNonSecureArray.Resize( (m_cFilters + 5) * sizeof(DWORD)) )
  499. {
  500. return FALSE;
  501. }
  502. }
  503. //
  504. // Load the filter DLL
  505. //
  506. EnterCriticalSection( &g_csFilterDlls );
  507. if ( !(pFilterDll = CheckoutFilterDll( pszFilterDll )))
  508. {
  509. pFilterDll = new HTTP_FILTER_DLL;
  510. if ( !pFilterDll ||
  511. !pFilterDll->LoadDll( pmb,
  512. pszKeyName,
  513. pfOpened,
  514. pszRelativeMBPath,
  515. pszFilterDll ) )
  516. {
  517. const CHAR * apszSubString[1];
  518. DWORD err = GetLastError();
  519. LeaveCriticalSection( &g_csFilterDlls );
  520. delete pFilterDll;
  521. apszSubString[0] = pszFilterDll;
  522. if ( err )
  523. {
  524. //
  525. // Log a warning here if the filter supplied an error code
  526. //
  527. pSvc->LogEvent( W3_EVENT_FILTER_DLL_LOAD_FAILED,
  528. 1,
  529. apszSubString,
  530. err );
  531. }
  532. DBGPRINTF(( DBG_CONTEXT,
  533. "Cannot load filter dll (err = %d)\n",
  534. err));
  535. if ( pmb &&
  536. (*pfOpened ||
  537. pmb->Open( pszKeyName, METADATA_PERMISSION_READ |
  538. METADATA_PERMISSION_WRITE )) )
  539. {
  540. *pfOpened = TRUE;
  541. pmb->SetDword( pszRelativeMBPath,
  542. MD_WIN32_ERROR,
  543. IIS_MD_UT_SERVER,
  544. err,
  545. 0 );
  546. pmb->SetDword( pszRelativeMBPath,
  547. MD_FILTER_STATE,
  548. IIS_MD_UT_SERVER,
  549. MD_FILTER_STATE_UNLOADED,
  550. 0 );
  551. }
  552. return FALSE;
  553. }
  554. //
  555. // This filter list now officially owns a reference to this filter dll
  556. //
  557. pFilterDll->Reference();
  558. }
  559. //
  560. // Not a fatal error if the status doesn't get updated
  561. //
  562. DBG_ASSERT( pFilterDll != NULL );
  563. if ( pmb &&
  564. (*pfOpened ||
  565. pmb->Open( pszKeyName, METADATA_PERMISSION_READ|METADATA_PERMISSION_WRITE )) )
  566. {
  567. *pfOpened = TRUE;
  568. if ( !pmb->SetDword( pszRelativeMBPath,
  569. MD_WIN32_ERROR,
  570. IIS_MD_UT_SERVER,
  571. NO_ERROR,
  572. 0 ) ||
  573. !pmb->SetDword( pszRelativeMBPath,
  574. MD_FILTER_STATE,
  575. IIS_MD_UT_SERVER,
  576. MD_FILTER_STATE_LOADED,
  577. 0 ))
  578. {
  579. DBGPRINTF(( DBG_CONTEXT,
  580. "Error %d setting filter status\n",
  581. GetLastError() ));
  582. }
  583. }
  584. //
  585. // Disallow any per-instance read raw filters
  586. //
  587. if ( !fAllowRawRead &&
  588. (pFilterDll->QueryNotificationFlags() & SF_NOTIFY_READ_RAW_DATA) )
  589. {
  590. const CHAR * apszSubString[1];
  591. apszSubString[0] = pszFilterDll;
  592. pSvc->LogEvent( W3_MSG_READ_RAW_MUST_BE_GLOBAL,
  593. 1,
  594. apszSubString,
  595. 0 );
  596. DBGPRINTF(( DBG_CONTEXT,
  597. "Refusing READ_RAW filter on server instance (%s)\n",
  598. pszFilterDll));
  599. if ( pmb &&
  600. (*pfOpened ||
  601. pmb->Open( pszKeyName, METADATA_PERMISSION_READ|METADATA_PERMISSION_WRITE )) )
  602. {
  603. *pfOpened = TRUE;
  604. if ( !pmb->SetDword( pszRelativeMBPath,
  605. MD_WIN32_ERROR,
  606. IIS_MD_UT_SERVER,
  607. ERROR_INVALID_PARAMETER,
  608. 0 ) ||
  609. !pmb->SetDword( pszRelativeMBPath,
  610. MD_FILTER_STATE,
  611. IIS_MD_UT_SERVER,
  612. MD_FILTER_STATE_UNLOADED,
  613. 0 ))
  614. {
  615. DBGPRINTF(( DBG_CONTEXT,
  616. "Error %d setting filter status\n",
  617. GetLastError() ));
  618. }
  619. }
  620. //
  621. // Undo the ref for being on this filter list
  622. //
  623. HTTP_FILTER_DLL::Dereference( pFilterDll );
  624. //
  625. // If nobody else is using this filter dll, then go ahead and force
  626. // an unload. The filter dll can't be checked out with the filter
  627. // critical section held so this is a safe operation.
  628. //
  629. if ( pFilterDll->QueryRef() == 1 )
  630. {
  631. RemoveEntryList( &pFilterDll->ListEntry );
  632. HTTP_FILTER_DLL::Dereference( pFilterDll );
  633. }
  634. LeaveCriticalSection( &g_csFilterDlls );
  635. return FALSE;
  636. }
  637. //
  638. // Find where pFilterDll goes in the list
  639. //
  640. for ( i = 0; i < m_cFilters; i++ )
  641. {
  642. if ( (QueryDll(i)->QueryNotificationFlags() & SF_NOTIFY_ORDER_MASK)
  643. < (pFilterDll->QueryNotificationFlags() & SF_NOTIFY_ORDER_MASK) )
  644. {
  645. break;
  646. }
  647. }
  648. //
  649. // And insert it into the array
  650. //
  651. memmove( (PVOID *) m_buffFilterArray.QueryPtr() + i + 1,
  652. (PVOID *) m_buffFilterArray.QueryPtr() + i,
  653. (m_cFilters - i) * sizeof(PVOID) );
  654. (((HTTP_FILTER_DLL * *) (m_buffFilterArray.QueryPtr())))[i] = pFilterDll;
  655. //
  656. // Add notification DWORDS to secure/non-secure arrays
  657. //
  658. memmove( (DWORD *) m_buffSecureArray.QueryPtr() + i + 1,
  659. (DWORD *) m_buffSecureArray.QueryPtr() + i,
  660. (m_cFilters - i) * sizeof(DWORD) );
  661. ((DWORD*) m_buffSecureArray.QueryPtr())[i] = pFilterDll->QuerySecureFlags();
  662. memmove( (DWORD *) m_buffNonSecureArray.QueryPtr() + i + 1,
  663. (DWORD *) m_buffNonSecureArray.QueryPtr() + i,
  664. (m_cFilters - i) * sizeof(DWORD) );
  665. ((DWORD*) m_buffNonSecureArray.QueryPtr())[i] = pFilterDll->QueryNonsecureFlags();
  666. m_cFilters++;
  667. //
  668. // Segregate the secure and non-secure port notifications
  669. //
  670. m_SecureNotifications |= pFilterDll->QuerySecureFlags();
  671. m_NonSecureNotifications |= pFilterDll->QueryNonsecureFlags();
  672. LeaveCriticalSection( &g_csFilterDlls );
  673. return TRUE;
  674. }
  675. #if 0
  676. BOOL
  677. FILTER_LIST::Copy(
  678. IN FILTER_LIST * pClone
  679. )
  680. /*++
  681. Routine Description:
  682. Clones the passed filter list
  683. Return Value:
  684. TRUE on success, FALSE on failure (call GetLastError)
  685. --*/
  686. {
  687. DWORD i;
  688. DBG_ASSERT( pClone->CheckSignature() );
  689. DBG_ASSERT( CheckSignature() );
  690. //
  691. // Walk the list to be cloned and load all of the dlls
  692. //
  693. EnterCriticalSection( &g_csFilterDlls );
  694. for ( i = 0; i < pClone->QueryFilterCount(); i++ )
  695. {
  696. if ( !LoadFilter( pClone->QueryDll( i )->QueryName(),
  697. FALSE ))
  698. {
  699. DBGPRINTF(( DBG_CONTEXT,
  700. "[FILTER_LIST::Copy] Failed loading %s, error %d\n",
  701. pClone->QueryDll( i )->QueryName(),
  702. GetLastError() ));
  703. }
  704. }
  705. LeaveCriticalSection( &g_csFilterDlls );
  706. return TRUE;
  707. }
  708. BOOL
  709. ReplaceFilterDll(
  710. IN const CHAR * pszNewDll,
  711. IN const CHAR * pszOldDll
  712. )
  713. /*++
  714. Routine Description:
  715. Given a new filter and an old filter, this function renames the old filter
  716. dll to a temporary name, copies the new .dll into place then walks the
  717. instance list and replaces all occurrences of the old .dll with the
  718. new .dll.
  719. Arguments:
  720. pszNewDll - New filter dll
  721. pszOldDll - Existing filter dll that should be replaced
  722. Return Value:
  723. TRUE on success, FALSE on failure (call GetLastError)
  724. --*/
  725. {
  726. CHAR achTmp[MAX_PATH + 1];
  727. CHAR * pszTmp;
  728. DWORD cVer = 1;
  729. CHAR achVer[32];
  730. const CHAR * apsz[3];
  731. apsz[0] = pszOldDll;
  732. apsz[1] = pszNewDll;
  733. g_pInetSvc->LogEvent( W3_MSG_REP_FILTER,
  734. 2,
  735. apsz,
  736. 0 );
  737. //
  738. // Find a back up name - this just appends a number onto the dll
  739. //
  740. strcpy( achTmp, pszOldDll );
  741. pszTmp = achTmp + strlen( pszOldDll );
  742. while ( TRUE )
  743. {
  744. _itoa( cVer, achVer, 10 );
  745. strcpy( pszTmp, achVer );
  746. if ( GetFileAttributes( achTmp ) != 0xffffffff ||
  747. GetLastError() != ERROR_FILE_NOT_FOUND )
  748. {
  749. cVer++;
  750. //
  751. // If we've tried a reasonable number of backups and we couldn't
  752. // find a candidate then get out
  753. //
  754. if ( cVer > 8192 )
  755. {
  756. SetLastError( ERROR_FILE_NOT_FOUND );
  757. return FALSE;
  758. }
  759. continue;
  760. }
  761. //
  762. // Rename the old DLL to the new dll name
  763. //
  764. if ( !MoveFileEx( pszOldDll,
  765. achTmp,
  766. MOVEFILE_WRITE_THROUGH | MOVEFILE_COPY_ALLOWED ))
  767. {
  768. DBGPRINTF(( DBG_CONTEXT,
  769. "[ReplaceFilterDll] Move old file failed, %s -> %s, error %d\n",
  770. pszOldDll,
  771. achTmp,
  772. GetLastError() ));
  773. if ( GetLastError() == ERROR_FILE_EXISTS )
  774. {
  775. cVer++;
  776. continue;
  777. }
  778. apsz[0] = pszOldDll;
  779. apsz[1] = pszNewDll;
  780. g_pInetSvc->LogEvent( W3_MSG_REP_FILTER,
  781. 2,
  782. apsz,
  783. GetLastError() );
  784. return FALSE;
  785. }
  786. break;
  787. }
  788. //
  789. // Rename the new DLL name to the old dll
  790. //
  791. if ( !MoveFileEx( pszNewDll,
  792. pszOldDll,
  793. MOVEFILE_WRITE_THROUGH | MOVEFILE_COPY_ALLOWED ))
  794. {
  795. DBGPRINTF(( DBG_CONTEXT,
  796. "[ReplaceFilterDll] Move new file failed, %s -> %s, error %d\n",
  797. pszNewDll,
  798. pszOldDll,
  799. GetLastError() ));
  800. apsz[0] = pszNewDll;
  801. apsz[1] = pszOldDll;
  802. g_pInetSvc->LogEvent( W3_MSG_REP_FILTER_FAILED,
  803. 2,
  804. apsz,
  805. 0 );
  806. if ( !MoveFileEx( achTmp,
  807. pszOldDll,
  808. MOVEFILE_WRITE_THROUGH | MOVEFILE_COPY_ALLOWED ))
  809. {
  810. DBGPRINTF(( DBG_CONTEXT,
  811. "[ReplaceFilterDll] Move tmp to old file failed, %s -> %s, error %d\n",
  812. achTmp,
  813. pszOldDll,
  814. GetLastError() ));
  815. apsz[0] = achTmp;
  816. apsz[1] = pszOldDll;
  817. g_pInetSvc->LogEvent( W3_MSG_REP_FILTER_FAILED,
  818. 2,
  819. apsz,
  820. 0 );
  821. }
  822. return FALSE;
  823. }
  824. //
  825. // Update all of the instance filters
  826. //
  827. if ( !g_pInetSvc->EnumServiceInstances(
  828. (PVOID) pszNewDll,
  829. (PVOID) pszOldDll,
  830. (PFN_INSTANCE_ENUM) UpdateInstanceFilters ))
  831. {
  832. return FALSE;
  833. }
  834. return TRUE;
  835. }
  836. BOOL
  837. UpdateInstanceFilters(
  838. IN const CHAR * pszNewDll,
  839. IN const CHAR * pszOldDll,
  840. IN W3_SERVER_INSTANCE * pInst
  841. )
  842. /*++
  843. Routine Description:
  844. This is a simple utility function that handles the instance callbacks
  845. Arguments:
  846. pszNewDll - New filter dll
  847. pszOldDll - Existing filter dll that should be replaced
  848. pInst - The instance the change is being applied to
  849. Return Value:
  850. TRUE on success, FALSE on failure (call GetLastError)
  851. --*/
  852. {
  853. #if 0
  854. if ( !pInst->UpdateFilterList( pszNewDll,
  855. pszOldDll ))
  856. {
  857. DBGPRINTF(( DBG_CONTEXT,
  858. "[UpdateInstanceFilters] Failed with error %d\n",
  859. GetLastError() ));
  860. return FALSE;
  861. }
  862. #endif
  863. return TRUE;
  864. }
  865. #endif
  866. BOOL
  867. FILTER_LIST::InsertGlobalFilters(
  868. VOID
  869. )
  870. /*++
  871. Routine Description:
  872. Transfers all of the global filters to the per-instance filter list
  873. Note: This method assumes the server filter list is not dynamic
  874. Return Value:
  875. TRUE on success, FALSE on failure (call GetLastError)
  876. --*/
  877. {
  878. DWORD i;
  879. HTTP_FILTER_DLL * pFilterDll;
  880. BOOL fOpened;
  881. for ( i = 0; i < GLOBAL_FILTER_LIST()->QueryFilterCount(); i++ )
  882. {
  883. //
  884. // Ignore the return code, an event gets logged in LoadFilter()
  885. // We allow raw read filters here as we're just duplicating the
  886. // global filter list
  887. //
  888. LoadFilter( NULL, NULL, &fOpened, "", GLOBAL_FILTER_LIST()->QueryDll( i )->QueryName(), TRUE );
  889. }
  890. return TRUE;
  891. }
  892. BOOL
  893. CheckForSecurityFilter(
  894. FILTER_LIST * pFilterList
  895. )
  896. /*++
  897. Routine Description:
  898. Checks to see if there are any global filters that are encryption filters
  899. Return Value:
  900. TRUE if an encryption filter was found, FALSE otherwise
  901. --*/
  902. {
  903. DWORD i;
  904. HTTP_FILTER_DLL * pFilterDll;
  905. BOOL fRet = FALSE;
  906. for ( i = 0; i < pFilterList->QueryFilterCount(); i++ )
  907. {
  908. pFilterDll = pFilterList->QueryDll( i );
  909. //
  910. // port notification, assume he's an encryption filter
  911. //
  912. #define SECURE_FILTER (SF_NOTIFY_SECURE_PORT | \
  913. SF_NOTIFY_READ_RAW_DATA | \
  914. SF_NOTIFY_SEND_RAW_DATA | \
  915. SF_NOTIFY_ORDER_HIGH)
  916. if ( (pFilterDll->QueryNotificationFlags() & SECURE_FILTER) ==
  917. SECURE_FILTER)
  918. {
  919. fRet = TRUE;
  920. break;
  921. }
  922. }
  923. return fRet;
  924. }
  925. BOOL
  926. AdjustFilterFlags(
  927. PVOID pfnSFProc,
  928. DWORD dwNewFlags
  929. )
  930. /*++
  931. Routine Description:
  932. Private exported routine that allows a filter to dynamically adjust its
  933. notification flags. This can only be done for global filters.
  934. Return Value:
  935. TRUE on success, FALSE on failure
  936. --*/
  937. {
  938. W3_IIS_SERVICE * pSvc = (W3_IIS_SERVICE *) g_pInetSvc;
  939. FILTER_LIST * pFilterList;
  940. HTTP_FILTER_DLL * pFilterDll;
  941. DWORD i;
  942. BOOL fFoundSvcDLL = FALSE;
  943. BOOL fFoundInstanceDLL = FALSE;
  944. //
  945. // Can't adjust priority, just notification flags
  946. //
  947. if ( dwNewFlags & SF_NOTIFY_ORDER_MASK )
  948. {
  949. SetLastError( ERROR_INVALID_PARAMETER );
  950. return FALSE;
  951. }
  952. pFilterList = pSvc->QueryGlobalFilterList();
  953. if ( !pFilterList )
  954. {
  955. //
  956. // Shouldn't happen but you never know
  957. //
  958. return TRUE;
  959. }
  960. //
  961. // Try to find the appropriate DLL in the single global per-service filter list
  962. //
  963. for ( i = 0; i < pFilterList->QueryFilterCount(); i++ )
  964. {
  965. DBG_ASSERT( pFilterList->QueryDll(i)->CheckSignature() );
  966. if ( pFilterList->QueryDll(i)->QueryEntryPoint() == pfnSFProc )
  967. {
  968. pFilterDll = pFilterList->QueryDll(i);
  969. //
  970. // We've found the matching filter dll, adjust the flags in the
  971. // filter dll object then adjust the flags in the filter list
  972. //
  973. pFilterDll->SetNotificationFlags( dwNewFlags );
  974. pFilterList->SetNotificationFlags( i, pFilterDll );
  975. fFoundSvcDLL = TRUE;
  976. }
  977. }
  978. if ( fFoundSvcDLL )
  979. {
  980. //
  981. // Try to update the flags in each of the per-instance filter lists
  982. //
  983. if ( pSvc )
  984. {
  985. if ( pSvc->EnumServiceInstances( (PVOID) &dwNewFlags,
  986. (PVOID) pfnSFProc,
  987. AdjustInstanceFilterListFlags ) )
  988. {
  989. fFoundInstanceDLL = TRUE;
  990. }
  991. }
  992. }
  993. if ( !( fFoundInstanceDLL && fFoundSvcDLL ) )
  994. {
  995. SetLastError( ERROR_FILE_NOT_FOUND );
  996. return FALSE;
  997. }
  998. return TRUE;
  999. }
  1000. BOOL AdjustInstanceFilterListFlags( IN PVOID pdwNewFlags,
  1001. IN PVOID pfnSFProc,
  1002. IN IIS_SERVER_INSTANCE *pInstance )
  1003. /*++
  1004. Routine Description:
  1005. This is the callback function called when we need to adjust the notification flags
  1006. of a particular filter dll for the filter list associated with a server instance.
  1007. Note that this filter list consists of the -global- [ie service-wide] filter dlls.
  1008. Arguments :
  1009. pdwNewFlags - pointer to DWORD containing new notification flags
  1010. pfnSFProc - pointer to filter entry point function
  1011. pInstance - pointer to W3_SERVER_INSTANCE whose filter list is to be updated
  1012. Return Value:
  1013. TRUE if the DLL was found and the flags adjusted, FALSE otherwise
  1014. --*/
  1015. {
  1016. HTTP_FILTER_DLL *pFilterDll = NULL;
  1017. W3_SERVER_INSTANCE *pW3Instance = (W3_SERVER_INSTANCE *) pInstance;
  1018. BOOL fFound = FALSE;
  1019. if ( !pInstance )
  1020. {
  1021. DBGPRINTF((DBG_CONTEXT,
  1022. "NULL instance passed to AdjustInstanceFilterFlags !\n"));
  1023. return FALSE;
  1024. }
  1025. pInstance->LockThisForRead();
  1026. FILTER_LIST *pFilterList = ((W3_SERVER_INSTANCE *) pInstance)->QueryFilterList();
  1027. pInstance->UnlockThis();
  1028. if ( !pFilterList )
  1029. {
  1030. DBGPRINTF((DBG_CONTEXT,
  1031. "Very odd - instance 0x%p has no filter list associated with it !\n",
  1032. pInstance));
  1033. return TRUE;
  1034. }
  1035. pInstance->LockThisForWrite();
  1036. //
  1037. // Try to find the appropriate DLL in the filter list for this instance
  1038. //
  1039. for ( DWORD i = 0; i < pFilterList->QueryFilterCount(); i++ )
  1040. {
  1041. DBG_ASSERT( pFilterList->QueryDll(i)->CheckSignature() );
  1042. if ( pFilterList->QueryDll(i)->QueryEntryPoint() == pfnSFProc )
  1043. {
  1044. pFilterDll = pFilterList->QueryDll(i);
  1045. //
  1046. // We've found the matching filter dll, adjust the flags in the
  1047. // filter dll object then adjust the flags in the filter list
  1048. //
  1049. pFilterDll->SetNotificationFlags( *((DWORD *) pdwNewFlags) );
  1050. pFilterList->SetNotificationFlags( i, pFilterDll );
  1051. fFound = TRUE;
  1052. break;
  1053. }
  1054. }
  1055. pInstance->UnlockThis();
  1056. return fFound;
  1057. }