Leaked source code of windows server 2003
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.

810 lines
20 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. w3site.cxx
  5. Abstract:
  6. W3_SITE object holds state for each site
  7. Author:
  8. Anil Ruia (AnilR) 18-Jan-2000
  9. Revision History:
  10. --*/
  11. #include "precomp.hxx"
  12. //
  13. // No advance notification
  14. //
  15. #define DEFAULT_W3_ADV_NOT_PWD_EXP_IN_DAYS 14
  16. //
  17. // OWA change flags
  18. //
  19. #define DEFAULT_W3_AUTH_CHANGE_FLAGS 6
  20. //
  21. // In seconds
  22. //
  23. #define DEFAULT_W3_ADV_CACHE_TTL ( 10 * 60 )
  24. //static
  25. CRITICAL_SECTION W3_SITE::sm_csIISCertMapLock;
  26. W3_SITE::W3_SITE(
  27. DWORD SiteId
  28. ) : m_SiteId ( SiteId ),
  29. m_cRefs ( 1 ),
  30. m_pInstanceFilterList ( NULL ),
  31. m_pLogging ( NULL ),
  32. m_fAllowPathInfoForScriptMappings ( FALSE ),
  33. m_fUseDSMapper ( FALSE ),
  34. m_dwAuthChangeFlags ( 0 ),
  35. m_dwAdvNotPwdExpInDays ( DEFAULT_W3_ADV_NOT_PWD_EXP_IN_DAYS ),
  36. m_dwAdvCacheTTL ( DEFAULT_W3_ADV_CACHE_TTL ),
  37. m_fSSLSupported ( FALSE ),
  38. m_pIISCertMap ( NULL ),
  39. m_fAlreadyAttemptedToLoadIISCertMap ( FALSE ),
  40. m_pDataSetCache ( NULL ),
  41. m_Signature ( W3_SITE_SIGNATURE )
  42. {
  43. ZeroMemory(&m_PerfCounters, sizeof m_PerfCounters);
  44. }
  45. W3_SITE::~W3_SITE()
  46. {
  47. if (m_pInstanceFilterList != NULL)
  48. {
  49. m_pInstanceFilterList->Dereference();
  50. m_pInstanceFilterList = NULL;
  51. }
  52. if (m_pLogging != NULL)
  53. {
  54. m_pLogging->Release();
  55. m_pLogging = NULL;
  56. }
  57. if ( m_pIISCertMap != NULL )
  58. {
  59. m_pIISCertMap->DereferenceCertMapping();
  60. m_pIISCertMap = NULL;
  61. }
  62. if ( m_pDataSetCache != NULL )
  63. {
  64. m_pDataSetCache->DereferenceDataSetCache();
  65. m_pDataSetCache = NULL;
  66. }
  67. m_Signature = W3_SITE_SIGNATURE_FREE;
  68. }
  69. HRESULT
  70. W3_SITE::Initialize(LOGGING *pLogging,
  71. FILTER_LIST *pFilterList)
  72. /*++
  73. Routine Description:
  74. Initialize W3_SITE. Should be called after constructor
  75. Arguments:
  76. None
  77. Return Value:
  78. HRESULT
  79. --*/
  80. {
  81. HRESULT hr = NO_ERROR;
  82. WCHAR idToStr[MAX_SITEID_LENGTH + 6];
  83. CHAR idToStrA[MAX_SITEID_LENGTH + 6];
  84. //
  85. // Setup Site Name like "W3SVC1"
  86. //
  87. sprintf(idToStrA, "W3SVC%u", m_SiteId);
  88. if (FAILED(hr = m_SiteName.Copy(idToStrA)))
  89. {
  90. goto Failure;
  91. }
  92. //
  93. // Setup site path (like "/LM/W3SVC/1")
  94. //
  95. hr = m_SiteMBPath.Copy(g_pW3Server->QueryMDPath());
  96. if ( FAILED( hr ) )
  97. {
  98. goto Failure;
  99. }
  100. _itow(m_SiteId, idToStr, 10);
  101. hr = m_SiteMBPath.Append( idToStr );
  102. if ( FAILED( hr ) )
  103. {
  104. goto Failure;
  105. }
  106. //
  107. // Setup site root (like "/LM/W3SVC/1/ROOT/")
  108. //
  109. hr = m_SiteMBRoot.Copy( m_SiteMBPath );
  110. if ( FAILED( hr ) )
  111. {
  112. goto Failure;
  113. }
  114. hr = m_SiteMBRoot.Append( L"/Root/" );
  115. if ( FAILED( hr ) )
  116. {
  117. goto Failure;
  118. }
  119. //
  120. // Read the per-site properties from the metabase
  121. //
  122. if (FAILED(hr = ReadPrivateProperties()))
  123. {
  124. goto Failure;
  125. }
  126. //
  127. // Initialize instance filters
  128. //
  129. if (pFilterList)
  130. {
  131. pFilterList->Reference();
  132. m_pInstanceFilterList = pFilterList;
  133. }
  134. else
  135. {
  136. m_pInstanceFilterList = new FILTER_LIST();
  137. if (m_pInstanceFilterList == NULL)
  138. {
  139. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  140. goto Failure;
  141. }
  142. hr = m_pInstanceFilterList->InsertGlobalFilters();
  143. if (FAILED(hr))
  144. {
  145. goto Failure;
  146. }
  147. hr = m_pInstanceFilterList->LoadFilters( m_SiteMBPath.QueryStr(),
  148. FALSE,
  149. TRUE );
  150. if (FAILED(hr))
  151. {
  152. goto Failure;
  153. }
  154. }
  155. //
  156. // Initialize logging
  157. //
  158. if (pLogging)
  159. {
  160. pLogging->AddRef();
  161. m_pLogging = pLogging;
  162. }
  163. else
  164. {
  165. m_pLogging = new LOGGING;
  166. if (m_pLogging == NULL)
  167. {
  168. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  169. goto Failure;
  170. }
  171. if (FAILED(hr = m_pLogging->ActivateLogging(m_SiteName.QueryStr(),
  172. m_SiteMBPath.QueryStr(),
  173. g_pW3Server->QueryMDObject(),
  174. g_pW3Server->QueryDoCentralBinaryLogging())))
  175. {
  176. LPCWSTR apsz[1];
  177. apsz[0] = idToStr;
  178. g_pW3Server->LogEvent(W3_EVENT_LOGGING_MODULE_FAILED_TO_LOAD,
  179. 1,
  180. apsz);
  181. goto Failure;
  182. }
  183. }
  184. return S_OK;
  185. Failure:
  186. return hr;
  187. }
  188. HRESULT W3_SITE::ReadPrivateProperties()
  189. /*++
  190. Routine description:
  191. Read the site specific properties from the metabase
  192. Arguments:
  193. none
  194. Return Value:
  195. HRESULT
  196. --*/
  197. {
  198. MB mb( g_pW3Server->QueryMDObject() );
  199. MULTISZ mszSecureBindings;
  200. //
  201. // Read per-site properties from the metabase
  202. //
  203. if ( !mb.Open(m_SiteMBPath.QueryStr()) )
  204. {
  205. return HRESULT_FROM_WIN32(GetLastError());
  206. }
  207. if ( !mb.GetDword(L"",
  208. MD_ALLOW_PATH_INFO_FOR_SCRIPT_MAPPINGS,
  209. IIS_MD_UT_FILE,
  210. (DWORD *)&m_fAllowPathInfoForScriptMappings,
  211. 0) )
  212. {
  213. m_fAllowPathInfoForScriptMappings = FALSE;
  214. }
  215. mb.GetStr( L"",
  216. MD_AUTH_CHANGE_URL,
  217. IIS_MD_UT_SERVER,
  218. &m_strAuthChangeUrl );
  219. mb.GetStr( L"",
  220. MD_AUTH_EXPIRED_URL,
  221. IIS_MD_UT_SERVER,
  222. &m_strAuthExpiredUrl );
  223. mb.GetStr( L"",
  224. MD_AUTH_NOTIFY_PWD_EXP_URL,
  225. IIS_MD_UT_SERVER,
  226. &m_strAdvNotPwdExpUrl );
  227. mb.GetStr( L"",
  228. MD_AUTH_EXPIRED_UNSECUREURL,
  229. IIS_MD_UT_SERVER,
  230. &m_strAuthExpiredUnsecureUrl );
  231. mb.GetStr( L"",
  232. MD_AUTH_NOTIFY_PWD_EXP_UNSECUREURL,
  233. IIS_MD_UT_SERVER,
  234. &m_strAdvNotPwdExpUnsecureUrl );
  235. if ( !mb.GetDword( L"",
  236. MD_ADV_NOTIFY_PWD_EXP_IN_DAYS,
  237. IIS_MD_UT_SERVER,
  238. &m_dwAdvNotPwdExpInDays ) )
  239. {
  240. m_dwAdvNotPwdExpInDays = DEFAULT_W3_ADV_NOT_PWD_EXP_IN_DAYS;
  241. }
  242. if ( !mb.GetDword( L"",
  243. MD_AUTH_CHANGE_FLAGS,
  244. IIS_MD_UT_SERVER,
  245. &m_dwAuthChangeFlags ) )
  246. {
  247. m_dwAuthChangeFlags = DEFAULT_W3_AUTH_CHANGE_FLAGS;
  248. }
  249. if ( !mb.GetDword( L"",
  250. MD_ADV_CACHE_TTL,
  251. IIS_MD_UT_SERVER,
  252. &m_dwAdvCacheTTL ) )
  253. {
  254. m_dwAdvCacheTTL = DEFAULT_W3_ADV_CACHE_TTL;
  255. }
  256. //
  257. // Read the secure bindings.
  258. //
  259. if ( mb.GetMultisz( L"",
  260. MD_SECURE_BINDINGS,
  261. IIS_MD_UT_SERVER,
  262. &mszSecureBindings ) )
  263. {
  264. if( !mszSecureBindings.IsEmpty() )
  265. {
  266. m_fSSLSupported = TRUE;
  267. }
  268. }
  269. DBG_REQUIRE( mb.Close() );
  270. //
  271. // Read global properties from the metabase that affect site config
  272. //
  273. if ( !mb.Open(g_pW3Server->QueryMDPath()) )
  274. {
  275. return HRESULT_FROM_WIN32(GetLastError());
  276. }
  277. if ( !mb.GetDword( L"",
  278. MD_SSL_USE_DS_MAPPER,
  279. IIS_MD_UT_SERVER,
  280. (DWORD*) &m_fUseDSMapper,
  281. 0 ))
  282. {
  283. m_fUseDSMapper = FALSE;
  284. }
  285. DBG_REQUIRE( mb.Close() );
  286. return S_OK;
  287. }
  288. HRESULT
  289. W3_SITE::HandleMetabaseChange(
  290. const MD_CHANGE_OBJECT &ChangeObject,
  291. IN W3_SITE_LIST *pTempSiteList
  292. )
  293. /*++
  294. Routine Description:
  295. Handle metabase changes. The change may be to
  296. either the /LM/W3SVC/ node or they may be
  297. changes to this site or one of its children.
  298. This routine needs to perform cache flushes
  299. and reget site metadata if necessary.
  300. Arguments:
  301. ChangeObject
  302. Return Value:
  303. See W3_SERVER_INSTANCE::MDChangeNotify and
  304. IIS_SERVER_INSTANCE::MDChangeNotify for
  305. implemenation details
  306. --*/
  307. {
  308. DBGPRINTF(( DBG_CONTEXT,
  309. "W3_SITE Notified - Path(%S) Type(%d) NumIds(%08x)\n",
  310. ChangeObject.pszMDPath,
  311. ChangeObject.dwMDChangeType,
  312. ChangeObject.dwMDNumDataIDs
  313. ));
  314. if (ChangeObject.dwMDChangeType == MD_CHANGE_TYPE_SET_DATA)
  315. {
  316. BOOL fDontCare = TRUE;
  317. //
  318. // Find out if we care about these properties
  319. // We definitely don't care about ServerState or Win32Error
  320. //
  321. for (DWORD i = 0; i < ChangeObject.dwMDNumDataIDs; i++)
  322. {
  323. DWORD PropertyID = ChangeObject.pdwMDDataIDs[i];
  324. if (PropertyID != MD_SERVER_STATE &&
  325. PropertyID != MD_WIN32_ERROR &&
  326. PropertyID != MD_SERVER_AUTOSTART)
  327. {
  328. fDontCare = FALSE;
  329. break;
  330. }
  331. }
  332. if (fDontCare)
  333. {
  334. return S_OK;
  335. }
  336. }
  337. //
  338. // Let the cache manager invalidate the various cache entries dependent
  339. // on metadata
  340. //
  341. W3CacheDoMetadataInvalidation( ChangeObject.pszMDPath,
  342. (DWORD)wcslen( ChangeObject.pszMDPath ) );
  343. //
  344. // Get rid of the data set cache if we have one
  345. //
  346. RemoveDataSetCache();
  347. //
  348. // Handle any site level change
  349. // That means any changes at /LM/w3svc/ or /LM/w3svc/n/ or
  350. // /LM/w3svc/n/Filters/
  351. //
  352. // IIS 1to1 Client certificate mappings are stored
  353. // under /Cert11/Mappings/ on the site level. Any change in mappings
  354. // will cause recreation of W3_SITE instance
  355. // This is not optimal but changes in 1to1 Cert mappings are not frequent
  356. // and feature itself is not used by many customers
  357. // so there should be no problems with this approach.
  358. //
  359. if ((_wcsicmp(ChangeObject.pszMDPath,
  360. W3_SERVER_MB_PATH) == 0) ||
  361. ((_wcsnicmp(ChangeObject.pszMDPath,
  362. m_SiteMBPath.QueryStr(),
  363. m_SiteMBPath.QueryCCH()) == 0) &&
  364. ((wcscmp(ChangeObject.pszMDPath + m_SiteMBPath.QueryCCH(),
  365. L"/") == 0) ||
  366. (_wcsicmp(ChangeObject.pszMDPath + m_SiteMBPath.QueryCCH(),
  367. L"/Filters/") == 0) ||
  368. (_wcsnicmp(ChangeObject.pszMDPath + m_SiteMBPath.QueryCCH(),
  369. L"/Cert11/Mappings/", wcslen(L"/Cert11/Mappings/") ) == 0)
  370. )))
  371. {
  372. //
  373. // If the site (or its root application) has been deleted, remove it
  374. // unless we are in the iterator in which case it will anyway be
  375. // removed
  376. //
  377. if (ChangeObject.dwMDChangeType == MD_CHANGE_TYPE_DELETE_OBJECT)
  378. {
  379. if (pTempSiteList == NULL)
  380. {
  381. g_pW3Server->RemoveSite(this);
  382. }
  383. return S_OK;
  384. }
  385. //
  386. // Now handle any property changes.
  387. //
  388. BOOL fLoggingHasChanged = FALSE;
  389. BOOL fFiltersHaveChanged = FALSE;
  390. //
  391. // Find out if we would need to handle any logging or filter changes
  392. //
  393. for (DWORD i = 0; i < ChangeObject.dwMDNumDataIDs; i++)
  394. {
  395. DWORD PropertyID = ChangeObject.pdwMDDataIDs[i];
  396. if (((PropertyID >= IIS_MD_LOG_BASE) &&
  397. (PropertyID <= IIS_MD_LOG_LAST)) ||
  398. ((PropertyID >= IIS_MD_LOGCUSTOM_BASE) &&
  399. (PropertyID <= IIS_MD_LOGCUSTOM_LAST)))
  400. {
  401. fLoggingHasChanged = TRUE;
  402. }
  403. else if (PropertyID == MD_FILTER_LOAD_ORDER)
  404. {
  405. fFiltersHaveChanged = TRUE;
  406. }
  407. }
  408. //
  409. // Create a new site
  410. //
  411. W3_SITE *site = new W3_SITE(m_SiteId);
  412. if (site == NULL)
  413. {
  414. return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  415. }
  416. //
  417. // Copy over the cache context, and also logging and filter info
  418. // if applicable
  419. //
  420. HRESULT hr;
  421. if (FAILED(hr = site->Initialize(
  422. fLoggingHasChanged ? NULL : m_pLogging,
  423. fFiltersHaveChanged ? NULL : m_pInstanceFilterList)))
  424. {
  425. site->DereferenceSite();
  426. return hr;
  427. }
  428. //
  429. // Depending on whether we are in the iterator, either replace the
  430. // site in the site list or add it to the temp list which will replace
  431. // the real list later
  432. //
  433. if (pTempSiteList == NULL)
  434. {
  435. g_pW3Server->AddSite(site, true);
  436. }
  437. else
  438. {
  439. pTempSiteList->InsertRecord(site);
  440. }
  441. // Release the extra reference
  442. site->DereferenceSite();
  443. }
  444. return S_OK;
  445. }
  446. VOID
  447. W3_SITE::RemoveDataSetCache(
  448. VOID
  449. )
  450. /*++
  451. Routine Description:
  452. Remove data set cache
  453. Arguments:
  454. None
  455. Return Value:
  456. None
  457. --*/
  458. {
  459. m_DataSetCacheLock.WriteLock();
  460. if ( m_pDataSetCache != NULL )
  461. {
  462. m_pDataSetCache->DereferenceDataSetCache();
  463. m_pDataSetCache = NULL;
  464. }
  465. m_DataSetCacheLock.WriteUnlock();
  466. }
  467. HRESULT
  468. W3_SITE::GetDataSetCache(
  469. DATA_SET_CACHE ** ppDataSetCache
  470. )
  471. /*++
  472. Routine Description:
  473. Retrieve a data set cache for this site
  474. Arguments:
  475. ppDataSetCache - Set to point to data set cache on success
  476. Return Value:
  477. HRESULT
  478. --*/
  479. {
  480. DATA_SET_CACHE * pDataSetCache;
  481. HRESULT hr;
  482. HANDLE hToken = NULL;
  483. if ( ppDataSetCache == NULL )
  484. {
  485. DBG_ASSERT( FALSE );
  486. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  487. }
  488. *ppDataSetCache = NULL;
  489. m_DataSetCacheLock.ReadLock();
  490. if ( m_pDataSetCache != NULL )
  491. {
  492. m_pDataSetCache->ReferenceDataSetCache();
  493. *ppDataSetCache = m_pDataSetCache;
  494. m_DataSetCacheLock.ReadUnlock();
  495. }
  496. else
  497. {
  498. m_DataSetCacheLock.ReadUnlock();
  499. if ( OpenThreadToken( GetCurrentThread(),
  500. TOKEN_IMPERSONATE,
  501. TRUE,
  502. &hToken ) )
  503. {
  504. DBG_ASSERT( hToken != NULL );
  505. DBG_REQUIRE( RevertToSelf() );
  506. }
  507. // Create a data set cache and then try to add it
  508. //
  509. pDataSetCache = new DATA_SET_CACHE;
  510. if ( pDataSetCache == NULL )
  511. {
  512. hr = HRESULT_FROM_WIN32( GetLastError() );
  513. goto Finished;
  514. }
  515. hr = pDataSetCache->Create( *QueryMBRoot() );
  516. if ( FAILED( hr ) )
  517. {
  518. pDataSetCache->DereferenceDataSetCache();
  519. goto Finished;
  520. }
  521. if ( hToken != NULL )
  522. {
  523. DBG_REQUIRE( SetThreadToken( NULL, hToken ) );
  524. DBG_REQUIRE( CloseHandle( hToken ) );
  525. hToken = NULL;
  526. }
  527. //
  528. //
  529. // Try to add it
  530. //
  531. m_DataSetCacheLock.WriteLock();
  532. if ( m_pDataSetCache != NULL )
  533. {
  534. //
  535. // Someone else added it. No problem -> we'll just kill the one
  536. // we just created
  537. //
  538. pDataSetCache->DereferenceDataSetCache();
  539. }
  540. else
  541. {
  542. m_pDataSetCache = pDataSetCache;
  543. }
  544. m_pDataSetCache->ReferenceDataSetCache();
  545. *ppDataSetCache = m_pDataSetCache;
  546. m_DataSetCacheLock.WriteUnlock();
  547. }
  548. DBG_ASSERT( *ppDataSetCache != NULL );
  549. return S_OK;
  550. Finished:
  551. if ( hToken != NULL )
  552. {
  553. DBG_REQUIRE( SetThreadToken( NULL, hToken ) );
  554. DBG_REQUIRE( CloseHandle( hToken ) );
  555. hToken = NULL;
  556. }
  557. return hr;
  558. }
  559. HRESULT
  560. W3_SITE::GetIISCertificateMapping(
  561. IIS_CERTIFICATE_MAPPING ** ppIISCertificateMapping
  562. )
  563. /*++
  564. Routine Description:
  565. Arguments:
  566. ppIISCertificateMapping - returns found iis cert mapping object
  567. m_pIISCertMap is created on demand. It will not be
  568. created when W3_SITE is created, only when first request that requires
  569. certificate mappings
  570. Return Value:
  571. HRESULT
  572. --*/
  573. {
  574. HRESULT hr = E_FAIL;
  575. DBG_ASSERT( ppIISCertificateMapping != NULL );
  576. if ( m_fAlreadyAttemptedToLoadIISCertMap )
  577. {
  578. *ppIISCertificateMapping = m_pIISCertMap;
  579. hr = S_OK;
  580. goto Finished;
  581. }
  582. else
  583. {
  584. IIS_CERTIFICATE_MAPPING * pCertMap = NULL;
  585. //
  586. // This lock only applies when certmapping was not yet read
  587. // Global lock will only apply for reading certmapper for site
  588. // on the very first attempt to fetch file that enables
  589. // IIS certmapping
  590. //
  591. GlobalLockIISCertMap();
  592. //
  593. // try again to prevent loading of mapping multiple times
  594. //
  595. if ( m_fAlreadyAttemptedToLoadIISCertMap )
  596. {
  597. hr = S_OK;
  598. }
  599. else
  600. {
  601. //
  602. // build IIS Certificate mapping structure and
  603. // add update W3_SITE structure
  604. //
  605. if ( m_fUseDSMapper )
  606. {
  607. m_pIISCertMap = NULL;
  608. hr = S_OK;
  609. }
  610. else
  611. {
  612. hr = IIS_CERTIFICATE_MAPPING::GetCertificateMapping( m_SiteId,
  613. &pCertMap );
  614. if ( SUCCEEDED( hr ) )
  615. {
  616. m_pIISCertMap = pCertMap;
  617. }
  618. }
  619. //
  620. // always set m_fAlreadyAttemptedToLoadIISCertMap to TRUE (regardless of error)
  621. // that would prevent reading mappings for each request in the case of failure
  622. // it is valid for m_pIISCertMap to be NULL (regardless of m_fAlreadyAttemptedToLoadIISCertMap)
  623. //
  624. InterlockedExchange( reinterpret_cast<LONG *>(&m_fAlreadyAttemptedToLoadIISCertMap),
  625. TRUE );
  626. }
  627. GlobalUnlockIISCertMap();
  628. if ( FAILED( hr ) )
  629. {
  630. //
  631. // Write event that certificate mappings couldn't be read
  632. // This will be written only once per W3_SITE instance
  633. // so it should not cause any event log overflow troubles
  634. // (unless to many site parameters change notifications
  635. // cause W3_SITE instance to be recreated over and
  636. // over which is unlikely)
  637. //
  638. LPCWSTR apsz[1];
  639. WCHAR achSiteId[ 33 ]; // _ultow uses up to 33 characters
  640. apsz[0] =_ultow( m_SiteId, achSiteId, 10 );
  641. g_pW3Server->LogEvent( W3_EVENT_CERTIFICATE_MAPPING_COULD_NOT_BE_LOADED,
  642. 1,
  643. apsz,
  644. (DWORD) hr ); // we are not converting to WIN32 error
  645. // not to lose HRESULT error
  646. goto Finished;
  647. }
  648. }
  649. *ppIISCertificateMapping = m_pIISCertMap;
  650. hr = S_OK;
  651. Finished:
  652. return hr;
  653. }