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
785 lines
21 KiB
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// METHUTIL.CPP
|
|
//
|
|
// Implementation of external IMethUtil interface
|
|
//
|
|
//
|
|
// Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
|
|
#include "_davprs.h"
|
|
#include "instdata.h"
|
|
|
|
// IIS MetaData header
|
|
#include <iiscnfg.h>
|
|
|
|
|
|
// ========================================================================
|
|
//
|
|
// CLASS CMethUtil
|
|
//
|
|
|
|
// ------------------------------------------------------------------------
|
|
//
|
|
// CMethUtil::FInScriptMap()
|
|
//
|
|
// Utility to determine whether there is information in the scriptmaps
|
|
// about a particular URI and whether it applies.
|
|
//
|
|
BOOL
|
|
CMethUtil::FInScriptMap (LPCWSTR pwszURI,
|
|
DWORD dwAccess,
|
|
BOOL * pfCGI,
|
|
SCODE * pscMatch) const
|
|
{
|
|
SCODE scMatch;
|
|
|
|
// Fetch the script map.
|
|
//
|
|
const IScriptMap * pScriptMap = m_pecb->MetaData().GetScriptMap();
|
|
|
|
// If we have a script map at all then check it for a match.
|
|
// Otherwise we have no match by definition.
|
|
//
|
|
if (pScriptMap)
|
|
{
|
|
scMatch = pScriptMap->ScMatched (LpwszMethod(),
|
|
MidMethod(),
|
|
pwszURI,
|
|
dwAccess,
|
|
pfCGI);
|
|
|
|
if (S_OK != scMatch)
|
|
{
|
|
// ScApplyChildISAPI need the SCODE value
|
|
//
|
|
if (pscMatch)
|
|
*pscMatch = scMatch;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
//
|
|
// CMethUtil::ScApplyChildISAPI()
|
|
//
|
|
// During normal method processing to actually forward a method.
|
|
//
|
|
// fCheckISAPIAccess flag tells us whether to do the "extra ACL check for ASP".
|
|
// FALSE means don't check for READ & WRITE in the acl, TRUE means do the check.
|
|
//
|
|
// fKeepQueryString is a special flag, TRUE by default. This flag is only
|
|
// used when actually forwarding the method. It can be set to FALSE
|
|
// when we are forwarding the request to a different URI
|
|
// (like a default document in a folder).
|
|
//
|
|
// Return codes
|
|
// NOTE: These codes were carefully chosen so that the FAILED() macro
|
|
// can be applied to the return code and tell us whether to
|
|
// terminate our method processing.
|
|
//
|
|
// This may seem counterintuitive, but this function FAILS if
|
|
// any of the following happened:
|
|
// o An ISAPI was found to handle this method (and the method
|
|
// was forwarded successfully.
|
|
// o The caller said Translate:F, but doesn't have correct Metabase access.
|
|
// o The caller said Translate:F, but doesn't have correct ACL access.
|
|
//
|
|
// This method SUCCEEDS if:
|
|
// o The caller said Translate:F, and passed all access checks.
|
|
// o No matching ISAPI was found.
|
|
//
|
|
// S_OK There was NO ISAPI to apply
|
|
// E_DAV_METHOD_FORWARDED
|
|
// There was an ISAPI to apply, and the method WAS successfully
|
|
// forwarded. NOTE: This IS a FAILED return code! We should STOP
|
|
// method processing if we see this return code!
|
|
//
|
|
//
|
|
//$REVIEW: Right now, we check the Author bit (Metabase::MD_ACCESS_SOURCE)
|
|
//$REVIEW: if they say Translate:F, but NOT if there are no scriptmaps or
|
|
//$REVIEW: if our forwarding fails. Is this right?
|
|
|
|
|
|
SCODE
|
|
CMethUtil::ScApplyChildISAPI(LPCWSTR pwszURI,
|
|
DWORD dwAccess,
|
|
BOOL fCheckISAPIAccess,
|
|
BOOL fKeepQueryString) const
|
|
{
|
|
BOOL fFoundMatch = FALSE;
|
|
BOOL fCGI;
|
|
SCODE sc = S_OK;
|
|
UINT cchURI = 0;
|
|
|
|
// If there is a scriptmap then grab it and see if there is a match.
|
|
// (If there is, remember if this was a CGI script or no.)
|
|
//
|
|
fFoundMatch = FInScriptMap (pwszURI,
|
|
dwAccess,
|
|
&fCGI,
|
|
&sc);
|
|
|
|
ScriptMapTrace ("CMethUtil::ScApplyChildISAPI()"
|
|
"-- matching scriptmap %s, sc=0x%08x\n",
|
|
fFoundMatch ? "found" : "not found",
|
|
sc);
|
|
|
|
// If we are just being called to check for matching scriptmaps,
|
|
// report our findings now. Or if there were no scriptmaps that
|
|
// applied, then we are also good to go.
|
|
//
|
|
if (!fFoundMatch)
|
|
goto ret;
|
|
|
|
// We do not call into the child ISAPI's if the "Translate" header
|
|
// is present and its value is "F"
|
|
//
|
|
if (!FTranslated())
|
|
{
|
|
// Translate header indicates no translation is allowed.
|
|
//
|
|
|
|
// Check our metabase access. We must have the Author bit
|
|
// (MD_ACCESS_SOURCE) in order to process raw source bits
|
|
// if, and only if, a scriptmap did apply to the resource.
|
|
//
|
|
if (!(dwAccess & MD_ACCESS_SOURCE))
|
|
{
|
|
DebugTrace ("CMethUtil::ScApplyChildISAPI()"
|
|
"-- Translate:F with NO metabase Authoring access.\n");
|
|
|
|
sc = E_DAV_NO_IIS_ACCESS_RIGHTS;
|
|
goto ret;
|
|
}
|
|
|
|
// One more thing, tho....
|
|
//
|
|
// IF they've asked for special access checking, AND we found a match,
|
|
// AND it's a script (NOT a CGI), then do the special access checking.
|
|
//
|
|
// NOTE: This all comes from "the ASP access bug". ASP overloaded
|
|
// the NTFS read-access-bit to also mean execute-access.
|
|
// That means that many agents will have read-access to ASP files.
|
|
// So how do we restrict access to fetch the raw ASP bits, when
|
|
// the read-bit means execute? Well, we're gonna assume that
|
|
// an agent that is allowed to read the raw bits is also allowed to
|
|
// WRITE the raw bits. If they have WRITE access to the ASP-file,
|
|
// then, and only then, let them fetch raw scriptfile bits.
|
|
//
|
|
if (fCheckISAPIAccess && !fCGI)
|
|
{
|
|
if (FAILED (ScChildISAPIAccessCheck (*m_pecb,
|
|
m_pecb->LpwszPathTranslated(),
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
NULL)))
|
|
{
|
|
// They didn't have read AND WRITE access.
|
|
// Return FALSE, and tell the caller that the access check failed.
|
|
//
|
|
DebugTrace ("ScChildISAPIAccessCheck() fails the processing of this method!\n");
|
|
sc = E_ACCESSDENIED;
|
|
goto ret;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Translate header says TRUE. we need execute permission to forward
|
|
// the request
|
|
//
|
|
if ((dwAccess & (MD_ACCESS_EXECUTE | MD_ACCESS_SCRIPT)) == 0)
|
|
{
|
|
sc = E_DAV_NO_IIS_EXECUTE_ACCESS;
|
|
goto ret;
|
|
}
|
|
|
|
ScriptMapTrace ("ScApplyChildISAPI -- Forwarding method\n");
|
|
|
|
// If the method is excluded, then we really do not want to
|
|
// touch the source, so "translate: t"/excluded is a no-access
|
|
//
|
|
if (sc == W_DAV_SCRIPTMAP_MATCH_EXCLUDED)
|
|
{
|
|
sc = E_DAV_NO_IIS_ACCESS_RIGHTS;
|
|
goto ret;
|
|
}
|
|
|
|
Assert (sc == W_DAV_SCRIPTMAP_MATCH_FOUND);
|
|
|
|
// if we are going forwarding this to a child ISAPI, we need to check
|
|
// if the URI has a trailing slash or backslash. if it does we will
|
|
// model httpext behavior and fail as file not found. trailing
|
|
// backslashes and slashes are not handled well if forwarded...
|
|
//
|
|
Assert (pwszURI);
|
|
cchURI = static_cast<UINT>(wcslen(pwszURI));
|
|
if (1 < cchURI)
|
|
{
|
|
if (L'/' == pwszURI[cchURI-1] || L'\\' == pwszURI[cchURI-1])
|
|
{
|
|
sc = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
|
|
goto ret;
|
|
}
|
|
}
|
|
|
|
// Try the forward.
|
|
//
|
|
// BIG NOTE: If it fails, we're gonna check the GetLastError,
|
|
// and if that happens to be ERROR_INVALID_PARAMETER,
|
|
// we're gonna assume that there's not actually any applicable
|
|
// scriptmap, and process the method ourselves after all!
|
|
//
|
|
sc = m_presponse->ScForward(pwszURI,
|
|
fKeepQueryString,
|
|
FALSE);
|
|
if (FAILED(sc))
|
|
{
|
|
// The forward attempt failed because there is no applicable
|
|
// scriptmap. Let's handle the method ourselves.
|
|
//$REVIEW: This is going to have the same end result as
|
|
//$REVIEW: Translate:F. Should we check the "author" bit here???
|
|
//
|
|
if (HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) == sc)
|
|
{
|
|
// We get to handle this method.
|
|
//
|
|
sc = S_OK;
|
|
|
|
if (!(dwAccess & MD_ACCESS_SOURCE))
|
|
{
|
|
DebugTrace ("ScApplyChildISAPI"
|
|
"-- Forward FAIL with NO metabase Authoring access.\n");
|
|
sc = E_DAV_NO_IIS_ACCESS_RIGHTS;
|
|
goto ret;
|
|
}
|
|
}
|
|
|
|
goto ret;
|
|
}
|
|
|
|
// We were forwarded...
|
|
//
|
|
sc = E_DAV_METHOD_FORWARDED;
|
|
}
|
|
|
|
ret:
|
|
|
|
return sc;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
//
|
|
// DwDirectoryAccess()
|
|
//
|
|
// Fetch access perms for the specified URI.
|
|
//
|
|
DWORD
|
|
DwDirectoryAccess(
|
|
const IEcb &ecb,
|
|
LPCWSTR pwszURI,
|
|
DWORD dwAccIfNone)
|
|
{
|
|
DWORD dwAcc = dwAccIfNone;
|
|
auto_ref_ptr<IMDData> pMDData;
|
|
|
|
if (SUCCEEDED(HrMDGetData(ecb, pwszURI, pMDData.load())))
|
|
dwAcc = pMDData->DwAccessPerms();
|
|
|
|
return dwAcc;
|
|
}
|
|
|
|
// IIS Access ----------------------------------------------------------------
|
|
//
|
|
SCODE
|
|
CMethUtil::ScIISAccess (
|
|
LPCWSTR pwszURI,
|
|
DWORD dwAccessRequested,
|
|
DWORD* pdwAccessOut) const
|
|
{
|
|
DWORD dw;
|
|
|
|
// Make sure the url is stripped of any prefix
|
|
//
|
|
pwszURI = PwszUrlStrippedOfPrefix (pwszURI);
|
|
|
|
//$ SECURITY:
|
|
//
|
|
// Plug the ::$DATA security hole for NT5.
|
|
//
|
|
if (! FSucceededColonColonCheck(pwszURI))
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
|
|
|
|
// Get the access from the cache
|
|
//
|
|
dw = DwDirectoryAccess( *m_pecb,
|
|
pwszURI,
|
|
dwAccessRequested );
|
|
|
|
// If the caller actually needs the bits back, pass them
|
|
// back here
|
|
//
|
|
if (pdwAccessOut)
|
|
*pdwAccessOut = dw;
|
|
|
|
// Check the access bits against the requested bits
|
|
//
|
|
if ((dw & dwAccessRequested) == dwAccessRequested)
|
|
return S_OK;
|
|
|
|
return E_DAV_NO_IIS_ACCESS_RIGHTS;
|
|
}
|
|
|
|
// Common IIS checking
|
|
// Apply child ISAPI if necessary, if not, verify if desired access
|
|
// is granted
|
|
//
|
|
// parameters
|
|
// pszURI the request URI
|
|
// dwDesired desired access, default is zero
|
|
// fCheckISAPIAccess Only used by GET/HEAD, default to FALSE.
|
|
//
|
|
SCODE
|
|
CMethUtil::ScIISCheck( LPCWSTR pwszURI,
|
|
DWORD dwDesired /* = 0 */,
|
|
BOOL fCheckISAPIAccess /* = FALSE */) const
|
|
{
|
|
SCODE sc = S_OK;
|
|
|
|
//$ SECURITY:
|
|
//
|
|
// Plug the ::$DATA security hole for NT5.
|
|
//
|
|
if (! FSucceededColonColonCheck(pwszURI))
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
|
|
|
|
// Whoa, baby. Do not let "*" urls get through this
|
|
// check unless the method is unknown or is an OPTIONS
|
|
// request.
|
|
//
|
|
if ((L'*' == pwszURI[0]) && ('\0' == pwszURI[1]))
|
|
{
|
|
if ((MID_UNKNOWN != m_mid) && (MID_OPTIONS != m_mid))
|
|
{
|
|
DebugTrace ("Dav: url: \"*\" not valid for '%ls'\n",
|
|
m_pecb->LpwszMethod());
|
|
|
|
return E_DAV_METHOD_FAILURE_STAR_URL;
|
|
}
|
|
}
|
|
|
|
// Get IIS access rights
|
|
//
|
|
DWORD dwAcc = DwDirectoryAccess (*m_pecb, pwszURI, 0);
|
|
|
|
// See if we need to hand things off to a child ISAPI.
|
|
//
|
|
sc = ScApplyChildISAPI (pwszURI,
|
|
dwAcc,
|
|
fCheckISAPIAccess,
|
|
TRUE);
|
|
if (FAILED(sc))
|
|
{
|
|
// Either the request has been forwarded, or some bad error occurred.
|
|
// In either case, quit here and map the error!
|
|
//
|
|
goto ret;
|
|
}
|
|
|
|
// Check to see if the desired access is granted
|
|
//
|
|
if (dwDesired != (dwAcc & dwDesired))
|
|
{
|
|
// At least one of the desired access rights is not granted,
|
|
// so generate an appropriate error. Note: if multiple rights
|
|
// were requested then multiple rights may not have been granted.
|
|
// The error is guaranteed to be appropriate to at least one
|
|
// of the rights not granted, but not necessariliy all of them.
|
|
//
|
|
switch (dwDesired & (MD_ACCESS_READ|MD_ACCESS_WRITE))
|
|
{
|
|
case MD_ACCESS_READ:
|
|
sc = E_DAV_NO_IIS_READ_ACCESS;
|
|
break;
|
|
|
|
case MD_ACCESS_WRITE:
|
|
sc = E_DAV_NO_IIS_WRITE_ACCESS;
|
|
break;
|
|
|
|
default:
|
|
sc = E_DAV_NO_IIS_ACCESS_RIGHTS;
|
|
break;
|
|
}
|
|
goto ret;
|
|
}
|
|
|
|
ret:
|
|
return sc;
|
|
}
|
|
|
|
// Destination url access ------------------------------------------------
|
|
//
|
|
SCODE __fastcall
|
|
CMethUtil::ScGetDestination (LPCWSTR* ppwszUrl,
|
|
LPCWSTR* ppwszPath,
|
|
UINT* pcchPath,
|
|
CVRoot** ppcvr) const // Defaults to NULL
|
|
{
|
|
SCODE sc = S_OK;
|
|
|
|
LPCWSTR pwszFullUrl = NULL;
|
|
|
|
Assert (ppwszUrl);
|
|
Assert (ppwszPath);
|
|
Assert (pcchPath);
|
|
|
|
*ppwszUrl = NULL;
|
|
*ppwszPath = NULL;
|
|
*pcchPath = 0;
|
|
if (ppcvr)
|
|
*ppcvr = NULL;
|
|
|
|
// If we haven't done this yet...
|
|
//
|
|
if (NULL == m_pwszDestinationUrl.get())
|
|
{
|
|
LPCWSTR pwszStripped;
|
|
UINT cch;
|
|
|
|
// Get the header in unicode, apply URL conversion. I.e.
|
|
// value will be escaped and and translated into unicode
|
|
// taking into account the Accept-Language: header
|
|
//
|
|
pwszFullUrl = m_prequest->LpwszGetHeader(gc_szDestination, TRUE);
|
|
|
|
// If they asked for a destination, there better be one...
|
|
//
|
|
if (NULL == pwszFullUrl)
|
|
{
|
|
sc = E_DAV_NO_DESTINATION;
|
|
DebugTrace ("CMethUtil::ScGetDestination() - required destination header not present\n");
|
|
goto ret;
|
|
}
|
|
|
|
// URL has been escaped at header retrieval step, the last step
|
|
// in order to get normalized URL is to canonicalize what we have
|
|
// at the current moment. So allocate enough space and fill it.
|
|
//
|
|
cch = static_cast<UINT>(wcslen(pwszFullUrl) + 1);
|
|
m_pwszDestinationUrl = static_cast<LPWSTR>(g_heap.Alloc(cch * sizeof(WCHAR)));
|
|
|
|
// Canonicalize the absolute URL. It does not mater what value we
|
|
// pass in for cch here - it is just an output parameter.
|
|
//
|
|
sc = ScCanonicalizePrefixedURL (pwszFullUrl,
|
|
m_pwszDestinationUrl.get(),
|
|
&cch);
|
|
if (S_OK != sc)
|
|
{
|
|
// We've given ScCanonicalizeURL() sufficient space, we
|
|
// should never see S_FALSE here - size can only shrink.
|
|
//
|
|
Assert(S_FALSE != sc);
|
|
DebugTrace ("CMethUtil::ScGetDestination() - ScCanonicalizeUrl() failed 0x%08lX\n", sc);
|
|
goto ret;
|
|
}
|
|
|
|
// Now translate the path, take a best guess and use MAX_PATH as
|
|
// the initial size of the path
|
|
//
|
|
cch = MAX_PATH;
|
|
m_pwszDestinationPath = static_cast<LPWSTR>(g_heap.Alloc(cch * sizeof(WCHAR)));
|
|
|
|
sc = ::ScStoragePathFromUrl (*m_pecb,
|
|
m_pwszDestinationUrl.get(),
|
|
m_pwszDestinationPath.get(),
|
|
&cch,
|
|
m_pcvrDestination.load());
|
|
|
|
// If there was not enough space -- ie. S_FALSE was returned --
|
|
// then reallocate and try again...
|
|
//
|
|
if (sc == S_FALSE)
|
|
{
|
|
m_pwszDestinationPath.realloc(cch * sizeof(WCHAR));
|
|
|
|
sc = ::ScStoragePathFromUrl (*m_pecb,
|
|
m_pwszDestinationUrl.get(),
|
|
m_pwszDestinationPath.get(),
|
|
&cch,
|
|
m_pcvrDestination.load());
|
|
|
|
// We should not get S_FALSE again --
|
|
// we allocated as much space as was requested.
|
|
//
|
|
Assert (S_FALSE != sc);
|
|
}
|
|
if (FAILED(sc))
|
|
goto ret;
|
|
|
|
// We always will get '\0' terminated string back, and cch will indicate
|
|
// the number of characters written (including '\0' termination). Thus it
|
|
// will always be greater than 0 at this point
|
|
//
|
|
Assert( cch > 0 );
|
|
m_cchDestinationPath = cch - 1;
|
|
|
|
// We must remove all trailing slashes, in case the path is not empty string
|
|
//
|
|
if ( 0 != m_cchDestinationPath )
|
|
{
|
|
// Since URL is normalized there may be not more than one trailing slash
|
|
//
|
|
if ((L'\\' == m_pwszDestinationPath[m_cchDestinationPath - 1]) ||
|
|
(L'/' == m_pwszDestinationPath[m_cchDestinationPath - 1]))
|
|
{
|
|
m_cchDestinationPath--;
|
|
m_pwszDestinationPath[m_cchDestinationPath] = L'\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
// We will have S_OK or W_DAV_SPANS_VIRTUAL_ROOTS here.
|
|
// In any case it is success
|
|
//
|
|
Assert(SUCCEEDED(sc));
|
|
|
|
// Return the pointers. For the url, make sure that any
|
|
// prefix is stripped off.
|
|
//
|
|
// Note that the ScStoragePathFromUrl() already has checked
|
|
// to see if the all important prefix matched, so we just need
|
|
// to strip
|
|
//
|
|
*ppwszUrl = PwszUrlStrippedOfPrefix (m_pwszDestinationUrl.get());
|
|
|
|
// Pass everything back to the caller
|
|
//
|
|
*ppwszPath = m_pwszDestinationPath.get();
|
|
*pcchPath = m_cchDestinationPath;
|
|
|
|
// If they wanted the destination virtual root, hand that back
|
|
// as well.
|
|
//
|
|
if (ppcvr)
|
|
{
|
|
*ppcvr = m_pcvrDestination.get();
|
|
}
|
|
|
|
ret:
|
|
|
|
// Do a cleanup if we failed. Subsequent calls to the
|
|
// function just may start returning partial data if
|
|
// we do not do that. That is undesirable.
|
|
//
|
|
if (FAILED (sc))
|
|
{
|
|
if (m_pwszDestinationUrl.get())
|
|
m_pwszDestinationUrl.clear();
|
|
|
|
if (m_pwszDestinationPath.get())
|
|
m_pwszDestinationPath.clear();
|
|
|
|
if (m_pcvrDestination.get())
|
|
m_pcvrDestination.clear();
|
|
|
|
m_cchDestinationPath = 0;
|
|
|
|
//$ WINBUGS: 403726: If we don't pass back the full url, then
|
|
// an incorrect result gets generated and no copy is done.
|
|
//
|
|
*ppwszUrl = pwszFullUrl;
|
|
//
|
|
//$ WINBUGS: end.
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
//
|
|
// CMethUtil::ScGetExpirationTime
|
|
//
|
|
// Gets the expiration time string from the metabase corresponding to a
|
|
// particular resource. If pszURI is NULL and there is information in the
|
|
// metabase for the particular resource, the function will return (in pcb) the number
|
|
// of bytes necessary to pass in as pszBuf to get the requested expiration
|
|
// string.
|
|
//
|
|
// [in] pszURI The resource you want the expiration time string for
|
|
// [in] pszBuf, The buffer we put the string into
|
|
// [in out]pcb On [in], the size of the buffer passed in,
|
|
// On [out], if the buffer size passed in would be
|
|
// insufficient or there was no buffer passed in.
|
|
// Otherwise unchanged from [in].
|
|
//
|
|
// Return values:
|
|
// S_OK: If pszBuf was non-NULL, then the data was successfully retrieved and
|
|
// the length of the actual data was put in pcb.
|
|
// HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER): The buffer passed in is not
|
|
// large enough to hold
|
|
// the requested data.
|
|
// HRESULT_FROM_WIN32(ERROR_NO_DATA): No data for expiration time exists in the
|
|
// metabase for this resource. Default value
|
|
// of 1 day expiration should be used in this
|
|
// case.
|
|
//
|
|
SCODE
|
|
CMethUtil::ScGetExpirationTime(IN LPCWSTR pwszURI,
|
|
IN LPWSTR pwszBuf,
|
|
IN OUT UINT * pcch)
|
|
{
|
|
SCODE sc = S_OK;
|
|
auto_ref_ptr<IMDData> pMDData;
|
|
LPCWSTR pwszExpires = NULL;
|
|
UINT cchExpires;
|
|
|
|
//
|
|
// Fetch the metadata for this URI. If it has a content type map
|
|
// then use it to look for a mapping. If it does not have a content
|
|
// type map then check the global mime map.
|
|
//
|
|
// Note: if we fail to get the metadata at all then default the
|
|
// content type to application/octet-stream. Do not use the global
|
|
// mime map just because we cannot get the metadata.
|
|
//
|
|
if ( FAILED(HrMDGetData(pwszURI, pMDData.load())) ||
|
|
(NULL == (pwszExpires = pMDData->PwszExpires())) )
|
|
{
|
|
sc = HRESULT_FROM_WIN32(ERROR_NO_DATA);
|
|
goto ret;
|
|
}
|
|
|
|
cchExpires = static_cast<UINT>(wcslen(pwszExpires) + 1);
|
|
if (*pcch < cchExpires)
|
|
{
|
|
sc = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
|
*pcch = cchExpires;
|
|
goto ret;
|
|
}
|
|
else
|
|
{
|
|
memcpy(pwszBuf, pwszExpires, cchExpires * sizeof(WCHAR));
|
|
*pcch = cchExpires;
|
|
}
|
|
|
|
ret:
|
|
|
|
return sc;
|
|
}
|
|
|
|
// ScCheckMoveCopyDeleteAccess() ---------------------------------------------
|
|
//
|
|
SCODE
|
|
CMethUtil::ScCheckMoveCopyDeleteAccess (
|
|
/* [in] */ LPCWSTR pwszUrl,
|
|
/* [in] */ CVRoot* pcvrUrl, // OPTIONAL (may be NULL)
|
|
/* [in] */ BOOL fDirectory,
|
|
/* [in] */ BOOL fCheckScriptmaps,
|
|
/* [in] */ DWORD dwAccess)
|
|
{
|
|
Assert (pwszUrl);
|
|
|
|
auto_ref_ptr<IMDData> pMDData;
|
|
BOOL fCGI = FALSE;
|
|
DWORD dwAccessActual = 0;
|
|
SCODE sc = S_OK;
|
|
|
|
// Get the metadata object
|
|
//
|
|
//$ REVIEW: Ideally we could get this without it being cached
|
|
//
|
|
if (NULL == pcvrUrl)
|
|
{
|
|
sc = HrMDGetData (pwszUrl, pMDData.load());
|
|
if (FAILED (sc))
|
|
goto ret;
|
|
}
|
|
else
|
|
{
|
|
LPCWSTR pwszMbPathVRoot;
|
|
CStackBuffer<WCHAR> pwszMbPathChild;
|
|
UINT cchPrefix;
|
|
UINT cchUrl = static_cast<UINT>(wcslen(pwszUrl));
|
|
|
|
// Map the URI to its equivalent metabase path, and make sure
|
|
// the URL is stripped before we call into the MDPath processing
|
|
//
|
|
Assert (pwszUrl == PwszUrlStrippedOfPrefix (pwszUrl));
|
|
cchPrefix = pcvrUrl->CchPrefixOfMetabasePath (&pwszMbPathVRoot);
|
|
if (!pwszMbPathChild.resize(CbSizeWsz(cchPrefix + cchUrl)))
|
|
return E_OUTOFMEMORY;
|
|
|
|
memcpy (pwszMbPathChild.get(), pwszMbPathVRoot, cchPrefix * sizeof(WCHAR));
|
|
memcpy (pwszMbPathChild.get() + cchPrefix, pwszUrl, (cchUrl + 1) * sizeof(WCHAR));
|
|
sc = HrMDGetData (pwszMbPathChild.get(), pwszMbPathVRoot, pMDData.load());
|
|
if (FAILED (sc))
|
|
goto ret;
|
|
}
|
|
//
|
|
//$ REVIEW: end.
|
|
|
|
// Check metabase access to see if we have the minimal access
|
|
// required for this operation.
|
|
//
|
|
dwAccessActual = pMDData->DwAccessPerms();
|
|
if ((dwAccessActual & dwAccess) != dwAccess)
|
|
{
|
|
sc = E_DAV_NO_IIS_ACCESS_RIGHTS;
|
|
goto ret;
|
|
}
|
|
|
|
//$ SECURITY: check for IP restrictions placed on this resource
|
|
//$ REVIEW: this may not be good enough, we may need to do more
|
|
// than this...
|
|
//
|
|
if (!m_pecb->MetaData().FSameIPRestriction(pMDData.get()))
|
|
{
|
|
sc = E_DAV_BAD_DESTINATION;
|
|
goto ret;
|
|
}
|
|
//
|
|
//$ REVIEW: end.
|
|
|
|
//$ SECURITY: Check to see if authorization is different than the
|
|
// request url's authorization.
|
|
//
|
|
if (m_pecb->MetaData().DwAuthorization() != pMDData->DwAuthorization())
|
|
{
|
|
sc = E_DAV_BAD_DESTINATION;
|
|
goto ret;
|
|
}
|
|
//
|
|
//$ REVIEW: end.
|
|
|
|
// Check to see if we have 'star' scriptmap honors over this
|
|
// file.
|
|
//
|
|
if (!m_pecb->MetaData().FSameStarScriptmapping(pMDData.get()))
|
|
{
|
|
sc = E_DAV_STAR_SCRIPTMAPING_MISMATCH;
|
|
goto ret;
|
|
}
|
|
|
|
// Check to see if there is a scriptmap that applies. If so, then
|
|
// we had better have MD_ACCESS_SOURCE rights to do a move or a copy.
|
|
//
|
|
if (fCheckScriptmaps && FInScriptMap(pwszUrl,
|
|
dwAccessActual,
|
|
&fCGI))
|
|
{
|
|
if (0 == (MD_ACCESS_SOURCE & dwAccessActual))
|
|
{
|
|
sc = E_DAV_NO_IIS_ACCESS_RIGHTS;
|
|
goto ret;
|
|
}
|
|
}
|
|
|
|
ret:
|
|
|
|
return sc;
|
|
}
|