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.

1423 lines
38 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name :
  4. metacach.cxx
  5. Abstract:
  6. This module contains the tsunami caching routines for metadata.
  7. Author:
  8. Henry Sanders ( henrysa ) 15-Oct-1996
  9. --*/
  10. //
  11. #include <tsunami.hxx>
  12. #include "TsunamiP.Hxx"
  13. #pragma hdrstop
  14. #include <dbgutil.h>
  15. #include <issched.hxx>
  16. #include <metacach.hxx>
  17. extern TCHAR * FlipSlashes( TCHAR * pszPath );
  18. //
  19. // The number of buckets in our hash table.
  20. //
  21. #define METACACHE_TABLE_SIZE 127
  22. #define METACACHE_ENTRY_SIGN ((DWORD)'ECEM')
  23. #define METACACHE_ENTRY_FREE ((DWORD)'ECEf')
  24. // time in minutes to keep entry in metachace after it was used last time
  25. #define TIME_TO_KEEP_METACACHE_ENTRY (5)
  26. //
  27. // Structure of a metacache table entry.
  28. //
  29. typedef struct _METACACHE_ENTRY {
  30. DWORD Signature;
  31. struct _METACACHE_ENTRY *pNext;
  32. DWORD dwDataSetNumber;
  33. DWORD dwServiceID;
  34. PVOID pMetaData;
  35. DWORD dwRefCount;
  36. DWORD dwLastUsedTime;
  37. PMDFREERTN pFreeRoutine;
  38. BOOL bValid;
  39. } METACACHE_ENTRY, *PMETACACHE_ENTRY;
  40. //
  41. // Structure of a hash table bucket.
  42. //
  43. typedef struct _METACACHE_BUCKET {
  44. PMETACACHE_ENTRY pEntry;
  45. CRITICAL_SECTION csCritSec;
  46. } METACACHE_BUCKET;
  47. METACACHE_BUCKET MetaCacheTable[METACACHE_TABLE_SIZE];
  48. DWORD MetaCacheTimerCookie = 0;
  49. DWORD g_dwMetaCacheScavengeCnt = 1;
  50. /************************************************************
  51. * Functions
  52. ************************************************************/
  53. dllexp
  54. PVOID
  55. TsFindMetaData(
  56. IN DWORD dwDataSetNumber,
  57. IN DWORD dwServiceID
  58. )
  59. /*++
  60. Routine Description:
  61. This function takes a data set number and service ID, and tries to find
  62. a formatted chunk of metadata in the cache. If it does so, it returns a
  63. pointer to it, otherwise it returns NULL.
  64. Arguments
  65. dwDataSetNumber - The data set number to be found.
  66. dwServiceID - ID of calling service.
  67. --*/
  68. {
  69. DWORD dwIndex;
  70. PMETACACHE_ENTRY pCurrentEntry;
  71. dwIndex = dwDataSetNumber % METACACHE_TABLE_SIZE;
  72. //
  73. // This needes to be protected, we use a critical section per bucket.
  74. //
  75. EnterCriticalSection(&MetaCacheTable[dwIndex].csCritSec);
  76. pCurrentEntry = MetaCacheTable[dwIndex].pEntry;
  77. // Walk the chain on the bucket. If we find a match, return it.
  78. //
  79. while (pCurrentEntry != NULL )
  80. {
  81. PCOMMON_METADATA pCMD;
  82. pCMD = (PCOMMON_METADATA)pCurrentEntry->pMetaData;
  83. pCMD->CheckSignature();
  84. ASSERT(pCMD->QueryCacheInfo() == pCurrentEntry);
  85. if (pCurrentEntry->dwDataSetNumber == dwDataSetNumber &&
  86. pCurrentEntry->dwServiceID == dwServiceID &&
  87. pCurrentEntry->bValid)
  88. {
  89. ASSERT( pCurrentEntry->Signature == METACACHE_ENTRY_SIGN );
  90. // Found a match. Increment the refcount and return a pointer
  91. // to the metadata.
  92. InterlockedIncrement((LONG *)&pCurrentEntry->dwRefCount);
  93. pCurrentEntry->dwLastUsedTime = g_dwMetaCacheScavengeCnt;
  94. LeaveCriticalSection(&MetaCacheTable[dwIndex].csCritSec);
  95. return pCurrentEntry->pMetaData;
  96. }
  97. // Otherwise try the next one.
  98. pCurrentEntry = pCurrentEntry->pNext;
  99. }
  100. // Didn't find a match, so we'll return NULL.
  101. LeaveCriticalSection(&MetaCacheTable[dwIndex].csCritSec);
  102. return NULL;
  103. }
  104. dllexp
  105. PVOID
  106. TsAddMetaData(
  107. IN PCOMMON_METADATA pMetaData,
  108. IN PMDFREERTN pFreeRoutine,
  109. IN DWORD dwDataSetNumber,
  110. IN DWORD dwServiceID
  111. )
  112. /*++
  113. Routine Description:
  114. Add a chunk of formatted metadata to our cache.
  115. Arguments
  116. pMetaData - MetaData to be added.
  117. dwDataSetNumber - The data set number to be found.
  118. dwServiceID - ID of calling service.
  119. Returns
  120. Pointer to metacache 'handle' to be used when freeing information.
  121. --*/
  122. {
  123. PMETACACHE_ENTRY pNewEntry;
  124. DWORD dwIndex;
  125. pMetaData->CheckSignature();
  126. dwIndex = dwDataSetNumber % METACACHE_TABLE_SIZE;
  127. pNewEntry = (PMETACACHE_ENTRY)ALLOC(sizeof(METACACHE_ENTRY));
  128. if (pNewEntry == NULL)
  129. {
  130. // Couldn't add the entry. No big deal, just return.
  131. return NULL;
  132. }
  133. pNewEntry->Signature = METACACHE_ENTRY_SIGN;
  134. pNewEntry->dwDataSetNumber = dwDataSetNumber;
  135. pNewEntry->dwServiceID = dwServiceID;
  136. pNewEntry->pMetaData = pMetaData;
  137. pNewEntry->pFreeRoutine = pFreeRoutine;
  138. pNewEntry->dwRefCount = 1;
  139. pNewEntry->bValid = TRUE;
  140. pNewEntry->dwLastUsedTime = g_dwMetaCacheScavengeCnt;
  141. pMetaData->SetCacheInfo(pNewEntry);
  142. EnterCriticalSection(&MetaCacheTable[dwIndex].csCritSec);
  143. pNewEntry->pNext = MetaCacheTable[dwIndex].pEntry;
  144. MetaCacheTable[dwIndex].pEntry = pNewEntry;
  145. LeaveCriticalSection(&MetaCacheTable[dwIndex].csCritSec);
  146. return pNewEntry;
  147. }
  148. dllexp
  149. VOID
  150. TsFreeMetaData(
  151. IN PVOID pCacheEntry
  152. )
  153. /*++
  154. Routine Description:
  155. Free a chunk of formatted metadata to the cache. What we really do here
  156. is decrement the ref count. If it goes to 0 and the cache element is
  157. marked deleted, we'll free it here.
  158. Arguments
  159. pMetaData - MetaData to be freed.
  160. --*/
  161. {
  162. PMETACACHE_ENTRY pEntry = (PMETACACHE_ENTRY)pCacheEntry;
  163. PCOMMON_METADATA pCMD;
  164. ASSERT( pEntry->Signature == METACACHE_ENTRY_SIGN );
  165. pCMD = (PCOMMON_METADATA)pEntry->pMetaData;
  166. pCMD->CheckSignature();
  167. ASSERT(pCMD->QueryCacheInfo() == pEntry);
  168. InterlockedDecrement((LONG *)&pEntry->dwRefCount);
  169. }
  170. dllexp
  171. VOID
  172. TsAddRefMetaData(
  173. IN PVOID pCacheEntry
  174. )
  175. /*++
  176. Routine Description:
  177. Increment reference count to chunk of formatted metadata
  178. Arguments
  179. pMetaData - MetaData to be AddRef'ed
  180. --*/
  181. {
  182. PMETACACHE_ENTRY pEntry = (PMETACACHE_ENTRY)pCacheEntry;
  183. ASSERT( pEntry->Signature == METACACHE_ENTRY_SIGN );
  184. InterlockedIncrement((LONG *)&pEntry->dwRefCount);
  185. }
  186. dllexp
  187. VOID
  188. TsFlushMetaCache(
  189. DWORD dwService,
  190. BOOL bTerminating
  191. )
  192. /*++
  193. Routine Description:
  194. Called when we need to flush all of our cached metainformation. We walk
  195. the table, and for each entry we check to see if it's in use. If it's not
  196. we'll free it, otherwise we'll mark it as deleted.
  197. If the passed in dwService ID is non-zero, then we'll only
  198. flush those entries that match the service. Also, if we're terminating,
  199. we'll do some additional checking, and also cancle any callbacks if we need
  200. to.
  201. Arguments
  202. dwService - Service ID of entries to be flushed, 0 for all
  203. services.
  204. bTerminating - TRUE if the caller is terminating.
  205. --*/
  206. {
  207. UINT i;
  208. PMETACACHE_ENTRY pEntry;
  209. PMETACACHE_ENTRY pTrailer;
  210. PCOMMON_METADATA pCMD;
  211. for (i = 0; i < METACACHE_TABLE_SIZE; i++)
  212. {
  213. EnterCriticalSection(&MetaCacheTable[i].csCritSec);
  214. pTrailer = CONTAINING_RECORD(&MetaCacheTable[i].pEntry,
  215. METACACHE_ENTRY, pNext);
  216. // Walk the chain on the bucket. For every entry, if it's not in
  217. // use, free it.
  218. //
  219. while (pTrailer->pNext != NULL )
  220. {
  221. pEntry = pTrailer->pNext;
  222. ASSERT( pEntry->Signature == METACACHE_ENTRY_SIGN );
  223. pCMD = (PCOMMON_METADATA)pEntry->pMetaData;
  224. pCMD->CheckSignature();
  225. ASSERT(pCMD->QueryCacheInfo() == pEntry);
  226. if (dwService == 0 || dwService == pEntry->dwServiceID)
  227. {
  228. if (pEntry->dwRefCount == 0)
  229. {
  230. // This entry is not in use.
  231. // If whoever added it gave us a free routine, call it now.
  232. if (pEntry->pFreeRoutine != NULL)
  233. {
  234. (*(pEntry->pFreeRoutine))(pEntry->pMetaData);
  235. }
  236. // Look at the next one.
  237. pTrailer->pNext = pEntry->pNext;
  238. pEntry->Signature = METACACHE_ENTRY_FREE;
  239. FREE(pEntry);
  240. }
  241. else
  242. {
  243. // In a debug build we'll assert here if we're terminating,
  244. // since that shouldn't happen. In a free build we won't
  245. // assert for that but we will NULL out the free routine to
  246. // keep it from getting called, since presumably the owner is
  247. // going away.
  248. if (bTerminating)
  249. {
  250. DBGPRINTF(( DBG_CONTEXT,
  251. "\n=========================================\n"
  252. "Leftover item in metacache - %8p, bValid = %s\n"
  253. "\t dwServiceID = %8d pMetaData = %8p\n"
  254. "\t dwRefCount = %8d pFreeRoutine = %8p\n"
  255. ,
  256. pEntry,
  257. (pEntry->bValid ? "TRUE" : "FALSE"),
  258. pEntry->dwServiceID,
  259. pEntry->pMetaData,
  260. pEntry->dwRefCount,
  261. pEntry->pFreeRoutine ));
  262. pEntry->pFreeRoutine = NULL;
  263. }
  264. pEntry->bValid = FALSE;
  265. pTrailer = pEntry;
  266. }
  267. }
  268. else
  269. {
  270. pTrailer = pEntry;
  271. }
  272. }
  273. LeaveCriticalSection(&MetaCacheTable[i].csCritSec);
  274. }
  275. }
  276. dllexp
  277. VOID
  278. TsReferenceMetaData(
  279. IN PVOID pEntry
  280. )
  281. /*++
  282. Routine Description:
  283. Called when we need to reference a metadata cache entry. The caller
  284. must have already referenced it once.
  285. Arguments
  286. pEntry - Entry to be referenced.
  287. --*/
  288. {
  289. PMETACACHE_ENTRY pCacheEntry = (PMETACACHE_ENTRY)pEntry;
  290. PCOMMON_METADATA pCMD;
  291. ASSERT( pCacheEntry->Signature == METACACHE_ENTRY_SIGN );
  292. pCMD = (PCOMMON_METADATA)pCacheEntry->pMetaData;
  293. pCMD->CheckSignature();
  294. ASSERT(pCMD->QueryCacheInfo() == pCacheEntry);
  295. InterlockedIncrement((LONG *)&pCacheEntry->dwRefCount);
  296. }
  297. VOID
  298. WINAPI
  299. MetaCacheScavenger(
  300. PVOID pContext
  301. )
  302. /*++
  303. Routine Description:
  304. Called periodically to time out metacache information. We scan the table;
  305. if we find an object that's not in use we free it.
  306. Arguments
  307. None.
  308. --*/
  309. {
  310. UINT i;
  311. PMETACACHE_ENTRY pEntry;
  312. PMETACACHE_ENTRY pTrailer;
  313. PCOMMON_METADATA pCMD;
  314. for (i = 0; i < METACACHE_TABLE_SIZE; i++)
  315. {
  316. if (MetaCacheTable[i].pEntry == NULL)
  317. {
  318. continue;
  319. }
  320. EnterCriticalSection(&MetaCacheTable[i].csCritSec);
  321. pTrailer = CONTAINING_RECORD(&MetaCacheTable[i].pEntry,
  322. METACACHE_ENTRY, pNext);
  323. // Walk the chain on the bucket. For every entry, if it's not in
  324. // use, free it.
  325. //
  326. while (pTrailer->pNext != NULL )
  327. {
  328. pEntry = pTrailer->pNext;
  329. ASSERT( pEntry->Signature == METACACHE_ENTRY_SIGN );
  330. pCMD = (PCOMMON_METADATA)pEntry->pMetaData;
  331. pCMD->CheckSignature();
  332. ASSERT(pCMD->QueryCacheInfo() == pEntry);
  333. if (pEntry->dwRefCount == 0 &&
  334. (pEntry->dwLastUsedTime + TIME_TO_KEEP_METACACHE_ENTRY < g_dwMetaCacheScavengeCnt))
  335. {
  336. // This entry is not in use.
  337. // If whoever added it gave us a free routine, call it now.
  338. if (pEntry->pFreeRoutine != NULL)
  339. {
  340. (*(pEntry->pFreeRoutine))(pEntry->pMetaData);
  341. }
  342. // Free the entry and look at the next one.
  343. pTrailer->pNext = pEntry->pNext;
  344. pEntry->Signature = METACACHE_ENTRY_FREE;
  345. FREE(pEntry);
  346. }
  347. else
  348. {
  349. pTrailer = pEntry;
  350. }
  351. }
  352. LeaveCriticalSection(&MetaCacheTable[i].csCritSec);
  353. }
  354. InterlockedIncrement ((long *)&g_dwMetaCacheScavengeCnt);
  355. }
  356. dllexp
  357. VOID
  358. _TsValidateMetaCache(
  359. VOID
  360. )
  361. /*++
  362. --*/
  363. {
  364. UINT i;
  365. PMETACACHE_ENTRY pEntry;
  366. PCOMMON_METADATA pCMD;
  367. for (i = 0; i < METACACHE_TABLE_SIZE; i++)
  368. {
  369. if (MetaCacheTable[i].pEntry == NULL)
  370. {
  371. continue;
  372. }
  373. EnterCriticalSection(&MetaCacheTable[i].csCritSec);
  374. pEntry = MetaCacheTable[i].pEntry;
  375. while (pEntry != NULL )
  376. {
  377. ASSERT( pEntry->Signature == METACACHE_ENTRY_SIGN );
  378. pCMD = (PCOMMON_METADATA)pEntry->pMetaData;
  379. pCMD->CheckSignature();
  380. ASSERT(pCMD->QueryCacheInfo() == pEntry);
  381. pEntry = pEntry->pNext;
  382. }
  383. LeaveCriticalSection(&MetaCacheTable[i].csCritSec);
  384. }
  385. }
  386. BOOL
  387. MetaCache_Initialize(
  388. VOID
  389. )
  390. /*++
  391. Routine Description:
  392. Initialize our metacache code.
  393. Arguments
  394. Nothing.
  395. --*/
  396. {
  397. UINT i;
  398. UINT j;
  399. BOOL fRet;
  400. for (i = 0; i < METACACHE_TABLE_SIZE; i++)
  401. {
  402. fRet = INITIALIZE_CRITICAL_SECTION(&MetaCacheTable[i].csCritSec);
  403. if ( !fRet )
  404. {
  405. //
  406. // Cleanup all inited critical sections
  407. //
  408. if ( i > 0 )
  409. {
  410. for ( j = 0; j < i - 1; j++ )
  411. {
  412. DeleteCriticalSection(&MetaCacheTable[i].csCritSec);
  413. }
  414. }
  415. return FALSE;
  416. }
  417. MetaCacheTable[i].pEntry = NULL;
  418. }
  419. MetaCacheTimerCookie = ScheduleWorkItem(
  420. MetaCacheScavenger,
  421. NULL,
  422. 60 * 1000, // 1 minute
  423. TRUE ); // Periodic
  424. if (!MetaCacheTimerCookie)
  425. {
  426. return FALSE;
  427. }
  428. return TRUE;
  429. }
  430. BOOL
  431. MetaCache_Terminate(
  432. VOID
  433. )
  434. /*++
  435. Routine Description:
  436. Terminate our metacache code.
  437. Arguments
  438. Nothing.
  439. --*/
  440. {
  441. UINT i;
  442. if (MetaCacheTimerCookie != 0)
  443. {
  444. RemoveWorkItem(MetaCacheTimerCookie);
  445. MetaCacheTimerCookie = 0;
  446. }
  447. TsFlushMetaCache(0, TRUE);
  448. for (i = 0; i < METACACHE_TABLE_SIZE; i++)
  449. {
  450. DeleteCriticalSection(&MetaCacheTable[i].csCritSec);
  451. }
  452. return TRUE;
  453. }
  454. COMMON_METADATA::COMMON_METADATA(VOID)
  455. : m_IpDnsAccessCheckSize( 0 ),
  456. m_IpDnsAccessCheckPtr ( NULL ),
  457. m_IpDnsAccessCheckTag ( 0 ),
  458. m_fDontLog ( FALSE ),
  459. m_dwAccessPerm ( MD_ACCESS_READ ),
  460. m_dwSslAccessPerm ( 0 ),
  461. m_pAcl ( NULL ),
  462. m_dwAclTag ( 0 ),
  463. m_dwVrLevel ( 0 ),
  464. m_dwVrLen ( 0 ),
  465. m_hVrToken ( NULL ),
  466. m_fVrPassThrough ( FALSE ),
  467. m_dwVrError ( 0 ),
  468. m_Signature ( CMD_SIG ),
  469. m_fDoCache ( TRUE )
  470. {
  471. //
  472. // Hmmm, since most of these values aren't getting initialized, if
  473. // somebody went and deleted all the metadata items from the tree, then
  474. // bad things could happen. We should initialize with defaults things
  475. // that might cause us trouble us
  476. //
  477. } // COMMON_METADATA::COMMON_METADATA()
  478. COMMON_METADATA::~COMMON_METADATA(VOID)
  479. {
  480. CheckSignature();
  481. if ( m_IpDnsAccessCheckTag )
  482. {
  483. FreeMdTag( m_IpDnsAccessCheckTag );
  484. m_IpDnsAccessCheckTag = 0;
  485. }
  486. else if ( m_IpDnsAccessCheckPtr != NULL )
  487. {
  488. LocalFree( m_IpDnsAccessCheckPtr );
  489. m_IpDnsAccessCheckPtr = NULL;
  490. }
  491. if ( m_dwAclTag )
  492. {
  493. FreeMdTag( m_dwAclTag );
  494. m_dwAclTag = 0;
  495. }
  496. if ( m_hVrToken )
  497. {
  498. TsDeleteUserToken( m_hVrToken );
  499. m_hVrToken = NULL;
  500. }
  501. } // COMMON_METADATA::~COMMON_METADATA()
  502. VOID
  503. COMMON_METADATA::FreeMdTag(
  504. DWORD dwTag
  505. )
  506. /*++
  507. Routine Description:
  508. Free a metadata object accessed by reference
  509. Arguments:
  510. dwTag - tag of metadata object reference
  511. Returns:
  512. Nothing
  513. --*/
  514. {
  515. MB mb( (IMDCOM*) m_pInstance->m_Service->QueryMDObject() );
  516. CheckSignature();
  517. mb.ReleaseReferenceData( dwTag );
  518. }
  519. //
  520. // Private constants.
  521. //
  522. #define DEFAULT_MD_RECORDS 40
  523. #define DEFAULT_RECORD_SIZE 50
  524. # define DEF_MD_REC_SIZE ((1 + DEFAULT_MD_RECORDS) * \
  525. (sizeof(METADATA_RECORD) + DEFAULT_RECORD_SIZE))
  526. #define RMD_ASSERT(x) if (!(x)) {DBG_ASSERT(FALSE); return FALSE; }
  527. BOOL
  528. COMMON_METADATA::ReadMetaData(
  529. PIIS_SERVER_INSTANCE pInstance,
  530. MB * pmb,
  531. LPSTR pszURL,
  532. PMETADATA_ERROR_INFO pMDError
  533. )
  534. {
  535. METADATA_GETALL_INTERNAL_RECORD *pMDRecord;
  536. DWORD dwNumMDRecords;
  537. BYTE tmpBuffer[ DEF_MD_REC_SIZE];
  538. BUFFER TempBuff( tmpBuffer, DEF_MD_REC_SIZE);
  539. DWORD i;
  540. DWORD dwDataSetNumber;
  541. INT ch;
  542. LPSTR pszInVr;
  543. LPSTR pszMinInVr;
  544. DWORD dwNeed;
  545. DWORD dwL;
  546. DWORD dwVRLen;
  547. LPSTR pszVrUserName;
  548. LPSTR pszVrPassword;
  549. BYTE tmpPrivateBuffer[ 20 ];
  550. BUFFER PrivateBuffer( tmpPrivateBuffer, 20 );
  551. DWORD dwPrivateBufferUsed;
  552. CheckSignature();
  553. TsValidateMetaCache();
  554. m_pInstance = pInstance;
  555. DBG_ASSERT( TempBuff.QuerySize() >=
  556. (DEFAULT_MD_RECORDS *
  557. (sizeof(METADATA_RECORD) + DEFAULT_RECORD_SIZE))
  558. );
  559. if ( !pmb->Open( pInstance->QueryMDVRPath() ))
  560. {
  561. return FALSE;
  562. }
  563. if ( !pmb->GetAll( pszURL,
  564. METADATA_INHERIT | METADATA_PARTIAL_PATH | METADATA_REFERENCE,
  565. IIS_MD_UT_FILE,
  566. &TempBuff,
  567. &dwNumMDRecords,
  568. &dwDataSetNumber ))
  569. {
  570. return FALSE;
  571. }
  572. pMDRecord = (METADATA_GETALL_INTERNAL_RECORD *)TempBuff.QueryPtr();
  573. i = 0;
  574. //
  575. // Check from where we got VR_PATH
  576. //
  577. pszMinInVr = pszURL ;
  578. if ( *pszURL )
  579. {
  580. for ( pszInVr = pszMinInVr + strlen(pszMinInVr) ;; )
  581. {
  582. ch = *pszInVr;
  583. *pszInVr = '\0';
  584. dwNeed = 0;
  585. if ( !pmb->GetString( pszURL, MD_VR_PATH, IIS_MD_UT_FILE, NULL, &dwNeed, 0 ) &&
  586. GetLastError() == ERROR_INSUFFICIENT_BUFFER )
  587. {
  588. *pszInVr = (CHAR)ch;
  589. // VR_PATH was defined at this level !
  590. break;
  591. }
  592. *pszInVr = (CHAR)ch;
  593. if ( ch )
  594. {
  595. if ( pszInVr > pszMinInVr )
  596. {
  597. pszInVr = CharPrev( pszMinInVr, pszInVr );
  598. }
  599. else
  600. {
  601. //
  602. // VR_PATH was defined above Instance vroot
  603. // or not at all. If defined above, then the reference
  604. // path is empty, so we can claim we found it.
  605. // if not defined, then this will be catch later.
  606. //
  607. break;
  608. }
  609. }
  610. // scan for previous delimiter
  611. while ( *pszInVr != '/' && *pszInVr != '\\' )
  612. {
  613. if ( pszInVr > pszMinInVr )
  614. {
  615. pszInVr = CharPrev( pszMinInVr, pszInVr );
  616. }
  617. else
  618. {
  619. //
  620. // VR_PATH was defined above Instance vroot
  621. // or not at all. If defined above, then the reference
  622. // path is empty, so we can claim we found it.
  623. // if not defined, then this will be catch later.
  624. //
  625. break;
  626. }
  627. }
  628. }
  629. dwVRLen = DIFF(pszInVr - pszMinInVr);
  630. }
  631. else
  632. {
  633. dwVRLen = 0;
  634. pszInVr = pszMinInVr;
  635. }
  636. // Close this now to minimize lock contention.
  637. DBG_REQUIRE(pmb->Close());
  638. for ( dwL = 0 ; pszMinInVr < pszInVr - 1 ; pszMinInVr = CharNext(pszMinInVr) )
  639. {
  640. if ( *pszMinInVr == '/' || *pszMinInVr == '\\' )
  641. {
  642. ++dwL;
  643. }
  644. }
  645. // Now walk through the array of returned metadata objects and format
  646. // each one into our predigested form.
  647. SetVrLevelAndLen( dwL, dwVRLen );
  648. pszVrPassword = NULL;
  649. pszVrUserName = NULL;
  650. dwPrivateBufferUsed = 0;
  651. pMDError->IsValid = FALSE;
  652. for ( ; i < dwNumMDRecords; i++, pMDRecord++ ) {
  653. PVOID pDataPointer;
  654. CHAR *pszMimePtr;
  655. CHAR *pszTemp;
  656. DWORD dwTemp;
  657. pDataPointer = (PVOID) ((PCHAR)TempBuff.QueryPtr() +
  658. pMDRecord->dwMDDataOffset);
  659. switch ( pMDRecord->dwMDIdentifier ) {
  660. case MD_IP_SEC:
  661. RMD_ASSERT( pMDRecord->dwMDDataType == BINARY_METADATA );
  662. if ( pMDRecord->dwMDDataLen )
  663. {
  664. if ( !SetIpDnsAccessCheck( pMDRecord->dwMDDataTag ?
  665. pMDRecord->pbMDData :
  666. pDataPointer,
  667. pMDRecord->dwMDDataLen,
  668. pMDRecord->dwMDDataTag ) )
  669. {
  670. goto FreeRefs;
  671. }
  672. }
  673. break;
  674. case MD_ACCESS_PERM:
  675. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  676. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  677. // 64bit alignment fix
  678. SetAccessPerms(*(UNALIGNED DWORD*) pDataPointer);
  679. break;
  680. case MD_SSL_ACCESS_PERM:
  681. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  682. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  683. // 64bit alignment fix
  684. SetSslAccessPerms( *((UNALIGNED DWORD *) pDataPointer) );
  685. break;
  686. case MD_DONT_LOG:
  687. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  688. DBG_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  689. // 64bit alignment fix
  690. SetDontLogFlag( *((UNALIGNED DWORD *) pDataPointer ));
  691. break;
  692. case MD_VR_PATH:
  693. RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
  694. if (!QueryVrPath()->Copy((const CHAR *)pDataPointer))
  695. {
  696. goto FreeRefs;
  697. }
  698. break;
  699. case MD_APP_ROOT:
  700. RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
  701. if (!QueryAppPath()->Copy((const CHAR *)pDataPointer))
  702. {
  703. goto FreeRefs;
  704. }
  705. break;
  706. case MD_VR_USERNAME:
  707. RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
  708. pszVrUserName = (LPSTR)pDataPointer;
  709. break;
  710. case MD_VR_PASSWORD:
  711. RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
  712. pszVrPassword = (LPSTR)pDataPointer;
  713. break;
  714. case MD_VR_PASSTHROUGH:
  715. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  716. // 64bit alignment fix
  717. SetVrPassThrough( !!*((UNALIGNED DWORD *) pDataPointer) );
  718. break;
  719. case MD_VR_ACL:
  720. DBG_ASSERT( pMDRecord->dwMDDataTag );
  721. RMD_ASSERT( pMDRecord->dwMDDataType == BINARY_METADATA );
  722. if ( pMDRecord->dwMDDataTag )
  723. {
  724. SetAcl( pMDRecord->pbMDData,
  725. pMDRecord->dwMDDataLen,
  726. pMDRecord->dwMDDataTag );
  727. }
  728. break;
  729. case MD_VR_NO_CACHE:
  730. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  731. // 64bit alignment fix
  732. SetDoCache( !*(UNALIGNED DWORD *) pDataPointer );
  733. break;
  734. default:
  735. if ( !HandlePrivateProperty( pszURL, pInstance, pMDRecord, pDataPointer, &PrivateBuffer, &dwPrivateBufferUsed, pMDError ) )
  736. {
  737. goto FreeRefs;
  738. }
  739. CheckSignature();
  740. break;
  741. }
  742. }
  743. if (!FinishPrivateProperties(&PrivateBuffer, dwPrivateBufferUsed, TRUE))
  744. {
  745. goto FreeRefs;
  746. }
  747. if ( QueryVrPath()->IsEmpty() &&
  748. !(QueryAccessPerms() & VROOT_MASK_NO_PHYSICAL_DIR) )
  749. {
  750. DBGPRINTF(( DBG_CONTEXT,
  751. "[ReadMetaData] Virtual Dir Path mapping not found\n" ));
  752. SetLastError( ERROR_FILE_NOT_FOUND );
  753. return FALSE;
  754. }
  755. //
  756. // If this is an UNC share, logon using associated credentials
  757. // keep a reference to this access token in the cache
  758. //
  759. if ( QueryVrPath()->QueryStr()[0] == '\\' &&
  760. QueryVrPath()->QueryStr()[1] == '\\' )
  761. {
  762. if ( pszVrUserName != NULL && pszVrPassword != NULL &&
  763. pszVrUserName[0] )
  764. {
  765. if ( !SetVrUserNameAndPassword( pInstance, pszVrUserName, pszVrPassword ) )
  766. {
  767. return FALSE;
  768. }
  769. }
  770. }
  771. CheckSignature();
  772. TsValidateMetaCache();
  773. return TRUE;
  774. FreeRefs:
  775. FinishPrivateProperties(&PrivateBuffer, dwPrivateBufferUsed, FALSE);
  776. CheckSignature();
  777. TsValidateMetaCache();
  778. for ( ; i < dwNumMDRecords; i++, pMDRecord++ )
  779. {
  780. if ( pMDRecord->dwMDDataTag )
  781. {
  782. pmb->ReleaseReferenceData( pMDRecord->dwMDDataTag );
  783. }
  784. }
  785. return FALSE;
  786. }
  787. BOOL
  788. COMMON_METADATA::SetVrUserNameAndPassword(
  789. PIIS_SERVER_INSTANCE pInstance,
  790. LPSTR pszUserName,
  791. LPSTR pszPassword
  792. )
  793. /*++
  794. Description:
  795. Set the account used to access the virtual root
  796. associated with this metadata
  797. Arguments:
  798. pInstance - current instance
  799. pszUserName - User name
  800. pszPassword - password
  801. Returns:
  802. TRUE if success, otherwise FALSE
  803. --*/
  804. {
  805. LARGE_INTEGER liPwdExpiry;
  806. BOOL fHaveExp;
  807. BOOL fAsGuest;
  808. BOOL fAsAnonymous;
  809. TCP_AUTHENT_INFO TAI;
  810. CheckSignature();
  811. TAI.fDontUseAnonSubAuth = TRUE;
  812. m_hVrToken = TsLogonUser( pszUserName,
  813. pszPassword,
  814. &fAsGuest,
  815. &fAsAnonymous,
  816. pInstance,
  817. &TAI,
  818. NULL,
  819. &liPwdExpiry,
  820. &fHaveExp );
  821. //
  822. // If fail to logo, we remember the error and return SUCCESS
  823. // Caller will have to check metadata after creating it to check
  824. // the error code. Necessary because metadata needs to be set in HTTP_REQUEST
  825. // to send back proper auth status even if virtual root init failed.
  826. //
  827. if ( !m_hVrToken )
  828. {
  829. m_dwVrError = GetLastError();
  830. }
  831. return TRUE;
  832. }
  833. BOOL
  834. COMMON_METADATA::BuildApplPhysicalPath(
  835. MB * pmb,
  836. STR * pstrApplPhysicalPath
  837. ) const
  838. /*++
  839. Description:
  840. This function builds the physical path for the ApplPath of the current
  841. METADATA object. The ApplPath is a metbase path of the form
  842. /LM/W3Svc/<instance>/app-root-path
  843. This function uses the VR_PATH & portion of the APPL_PATH to
  844. construct the appropriate physical path.
  845. Arguments:
  846. pmb - pointer to MB object (Metabase pointer)
  847. pstrApplPhysicalPath - pointer to STR object that will contain
  848. the physical path on return.
  849. Returns:
  850. TRUE on success and FALSE if there are errors.
  851. Use GetLastError() to get the appropriate error code.
  852. --*/
  853. {
  854. BOOL fRet;
  855. INT cOffSet = 0;
  856. CheckSignature();
  857. DBG_ASSERT(NULL != pmb && NULL != pstrApplPhysicalPath);
  858. // m_strAppPath is in the format of /LM/W3SVC/X/ROOT/AppRoot.....
  859. // Now, the next code segment split this format into
  860. // strInstanceMDPath = /LM/W3SVC/X/ROOT/
  861. // strVrPath = /AppRoot....
  862. STR strInstanceMDPath = STR(m_strAppPath);
  863. LPSTR pszVrPath = strInstanceMDPath.QueryStr();
  864. INT VrLevel = 0;
  865. while(*pszVrPath != NULL)
  866. {
  867. if ('/' == *pszVrPath)
  868. {
  869. VrLevel++;
  870. if (5 == VrLevel)
  871. {
  872. break;
  873. }
  874. }
  875. pszVrPath++;
  876. }
  877. STR strVrPath = STR(pszVrPath);
  878. // Case: /LM/W3SVC/1/ROOT
  879. if (4 == VrLevel)
  880. {
  881. strVrPath.Append('/');
  882. // OffSet needs to minus 1 because strInstanceMDPath does not have
  883. // ending '/'
  884. cOffSet = strInstanceMDPath.QueryCCH()-1;
  885. }
  886. else if ( 5 == VrLevel)
  887. {
  888. // Make a copy of VRPath
  889. // Caculate the cOffSet of /LM/W3SVC/X/Root/
  890. // Set the strInstanceMDPath
  891. cOffSet = DIFF(pszVrPath-strInstanceMDPath.QueryStr());
  892. strInstanceMDPath.SetLen(cOffSet);
  893. }
  894. else
  895. {
  896. // Can not resolve Application Physical Path.
  897. DBG_ASSERT(FALSE);
  898. pstrApplPhysicalPath->SetLen(0);
  899. return FALSE;
  900. }
  901. // Open the metabase key from /LM/W3SVC/X/ROOT/
  902. fRet = pmb->Open(strInstanceMDPath.QueryStr());
  903. if (TRUE == fRet)
  904. {
  905. // Get VR Path first. (Note, this is not the final VRpath).
  906. fRet = pmb->GetStr(strVrPath.QueryStr(),
  907. MD_VR_PATH,
  908. IIS_MD_UT_FILE,
  909. pstrApplPhysicalPath,
  910. METADATA_INHERIT,
  911. NULL);
  912. if (TRUE == fRet)
  913. {
  914. BOOL fFound = FALSE;
  915. DWORD dwBufferSizeNeeded;
  916. LPSTR pszTempMDPath = strVrPath.QueryStr();
  917. LPSTR pszTemp = pszTempMDPath + strVrPath.QueryCCH() - 1;
  918. BOOL fNoMoreVR = FALSE; // used to break out infinite loop if there is no VR_PATH
  919. // defined at /LM/W3SVC/X/ROOT
  920. // Find where we get the VR path
  921. do
  922. {
  923. dwBufferSizeNeeded = 0;
  924. if ( !pmb->GetString(strVrPath.QueryStr(),
  925. MD_VR_PATH,
  926. IIS_MD_UT_FILE,
  927. NULL,
  928. &dwBufferSizeNeeded,
  929. 0
  930. )
  931. && GetLastError() == ERROR_INSUFFICIENT_BUFFER )
  932. {
  933. fFound = TRUE;
  934. // cOffSet is the strlen(closest Metabase path that defined
  935. // a MDVrPath property).
  936. // For Example:
  937. // /LM/W3SVC/1/ROOT/VR1/VR2/VR3
  938. // VR2 defines MDVrPath. cOffSet is strlen(/VR2)
  939. // so, based on cOffSet, we can find VR3 later.
  940. cOffSet += strVrPath.QueryCCH();
  941. }
  942. else
  943. {
  944. // '/' is not a DBCS trailing byte.
  945. // going backwords in /VR1/VR2/VR3/.../VRn and search '/'
  946. // and shrink one VR Level
  947. pszTemp = strrchr(pszTempMDPath, '/');
  948. strVrPath.SetLen(DIFF(pszTemp-pszTempMDPath));
  949. // if this is TRUE, then, strVrPath is empty now, and there is no VR_PATH
  950. // defined.
  951. if (fNoMoreVR)
  952. {
  953. break;
  954. }
  955. if (0 == strVrPath.QueryCCH())
  956. {
  957. fNoMoreVR = TRUE;
  958. }
  959. }
  960. } while (!fFound);
  961. pmb->Close();
  962. if (!fFound && 0 == strVrPath.QueryCCH())
  963. {
  964. DBG_ASSERT(FALSE);
  965. pstrApplPhysicalPath->SetLen(0);
  966. return FALSE;
  967. }
  968. pstrApplPhysicalPath->Append(m_strAppPath.QueryStr()+cOffSet);
  969. if (pstrApplPhysicalPath->QueryCCH())
  970. {
  971. CHAR ch;
  972. ch = *CharPrev(pstrApplPhysicalPath->QueryStr(),
  973. pstrApplPhysicalPath->QueryStr()+pstrApplPhysicalPath->QueryCCH());
  974. if (ch != '\\' && ch != '/')
  975. {
  976. pstrApplPhysicalPath->Append("\\");
  977. }
  978. }
  979. FlipSlashes(pstrApplPhysicalPath->QueryStr());
  980. }
  981. else
  982. {
  983. pmb->Close();
  984. }
  985. }
  986. return fRet;
  987. } // COMMON_METADATA::BuildApplPhysicalPath()
  988. BOOL
  989. COMMON_METADATA::BuildPhysicalPath(
  990. LPSTR pszURL,
  991. STR * pstrPhysicalPath
  992. )
  993. {
  994. return BuildPhysicalPathWithAltRoot( pszURL, pstrPhysicalPath, NULL );
  995. }
  996. BOOL
  997. COMMON_METADATA::BuildPhysicalPathWithAltRoot(
  998. LPSTR pszURL,
  999. STR * pstrPhysicalPath,
  1000. PCSTR pstrAltRoot
  1001. )
  1002. /*++
  1003. Description:
  1004. Construct a physical path of the following components:
  1005. - the virtual root mapping
  1006. - an alternate root (if provided)
  1007. - the significant part of the URI
  1008. Arguments:
  1009. pszURL - The URL to be converted
  1010. pstrPhysicalPath - the resulting physical path
  1011. pstrAltRoot - the alternat root
  1012. Returns:
  1013. TRUE if success, otherwise FALSE
  1014. --*/
  1015. {
  1016. LPSTR pszInVr;
  1017. DWORD dwL;
  1018. INT ch;
  1019. CheckSignature();
  1020. TsValidateMetaCache();
  1021. //
  1022. // Build physical path from VR_PATH & portion of URI not used to define VR_PATH
  1023. //
  1024. //
  1025. // skip the URI components used to locate the virtual root
  1026. //
  1027. pszInVr = pszURL ;
  1028. dwL = QueryVrLevel();
  1029. while ( dwL-- )
  1030. {
  1031. if ( *pszInVr )
  1032. {
  1033. DBG_ASSERT( *pszInVr == '/' || *pszInVr == '\\' );
  1034. ++pszInVr;
  1035. while ( (ch = *pszInVr) && ch != '/' && ch !='\\' )
  1036. {
  1037. pszInVr = CharNext( pszInVr );
  1038. }
  1039. }
  1040. }
  1041. DBG_ASSERT( dwL == (DWORD)-1 );
  1042. if ( !pstrPhysicalPath->Copy( m_strVrPath ) )
  1043. {
  1044. return FALSE;
  1045. }
  1046. //
  1047. // Add the alternate root
  1048. //
  1049. if ( pstrAltRoot )
  1050. {
  1051. if ( pstrPhysicalPath->QueryCCH() )
  1052. {
  1053. //
  1054. // ensure there is one and only one separator
  1055. //
  1056. ch = *CharPrev(pstrPhysicalPath->QueryStr(), pstrPhysicalPath->QueryStr() +
  1057. pstrPhysicalPath->QueryCCH());
  1058. if ( (ch != '/') && (ch != '\\') &&
  1059. (*pstrAltRoot != '/') && (*pstrAltRoot != '\\') )
  1060. {
  1061. if ( !pstrPhysicalPath->Append( "\\" ) )
  1062. {
  1063. return FALSE;
  1064. }
  1065. } else if ( (ch == '/' || ch == '\\') &&
  1066. (*pstrAltRoot == '/' || *pstrAltRoot == '\\') )
  1067. {
  1068. ++pstrAltRoot;
  1069. }
  1070. }
  1071. if ( !pstrPhysicalPath->Append( pstrAltRoot ) )
  1072. {
  1073. return FALSE;
  1074. }
  1075. }
  1076. //
  1077. // Add a path delimiter char between virtual root mount point & significant part of URI
  1078. //
  1079. if ( pstrPhysicalPath->QueryCCH() )
  1080. {
  1081. ch = *CharPrev(pstrPhysicalPath->QueryStr(), pstrPhysicalPath->QueryStr() +
  1082. pstrPhysicalPath->QueryCCH());
  1083. if ( (ch == '/' || ch == '\\') && *pszInVr )
  1084. {
  1085. ++pszInVr;
  1086. }
  1087. }
  1088. if ( !pstrPhysicalPath->Append( pszInVr ) )
  1089. {
  1090. return FALSE;
  1091. }
  1092. //
  1093. // insure physical path last char uses standard directory delimiter
  1094. //
  1095. FlipSlashes( pstrPhysicalPath->QueryStr() );
  1096. CheckSignature();
  1097. TsValidateMetaCache();
  1098. return TRUE;
  1099. }