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.

770 lines
16 KiB

  1. /*++
  2. Copyright (c) 1995-1996 Microsoft Corporation
  3. Module Name :
  4. setable.cxx
  5. Abstract:
  6. This module declares the SE_TABLE object which consists
  7. of all the extensions for W3 service
  8. Author:
  9. Murali R. Krishnan ( MuraliK ) 18-July-1996
  10. Environment:
  11. User Mode - Win32
  12. Project:
  13. W3 Services DLL
  14. --*/
  15. /************************************************************
  16. * Include Headers
  17. ************************************************************/
  18. # include <isapip.hxx>
  19. # include "isapidll.hxx"
  20. # include "setable.hxx"
  21. # include <issched.hxx>
  22. /************************************************************
  23. * Global Data
  24. ************************************************************/
  25. PSE_TABLE g_psextensions; // all extensions
  26. static BOOL g_fExtInitialized = FALSE;
  27. /**************************************************
  28. * Member functions of SESD_LIST
  29. **************************************************/
  30. SESD_LIST::SESD_LIST(VOID)
  31. : m_idWorkItem( 0)
  32. {
  33. INITIALIZE_CRITICAL_SECTION( &m_csLock);
  34. InitializeListHead( &m_Head);
  35. } // SESD_LIST::SESD_LIST()
  36. SESD_LIST::~SESD_LIST(VOID)
  37. {
  38. // Should be all done
  39. DBG_ASSERT( 0 == m_idWorkItem);
  40. DBG_ASSERT( IsListEmpty( &m_Head));
  41. DeleteCriticalSection( &m_csLock);
  42. } // SESD_LIST::~SESD_LIST()
  43. VOID
  44. SESD_LIST::ScheduleExtensionForDeletion(
  45. IN PHSE psExt
  46. )
  47. {
  48. Lock();
  49. // add to the list
  50. InsertHeadList( &m_Head, &psExt->m_ListEntry);
  51. if ( 0 == m_idWorkItem) {
  52. // schedule the work item if not scheduled one already
  53. m_idWorkItem = ScheduleWorkItem( SchedulerCallback, this, 0);
  54. DBG_ASSERT( 0 != m_idWorkItem);
  55. }
  56. Unlock();
  57. return;
  58. } // SESD_LIST::ScheduleExtensionForDeletion()
  59. VOID
  60. SESD_LIST::WaitTillFinished(VOID)
  61. {
  62. Lock();
  63. // wait until nothing is scheduled
  64. while ( 0 != m_idWorkItem) {
  65. // let it drain itself while in the unlocked state
  66. Unlock();
  67. Sleep( 200 );
  68. Lock();
  69. }
  70. Unlock();
  71. return;
  72. } // SESD_LIST::WaitTillFinished()
  73. VOID
  74. WINAPI
  75. SESD_LIST::SchedulerCallback(
  76. void *pvContext
  77. )
  78. {
  79. DBG_ASSERT( NULL != pvContext);
  80. ((SESD_LIST *)pvContext)->DeleteScheduledExtensions();
  81. return;
  82. } // SESD_LIST::SchedulerCallback()
  83. VOID
  84. SESD_LIST::DeleteScheduledExtensions(VOID)
  85. {
  86. PHSE psExt;
  87. Lock();
  88. // If it is scheduled there better be a reason why
  89. DBG_ASSERT( 0 != m_idWorkItem);
  90. while ( !IsListEmpty( &m_Head)) {
  91. // extract extension from the list and delete it
  92. psExt = CONTAINING_RECORD( m_Head.Flink,
  93. HSE_BASE,
  94. m_ListEntry );
  95. RemoveEntryList( &psExt->m_ListEntry );
  96. InitializeListHead( &psExt->m_ListEntry);
  97. delete psExt;
  98. } // while
  99. // reset to 0 to indicate that we are done
  100. m_idWorkItem = 0;
  101. Unlock();
  102. return;
  103. } // SESD_LIST::DeleteScheduledExtensions()
  104. /**************************************************
  105. * Member functions of SE_TABLE
  106. **************************************************/
  107. SE_TABLE::SE_TABLE(VOID)
  108. : m_cRefWams ( 0)
  109. {
  110. IF_DEBUG( INIT_CLEAN) {
  111. DBGPRINTF(( DBG_CONTEXT, "Constructing SE_TABLE(%08x)\n", this));
  112. }
  113. INITIALIZE_CRITICAL_SECTION( &m_csLock);
  114. InitializeListHead( &m_ExtensionHead);
  115. } // SE_TABLE::SE_TABLE()
  116. SE_TABLE::~SE_TABLE(VOID)
  117. {
  118. IF_DEBUG( INIT_CLEAN) {
  119. DBGPRINTF(( DBG_CONTEXT, "Deleteing SE_TABLE(%08x) cWamRef=%d\n",
  120. this, m_cRefWams));
  121. }
  122. // unload all the extensions if not already done
  123. DBG_REQUIRE( UnloadExtensions());
  124. // No WAM should be holding ref to the SE_TABLE
  125. DBG_ASSERT( 0 == m_cRefWams);
  126. DeleteCriticalSection( &m_csLock);
  127. DBG_ASSERT( IsListEmpty( &m_ExtensionHead));
  128. } // SE_TABLE::~SE_TABLE()
  129. VOID
  130. SE_TABLE::Print(VOID)
  131. {
  132. PLIST_ENTRY pEntry;
  133. int i = 0;
  134. // NYI: I need to write code to print out data here.
  135. DBGPRINTF(( DBG_CONTEXT,
  136. " SE_TABLE(%08x) ListHead=%08x [%08x:%08x] cRefWams=%d\n",
  137. this, &m_ExtensionHead,
  138. m_ExtensionHead.Flink, m_ExtensionHead.Blink,
  139. m_cRefWams
  140. ));
  141. Lock();
  142. for ( pEntry = m_ExtensionHead.Flink;
  143. (pEntry != &m_ExtensionHead);
  144. pEntry = pEntry->Flink, i++ )
  145. {
  146. HSE_BASE *
  147. pExtension = CONTAINING_RECORD( pEntry, HSE_BASE, m_ListEntry );
  148. DBGPRINTF(( DBG_CONTEXT,
  149. " Dll(%d): HSE_BASE = %08x [%08x:%08x]; Module=%s\n",
  150. i, pExtension,
  151. pExtension->m_ListEntry.Flink,
  152. pExtension->m_ListEntry.Blink,
  153. pExtension->QueryModuleName()));
  154. } // for all entries in table
  155. Unlock();
  156. return;
  157. } // SE_TABLE::Print()
  158. BOOL
  159. SE_TABLE::GetExtension(
  160. IN const CHAR * pchModuleName,
  161. IN HANDLE hImpersonation,
  162. IN BOOL fCacheImpersonation,
  163. IN BOOL fCache,
  164. OUT PHSE * ppsExt
  165. )
  166. /*++
  167. Routine Description:
  168. Retrieves an extension's DLL entry point
  169. The appropriate user should be impersonated before calling this function
  170. Arguments:
  171. pchModuleName - Extension DLL module name
  172. hImpersonation - Impersonation token of user making this call
  173. fCacheImpersonation - if TRUE, the hImpersonation can be cached
  174. fCache - TRUE if this item should be cached, FALSE otherwise
  175. ppsExt - pointer to the Extensions handler object
  176. Return Value:
  177. TRUE if successful, FALSE on error
  178. --*/
  179. {
  180. LIST_ENTRY * pEntry;
  181. HSE_BASE * pExtension = NULL;
  182. BOOL fRet = FALSE;
  183. IF_DEBUG( BGI ) {
  184. DBGPRINTF(( DBG_CONTEXT, "[GetEntryPoint] Looking for module %s\n",
  185. pchModuleName ));
  186. }
  187. //
  188. // NYI: Optimize the locked section here - reduce time spent inside
  189. // the locked block.
  190. // Check cache to see if DLL is already loaded
  191. //
  192. DWORD cchModuleName = strlen( pchModuleName);
  193. Lock();
  194. for ( pEntry = m_ExtensionHead.Flink;
  195. pEntry != &m_ExtensionHead;
  196. pEntry = pEntry->Flink )
  197. {
  198. pExtension = CONTAINING_RECORD( pEntry, HSE_BASE, m_ListEntry );
  199. if ( pExtension->IsMatch( pchModuleName, cchModuleName)) {
  200. //
  201. // Already Loaded, return the extension object after access check
  202. //
  203. fRet = TRUE;
  204. break;
  205. } // a match
  206. } // for all entries in table
  207. IF_DEBUG( BGI ) {
  208. DBGPRINTF(( DBG_CONTEXT,
  209. "[GetEntryPoint] Lookup module %s => fRet =%d\n",
  210. pchModuleName, fRet ));
  211. }
  212. if ( !fRet) {
  213. //
  214. // The module is not loaded. Load the module now.
  215. // The module name refers to an ISAPI application.
  216. // Try ISAPI app loader now...
  217. pExtension = HSE_APPDLL::LoadModule( pchModuleName,
  218. hImpersonation,
  219. fCache);
  220. fRet = (pExtension != NULL);
  221. if (fRet) {
  222. if ( !fCache) {
  223. // Temporarily the ref count will drop to 0, but the code below
  224. // will bump this up to 1.
  225. pExtension->Dereference();
  226. } else {
  227. // add this extension to the list of cached extensions
  228. InsertIntoListWithLock( pExtension);
  229. }
  230. } else {
  231. DBGPRINTF((DBG_CONTEXT,
  232. "LoadModule failed with %x\n",GetLastError()));
  233. }
  234. }
  235. if ( fRet ) {
  236. if ( pExtension->AccessCheck( hImpersonation, fCacheImpersonation)) {
  237. DBG_ASSERT( pExtension != NULL);
  238. if ( ppsExt != NULL) {
  239. // ref the object before giving ptr away
  240. pExtension->Reference();
  241. *ppsExt = pExtension;
  242. }
  243. } else {
  244. fRet = FALSE;
  245. }
  246. }
  247. Unlock();
  248. return fRet;
  249. } // SE_TABLE::GetExtension()
  250. BOOL
  251. SE_TABLE::RefreshAcl(
  252. IN const CHAR * pchDLL
  253. )
  254. /*++
  255. Routine Description:
  256. This function reloads the ACL on an ISAPI Application .dll after that
  257. .dll has already been loaded.
  258. Arguments:
  259. pchDLL - pointer to the ISAPI DLL for which ACL has to be refreshed.
  260. Return Value:
  261. TRUE on success, FALSE on failure
  262. --*/
  263. {
  264. LIST_ENTRY * pEntry;
  265. PHSE pExtension;
  266. BOOL fRet = FALSE;
  267. BOOL fFound = FALSE;
  268. IF_DEBUG( BGI )
  269. {
  270. DBGPRINTF(( DBG_CONTEXT,
  271. "[RefreshISAPIAcl] Rereading ACL for %s\n",
  272. pchDLL ));
  273. }
  274. //
  275. // Check cache to see if the DLL is loaded
  276. //
  277. DWORD cchDll = strlen( pchDLL);
  278. Lock();
  279. for ( pEntry = m_ExtensionHead.Flink;
  280. pEntry != &m_ExtensionHead;
  281. pEntry = pEntry->Flink )
  282. {
  283. pExtension = CONTAINING_RECORD( pEntry, HSE_BASE, m_ListEntry );
  284. if ( pExtension->IsMatch( pchDLL, cchDll) )
  285. {
  286. //
  287. // Force an access check on the next request with the new ACL
  288. //
  289. fRet = pExtension->LoadAcl();
  290. fFound = TRUE;
  291. break;
  292. }
  293. }
  294. Unlock();
  295. if ( !fFound) { SetLastError( ERROR_FILE_NOT_FOUND ); }
  296. return (fRet);
  297. } // SE_TABLE::RefreshAcl()
  298. BOOL
  299. SE_TABLE::RefreshAcl(
  300. IN DWORD dwId
  301. )
  302. /*++
  303. Routine Description:
  304. This function reloads the ACL on an ISAPI Application .dll after that
  305. .dll has already been loaded.
  306. Arguments:
  307. pchDLL - pointer to the ISAPI DLL for which ACL has to be refreshed.
  308. Return Value:
  309. TRUE on success, FALSE on failure
  310. --*/
  311. {
  312. LIST_ENTRY * pEntry;
  313. PHSE pExtension;
  314. BOOL fRet = FALSE;
  315. BOOL fFound = FALSE;
  316. IF_DEBUG( BGI )
  317. {
  318. DBGPRINTF(( DBG_CONTEXT,
  319. "[RefreshISAPIAcl] Rereading ACL for %d\n",
  320. dwId ));
  321. }
  322. //
  323. // Check cache to see if the DLL is loaded
  324. //
  325. Lock();
  326. for ( pEntry = m_ExtensionHead.Flink;
  327. pEntry != &m_ExtensionHead;
  328. pEntry = pEntry->Flink )
  329. {
  330. pExtension = CONTAINING_RECORD( pEntry, HSE_BASE, m_ListEntry );
  331. if ( pExtension->GetDirMonitorId() == dwId )
  332. {
  333. //
  334. // Force an access check on the next request with the new ACL
  335. //
  336. fRet = pExtension->LoadAcl();
  337. fFound = TRUE;
  338. break;
  339. }
  340. }
  341. Unlock();
  342. if ( !fFound) { SetLastError( ERROR_FILE_NOT_FOUND ); }
  343. return (fRet);
  344. } // SE_TABLE::RefreshAcl()
  345. BOOL
  346. SE_TABLE::FlushAccessToken(
  347. IN HANDLE hAccTok
  348. )
  349. /*++
  350. Routine Description:
  351. Reset last successfull user it same as hAccTok
  352. Arguments:
  353. hAccTok - access token to remove from cache
  354. Return Value:
  355. TRUE on success, FALSE on failure
  356. --*/
  357. {
  358. LIST_ENTRY * pEntry;
  359. HSE_APPDLL * pExtension;
  360. BOOL fRet = FALSE;
  361. BOOL fFound = FALSE;
  362. IF_DEBUG( BGI )
  363. {
  364. DBGPRINTF(( DBG_CONTEXT,
  365. "[FlushAccessToken] removing handle %x from cache\n",
  366. hAccTok ));
  367. }
  368. //
  369. // Check cache for access token
  370. //
  371. Lock();
  372. for ( pEntry = m_ExtensionHead.Flink;
  373. pEntry != &m_ExtensionHead;
  374. pEntry = pEntry->Flink )
  375. {
  376. pExtension = CONTAINING_RECORD( pEntry, HSE_APPDLL, m_ListEntry );
  377. if ( pExtension->QueryLastSuccessfulUser() == hAccTok )
  378. {
  379. //
  380. // Force an access check on the next request for this token
  381. //
  382. pExtension->SetLastSuccessfulUser( NULL );
  383. }
  384. }
  385. Unlock();
  386. return TRUE;
  387. } // SE_TABLE::RefreshAcl()
  388. BOOL
  389. SE_TABLE::UnloadExtensions(VOID)
  390. {
  391. PHSE psExt;
  392. DBG_ASSERT( m_cRefWams == 0);
  393. Lock();
  394. while ( !IsListEmpty( &m_ExtensionHead )) {
  395. psExt = CONTAINING_RECORD( m_ExtensionHead.Flink,
  396. HSE_BASE,
  397. m_ListEntry );
  398. //
  399. // Move from the current list to the UnloadList
  400. //
  401. RemoveEntryList( &psExt->m_ListEntry );
  402. InitializeListHead( &psExt->m_ListEntry); // Cleanup
  403. IF_DEBUG( INIT_CLEAN) {
  404. DBGPRINTF(( DBG_CONTEXT,
  405. "Deref of HSE_APPDLL(%08x) = %s. Ref=%d\n",
  406. psExt, psExt->QueryModuleName(), psExt->RefCount()));
  407. }
  408. //
  409. // Cause an Unload of the ISAPI DLL
  410. // Ugly cast should be cleaned up post-beta2
  411. //
  412. DBG_REQUIRE( ((HSE_APPDLL * )psExt)->Unload() == NO_ERROR);
  413. // Decrement the life reference count of the ISAPI DLL structure
  414. if ( !psExt->Dereference()) {
  415. delete psExt;
  416. }
  417. } // while
  418. Unlock();
  419. // Drain the list of non-cached extensions scheduled for deletion
  420. m_sesdExtensions.WaitTillFinished();
  421. return (TRUE);
  422. } // SE_TABLE::UnloadExtensions()
  423. VOID
  424. SE_TABLE::PrintRequestCounts(VOID)
  425. /*++
  426. Description:
  427. Prints a summary of all the ISAPI Dlls loaded and the # requests
  428. pending in each of them primarily for debugging purposes.
  429. Arguments:
  430. None
  431. Return:
  432. None
  433. --*/
  434. {
  435. PHSE psExt;
  436. PLIST_ENTRY pEntry;
  437. Lock();
  438. if( m_ExtensionHead.Flink != &m_ExtensionHead ) {
  439. DBGPRINTF( (DBG_CONTEXT, "SE_TABLE::Printing refs for all loaded ISAPI\n") );
  440. for ( pEntry = m_ExtensionHead.Flink;
  441. pEntry != &m_ExtensionHead;
  442. pEntry = pEntry->Flink )
  443. {
  444. psExt = CONTAINING_RECORD( pEntry, HSE_BASE, m_ListEntry );
  445. RemoveEntryList( &psExt->m_ListEntry );
  446. DBGPRINTF( (DBG_CONTEXT,
  447. " \'%s\') has RefCount = %d\n",
  448. psExt->QueryModuleName(),
  449. psExt->RefCount()
  450. ) );
  451. } // for
  452. DBGPRINTF( (DBG_CONTEXT, "-------------------------------\n") );
  453. } // if
  454. Unlock();
  455. return;
  456. } // SE_TABLE::PrintRequestCounts()
  457. VOID
  458. SE_TABLE::ReleaseExtension( IN PHSE psExt)
  459. {
  460. // decrement ref count and remove from table if needed
  461. if ( !psExt->Dereference()) {
  462. if ( psExt->IsCached())
  463. {
  464. RemoveFromList( psExt);
  465. delete psExt;
  466. }
  467. else {
  468. // non cached ISAPIs should be deleted (TerminateExtension
  469. // call should be called) from a different thread because
  470. // this thread could be an ISAPI thread (in case of pended
  471. // ISAPI this could be the DONE_WITH_SESSION thread)
  472. m_sesdExtensions.ScheduleExtensionForDeletion( psExt);
  473. }
  474. }
  475. return;
  476. } // SE_TABLE::ReleaseExtension()
  477. APIERR
  478. InitializeHseExtensions(
  479. VOID
  480. )
  481. /*++
  482. Routine Description:
  483. Initializes the extension list cache
  484. Return Value:
  485. 0 on success, win32 error on failure
  486. --*/
  487. {
  488. DBGPRINTF(( DBG_CONTEXT, " InitExtensions() entered \n"));
  489. DWORD err = NO_ERROR;
  490. // UNDONE needs to move into wam.dll DllInit
  491. if ( err == NO_ERROR ) {
  492. // initialize other objects
  493. g_psextensions = new SE_TABLE();
  494. if ( (g_psextensions == NULL) ) {
  495. err = (ERROR_NOT_ENOUGH_MEMORY);
  496. if ( g_psextensions != NULL ) {
  497. delete (g_psextensions);
  498. g_psextensions = NULL;
  499. }
  500. } else {
  501. g_fExtInitialized = TRUE;
  502. }
  503. }
  504. DBGPRINTF(( DBG_CONTEXT, " Leaving InitExtensions().\n" ));
  505. return ( err);
  506. } // InitializeHseExtensions()
  507. VOID
  508. CleanupHseExtensions(
  509. VOID
  510. )
  511. /*++
  512. Routine Description:
  513. Walks list and unloads each extension. No clients should be in an
  514. extension at this point
  515. --*/
  516. {
  517. DWORD i;
  518. DBGPRINTF(( DBG_CONTEXT, " TerminateExtensions() called \n"
  519. ));
  520. if ( !g_fExtInitialized )
  521. return;
  522. DBG_ASSERT( g_psextensions != NULL);
  523. delete g_psextensions;
  524. return;
  525. } // CleanupHseExtensions()
  526. /************************ End of File ***********************/