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.

785 lines
21 KiB

  1. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. //
  3. // METHUTIL.CPP
  4. //
  5. // Implementation of external IMethUtil interface
  6. //
  7. //
  8. // Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
  9. //
  10. #include "_davprs.h"
  11. #include "instdata.h"
  12. // IIS MetaData header
  13. #include <iiscnfg.h>
  14. // ========================================================================
  15. //
  16. // CLASS CMethUtil
  17. //
  18. // ------------------------------------------------------------------------
  19. //
  20. // CMethUtil::FInScriptMap()
  21. //
  22. // Utility to determine whether there is information in the scriptmaps
  23. // about a particular URI and whether it applies.
  24. //
  25. BOOL
  26. CMethUtil::FInScriptMap (LPCWSTR pwszURI,
  27. DWORD dwAccess,
  28. BOOL * pfCGI,
  29. SCODE * pscMatch) const
  30. {
  31. SCODE scMatch;
  32. // Fetch the script map.
  33. //
  34. const IScriptMap * pScriptMap = m_pecb->MetaData().GetScriptMap();
  35. // If we have a script map at all then check it for a match.
  36. // Otherwise we have no match by definition.
  37. //
  38. if (pScriptMap)
  39. {
  40. scMatch = pScriptMap->ScMatched (LpwszMethod(),
  41. MidMethod(),
  42. pwszURI,
  43. dwAccess,
  44. pfCGI);
  45. if (S_OK != scMatch)
  46. {
  47. // ScApplyChildISAPI need the SCODE value
  48. //
  49. if (pscMatch)
  50. *pscMatch = scMatch;
  51. return TRUE;
  52. }
  53. }
  54. return FALSE;
  55. }
  56. // ------------------------------------------------------------------------
  57. //
  58. // CMethUtil::ScApplyChildISAPI()
  59. //
  60. // During normal method processing to actually forward a method.
  61. //
  62. // fCheckISAPIAccess flag tells us whether to do the "extra ACL check for ASP".
  63. // FALSE means don't check for READ & WRITE in the acl, TRUE means do the check.
  64. //
  65. // fKeepQueryString is a special flag, TRUE by default. This flag is only
  66. // used when actually forwarding the method. It can be set to FALSE
  67. // when we are forwarding the request to a different URI
  68. // (like a default document in a folder).
  69. //
  70. // Return codes
  71. // NOTE: These codes were carefully chosen so that the FAILED() macro
  72. // can be applied to the return code and tell us whether to
  73. // terminate our method processing.
  74. //
  75. // This may seem counterintuitive, but this function FAILS if
  76. // any of the following happened:
  77. // o An ISAPI was found to handle this method (and the method
  78. // was forwarded successfully.
  79. // o The caller said Translate:F, but doesn't have correct Metabase access.
  80. // o The caller said Translate:F, but doesn't have correct ACL access.
  81. //
  82. // This method SUCCEEDS if:
  83. // o The caller said Translate:F, and passed all access checks.
  84. // o No matching ISAPI was found.
  85. //
  86. // S_OK There was NO ISAPI to apply
  87. // E_DAV_METHOD_FORWARDED
  88. // There was an ISAPI to apply, and the method WAS successfully
  89. // forwarded. NOTE: This IS a FAILED return code! We should STOP
  90. // method processing if we see this return code!
  91. //
  92. //
  93. //$REVIEW: Right now, we check the Author bit (Metabase::MD_ACCESS_SOURCE)
  94. //$REVIEW: if they say Translate:F, but NOT if there are no scriptmaps or
  95. //$REVIEW: if our forwarding fails. Is this right?
  96. SCODE
  97. CMethUtil::ScApplyChildISAPI(LPCWSTR pwszURI,
  98. DWORD dwAccess,
  99. BOOL fCheckISAPIAccess,
  100. BOOL fKeepQueryString) const
  101. {
  102. BOOL fFoundMatch = FALSE;
  103. BOOL fCGI;
  104. SCODE sc = S_OK;
  105. UINT cchURI = 0;
  106. // If there is a scriptmap then grab it and see if there is a match.
  107. // (If there is, remember if this was a CGI script or no.)
  108. //
  109. fFoundMatch = FInScriptMap (pwszURI,
  110. dwAccess,
  111. &fCGI,
  112. &sc);
  113. ScriptMapTrace ("CMethUtil::ScApplyChildISAPI()"
  114. "-- matching scriptmap %s, sc=0x%08x\n",
  115. fFoundMatch ? "found" : "not found",
  116. sc);
  117. // If we are just being called to check for matching scriptmaps,
  118. // report our findings now. Or if there were no scriptmaps that
  119. // applied, then we are also good to go.
  120. //
  121. if (!fFoundMatch)
  122. goto ret;
  123. // We do not call into the child ISAPI's if the "Translate" header
  124. // is present and its value is "F"
  125. //
  126. if (!FTranslated())
  127. {
  128. // Translate header indicates no translation is allowed.
  129. //
  130. // Check our metabase access. We must have the Author bit
  131. // (MD_ACCESS_SOURCE) in order to process raw source bits
  132. // if, and only if, a scriptmap did apply to the resource.
  133. //
  134. if (!(dwAccess & MD_ACCESS_SOURCE))
  135. {
  136. DebugTrace ("CMethUtil::ScApplyChildISAPI()"
  137. "-- Translate:F with NO metabase Authoring access.\n");
  138. sc = E_DAV_NO_IIS_ACCESS_RIGHTS;
  139. goto ret;
  140. }
  141. // One more thing, tho....
  142. //
  143. // IF they've asked for special access checking, AND we found a match,
  144. // AND it's a script (NOT a CGI), then do the special access checking.
  145. //
  146. // NOTE: This all comes from "the ASP access bug". ASP overloaded
  147. // the NTFS read-access-bit to also mean execute-access.
  148. // That means that many agents will have read-access to ASP files.
  149. // So how do we restrict access to fetch the raw ASP bits, when
  150. // the read-bit means execute? Well, we're gonna assume that
  151. // an agent that is allowed to read the raw bits is also allowed to
  152. // WRITE the raw bits. If they have WRITE access to the ASP-file,
  153. // then, and only then, let them fetch raw scriptfile bits.
  154. //
  155. if (fCheckISAPIAccess && !fCGI)
  156. {
  157. if (FAILED (ScChildISAPIAccessCheck (*m_pecb,
  158. m_pecb->LpwszPathTranslated(),
  159. GENERIC_READ | GENERIC_WRITE,
  160. NULL)))
  161. {
  162. // They didn't have read AND WRITE access.
  163. // Return FALSE, and tell the caller that the access check failed.
  164. //
  165. DebugTrace ("ScChildISAPIAccessCheck() fails the processing of this method!\n");
  166. sc = E_ACCESSDENIED;
  167. goto ret;
  168. }
  169. }
  170. }
  171. else
  172. {
  173. // Translate header says TRUE. we need execute permission to forward
  174. // the request
  175. //
  176. if ((dwAccess & (MD_ACCESS_EXECUTE | MD_ACCESS_SCRIPT)) == 0)
  177. {
  178. sc = E_DAV_NO_IIS_EXECUTE_ACCESS;
  179. goto ret;
  180. }
  181. ScriptMapTrace ("ScApplyChildISAPI -- Forwarding method\n");
  182. // If the method is excluded, then we really do not want to
  183. // touch the source, so "translate: t"/excluded is a no-access
  184. //
  185. if (sc == W_DAV_SCRIPTMAP_MATCH_EXCLUDED)
  186. {
  187. sc = E_DAV_NO_IIS_ACCESS_RIGHTS;
  188. goto ret;
  189. }
  190. Assert (sc == W_DAV_SCRIPTMAP_MATCH_FOUND);
  191. // if we are going forwarding this to a child ISAPI, we need to check
  192. // if the URI has a trailing slash or backslash. if it does we will
  193. // model httpext behavior and fail as file not found. trailing
  194. // backslashes and slashes are not handled well if forwarded...
  195. //
  196. Assert (pwszURI);
  197. cchURI = static_cast<UINT>(wcslen(pwszURI));
  198. if (1 < cchURI)
  199. {
  200. if (L'/' == pwszURI[cchURI-1] || L'\\' == pwszURI[cchURI-1])
  201. {
  202. sc = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
  203. goto ret;
  204. }
  205. }
  206. // Try the forward.
  207. //
  208. // BIG NOTE: If it fails, we're gonna check the GetLastError,
  209. // and if that happens to be ERROR_INVALID_PARAMETER,
  210. // we're gonna assume that there's not actually any applicable
  211. // scriptmap, and process the method ourselves after all!
  212. //
  213. sc = m_presponse->ScForward(pwszURI,
  214. fKeepQueryString,
  215. FALSE);
  216. if (FAILED(sc))
  217. {
  218. // The forward attempt failed because there is no applicable
  219. // scriptmap. Let's handle the method ourselves.
  220. //$REVIEW: This is going to have the same end result as
  221. //$REVIEW: Translate:F. Should we check the "author" bit here???
  222. //
  223. if (HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) == sc)
  224. {
  225. // We get to handle this method.
  226. //
  227. sc = S_OK;
  228. if (!(dwAccess & MD_ACCESS_SOURCE))
  229. {
  230. DebugTrace ("ScApplyChildISAPI"
  231. "-- Forward FAIL with NO metabase Authoring access.\n");
  232. sc = E_DAV_NO_IIS_ACCESS_RIGHTS;
  233. goto ret;
  234. }
  235. }
  236. goto ret;
  237. }
  238. // We were forwarded...
  239. //
  240. sc = E_DAV_METHOD_FORWARDED;
  241. }
  242. ret:
  243. return sc;
  244. }
  245. // ------------------------------------------------------------------------
  246. //
  247. // DwDirectoryAccess()
  248. //
  249. // Fetch access perms for the specified URI.
  250. //
  251. DWORD
  252. DwDirectoryAccess(
  253. const IEcb &ecb,
  254. LPCWSTR pwszURI,
  255. DWORD dwAccIfNone)
  256. {
  257. DWORD dwAcc = dwAccIfNone;
  258. auto_ref_ptr<IMDData> pMDData;
  259. if (SUCCEEDED(HrMDGetData(ecb, pwszURI, pMDData.load())))
  260. dwAcc = pMDData->DwAccessPerms();
  261. return dwAcc;
  262. }
  263. // IIS Access ----------------------------------------------------------------
  264. //
  265. SCODE
  266. CMethUtil::ScIISAccess (
  267. LPCWSTR pwszURI,
  268. DWORD dwAccessRequested,
  269. DWORD* pdwAccessOut) const
  270. {
  271. DWORD dw;
  272. // Make sure the url is stripped of any prefix
  273. //
  274. pwszURI = PwszUrlStrippedOfPrefix (pwszURI);
  275. //$ SECURITY:
  276. //
  277. // Plug the ::$DATA security hole for NT5.
  278. //
  279. if (! FSucceededColonColonCheck(pwszURI))
  280. return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
  281. // Get the access from the cache
  282. //
  283. dw = DwDirectoryAccess( *m_pecb,
  284. pwszURI,
  285. dwAccessRequested );
  286. // If the caller actually needs the bits back, pass them
  287. // back here
  288. //
  289. if (pdwAccessOut)
  290. *pdwAccessOut = dw;
  291. // Check the access bits against the requested bits
  292. //
  293. if ((dw & dwAccessRequested) == dwAccessRequested)
  294. return S_OK;
  295. return E_DAV_NO_IIS_ACCESS_RIGHTS;
  296. }
  297. // Common IIS checking
  298. // Apply child ISAPI if necessary, if not, verify if desired access
  299. // is granted
  300. //
  301. // parameters
  302. // pszURI the request URI
  303. // dwDesired desired access, default is zero
  304. // fCheckISAPIAccess Only used by GET/HEAD, default to FALSE.
  305. //
  306. SCODE
  307. CMethUtil::ScIISCheck( LPCWSTR pwszURI,
  308. DWORD dwDesired /* = 0 */,
  309. BOOL fCheckISAPIAccess /* = FALSE */) const
  310. {
  311. SCODE sc = S_OK;
  312. //$ SECURITY:
  313. //
  314. // Plug the ::$DATA security hole for NT5.
  315. //
  316. if (! FSucceededColonColonCheck(pwszURI))
  317. return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
  318. // Whoa, baby. Do not let "*" urls get through this
  319. // check unless the method is unknown or is an OPTIONS
  320. // request.
  321. //
  322. if ((L'*' == pwszURI[0]) && ('\0' == pwszURI[1]))
  323. {
  324. if ((MID_UNKNOWN != m_mid) && (MID_OPTIONS != m_mid))
  325. {
  326. DebugTrace ("Dav: url: \"*\" not valid for '%ls'\n",
  327. m_pecb->LpwszMethod());
  328. return E_DAV_METHOD_FAILURE_STAR_URL;
  329. }
  330. }
  331. // Get IIS access rights
  332. //
  333. DWORD dwAcc = DwDirectoryAccess (*m_pecb, pwszURI, 0);
  334. // See if we need to hand things off to a child ISAPI.
  335. //
  336. sc = ScApplyChildISAPI (pwszURI,
  337. dwAcc,
  338. fCheckISAPIAccess,
  339. TRUE);
  340. if (FAILED(sc))
  341. {
  342. // Either the request has been forwarded, or some bad error occurred.
  343. // In either case, quit here and map the error!
  344. //
  345. goto ret;
  346. }
  347. // Check to see if the desired access is granted
  348. //
  349. if (dwDesired != (dwAcc & dwDesired))
  350. {
  351. // At least one of the desired access rights is not granted,
  352. // so generate an appropriate error. Note: if multiple rights
  353. // were requested then multiple rights may not have been granted.
  354. // The error is guaranteed to be appropriate to at least one
  355. // of the rights not granted, but not necessariliy all of them.
  356. //
  357. switch (dwDesired & (MD_ACCESS_READ|MD_ACCESS_WRITE))
  358. {
  359. case MD_ACCESS_READ:
  360. sc = E_DAV_NO_IIS_READ_ACCESS;
  361. break;
  362. case MD_ACCESS_WRITE:
  363. sc = E_DAV_NO_IIS_WRITE_ACCESS;
  364. break;
  365. default:
  366. sc = E_DAV_NO_IIS_ACCESS_RIGHTS;
  367. break;
  368. }
  369. goto ret;
  370. }
  371. ret:
  372. return sc;
  373. }
  374. // Destination url access ------------------------------------------------
  375. //
  376. SCODE __fastcall
  377. CMethUtil::ScGetDestination (LPCWSTR* ppwszUrl,
  378. LPCWSTR* ppwszPath,
  379. UINT* pcchPath,
  380. CVRoot** ppcvr) const // Defaults to NULL
  381. {
  382. SCODE sc = S_OK;
  383. LPCWSTR pwszFullUrl = NULL;
  384. Assert (ppwszUrl);
  385. Assert (ppwszPath);
  386. Assert (pcchPath);
  387. *ppwszUrl = NULL;
  388. *ppwszPath = NULL;
  389. *pcchPath = 0;
  390. if (ppcvr)
  391. *ppcvr = NULL;
  392. // If we haven't done this yet...
  393. //
  394. if (NULL == m_pwszDestinationUrl.get())
  395. {
  396. LPCWSTR pwszStripped;
  397. UINT cch;
  398. // Get the header in unicode, apply URL conversion. I.e.
  399. // value will be escaped and and translated into unicode
  400. // taking into account the Accept-Language: header
  401. //
  402. pwszFullUrl = m_prequest->LpwszGetHeader(gc_szDestination, TRUE);
  403. // If they asked for a destination, there better be one...
  404. //
  405. if (NULL == pwszFullUrl)
  406. {
  407. sc = E_DAV_NO_DESTINATION;
  408. DebugTrace ("CMethUtil::ScGetDestination() - required destination header not present\n");
  409. goto ret;
  410. }
  411. // URL has been escaped at header retrieval step, the last step
  412. // in order to get normalized URL is to canonicalize what we have
  413. // at the current moment. So allocate enough space and fill it.
  414. //
  415. cch = static_cast<UINT>(wcslen(pwszFullUrl) + 1);
  416. m_pwszDestinationUrl = static_cast<LPWSTR>(g_heap.Alloc(cch * sizeof(WCHAR)));
  417. // Canonicalize the absolute URL. It does not mater what value we
  418. // pass in for cch here - it is just an output parameter.
  419. //
  420. sc = ScCanonicalizePrefixedURL (pwszFullUrl,
  421. m_pwszDestinationUrl.get(),
  422. &cch);
  423. if (S_OK != sc)
  424. {
  425. // We've given ScCanonicalizeURL() sufficient space, we
  426. // should never see S_FALSE here - size can only shrink.
  427. //
  428. Assert(S_FALSE != sc);
  429. DebugTrace ("CMethUtil::ScGetDestination() - ScCanonicalizeUrl() failed 0x%08lX\n", sc);
  430. goto ret;
  431. }
  432. // Now translate the path, take a best guess and use MAX_PATH as
  433. // the initial size of the path
  434. //
  435. cch = MAX_PATH;
  436. m_pwszDestinationPath = static_cast<LPWSTR>(g_heap.Alloc(cch * sizeof(WCHAR)));
  437. sc = ::ScStoragePathFromUrl (*m_pecb,
  438. m_pwszDestinationUrl.get(),
  439. m_pwszDestinationPath.get(),
  440. &cch,
  441. m_pcvrDestination.load());
  442. // If there was not enough space -- ie. S_FALSE was returned --
  443. // then reallocate and try again...
  444. //
  445. if (sc == S_FALSE)
  446. {
  447. m_pwszDestinationPath.realloc(cch * sizeof(WCHAR));
  448. sc = ::ScStoragePathFromUrl (*m_pecb,
  449. m_pwszDestinationUrl.get(),
  450. m_pwszDestinationPath.get(),
  451. &cch,
  452. m_pcvrDestination.load());
  453. // We should not get S_FALSE again --
  454. // we allocated as much space as was requested.
  455. //
  456. Assert (S_FALSE != sc);
  457. }
  458. if (FAILED(sc))
  459. goto ret;
  460. // We always will get '\0' terminated string back, and cch will indicate
  461. // the number of characters written (including '\0' termination). Thus it
  462. // will always be greater than 0 at this point
  463. //
  464. Assert( cch > 0 );
  465. m_cchDestinationPath = cch - 1;
  466. // We must remove all trailing slashes, in case the path is not empty string
  467. //
  468. if ( 0 != m_cchDestinationPath )
  469. {
  470. // Since URL is normalized there may be not more than one trailing slash
  471. //
  472. if ((L'\\' == m_pwszDestinationPath[m_cchDestinationPath - 1]) ||
  473. (L'/' == m_pwszDestinationPath[m_cchDestinationPath - 1]))
  474. {
  475. m_cchDestinationPath--;
  476. m_pwszDestinationPath[m_cchDestinationPath] = L'\0';
  477. }
  478. }
  479. }
  480. // We will have S_OK or W_DAV_SPANS_VIRTUAL_ROOTS here.
  481. // In any case it is success
  482. //
  483. Assert(SUCCEEDED(sc));
  484. // Return the pointers. For the url, make sure that any
  485. // prefix is stripped off.
  486. //
  487. // Note that the ScStoragePathFromUrl() already has checked
  488. // to see if the all important prefix matched, so we just need
  489. // to strip
  490. //
  491. *ppwszUrl = PwszUrlStrippedOfPrefix (m_pwszDestinationUrl.get());
  492. // Pass everything back to the caller
  493. //
  494. *ppwszPath = m_pwszDestinationPath.get();
  495. *pcchPath = m_cchDestinationPath;
  496. // If they wanted the destination virtual root, hand that back
  497. // as well.
  498. //
  499. if (ppcvr)
  500. {
  501. *ppcvr = m_pcvrDestination.get();
  502. }
  503. ret:
  504. // Do a cleanup if we failed. Subsequent calls to the
  505. // function just may start returning partial data if
  506. // we do not do that. That is undesirable.
  507. //
  508. if (FAILED (sc))
  509. {
  510. if (m_pwszDestinationUrl.get())
  511. m_pwszDestinationUrl.clear();
  512. if (m_pwszDestinationPath.get())
  513. m_pwszDestinationPath.clear();
  514. if (m_pcvrDestination.get())
  515. m_pcvrDestination.clear();
  516. m_cchDestinationPath = 0;
  517. //$ WINBUGS: 403726: If we don't pass back the full url, then
  518. // an incorrect result gets generated and no copy is done.
  519. //
  520. *ppwszUrl = pwszFullUrl;
  521. //
  522. //$ WINBUGS: end.
  523. }
  524. return sc;
  525. }
  526. // ------------------------------------------------------------------------
  527. //
  528. // CMethUtil::ScGetExpirationTime
  529. //
  530. // Gets the expiration time string from the metabase corresponding to a
  531. // particular resource. If pszURI is NULL and there is information in the
  532. // metabase for the particular resource, the function will return (in pcb) the number
  533. // of bytes necessary to pass in as pszBuf to get the requested expiration
  534. // string.
  535. //
  536. // [in] pszURI The resource you want the expiration time string for
  537. // [in] pszBuf, The buffer we put the string into
  538. // [in out]pcb On [in], the size of the buffer passed in,
  539. // On [out], if the buffer size passed in would be
  540. // insufficient or there was no buffer passed in.
  541. // Otherwise unchanged from [in].
  542. //
  543. // Return values:
  544. // S_OK: If pszBuf was non-NULL, then the data was successfully retrieved and
  545. // the length of the actual data was put in pcb.
  546. // HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER): The buffer passed in is not
  547. // large enough to hold
  548. // the requested data.
  549. // HRESULT_FROM_WIN32(ERROR_NO_DATA): No data for expiration time exists in the
  550. // metabase for this resource. Default value
  551. // of 1 day expiration should be used in this
  552. // case.
  553. //
  554. SCODE
  555. CMethUtil::ScGetExpirationTime(IN LPCWSTR pwszURI,
  556. IN LPWSTR pwszBuf,
  557. IN OUT UINT * pcch)
  558. {
  559. SCODE sc = S_OK;
  560. auto_ref_ptr<IMDData> pMDData;
  561. LPCWSTR pwszExpires = NULL;
  562. UINT cchExpires;
  563. //
  564. // Fetch the metadata for this URI. If it has a content type map
  565. // then use it to look for a mapping. If it does not have a content
  566. // type map then check the global mime map.
  567. //
  568. // Note: if we fail to get the metadata at all then default the
  569. // content type to application/octet-stream. Do not use the global
  570. // mime map just because we cannot get the metadata.
  571. //
  572. if ( FAILED(HrMDGetData(pwszURI, pMDData.load())) ||
  573. (NULL == (pwszExpires = pMDData->PwszExpires())) )
  574. {
  575. sc = HRESULT_FROM_WIN32(ERROR_NO_DATA);
  576. goto ret;
  577. }
  578. cchExpires = static_cast<UINT>(wcslen(pwszExpires) + 1);
  579. if (*pcch < cchExpires)
  580. {
  581. sc = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  582. *pcch = cchExpires;
  583. goto ret;
  584. }
  585. else
  586. {
  587. memcpy(pwszBuf, pwszExpires, cchExpires * sizeof(WCHAR));
  588. *pcch = cchExpires;
  589. }
  590. ret:
  591. return sc;
  592. }
  593. // ScCheckMoveCopyDeleteAccess() ---------------------------------------------
  594. //
  595. SCODE
  596. CMethUtil::ScCheckMoveCopyDeleteAccess (
  597. /* [in] */ LPCWSTR pwszUrl,
  598. /* [in] */ CVRoot* pcvrUrl, // OPTIONAL (may be NULL)
  599. /* [in] */ BOOL fDirectory,
  600. /* [in] */ BOOL fCheckScriptmaps,
  601. /* [in] */ DWORD dwAccess)
  602. {
  603. Assert (pwszUrl);
  604. auto_ref_ptr<IMDData> pMDData;
  605. BOOL fCGI = FALSE;
  606. DWORD dwAccessActual = 0;
  607. SCODE sc = S_OK;
  608. // Get the metadata object
  609. //
  610. //$ REVIEW: Ideally we could get this without it being cached
  611. //
  612. if (NULL == pcvrUrl)
  613. {
  614. sc = HrMDGetData (pwszUrl, pMDData.load());
  615. if (FAILED (sc))
  616. goto ret;
  617. }
  618. else
  619. {
  620. LPCWSTR pwszMbPathVRoot;
  621. CStackBuffer<WCHAR> pwszMbPathChild;
  622. UINT cchPrefix;
  623. UINT cchUrl = static_cast<UINT>(wcslen(pwszUrl));
  624. // Map the URI to its equivalent metabase path, and make sure
  625. // the URL is stripped before we call into the MDPath processing
  626. //
  627. Assert (pwszUrl == PwszUrlStrippedOfPrefix (pwszUrl));
  628. cchPrefix = pcvrUrl->CchPrefixOfMetabasePath (&pwszMbPathVRoot);
  629. if (!pwszMbPathChild.resize(CbSizeWsz(cchPrefix + cchUrl)))
  630. return E_OUTOFMEMORY;
  631. memcpy (pwszMbPathChild.get(), pwszMbPathVRoot, cchPrefix * sizeof(WCHAR));
  632. memcpy (pwszMbPathChild.get() + cchPrefix, pwszUrl, (cchUrl + 1) * sizeof(WCHAR));
  633. sc = HrMDGetData (pwszMbPathChild.get(), pwszMbPathVRoot, pMDData.load());
  634. if (FAILED (sc))
  635. goto ret;
  636. }
  637. //
  638. //$ REVIEW: end.
  639. // Check metabase access to see if we have the minimal access
  640. // required for this operation.
  641. //
  642. dwAccessActual = pMDData->DwAccessPerms();
  643. if ((dwAccessActual & dwAccess) != dwAccess)
  644. {
  645. sc = E_DAV_NO_IIS_ACCESS_RIGHTS;
  646. goto ret;
  647. }
  648. //$ SECURITY: check for IP restrictions placed on this resource
  649. //$ REVIEW: this may not be good enough, we may need to do more
  650. // than this...
  651. //
  652. if (!m_pecb->MetaData().FSameIPRestriction(pMDData.get()))
  653. {
  654. sc = E_DAV_BAD_DESTINATION;
  655. goto ret;
  656. }
  657. //
  658. //$ REVIEW: end.
  659. //$ SECURITY: Check to see if authorization is different than the
  660. // request url's authorization.
  661. //
  662. if (m_pecb->MetaData().DwAuthorization() != pMDData->DwAuthorization())
  663. {
  664. sc = E_DAV_BAD_DESTINATION;
  665. goto ret;
  666. }
  667. //
  668. //$ REVIEW: end.
  669. // Check to see if we have 'star' scriptmap honors over this
  670. // file.
  671. //
  672. if (!m_pecb->MetaData().FSameStarScriptmapping(pMDData.get()))
  673. {
  674. sc = E_DAV_STAR_SCRIPTMAPING_MISMATCH;
  675. goto ret;
  676. }
  677. // Check to see if there is a scriptmap that applies. If so, then
  678. // we had better have MD_ACCESS_SOURCE rights to do a move or a copy.
  679. //
  680. if (fCheckScriptmaps && FInScriptMap(pwszUrl,
  681. dwAccessActual,
  682. &fCGI))
  683. {
  684. if (0 == (MD_ACCESS_SOURCE & dwAccessActual))
  685. {
  686. sc = E_DAV_NO_IIS_ACCESS_RIGHTS;
  687. goto ret;
  688. }
  689. }
  690. ret:
  691. return sc;
  692. }