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.

1156 lines
30 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name :
  4. urlinfo.cxx
  5. Abstract:
  6. Gets metadata for URL
  7. Author:
  8. Bilal Alam (balam) 8-Jan-2000
  9. Environment:
  10. Win32 - User Mode
  11. Project:
  12. ULW3.DLL
  13. --*/
  14. #include "precomp.hxx"
  15. #include <stringau.hxx>
  16. //
  17. // Utility to guard against ~ inconsistency
  18. //
  19. DWORD
  20. CheckIfShortFileName(
  21. IN WCHAR * pszPath,
  22. IN HANDLE hImpersonation,
  23. OUT BOOL * pfShort
  24. );
  25. W3_STATE_URLINFO::W3_STATE_URLINFO()
  26. {
  27. _hr = URL_CONTEXT::Initialize();
  28. }
  29. W3_STATE_URLINFO::~W3_STATE_URLINFO()
  30. {
  31. URL_CONTEXT::Terminate();
  32. }
  33. CONTEXT_STATUS
  34. W3_STATE_URLINFO::OnCompletion(
  35. W3_MAIN_CONTEXT * pMainContext,
  36. DWORD cbCompletion,
  37. DWORD dwCompletionStatus
  38. )
  39. /*++
  40. Routine Description:
  41. Handle URLINFO completions. CheckAccess() is called in DoWork() and this
  42. call is asynchronous.
  43. Arguments:
  44. pMainContext - W3_MAIN_CONTEXT representing execution of state machine
  45. cbCompletion - Number of bytes in an async completion
  46. dwCompletionStatus - Error status of a completion
  47. Return Value:
  48. CONTEXT_STATUS_CONTINUE - if we should continue in state machine
  49. else stop executing the machine and free up the current thread
  50. --*/
  51. {
  52. CONTEXT_STATUS contextStatus;
  53. BOOL fAccessAllowed;
  54. contextStatus = pMainContext->CheckAccess( TRUE, // this is a completion
  55. cbCompletion,
  56. dwCompletionStatus,
  57. &fAccessAllowed );
  58. if ( contextStatus == CONTEXT_STATUS_PENDING )
  59. {
  60. return CONTEXT_STATUS_PENDING;
  61. }
  62. //
  63. // If access is not allowed, then just finish state machine (
  64. // response has already been sent)
  65. //
  66. if ( !fAccessAllowed )
  67. {
  68. pMainContext->SetFinishedResponse();
  69. }
  70. return CONTEXT_STATUS_CONTINUE;
  71. }
  72. CONTEXT_STATUS
  73. W3_STATE_URLINFO::DoWork(
  74. W3_MAIN_CONTEXT * pMainContext,
  75. DWORD cbCompletion,
  76. DWORD dwCompletionStatus
  77. )
  78. /*++
  79. Routine Description:
  80. Handle retrieving the metadata for this request
  81. Arguments:
  82. pMainContext - W3_MAIN_CONTEXT representing execution of state machine
  83. cbCompletion - Number of bytes in an async completion
  84. dwCompletionStatus - Error status of a completion
  85. Return Value:
  86. CONTEXT_STATUS_CONTINUE - if we should continue in state machine
  87. else stop executing the machine and free up the current thread
  88. --*/
  89. {
  90. URL_CONTEXT * pUrlContext = NULL;
  91. BOOL fFinished = FALSE;
  92. HRESULT hr = NO_ERROR;
  93. W3_METADATA * pMetaData = NULL;
  94. CONTEXT_STATUS contextStatus = CONTEXT_STATUS_CONTINUE;
  95. W3_REQUEST * pHttpRequest = pMainContext->QueryRequest();
  96. W3_RESPONSE * pResponse = pMainContext->QueryResponse();
  97. BOOL fAccessAllowed = FALSE;
  98. DBG_ASSERT( pHttpRequest != NULL );
  99. DBG_ASSERT( pResponse != NULL );
  100. //
  101. // Set the context state. Note that passing TRUE as the final
  102. // argument pushes the URL_CONTEXT into the main context. As
  103. // a result, errors in this function should not attempt to
  104. // clean it up.
  105. //
  106. hr = URL_CONTEXT::RetrieveUrlContext( pMainContext,
  107. pMainContext->QueryRequest(),
  108. &pUrlContext,
  109. &fFinished,
  110. TRUE );
  111. if ( FAILED( hr ) )
  112. {
  113. goto Failure;
  114. }
  115. DBG_ASSERT( fFinished || ( pUrlContext != NULL ) );
  116. //
  117. // From now on, errors in this function should not cleanup the URL
  118. // context since it is owned by the main context
  119. //
  120. pUrlContext = NULL;
  121. //
  122. // If filter wants out, leave
  123. //
  124. if ( fFinished )
  125. {
  126. pMainContext->SetDone();
  127. return CONTEXT_STATUS_CONTINUE;
  128. }
  129. //
  130. // Check access now. That means checking for IP/SSL/Certs. We will
  131. // avoid the authentication type check since the others (IP/SSL/Certs)
  132. // take priority.
  133. //
  134. contextStatus = pMainContext->CheckAccess( FALSE, // not a completion
  135. 0, // cbCompletion,
  136. NO_ERROR,
  137. &fAccessAllowed );
  138. if ( contextStatus == CONTEXT_STATUS_PENDING )
  139. {
  140. return CONTEXT_STATUS_PENDING;
  141. }
  142. //
  143. // If we don't have access, then the appropriate error response was
  144. // already sent. Just finish the state machine
  145. //
  146. if ( !fAccessAllowed )
  147. {
  148. pMainContext->SetFinishedResponse();
  149. }
  150. return CONTEXT_STATUS_CONTINUE;
  151. Failure:
  152. if ( pUrlContext != NULL )
  153. {
  154. delete pUrlContext;
  155. }
  156. if ( !pMainContext->QueryResponseSent() )
  157. {
  158. if ( hr == HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) )
  159. {
  160. // For the non-8dot3 case
  161. pMainContext->QueryResponse()->SetStatus( HttpStatusNotFound );
  162. }
  163. else if ( hr == HRESULT_FROM_WIN32( ERROR_INVALID_DATA ) )
  164. {
  165. pMainContext->QueryResponse()->SetStatus( HttpStatusServerError,
  166. Http500BadMetadata );
  167. }
  168. else if ( hr == HRESULT_FROM_WIN32( ERROR_LOGON_FAILURE ) )
  169. {
  170. pMainContext->QueryResponse()->SetStatus( HttpStatusServerError,
  171. Http500UNCAccess );
  172. }
  173. else
  174. {
  175. pMainContext->QueryResponse()->SetStatus( HttpStatusServerError );
  176. }
  177. }
  178. pMainContext->SetFinishedResponse();
  179. pMainContext->SetErrorStatus( hr );
  180. return CONTEXT_STATUS_CONTINUE;
  181. }
  182. //static
  183. HRESULT
  184. URL_CONTEXT::RetrieveUrlContext(
  185. W3_CONTEXT * pW3Context,
  186. W3_REQUEST * pRequest,
  187. OUT URL_CONTEXT ** ppUrlContext,
  188. BOOL * pfFinished,
  189. BOOL fSetInW3Context
  190. )
  191. /*++
  192. Routine Description:
  193. For a given request, get a URL_CONTEXT which represents the
  194. metadata and URI-specific info for that request
  195. Arguments:
  196. pW3Context - W3_CONTEXT for the request
  197. pRequest - New request to lookup
  198. ppUrlContext - Set to point to new URL_CONTEXT
  199. pfFinished - Set to true if isapi filter said we're finished
  200. fSetInW3Context - OPTIONAL default FALSE
  201. Return Value:
  202. HRESULT
  203. --*/
  204. {
  205. STACK_STRU( strUrl, MAX_PATH );
  206. W3_URL_INFO * pUrlInfo = NULL;
  207. W3_METADATA * pMetaData = NULL;
  208. TOKEN_CACHE_ENTRY * pTokenEntry = NULL;
  209. URL_CONTEXT * pUrlContext = NULL;
  210. HRESULT hr = NO_ERROR;
  211. HANDLE hToken = NULL;
  212. W3_TRACE_LOG * pTraceLog;
  213. if ( pW3Context == NULL ||
  214. pRequest == NULL ||
  215. ppUrlContext == NULL ||
  216. pfFinished == NULL )
  217. {
  218. DBG_ASSERT( FALSE );
  219. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  220. }
  221. *ppUrlContext = NULL;
  222. hr = pRequest->GetUrl( &strUrl );
  223. if ( FAILED( hr ) )
  224. {
  225. goto Failure;
  226. }
  227. //
  228. // Lookup the URI info for this request
  229. //
  230. DBG_ASSERT( g_pW3Server->QueryUrlInfoCache() != NULL );
  231. hr = g_pW3Server->QueryUrlInfoCache()->GetUrlInfo(
  232. pW3Context,
  233. strUrl,
  234. &pUrlInfo );
  235. if ( FAILED( hr ) )
  236. {
  237. goto Failure;
  238. }
  239. //
  240. // Now, create a URL_CONTEXT object which contains the W3_URL_INFO and
  241. // W3_METADATA pointers as well as state information for use on cleanup
  242. //
  243. DBG_ASSERT( pUrlInfo != NULL );
  244. pMetaData = (W3_METADATA*) pUrlInfo->QueryMetaData();
  245. DBG_ASSERT( pMetaData != NULL );
  246. pUrlContext = new (pW3Context) URL_CONTEXT( pMetaData, pUrlInfo );
  247. if ( pUrlContext == NULL )
  248. {
  249. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  250. goto Failure;
  251. }
  252. else if( fSetInW3Context )
  253. {
  254. //
  255. // If specified, set the UrlContext in pW3Context. This is necessary
  256. // since the below filter notification depends on having this context
  257. // for APPL_MD_PATH and APPL_PHYSICAL_PATH. Once set the context owns
  258. // cleaning it up.
  259. //
  260. ((W3_MAIN_CONTEXT*)pW3Context)->SetUrlContext( pUrlContext );
  261. }
  262. //
  263. // Now notify URL_MAP filters
  264. //
  265. if ( pW3Context->IsNotificationNeeded( SF_NOTIFY_URL_MAP ) )
  266. {
  267. STACK_STRA( straPhys, MAX_PATH + 1 );
  268. STACK_STRA( straSavePhys, MAX_PATH + 1 );
  269. STACK_STRA( straUrl, MAX_PATH + 1 );
  270. STACK_STRA( straScriptMap, MAX_PATH + 1 );
  271. BOOL fRet;
  272. HTTP_FILTER_URL_MAP_EX filterMap;
  273. STACK_STRU( strPhysicalPath, MAX_PATH );
  274. hr = straPhys.CopyW( pUrlInfo->QueryPhysicalPath()->QueryStr() );
  275. if ( FAILED( hr ) )
  276. {
  277. goto Failure;
  278. }
  279. //
  280. // Save a copy for comparison after filter notification
  281. //
  282. hr = straSavePhys.Copy( straPhys );
  283. if ( FAILED( hr ) )
  284. {
  285. goto Failure;
  286. }
  287. hr = straUrl.CopyW( strUrl.QueryStr() );
  288. if ( FAILED( hr ) )
  289. {
  290. goto Failure;
  291. }
  292. filterMap.pszURL = straUrl.QueryStr();
  293. filterMap.pszPhysicalPath = straPhys.QueryStr();
  294. filterMap.cbPathBuff = straPhys.QuerySize();
  295. filterMap.dwFlags = pMetaData->QueryAccessPerms();
  296. filterMap.cchMatchingPath = pMetaData->QueryCBMatchingPathA();
  297. filterMap.cchMatchingURL = pMetaData->QueryCBMatchingUrlA();
  298. filterMap.pszScriptMapEntry = NULL;
  299. if ( pUrlInfo->QueryScriptMapEntry() )
  300. {
  301. hr = straScriptMap.CopyW( pUrlInfo->QueryScriptMapEntry()->QueryExecutable()->QueryStr() );
  302. if ( FAILED( hr ) )
  303. {
  304. goto Failure;
  305. }
  306. filterMap.pszScriptMapEntry = straScriptMap.QueryStr();
  307. }
  308. fRet = pW3Context->NotifyFilters( SF_NOTIFY_URL_MAP,
  309. &filterMap,
  310. pfFinished );
  311. if ( !fRet )
  312. {
  313. W3_MAIN_CONTEXT * pMainContext = pW3Context->QueryMainContext();
  314. DWORD dwError = GetLastError();
  315. hr = HRESULT_FROM_WIN32( dwError );
  316. pMainContext->SetErrorStatus( hr );
  317. if ( dwError == ERROR_ACCESS_DENIED )
  318. {
  319. pMainContext->QueryResponse()->SetStatus( HttpStatusUnauthorized,
  320. Http401Filter );
  321. }
  322. else if ( dwError == ERROR_FILE_NOT_FOUND ||
  323. dwError == ERROR_PATH_NOT_FOUND )
  324. {
  325. pMainContext->QueryResponse()->SetStatus( HttpStatusNotFound );
  326. }
  327. else
  328. {
  329. pMainContext->QueryResponse()->SetStatus( HttpStatusServerError );
  330. }
  331. goto Failure;
  332. }
  333. //
  334. // If the filter is done, then we're done
  335. //
  336. if ( *pfFinished )
  337. {
  338. hr = NO_ERROR;
  339. goto Failure;
  340. }
  341. //
  342. // If the physical path was changed, remember it here
  343. //
  344. if ( strcmp( straSavePhys.QueryStr(),
  345. filterMap.pszPhysicalPath ) != 0 )
  346. {
  347. hr = strPhysicalPath.CopyA( (CHAR*) filterMap.pszPhysicalPath );
  348. if ( FAILED( hr ) )
  349. {
  350. goto Failure;
  351. }
  352. hr = pUrlContext->SetPhysicalPath( strPhysicalPath );
  353. if ( FAILED( hr ) )
  354. {
  355. goto Failure;
  356. }
  357. }
  358. }
  359. //
  360. // We don't accept short filename since they can break metabase
  361. // equivalency
  362. //
  363. if ( wcschr( pUrlContext->QueryPhysicalPath()->QueryStr(),
  364. L'~' ) )
  365. {
  366. BOOL fShort = FALSE;
  367. hr = pMetaData->GetAndRefVrAccessToken( &pTokenEntry );
  368. if( FAILED( hr ) )
  369. {
  370. goto Failure;
  371. }
  372. if ( pTokenEntry != NULL )
  373. {
  374. hToken = pTokenEntry->QueryImpersonationToken();
  375. }
  376. else
  377. {
  378. hToken = NULL;
  379. }
  380. DWORD dwError = CheckIfShortFileName(
  381. pUrlContext->QueryPhysicalPath()->QueryStr(),
  382. hToken,
  383. &fShort );
  384. if ( dwError != ERROR_SUCCESS )
  385. {
  386. hr = HRESULT_FROM_WIN32( dwError );
  387. goto Failure;
  388. }
  389. if ( fShort )
  390. {
  391. hr = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  392. goto Failure;
  393. }
  394. }
  395. //
  396. // Check whether the UNC user was valid. If not, fail
  397. //
  398. if ( pMetaData->QueryUNCUserInvalid() )
  399. {
  400. hr = HRESULT_FROM_WIN32( ERROR_LOGON_FAILURE );
  401. goto Failure;
  402. }
  403. pTraceLog = pW3Context->QueryMainContext()->QueryTraceLog();
  404. if ( pTraceLog != NULL )
  405. {
  406. pTraceLog->Trace( L"%I64x: Successfully metadata for URL '%ws'\n",
  407. pRequest->QueryRequestId(),
  408. strUrl.QueryStr() );
  409. }
  410. *ppUrlContext = pUrlContext;
  411. if( pTokenEntry != NULL )
  412. {
  413. pTokenEntry->DereferenceCacheEntry();
  414. pTokenEntry = NULL;
  415. }
  416. return S_OK;
  417. Failure:
  418. pTraceLog = pW3Context->QueryMainContext()->QueryTraceLog();
  419. if ( pTraceLog != NULL )
  420. {
  421. pTraceLog->Trace( L"%I64x: Failed to retrieve metadata for URL '%ws'. hr = %08X\n",
  422. pRequest->QueryRequestId(),
  423. strUrl.QueryStr(),
  424. hr );
  425. }
  426. if ( pUrlContext != NULL )
  427. {
  428. if( !fSetInW3Context )
  429. {
  430. delete pUrlContext;
  431. }
  432. }
  433. else
  434. {
  435. if ( pUrlInfo != NULL )
  436. {
  437. pUrlInfo->DereferenceCacheEntry();
  438. }
  439. }
  440. if( pTokenEntry != NULL )
  441. {
  442. pTokenEntry->DereferenceCacheEntry();
  443. pTokenEntry = NULL;
  444. }
  445. return hr;
  446. }
  447. //static
  448. HRESULT
  449. W3_STATE_URLINFO::MapPath(
  450. W3_CONTEXT * pW3Context,
  451. STRU & strUrl,
  452. STRU * pstrPhysicalPath,
  453. BOOL fDoFiltering,
  454. DWORD * pcchDirRoot,
  455. DWORD * pcchVRoot,
  456. DWORD * pcbAnsiDirRoot,
  457. DWORD * pcbAnsiVRoot,
  458. DWORD * pdwMask
  459. )
  460. /*++
  461. Routine Description:
  462. Send a URL/Physical-Path pair to a filter for processing
  463. Arguments:
  464. pW3Context - W3_CONTEXT for the request
  465. strUrl - The URL to be mapped
  466. pstrPhysicalPath - Filled with the mapped path upon return. Set with
  467. metadata physical path on entry
  468. fDoFiltering - Enable filters
  469. pcchDirRoot - Set to point to number of characters in found physical path
  470. pcchVRoot - Set to point to number of characters in found virtual path
  471. pcbAnsiDirRoot - Set to point to number of bytes in found ANSI physical path
  472. pcbAnsiVRoot - Set to point to number of bytes in found ANSI virtual path
  473. pdwMask - Set to point to the access perms mask of virtual path
  474. Return Value:
  475. SUCCEEDED()/FAILED()
  476. --*/
  477. {
  478. HRESULT hr = S_OK;
  479. W3_URL_INFO * pUrlInfo = NULL;
  480. W3_METADATA * pMetaData = NULL;
  481. DBG_ASSERT( pstrPhysicalPath );
  482. //
  483. // Get and keep the metadata and urlinfo for this path
  484. //
  485. DBG_ASSERT( g_pW3Server->QueryUrlInfoCache() != NULL );
  486. hr = g_pW3Server->QueryUrlInfoCache()->GetUrlInfo(
  487. pW3Context,
  488. strUrl,
  489. &pUrlInfo );
  490. if ( FAILED( hr ) )
  491. {
  492. goto Exit;
  493. }
  494. DBG_ASSERT( pUrlInfo != NULL );
  495. //
  496. // Call the filters if we should do so
  497. //
  498. if ( fDoFiltering )
  499. {
  500. hr = FilterMapPath( pW3Context,
  501. pUrlInfo,
  502. pstrPhysicalPath );
  503. }
  504. else
  505. {
  506. hr = pstrPhysicalPath->Copy( *( pUrlInfo->QueryUrlTranslated() ) );
  507. }
  508. if ( FAILED( hr ) )
  509. {
  510. goto Exit;
  511. }
  512. pMetaData = pUrlInfo->QueryMetaData();
  513. DBG_ASSERT( pMetaData != NULL );
  514. //
  515. // Return the other goodies
  516. //
  517. if ( pcchDirRoot != NULL )
  518. {
  519. *pcchDirRoot = pMetaData->QueryVrPath()->QueryCCH();
  520. }
  521. if ( pcchVRoot != NULL )
  522. {
  523. if (strUrl.QueryCCH())
  524. {
  525. *pcchVRoot = pMetaData->QueryVrLen();
  526. }
  527. else
  528. {
  529. *pcchVRoot = 0;
  530. }
  531. }
  532. if ( pcbAnsiDirRoot != NULL )
  533. {
  534. *pcbAnsiDirRoot = pMetaData->QueryCBMatchingPathA();
  535. }
  536. if ( pcbAnsiVRoot != NULL )
  537. {
  538. if ( strUrl.QueryCCH() )
  539. {
  540. *pcbAnsiVRoot = pMetaData->QueryCBMatchingUrlA();
  541. }
  542. else
  543. {
  544. *pcbAnsiVRoot = 0;
  545. }
  546. }
  547. if ( pdwMask != NULL )
  548. {
  549. *pdwMask = pMetaData->QueryAccessPerms();
  550. }
  551. Exit:
  552. if ( pUrlInfo != NULL )
  553. {
  554. pUrlInfo->DereferenceCacheEntry();
  555. pUrlInfo = NULL;
  556. }
  557. return hr;
  558. }
  559. // static
  560. HRESULT
  561. W3_STATE_URLINFO::FilterMapPath(
  562. W3_CONTEXT * pW3Context,
  563. W3_URL_INFO * pUrlInfo,
  564. STRU * pstrPhysicalPath
  565. )
  566. /*++
  567. Routine Description:
  568. Have URL_MAP filters do their thing
  569. Arguments:
  570. pW3Context - Context
  571. pUrlInfo - Contains virtual/physical path
  572. pstrPhysicalPath - Filled with physical path
  573. Return Value:
  574. SUCCEEDED()/FAILED()
  575. --*/
  576. {
  577. HRESULT hr = S_OK;
  578. BOOL fFinished = FALSE;
  579. W3_METADATA * pMetaData = NULL;
  580. STACK_STRU( strFilterPath, MAX_PATH );
  581. STRU * pstrFinalPhysical = NULL;
  582. if ( pW3Context == NULL ||
  583. pUrlInfo == NULL ||
  584. pstrPhysicalPath == NULL )
  585. {
  586. DBG_ASSERT( FALSE );
  587. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  588. }
  589. pMetaData = pUrlInfo->QueryMetaData();
  590. DBG_ASSERT( pMetaData != NULL );
  591. //
  592. // We now have the metadata physical path. Let filters change it here
  593. //
  594. if ( pW3Context->IsNotificationNeeded( SF_NOTIFY_URL_MAP ) )
  595. {
  596. STACK_STRA( straPhys, MAX_PATH + 1 );
  597. STACK_STRA( straSavePhys, MAX_PATH + 1 );
  598. STACK_STRA( straUrl, MAX_PATH + 1 );
  599. STACK_STRA( straScriptMap, MAX_PATH + 1 );
  600. BOOL fRet;
  601. HTTP_FILTER_URL_MAP_EX filterMap;
  602. hr = straPhys.CopyW( pUrlInfo->QueryUrlTranslated()->QueryStr() );
  603. if ( FAILED( hr ) )
  604. {
  605. goto Exit;
  606. }
  607. //
  608. // Save a copy for comparison after filter notification
  609. //
  610. hr = straSavePhys.Copy( straPhys );
  611. if ( FAILED( hr ) )
  612. {
  613. goto Exit;
  614. }
  615. hr = straUrl.CopyW( pUrlInfo->QueryUrl() );
  616. if ( FAILED( hr ) )
  617. {
  618. goto Exit;
  619. }
  620. filterMap.pszURL = straUrl.QueryStr();
  621. filterMap.pszPhysicalPath = straPhys.QueryStr();
  622. filterMap.cbPathBuff = straPhys.QuerySize();
  623. filterMap.dwFlags = pMetaData->QueryAccessPerms();
  624. filterMap.cchMatchingPath = pMetaData->QueryCBMatchingPathA();
  625. filterMap.cchMatchingURL = pMetaData->QueryCBMatchingUrlA();
  626. filterMap.pszScriptMapEntry = NULL;
  627. if ( pUrlInfo->QueryScriptMapEntry() )
  628. {
  629. hr = straScriptMap.CopyW( pUrlInfo->QueryScriptMapEntry()->QueryExecutable()->QueryStr() );
  630. if ( FAILED( hr ) )
  631. {
  632. goto Exit;
  633. }
  634. filterMap.pszScriptMapEntry = straScriptMap.QueryStr();
  635. }
  636. fRet = pW3Context->NotifyFilters( SF_NOTIFY_URL_MAP,
  637. &filterMap,
  638. &fFinished );
  639. //
  640. // Ignore finished flag in this case since we really can't do much
  641. // to advance to finish (since an ISAPI is calling this)
  642. //
  643. if ( !fRet )
  644. {
  645. hr = HRESULT_FROM_WIN32( GetLastError() );
  646. goto Exit;
  647. }
  648. //
  649. // Remember the mapped path
  650. //
  651. if ( strcmp( straSavePhys.QueryStr(),
  652. filterMap.pszPhysicalPath ) != 0 )
  653. {
  654. hr = strFilterPath.CopyA( (CHAR*) filterMap.pszPhysicalPath );
  655. if ( FAILED( hr ) )
  656. {
  657. goto Exit;
  658. }
  659. pstrFinalPhysical = &strFilterPath;
  660. }
  661. else
  662. {
  663. pstrFinalPhysical = pUrlInfo->QueryUrlTranslated();
  664. }
  665. }
  666. else
  667. {
  668. //
  669. // No filter is mapping, therefore just take the URL_INFO's physical
  670. // path
  671. //
  672. pstrFinalPhysical = pUrlInfo->QueryUrlTranslated();
  673. DBG_ASSERT( pstrFinalPhysical != NULL );
  674. }
  675. //
  676. // We don't accept short filename since they can break metabase
  677. // equivalency
  678. //
  679. if ( wcschr( pstrFinalPhysical->QueryStr(),
  680. L'~' ) )
  681. {
  682. BOOL fShort = FALSE;
  683. DWORD dwError = CheckIfShortFileName(
  684. pstrFinalPhysical->QueryStr(),
  685. pW3Context->QueryImpersonationToken(),
  686. &fShort );
  687. if ( dwError != ERROR_SUCCESS )
  688. {
  689. hr = HRESULT_FROM_WIN32( dwError );
  690. goto Exit;
  691. }
  692. if ( fShort )
  693. {
  694. hr = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  695. goto Exit;
  696. }
  697. }
  698. //
  699. // Copy the physical path is requested
  700. //
  701. hr = pstrPhysicalPath->Copy( *pstrFinalPhysical );
  702. if ( FAILED( hr ) )
  703. {
  704. goto Exit;
  705. }
  706. Exit:
  707. return hr;
  708. }
  709. DWORD
  710. CheckIfShortFileName(
  711. IN WCHAR * pszPath,
  712. IN HANDLE hImpersonation,
  713. OUT BOOL * pfShort
  714. )
  715. /*++
  716. Description:
  717. This function takes a suspected NT/Win95 short filename and checks if there's
  718. an equivalent long filename. For example, c:\foobar\ABCDEF~1.ABC is the same
  719. as c:\foobar\abcdefghijklmnop.abc.
  720. NOTE: This function should be called unimpersonated - the FindFirstFile() must
  721. be called in the system context since most systems have traverse checking turned
  722. off - except for the UNC case where we must be impersonated to get network access.
  723. Arguments:
  724. pszPath - Path to check
  725. hImpersonation - Impersonation handle if this is a UNC path - can be NULL if not UNC
  726. pfShort - Set to TRUE if an equivalent long filename is found
  727. Returns:
  728. Win32 error on failure
  729. --*/
  730. {
  731. DWORD err = NO_ERROR;
  732. WIN32_FIND_DATA FindData;
  733. WCHAR * psz;
  734. BOOL fUNC;
  735. psz = wcschr( pszPath, L'~' );
  736. *pfShort = FALSE;
  737. fUNC = (*pszPath == L'\\');
  738. //
  739. // Loop for multiple tildas - watch for a # after the tilda
  740. //
  741. while ( psz++ )
  742. {
  743. if ( *psz >= L'0' && *psz <= L'9' )
  744. {
  745. WCHAR achTmp[MAX_PATH];
  746. WCHAR * pchEndSeg;
  747. WCHAR * pchBeginSeg;
  748. HANDLE hFind;
  749. //
  750. // Isolate the path up to the segment with the
  751. // '~' and do the FindFirst with that path
  752. //
  753. pchEndSeg = wcschr( psz, L'\\' );
  754. if ( !pchEndSeg )
  755. {
  756. pchEndSeg = psz + wcslen( psz );
  757. }
  758. //
  759. // If the string is beyond MAX_PATH then we allow it through
  760. //
  761. if ( ((INT) (pchEndSeg - pszPath)) >= MAX_PATH )
  762. {
  763. return NO_ERROR;
  764. }
  765. memcpy( achTmp,
  766. pszPath,
  767. (INT) (pchEndSeg - pszPath) * sizeof( WCHAR ) );
  768. achTmp[pchEndSeg - pszPath] = L'\0';
  769. if ( fUNC && hImpersonation )
  770. {
  771. if ( !SetThreadToken( NULL, hImpersonation ))
  772. {
  773. return GetLastError();
  774. }
  775. }
  776. //
  777. // IVANPASH: Although it looks simpler to use GetLongPathName
  778. // instead of manually traversing the folders, we must use
  779. // FindFirstFileW, because GetLongPathName requires ACLs for
  780. // IIS_WPG from the root of the drive to work.
  781. //
  782. hFind = FindFirstFileW( achTmp, &FindData );
  783. if ( fUNC && hImpersonation )
  784. {
  785. RevertToSelf();
  786. }
  787. if ( hFind == INVALID_HANDLE_VALUE )
  788. {
  789. err = GetLastError();
  790. DBGPRINTF(( DBG_CONTEXT,
  791. "FindFirst failed!! - \"%s\", error %d\n",
  792. achTmp,
  793. GetLastError() ));
  794. //
  795. // If the FindFirstFile() fails to find the file then return
  796. // success - the path doesn't appear to be a valid path which
  797. // is ok.
  798. //
  799. if ( err == ERROR_FILE_NOT_FOUND ||
  800. err == ERROR_PATH_NOT_FOUND ||
  801. err == ERROR_INVALID_NAME )
  802. {
  803. return NO_ERROR;
  804. }
  805. return err;
  806. }
  807. DBG_REQUIRE( FindClose( hFind ));
  808. //
  809. // Isolate the last segment of the string which should be
  810. // the potential short name equivalency
  811. //
  812. pchBeginSeg = wcsrchr( achTmp, L'\\' );
  813. DBG_ASSERT( pchBeginSeg );
  814. pchBeginSeg++;
  815. //
  816. // If the last segment doesn't match the long name then this is
  817. // the short name version of the path
  818. //
  819. if ( _wcsicmp( FindData.cFileName, pchBeginSeg ))
  820. {
  821. *pfShort = TRUE;
  822. return NO_ERROR;
  823. }
  824. }
  825. psz = wcschr( psz, L'~' );
  826. }
  827. return err;
  828. }
  829. HRESULT
  830. URL_CONTEXT::OpenFile(
  831. CACHE_USER * pFileUser,
  832. W3_FILE_INFO ** ppOpenFile,
  833. FILE_CACHE_ASYNC_CONTEXT * pAsyncContext,
  834. BOOL * pfHandledSync,
  835. BOOL fAllowNoBuffering,
  836. BOOL fCheckForExistenceOnly
  837. )
  838. /*++
  839. Routine Description:
  840. Open the physical path for this request. If a map path filter did some
  841. redirecting, we will use that path. Otherwise we will just use the
  842. path determined by metadata and cached in the W3_URL_INFO
  843. Arguments:
  844. pFileUser - User to open file as
  845. ppOpenFile - Set to file cache entry on success
  846. pAsyncContext - In case an async read is desired, context with callback information
  847. pfHandledSync - Did the open complete synchronously
  848. fAllowNoBuffering - Allow the file to be opened with FILE_FLAG_NO_BUFFERING
  849. fCheckForExistenceOnly - Only interested in existence of the file
  850. Return Value:
  851. HRESULT
  852. --*/
  853. {
  854. HRESULT hr;
  855. BOOL fDoCache;
  856. DBG_ASSERT( QueryMetaData() != NULL );
  857. fDoCache = !QueryMetaData()->QueryNoCache();
  858. //
  859. // If an ISAPI filter changed the physical path, then we need to go
  860. // directly to the file cache. Otherwise, we can go thru the
  861. // W3_URL_INFO which may already have the cached file associated
  862. //
  863. if ( _strPhysicalPath.IsEmpty() )
  864. {
  865. //
  866. // No filter. Fast path :-)
  867. //
  868. DBG_ASSERT( _pUrlInfo != NULL );
  869. hr = _pUrlInfo->GetFileInfo( pFileUser,
  870. fDoCache,
  871. ppOpenFile,
  872. pAsyncContext,
  873. pfHandledSync,
  874. fAllowNoBuffering,
  875. fCheckForExistenceOnly );
  876. }
  877. else
  878. {
  879. //
  880. // Filter case. Must lookup in file cache :-(
  881. //
  882. DBG_ASSERT( g_pW3Server->QueryFileCache() != NULL );
  883. hr = g_pW3Server->QueryFileCache()->GetFileInfo(
  884. _strPhysicalPath,
  885. QueryMetaData()->QueryDirmonConfig(),
  886. pFileUser,
  887. fDoCache,
  888. ppOpenFile,
  889. pAsyncContext,
  890. pfHandledSync,
  891. fAllowNoBuffering,
  892. fCheckForExistenceOnly );
  893. }
  894. return hr;
  895. }
  896. //static
  897. HRESULT
  898. URL_CONTEXT::Initialize(
  899. VOID
  900. )
  901. /*++
  902. Routine Description:
  903. Initialize URL_CONTEXT lookaside
  904. Arguments:
  905. None
  906. Return Value:
  907. HRESULT
  908. --*/
  909. {
  910. return NO_ERROR;
  911. }
  912. //static
  913. VOID
  914. URL_CONTEXT::Terminate(
  915. VOID
  916. )
  917. /*++
  918. Routine Description:
  919. Clean up URL_CONTEXT lookaside
  920. Arguments:
  921. None
  922. Return Value:
  923. HRESULT
  924. --*/
  925. {
  926. }