2580 lines
61 KiB
C++
2580 lines
61 KiB
C++
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name :
|
|
w3metadata.cxx
|
|
|
|
Abstract:
|
|
Code to read metadata and generate W3_METADATA objects
|
|
|
|
Author:
|
|
Bilal Alam (balam) 23-Jan-2000
|
|
|
|
Environment:
|
|
Win32 - User Mode
|
|
|
|
Project:
|
|
ULW3.DLL
|
|
--*/
|
|
|
|
#include "precomp.hxx"
|
|
#include "redirect.hxx"
|
|
|
|
ALLOC_CACHE_HANDLER * W3_METADATA::sm_pachW3MetaData;
|
|
|
|
W3_METADATA::W3_METADATA( OBJECT_CACHE * pObjectCache )
|
|
: CACHE_ENTRY ( pObjectCache ),
|
|
_dwAccessPerm ( MD_ACCESS_READ ),
|
|
_dwSslAccessPerm ( 0 ),
|
|
_cbIpAccessCheck ( 0 ),
|
|
_dwLogonMethod ( LOGON32_LOGON_INTERACTIVE ),
|
|
_dwVrLevel ( 0 ),
|
|
_dwVrLen ( 0 ),
|
|
_pRedirectBlob ( NULL ),
|
|
_dwDirBrowseFlags ( MD_DIRBROW_LOADDEFAULT ),
|
|
_dwAuthentication ( 0 ),
|
|
_dwAuthPersistence ( 0 ),
|
|
_strUserName ( _rgUserName, sizeof( _rgUserName ) ),
|
|
_strPasswd ( _rgPasswd, sizeof( _rgPasswd ) ),
|
|
_strDomainName ( _rgDomainName, sizeof( _rgDomainName ) ),
|
|
_strRealm ( _rgRealm, sizeof( _rgRealm ) ),
|
|
_pctVrToken ( NULL ),
|
|
_pctAnonymousToken ( NULL ),
|
|
_fCreateProcessAsUser ( TRUE ),
|
|
_fCreateProcessNewConsole ( FALSE ),
|
|
_fDoStaticCompression ( HTTP_COMPRESSION::QueryDoStaticCompression() ),
|
|
_fDoDynamicCompression ( HTTP_COMPRESSION::QueryDoDynamicCompression() ),
|
|
_dwCGIScriptTimeout ( DEFAULT_SCRIPT_TIMEOUT ),
|
|
_ScriptMap (),
|
|
_pMimeMap ( NULL ),
|
|
_fIgnoreTranslate ( FALSE ),
|
|
_fSSIExecDisabled ( FALSE ),
|
|
_fVrPassThrough ( FALSE ),
|
|
_fDontLog ( FALSE ),
|
|
_fFooterEnabled ( FALSE ),
|
|
_dwExpireMode ( EXPIRE_MODE_NONE ),
|
|
_fHaveNoCache ( FALSE ),
|
|
_fHaveMaxAge ( FALSE ),
|
|
_fDoReverseDNS ( FALSE ),
|
|
_cbEntityReadAhead ( DEFAULT_ENTITY_READ_AHEAD ),
|
|
_fNoCache ( FALSE ),
|
|
_fDisableDav ( FALSE ),
|
|
_dwAppIsolated ( 0 ),
|
|
_dwAppOopRecoverLimit ( 0 )
|
|
{
|
|
//
|
|
// Hmmm, since most of these values aren't getting initialized, if
|
|
// somebody went and deleted all the metadata items from the tree,
|
|
// then bad things could happen. We should initialize with defaults
|
|
// things that might screw us
|
|
//
|
|
|
|
_dirmonConfig.hToken = NULL;
|
|
_dirmonConfig.pszDirPath = NULL;
|
|
}
|
|
|
|
W3_METADATA::~W3_METADATA()
|
|
{
|
|
if ( _pctVrToken != NULL )
|
|
{
|
|
_pctVrToken->DereferenceCacheEntry();
|
|
_pctVrToken = NULL;
|
|
}
|
|
|
|
if ( _pctAnonymousToken != NULL )
|
|
{
|
|
_pctAnonymousToken->DereferenceCacheEntry();
|
|
_pctAnonymousToken = NULL;
|
|
}
|
|
|
|
if ( _pMimeMap )
|
|
{
|
|
delete _pMimeMap;
|
|
_pMimeMap = NULL;
|
|
}
|
|
|
|
if (_pRedirectBlob)
|
|
{
|
|
delete _pRedirectBlob;
|
|
_pRedirectBlob = NULL;
|
|
}
|
|
|
|
DBG_ASSERT(CheckSignature());
|
|
}
|
|
|
|
//static
|
|
HRESULT
|
|
W3_METADATA::Initialize(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize metadata lookaside
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ALLOC_CACHE_CONFIGURATION acConfig;
|
|
HRESULT hr;
|
|
|
|
//
|
|
// Initialize allocation lookaside
|
|
//
|
|
|
|
acConfig.nConcurrency = 1;
|
|
acConfig.nThreshold = 100;
|
|
acConfig.cbSize = sizeof( W3_METADATA );
|
|
|
|
DBG_ASSERT( sm_pachW3MetaData == NULL );
|
|
|
|
sm_pachW3MetaData = new ALLOC_CACHE_HANDLER( "W3_METADATA",
|
|
&acConfig );
|
|
|
|
if ( sm_pachW3MetaData == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
|
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"Error initializing sm_pachW3MetaData. hr = 0x%x\n",
|
|
hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//static
|
|
VOID
|
|
W3_METADATA::Terminate(
|
|
VOID
|
|
)
|
|
{
|
|
if ( sm_pachW3MetaData != NULL )
|
|
{
|
|
delete sm_pachW3MetaData;
|
|
sm_pachW3MetaData = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Private constants.
|
|
//
|
|
|
|
#define DEFAULT_MD_RECORDS 40
|
|
#define DEFAULT_RECORD_SIZE 50
|
|
|
|
# define DEF_MD_REC_SIZE ((1 + DEFAULT_MD_RECORDS) * \
|
|
(sizeof(METADATA_GETALL_RECORD) + DEFAULT_RECORD_SIZE))
|
|
|
|
HRESULT
|
|
W3_METADATA::ReadMetaData(
|
|
const STRU & strMetabasePath,
|
|
const STRU & strURL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads the metabase (directly) to get the metadata for the given URL
|
|
|
|
Arguments:
|
|
|
|
strMetabasePath - The preceding service/instance goo (like "LM/W3SVC/1/ROOT" )
|
|
strURL - URL in question
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
PMETADATA_GETALL_RECORD pMDRecord;
|
|
DWORD dwNumMDRecords;
|
|
DWORD dwNumWamRecords;
|
|
BYTE tmpBuffer[ DEF_MD_REC_SIZE];
|
|
BYTE tmpWamBuffer[ DEF_MD_REC_SIZE];
|
|
BUFFER TempBuff( tmpBuffer, DEF_MD_REC_SIZE);
|
|
BUFFER WamBuff( tmpWamBuffer, DEF_MD_REC_SIZE);
|
|
DWORD i;
|
|
DWORD dwDataSetNumber;
|
|
DWORD dwWamDataSetNumber;
|
|
WCHAR ch;
|
|
LPWSTR pszInVr;
|
|
LPWSTR pszMinInVr;
|
|
LPWSTR pszURL;
|
|
DWORD dwNeed;
|
|
DWORD dwL;
|
|
DWORD dwVRLen;
|
|
BYTE tmpPrivateBuffer[ 20 ];
|
|
BUFFER PrivateBuffer( tmpPrivateBuffer, 20 );
|
|
DWORD dwPrivateBufferUsed;
|
|
MB mb( g_pW3Server->QueryMDObject() );
|
|
MB * pmb = &mb;
|
|
HRESULT hr = NO_ERROR;
|
|
WCHAR * pszVrUserName = NULL;
|
|
WCHAR * pszVrPasswd = NULL;
|
|
HANDLE hVrToken = NULL;
|
|
WCHAR * pszStart = NULL;
|
|
DWORD cchLength = 0;
|
|
|
|
//
|
|
// We lie about modifying the input path
|
|
//
|
|
pszURL = (LPWSTR)strURL.QueryStr();
|
|
DBG_ASSERT( pszURL != NULL );
|
|
|
|
DBG_ASSERT( TempBuff.QuerySize() >=
|
|
(DEFAULT_MD_RECORDS *
|
|
(sizeof(METADATA_GETALL_RECORD) + DEFAULT_RECORD_SIZE))
|
|
);
|
|
|
|
DBG_ASSERT( WamBuff.QuerySize() >=
|
|
(DEFAULT_MD_RECORDS *
|
|
(sizeof(METADATA_GETALL_RECORD) + DEFAULT_RECORD_SIZE))
|
|
);
|
|
|
|
//
|
|
// Read the metabase
|
|
//
|
|
|
|
if ( !pmb->Open( strMetabasePath.QueryStr() ))
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// Get the UT_FILE info
|
|
//
|
|
|
|
if ( !pmb->GetAll( pszURL,
|
|
METADATA_INHERIT | METADATA_PARTIAL_PATH,
|
|
IIS_MD_UT_FILE,
|
|
&TempBuff,
|
|
&dwNumMDRecords,
|
|
&dwDataSetNumber ))
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// Get the UT_WAM info
|
|
//
|
|
|
|
if ( !pmb->GetAll( pszURL,
|
|
METADATA_INHERIT | METADATA_PARTIAL_PATH,
|
|
IIS_MD_UT_WAM,
|
|
&WamBuff,
|
|
&dwNumWamRecords,
|
|
&dwWamDataSetNumber ))
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// Both sets of data better have the same data set number
|
|
//
|
|
|
|
DBG_ASSERT( dwDataSetNumber == dwWamDataSetNumber );
|
|
|
|
//
|
|
// Set the data set number, so that this object is metadata cachable
|
|
//
|
|
|
|
_cacheKey.SetDataSetNumber( dwDataSetNumber );
|
|
|
|
//
|
|
// Grok the buffer containing all the records
|
|
//
|
|
|
|
pMDRecord = (PMETADATA_GETALL_RECORD)TempBuff.QueryPtr();
|
|
|
|
i = 0;
|
|
|
|
//
|
|
// Check from where we got VR_PATH
|
|
//
|
|
|
|
pszMinInVr = pszURL ;
|
|
if ( *pszURL )
|
|
{
|
|
for ( pszInVr = pszMinInVr + wcslen(pszMinInVr) ;; )
|
|
{
|
|
ch = *pszInVr;
|
|
*pszInVr = L'\0';
|
|
dwNeed = 0;
|
|
if ( !pmb->GetString( pszURL,
|
|
MD_VR_PATH,
|
|
IIS_MD_UT_FILE,
|
|
NULL,
|
|
&dwNeed,
|
|
0 ) &&
|
|
GetLastError() == ERROR_INSUFFICIENT_BUFFER )
|
|
{
|
|
*pszInVr = ch;
|
|
// VR_PATH was defined at this level !
|
|
|
|
break;
|
|
}
|
|
*pszInVr = ch;
|
|
|
|
if ( ch )
|
|
{
|
|
if ( pszInVr > pszMinInVr )
|
|
{
|
|
pszInVr--;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// VR_PATH was defined above Instance vroot
|
|
// or not at all. If defined above, then the reference
|
|
// path is empty, so we can claim we found it.
|
|
// if not defined, then this will be catch later.
|
|
//
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
// scan for previous delimiter
|
|
|
|
while ( *pszInVr != L'/' && *pszInVr != L'\\' )
|
|
{
|
|
if ( pszInVr > pszMinInVr )
|
|
{
|
|
pszInVr--;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// VR_PATH was defined above Instance vroot
|
|
// or not at all. If defined above, then the reference
|
|
// path is empty, so we can claim we found it.
|
|
// if not defined, then this will be catch later.
|
|
//
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
dwVRLen = DIFF(pszInVr - pszMinInVr);
|
|
}
|
|
else
|
|
{
|
|
dwVRLen = 0;
|
|
pszInVr = pszMinInVr;
|
|
}
|
|
|
|
// Close this now to minimize lock contention.
|
|
DBG_REQUIRE(pmb->Close());
|
|
|
|
for ( dwL = 0 ; pszMinInVr < pszInVr - 1 ; pszMinInVr++ )
|
|
{
|
|
if ( *pszMinInVr == L'/' || *pszMinInVr == L'\\' )
|
|
{
|
|
++dwL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now walk through the array of returned metadata objects and format
|
|
// each one into our predigested form.
|
|
//
|
|
|
|
_dwVrLevel = dwL;
|
|
_dwVrLen = dwVRLen;
|
|
|
|
dwPrivateBufferUsed = 0;
|
|
|
|
for ( ; i < dwNumMDRecords; i++, pMDRecord++ ) {
|
|
|
|
PVOID pDataPointer;
|
|
|
|
pDataPointer = (PVOID) ((PCHAR)TempBuff.QueryPtr() +
|
|
pMDRecord->dwMDDataOffset);
|
|
|
|
DBG_ASSERT(pMDRecord->dwMDDataTag == 0);
|
|
|
|
switch ( pMDRecord->dwMDIdentifier )
|
|
{
|
|
|
|
case MD_DAV_ENABLED:
|
|
if (pMDRecord->dwMDDataType != DWORD_METADATA)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
goto Failure;
|
|
}
|
|
|
|
_fDisableDav = !*((DWORD *) pDataPointer );
|
|
break;
|
|
|
|
case MD_FOOTER_DOCUMENT:
|
|
if (pMDRecord->dwMDDataType != STRING_METADATA)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
goto Failure;
|
|
}
|
|
|
|
if (FAILED(hr = ReadCustomFooter((WCHAR *)pDataPointer)))
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
break;
|
|
|
|
case MD_FOOTER_ENABLED:
|
|
if (pMDRecord->dwMDDataType != DWORD_METADATA)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
goto Failure;
|
|
}
|
|
|
|
_fFooterEnabled = !!*((DWORD *) pDataPointer );
|
|
|
|
if ( _fFooterEnabled )
|
|
{
|
|
//
|
|
// If we have footers for a static file, we cannot do static
|
|
// compression on it
|
|
//
|
|
|
|
_fDoStaticCompression = FALSE;
|
|
}
|
|
break;
|
|
|
|
case MD_HTTP_EXPIRES:
|
|
if (pMDRecord->dwMDDataType != STRING_METADATA)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
goto Failure;
|
|
}
|
|
|
|
if (FAILED(hr = SetExpire((WCHAR *)pDataPointer)))
|
|
{
|
|
goto Failure;
|
|
}
|
|
break;
|
|
|
|
case MD_CC_NO_CACHE:
|
|
if (pMDRecord->dwMDDataType != DWORD_METADATA)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
goto Failure;
|
|
}
|
|
|
|
if (*(BOOL *)pDataPointer)
|
|
{
|
|
_fHaveNoCache = TRUE;
|
|
}
|
|
break;
|
|
|
|
case MD_CC_MAX_AGE:
|
|
if (pMDRecord->dwMDDataType != DWORD_METADATA)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
goto Failure;
|
|
}
|
|
|
|
_dwMaxAge = *(DWORD *)pDataPointer;
|
|
_fHaveMaxAge = TRUE;
|
|
break;
|
|
|
|
case MD_CC_OTHER:
|
|
if (pMDRecord->dwMDDataType != STRING_METADATA)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
goto Failure;
|
|
}
|
|
|
|
if (FAILED(hr = _strCacheControlHeader.CopyWTruncate((WCHAR *)pDataPointer)))
|
|
{
|
|
goto Failure;
|
|
}
|
|
break;
|
|
|
|
case MD_HTTP_REDIRECT:
|
|
{
|
|
if (pMDRecord->dwMDDataType != STRING_METADATA &&
|
|
pMDRecord->dwMDDataType != MULTISZ_METADATA)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
goto Failure;
|
|
}
|
|
|
|
STACK_STRU( strRealSource, MAX_PATH );
|
|
STACK_STRU( strDestination, MAX_PATH );
|
|
|
|
if (FAILED(hr = strDestination.Copy((WCHAR *)pDataPointer)) ||
|
|
FAILED(hr = GetTrueRedirectionSource(
|
|
pszURL,
|
|
strMetabasePath.QueryStr(),
|
|
(WCHAR *)pDataPointer,
|
|
pMDRecord->dwMDDataType == STRING_METADATA,
|
|
&strRealSource)) ||
|
|
FAILED(hr = SetRedirectionBlob(strRealSource,
|
|
strDestination)))
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
if (pMDRecord->dwMDDataType == MULTISZ_METADATA)
|
|
{
|
|
//
|
|
// Have some conditional headers, add them now.
|
|
//
|
|
|
|
if (FAILED(hr = QueryRedirectionBlob()->SetConditionalHeaders(
|
|
(WCHAR *)pDataPointer + wcslen((WCHAR *)pDataPointer) + 1)
|
|
))
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case MD_DONT_LOG:
|
|
if (pMDRecord->dwMDDataType != DWORD_METADATA)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
goto Failure;
|
|
}
|
|
|
|
_fDontLog = *(BOOL *)pDataPointer;
|
|
break;
|
|
|
|
case MD_CREATE_PROCESS_AS_USER:
|
|
if (pMDRecord->dwMDDataType != DWORD_METADATA)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
goto Failure;
|
|
}
|
|
|
|
_fCreateProcessAsUser = *(BOOL *)pDataPointer;
|
|
break;
|
|
|
|
case MD_CREATE_PROC_NEW_CONSOLE:
|
|
if (pMDRecord->dwMDDataType != DWORD_METADATA)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
goto Failure;
|
|
}
|
|
|
|
_fCreateProcessNewConsole = *(BOOL *)pDataPointer;
|
|
break;
|
|
|
|
case MD_SCRIPT_TIMEOUT:
|
|
if (pMDRecord->dwMDDataType != DWORD_METADATA)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
goto Failure;
|
|
}
|
|
|
|
_dwCGIScriptTimeout = *(DWORD *)pDataPointer;
|
|
break;
|
|
|
|
case MD_MIME_MAP:
|
|
if (pMDRecord->dwMDDataType != MULTISZ_METADATA)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
goto Failure;
|
|
}
|
|
|
|
if (*(WCHAR *)pDataPointer)
|
|
{
|
|
_pMimeMap = new MIME_MAP((WCHAR *)pDataPointer);
|
|
if (_pMimeMap == NULL)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto Failure;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MD_HC_DO_NAMESPACE_DYNAMIC_COMPRESSION:
|
|
if (pMDRecord->dwMDDataType != DWORD_METADATA)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
goto Failure;
|
|
}
|
|
|
|
_fDoDynamicCompression = *(BOOL *)pDataPointer;
|
|
break;
|
|
|
|
case MD_HC_DO_NAMESPACE_STATIC_COMPRESSION:
|
|
if (pMDRecord->dwMDDataType != DWORD_METADATA)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
goto Failure;
|
|
}
|
|
|
|
_fDoStaticCompression = *(BOOL *)pDataPointer;
|
|
break;
|
|
|
|
case MD_VR_IGNORE_TRANSLATE:
|
|
if (pMDRecord->dwMDDataType != DWORD_METADATA)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
goto Failure;
|
|
}
|
|
|
|
_fIgnoreTranslate = *(DWORD*) pDataPointer;
|
|
break;
|
|
|
|
case MD_ANONYMOUS_USER_NAME:
|
|
if ( pMDRecord->dwMDDataType != STRING_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
if ( FAILED( hr = _strUserName.Copy(
|
|
(WCHAR *)pDataPointer) ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
break;
|
|
|
|
case MD_ANONYMOUS_PWD:
|
|
if ( pMDRecord->dwMDDataType != STRING_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
if ( FAILED( hr = _strPasswd.Copy(
|
|
(WCHAR *)pDataPointer) ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
break;
|
|
|
|
case MD_DEFAULT_LOGON_DOMAIN:
|
|
if ( pMDRecord->dwMDDataType != STRING_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
if ( FAILED( hr = _strDomainName.Copy(
|
|
(WCHAR *)pDataPointer) ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
break;
|
|
|
|
case MD_HTTP_PICS:
|
|
case MD_HTTP_CUSTOM:
|
|
|
|
if ( pMDRecord->dwMDDataType != MULTISZ_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// Copy all the specified headers into our header buffer
|
|
//
|
|
|
|
pszStart = (WCHAR*) pDataPointer;
|
|
while ( *pszStart != L'\0' )
|
|
{
|
|
cchLength = wcslen( pszStart );
|
|
|
|
hr = _strCustomHeaders.AppendW( pszStart );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
hr = _strCustomHeaders.Append( "\r\n", 2 );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
pszStart += ( cchLength + 1 );
|
|
}
|
|
break;
|
|
|
|
case MD_LOGON_METHOD:
|
|
if ( pMDRecord->dwMDDataType != DWORD_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// The MD_LOGON_METHOD values in the metabase don't match
|
|
// the NT logon values, so we'll convert them
|
|
//
|
|
switch ( *((DWORD *) pDataPointer ) )
|
|
{
|
|
case MD_LOGON_BATCH:
|
|
_dwLogonMethod = LOGON32_LOGON_BATCH;
|
|
break;
|
|
|
|
case MD_LOGON_INTERACTIVE:
|
|
_dwLogonMethod = LOGON32_LOGON_INTERACTIVE;
|
|
break;
|
|
|
|
case MD_LOGON_NETWORK:
|
|
_dwLogonMethod = LOGON32_LOGON_NETWORK;
|
|
break;
|
|
|
|
case MD_LOGON_NETWORK_CLEARTEXT:
|
|
_dwLogonMethod = LOGON32_LOGON_NETWORK_CLEARTEXT;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case MD_AUTHORIZATION:
|
|
if( pMDRecord->dwMDDataType != DWORD_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
_dwAuthentication = *((DWORD *) pDataPointer );
|
|
break;
|
|
|
|
case MD_REALM:
|
|
if( pMDRecord->dwMDDataType != STRING_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
if( FAILED( hr = _strRealm.Copy( ( WCHAR* )pDataPointer ) ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
break;
|
|
|
|
case MD_NTAUTHENTICATION_PROVIDERS:
|
|
if( pMDRecord->dwMDDataType != STRING_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
hr = BuildProviderList( ( WCHAR* )pDataPointer );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
break;
|
|
|
|
case MD_AUTHORIZATION_PERSISTENCE:
|
|
if( pMDRecord->dwMDDataType != DWORD_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
_dwAuthPersistence = *((DWORD *) pDataPointer );
|
|
break;
|
|
|
|
case MD_IP_SEC:
|
|
if( pMDRecord->dwMDDataType != BINARY_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
if ( pMDRecord->dwMDDataLen )
|
|
{
|
|
hr = SetIpAccessCheck( pDataPointer,
|
|
pMDRecord->dwMDDataLen );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case MD_ACCESS_PERM:
|
|
if ( pMDRecord->dwMDDataType != DWORD_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
_dwAccessPerm = *((DWORD*) pDataPointer);
|
|
break;
|
|
|
|
case MD_SSL_ACCESS_PERM:
|
|
if ( pMDRecord->dwMDDataType != DWORD_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
_dwSslAccessPerm = *((DWORD*)pDataPointer) & MD_SSL_ACCESS_MASK;
|
|
break;
|
|
|
|
case MD_VR_PATH:
|
|
if ( pMDRecord->dwMDDataType != STRING_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
if ( FAILED( hr = _strVrPath.Copy((WCHAR *)pDataPointer) ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
break;
|
|
|
|
case MD_APP_ROOT:
|
|
|
|
if ( pMDRecord->dwMDDataType != STRING_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
if ( FAILED( hr = _strAppMetaPath.Copy((WCHAR *)pDataPointer) ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
break;
|
|
|
|
case MD_VR_USERNAME:
|
|
if ( pMDRecord->dwMDDataType != STRING_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
pszVrUserName = ( WCHAR * )pDataPointer;
|
|
|
|
break;
|
|
|
|
case MD_VR_PASSWORD:
|
|
if ( pMDRecord->dwMDDataType != STRING_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
pszVrPasswd = ( WCHAR * )pDataPointer;
|
|
|
|
break;
|
|
|
|
case MD_VR_PASSTHROUGH:
|
|
if ( pMDRecord->dwMDDataType != DWORD_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
_fVrPassThrough = !!*((DWORD *) pDataPointer );
|
|
|
|
break;
|
|
|
|
case MD_REDIRECT_HEADERS:
|
|
if ( pMDRecord->dwMDDataType != MULTISZ_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// Copy all the specified headers into our header buffer
|
|
//
|
|
|
|
pszStart = (WCHAR*) pDataPointer;
|
|
while ( *pszStart != L'\0' )
|
|
{
|
|
cchLength = wcslen( pszStart );
|
|
|
|
hr = _strRedirectHeaders.AppendW( pszStart );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
hr = _strRedirectHeaders.Append( "\r\n", 2 );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
pszStart += ( cchLength + 1 );
|
|
}
|
|
break;
|
|
|
|
case MD_DIRECTORY_BROWSING:
|
|
if ( pMDRecord->dwMDDataType != DWORD_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
_dwDirBrowseFlags = *((DWORD *) pDataPointer );
|
|
break;
|
|
|
|
case MD_DEFAULT_LOAD_FILE:
|
|
if ( pMDRecord->dwMDDataType != STRING_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
hr = _strDefaultLoad.Copy( (WCHAR*) pDataPointer );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
break;
|
|
|
|
case MD_SCRIPT_MAPS:
|
|
if ( pMDRecord->dwMDDataType != MULTISZ_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
hr = _ScriptMap.Initialize( (WCHAR *)pDataPointer );
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
break;
|
|
|
|
case MD_CUSTOM_ERROR:
|
|
if ( pMDRecord->dwMDDataType != MULTISZ_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// An empty string means use hard-coded errors
|
|
//
|
|
|
|
if ( *((WCHAR*)pDataPointer) == L'\0' )
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = _customErrorTable.BuildTable( (WCHAR*) pDataPointer );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
break;
|
|
|
|
case MD_SSI_EXEC_DISABLED:
|
|
if ( pMDRecord->dwMDDataType != DWORD_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
_fSSIExecDisabled = !!*( ( DWORD * ) pDataPointer );
|
|
break;
|
|
|
|
case MD_DO_REVERSE_DNS:
|
|
if ( pMDRecord->dwMDDataType != DWORD_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
_fDoReverseDNS = !!*((DWORD*)pDataPointer);
|
|
break;
|
|
|
|
case MD_UPLOAD_READAHEAD_SIZE:
|
|
if ( pMDRecord->dwMDDataType != DWORD_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
_cbEntityReadAhead = *(DWORD*)pDataPointer;
|
|
break;
|
|
|
|
case MD_APPPOOL_APPPOOL_ID:
|
|
|
|
if ( pMDRecord->dwMDDataType != STRING_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
hr = _strAppPoolId.Copy( (WCHAR*) pDataPointer );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
break;
|
|
|
|
case MD_VR_NO_CACHE:
|
|
|
|
if ( pMDRecord->dwMDDataType != DWORD_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
_fNoCache = !!*((DWORD*)pDataPointer);
|
|
break;
|
|
|
|
default:
|
|
// BUGBUGBUG
|
|
DBG_ASSERT(CheckSignature());
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Walk through the WAM data
|
|
//
|
|
|
|
pMDRecord = (PMETADATA_GETALL_RECORD)WamBuff.QueryPtr();
|
|
|
|
i = 0;
|
|
|
|
for ( ; i < dwNumWamRecords; i++, pMDRecord++ ) {
|
|
|
|
PVOID pDataPointer;
|
|
|
|
pDataPointer = (PVOID) ((PCHAR)WamBuff.QueryPtr() +
|
|
pMDRecord->dwMDDataOffset);
|
|
|
|
DBG_ASSERT(pMDRecord->dwMDDataTag == 0);
|
|
|
|
switch ( pMDRecord->dwMDIdentifier )
|
|
{
|
|
case MD_APP_ISOLATED:
|
|
|
|
if ( pMDRecord->dwMDDataType != DWORD_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
_dwAppIsolated = *(DWORD*)pDataPointer;
|
|
|
|
break;
|
|
|
|
case MD_APP_WAM_CLSID:
|
|
|
|
if ( pMDRecord->dwMDDataType != STRING_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
hr = _strWamClsId.Copy( (WCHAR*)pDataPointer );
|
|
|
|
break;
|
|
|
|
case MD_APP_OOP_RECOVER_LIMIT:
|
|
|
|
if ( pMDRecord->dwMDDataType != DWORD_METADATA )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
goto Failure;
|
|
}
|
|
|
|
_dwAppOopRecoverLimit = *(DWORD*)pDataPointer;
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If no-cache, max-age or a dynamic expires directive is present, add
|
|
// it to Cache-Control header
|
|
//
|
|
if (FAILED(hr = SetCacheControlHeader()))
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
if ( _strVrPath.IsEmpty() )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"[ReadMetaData] Virtual Dir Path mapping not found\n" ));
|
|
|
|
hr = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// If this is an UNC share, logon using associated credentials
|
|
// keep a reference to this access token in the cache
|
|
//
|
|
|
|
if ( _strVrPath.QueryStr()[0] == L'\\' &&
|
|
_strVrPath.QueryStr()[1] == L'\\' )
|
|
{
|
|
if ( pszVrUserName != NULL && pszVrPasswd != NULL &&
|
|
pszVrUserName[0] )
|
|
{
|
|
hr = CreateUNCVrToken( pszVrUserName, pszVrPasswd );
|
|
if( FAILED( hr ) )
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT,
|
|
"Error logging on the UNC account. hr = 0x%x.\n",
|
|
hr ));
|
|
|
|
goto Failure;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Setup the dirmon configuration
|
|
//
|
|
|
|
if ( _pctVrToken != NULL )
|
|
{
|
|
_dirmonConfig.hToken = _pctVrToken->QueryImpersonationToken();
|
|
}
|
|
else
|
|
{
|
|
_dirmonConfig.hToken = NULL;
|
|
}
|
|
_dirmonConfig.pszDirPath = _strVrPath.QueryStr();
|
|
|
|
//
|
|
// Get anonymous user token
|
|
//
|
|
|
|
hr = CreateAnonymousToken( _strUserName.QueryStr(),
|
|
_strPasswd.QueryStr() );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
DBG_ASSERT( CheckSignature() );
|
|
|
|
return S_OK;
|
|
|
|
Failure:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
W3_METADATA::BuildPhysicalPath(
|
|
STRU & strUrl,
|
|
STRU * pstrPhysicalPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
From the current metadata, convert a URL to a physical path
|
|
(using the MD_VR_ROOT property and inheritance level calculated on read)
|
|
|
|
Arguments:
|
|
|
|
strUrl - Virtual path
|
|
pstrPhysicalPath - String filled with physical path of strURL
|
|
|
|
Return Value:
|
|
|
|
BOOL
|
|
|
|
--*/
|
|
{
|
|
LPWSTR pszInVr;
|
|
DWORD dwL;
|
|
WCHAR ch;
|
|
HRESULT hr = S_OK;
|
|
|
|
DBG_ASSERT(CheckSignature());
|
|
|
|
//
|
|
// Build physical path from VR_PATH & portion of URI not used to define VR_PATH
|
|
//
|
|
|
|
|
|
//
|
|
// skip the URI components used to locate the virtual root
|
|
//
|
|
|
|
pszInVr = strUrl.QueryStr();
|
|
dwL = _dwVrLevel;
|
|
while ( dwL-- )
|
|
{
|
|
if ( *pszInVr )
|
|
{
|
|
DBG_ASSERT( *pszInVr == L'/' || *pszInVr == L'\\' );
|
|
|
|
++pszInVr;
|
|
|
|
while ( (ch = *pszInVr) && ch != L'/' && ch !=L'\\' )
|
|
{
|
|
pszInVr++;
|
|
}
|
|
}
|
|
}
|
|
|
|
DBG_ASSERT( dwL == (DWORD)-1 );
|
|
|
|
if ( FAILED(hr = pstrPhysicalPath->Copy( _strVrPath ) ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Add a path delimiter char between virtual root mount point & significant part of URI
|
|
//
|
|
|
|
if ( pstrPhysicalPath->QueryCCH() )
|
|
{
|
|
ch = pstrPhysicalPath->QueryStr()[ pstrPhysicalPath->QueryCCH() - 1 ];
|
|
if ( (ch == L'/' || ch == L'\\') && *pszInVr )
|
|
{
|
|
++pszInVr;
|
|
}
|
|
}
|
|
|
|
if ( FAILED(hr = pstrPhysicalPath->Append( pszInVr ) ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// insure physical path last char uses standard directory delimiter
|
|
//
|
|
|
|
FlipSlashes( pstrPhysicalPath->QueryStr() );
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
HRESULT
|
|
W3_METADATA::BuildProviderList(
|
|
IN WCHAR * pszProviders
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Builds a name array of SSPI Authentication providers
|
|
|
|
Arguments:
|
|
|
|
pszProviders - Comma separated list of providers
|
|
|
|
Returns:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
WCHAR * pszCursor;
|
|
WCHAR * pszEnd;
|
|
HRESULT hr;
|
|
BOOL fFinished = FALSE;
|
|
|
|
DBG_ASSERT(CheckSignature());
|
|
|
|
if ( pszProviders == NULL )
|
|
{
|
|
DBG_ASSERT( FALSE );
|
|
return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
|
}
|
|
|
|
//
|
|
// Parse comma delimited list of providers, removing white space
|
|
//
|
|
|
|
pszCursor = SkipWhite( pszProviders );
|
|
for( ; ; )
|
|
{
|
|
pszEnd = wcschr( pszCursor, L',' );
|
|
if ( pszEnd == NULL )
|
|
{
|
|
fFinished = TRUE;
|
|
pszEnd = pszCursor + wcslen( pszCursor );
|
|
}
|
|
|
|
while ( pszEnd > pszCursor )
|
|
{
|
|
if ( !ISWHITEW( *pszEnd ) )
|
|
{
|
|
break;
|
|
}
|
|
pszEnd--;
|
|
}
|
|
|
|
*pszEnd = L'\0';
|
|
|
|
if ( !_mstrAuthProviders.AppendW( pszCursor ) )
|
|
{
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
if ( fFinished )
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Advance to next provider
|
|
//
|
|
|
|
pszCursor = SkipWhite( pszEnd + 1 );
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
BOOL
|
|
W3_METADATA::CheckAuthProvider(
|
|
IN CHAR * pszPkgName
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Check if we support the SSP package of name pszPkgName
|
|
|
|
Arguments:
|
|
|
|
pszPkgName - Name of the package we check against
|
|
|
|
Returns:
|
|
|
|
TRUE if we support the package, FALSE if we don't.
|
|
|
|
--*/
|
|
{
|
|
const CHAR * pszProvider;
|
|
|
|
DBG_ASSERT( CheckSignature() );
|
|
|
|
if ( pszPkgName == NULL )
|
|
{
|
|
DBG_ASSERT( FALSE );
|
|
return FALSE;
|
|
}
|
|
|
|
pszProvider = _mstrAuthProviders.First();
|
|
while ( pszProvider != NULL )
|
|
{
|
|
if ( _stricmp( pszPkgName, pszProvider ) == 0 )
|
|
{
|
|
return TRUE;
|
|
}
|
|
pszProvider = _mstrAuthProviders.Next( pszProvider );
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT
|
|
W3_METADATA::CreateUNCVrToken(
|
|
IN LPWSTR pszUserName,
|
|
IN LPWSTR pszPasswd
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Logon the user account for the UNC virtual path
|
|
|
|
Arguments:
|
|
|
|
pszUserName - User name of the account in format domain\username
|
|
pszPasswd - Passwd of the account
|
|
|
|
Returns:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
STACK_STRU( strUserName, UNLEN + 1 );
|
|
STACK_STRU( strDomainName, IIS_DNLEN + 1 );
|
|
// add 1 to strUserDomain for separator "\"
|
|
STACK_STRU( strUserDomain, UNLEN + IIS_DNLEN + 1 + 1);
|
|
HRESULT hr;
|
|
DWORD dwError;
|
|
BOOL fPossibleUPNLogon = FALSE;
|
|
|
|
hr = strUserDomain.Copy( pszUserName );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
hr = W3_STATE_AUTHENTICATION::SplitUserDomain( strUserDomain,
|
|
&strUserName,
|
|
&strDomainName,
|
|
QueryDomainName(),
|
|
&fPossibleUPNLogon );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
DBG_ASSERT( g_pW3Server->QueryTokenCache() != NULL );
|
|
|
|
hr = g_pW3Server->QueryTokenCache()->GetCachedToken(
|
|
strUserName.QueryStr(),
|
|
strDomainName.QueryStr(),
|
|
pszPasswd,
|
|
QueryLogonMethod(),
|
|
fPossibleUPNLogon,
|
|
&_pctVrToken,
|
|
&dwError );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
HRESULT
|
|
W3_METADATA::CreateAnonymousToken(
|
|
IN LPWSTR pszUserName,
|
|
IN LPWSTR pszPasswd
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Logon the user account for the UNC virtual path
|
|
|
|
Arguments:
|
|
|
|
pszUserName - User name of the account in format domain\username
|
|
pszPasswd - Passwd of the account
|
|
|
|
Returns:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
STACK_STRU( strUserName, UNLEN );
|
|
STACK_STRU( strDomainName, IIS_DNLEN );
|
|
// add 1 to strUserDomain for separator "\"
|
|
STACK_STRU( strUserDomain, UNLEN + IIS_DNLEN + 1 );
|
|
HRESULT hr;
|
|
DWORD dwLogonError;
|
|
BOOL fPossibleUPNLogon = FALSE;
|
|
|
|
hr = strUserDomain.Copy( pszUserName );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
hr = W3_STATE_AUTHENTICATION::SplitUserDomain( strUserDomain,
|
|
&strUserName,
|
|
&strDomainName,
|
|
QueryDomainName(),
|
|
&fPossibleUPNLogon );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
DBG_ASSERT( g_pW3Server->QueryTokenCache() != NULL );
|
|
|
|
hr = g_pW3Server->QueryTokenCache()->GetCachedToken(
|
|
strUserName.QueryStr(),
|
|
strDomainName.QueryStr(),
|
|
pszPasswd,
|
|
QueryLogonMethod(),
|
|
fPossibleUPNLogon,
|
|
&_pctAnonymousToken,
|
|
&dwLogonError );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
HRESULT
|
|
W3_METADATA::SetIpAccessCheck(
|
|
LPVOID pMDData,
|
|
DWORD dwDataLen
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Store away the IP DNS list
|
|
|
|
Arguments:
|
|
|
|
pMDData - Beginning of binary blob to store
|
|
dwDataLen - Length of binary data
|
|
|
|
Returns:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
if ( !_buffIpAccessCheck.Resize( dwDataLen ) )
|
|
{
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
memcpy( _buffIpAccessCheck.QueryPtr(),
|
|
pMDData,
|
|
dwDataLen );
|
|
|
|
_cbIpAccessCheck = dwDataLen;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
HRESULT
|
|
W3_METADATA::ReadCustomFooter(
|
|
WCHAR * pszFooter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process a footer string, either reading the file or copying the string
|
|
to the buffer.
|
|
|
|
Arguments:
|
|
|
|
pszFooter - The footer string, which may be a string or a file name.
|
|
It looks like "STRING : some-string" or "FILE : file-name"
|
|
|
|
Returns:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr;
|
|
STACK_STRU( strFooter, MAX_PATH );
|
|
BOOL fFooterIsString = FALSE;
|
|
|
|
// First thing to do is to determine if this is a string or a file name.
|
|
// Skip preceding whitespace and then strcmp.
|
|
|
|
while (iswspace(*pszFooter))
|
|
{
|
|
pszFooter++;
|
|
}
|
|
|
|
if (!_wcsnicmp(pszFooter, L"STRING", 6))
|
|
{
|
|
fFooterIsString = TRUE;
|
|
pszFooter += 6;
|
|
}
|
|
else if (!_wcsnicmp(pszFooter, L"FILE", 4))
|
|
{
|
|
fFooterIsString = FALSE;
|
|
pszFooter += 4;
|
|
}
|
|
else
|
|
{
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
// Now we look for 0 or more white space, followed by a colon, followed by
|
|
// more white space.
|
|
|
|
while (iswspace(*pszFooter))
|
|
{
|
|
pszFooter++;
|
|
}
|
|
|
|
if (*pszFooter != L':')
|
|
{
|
|
// No colon seperator, error.
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
pszFooter++;
|
|
|
|
//
|
|
// OK, now if this is a string we take everything after the colon to the
|
|
// end for the string. If this is a file name then we'll open and read the
|
|
// file.
|
|
//
|
|
if (fFooterIsString)
|
|
{
|
|
return _strFooterString.CopyW(pszFooter);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// For files, we'll skip any more white space before the name.
|
|
//
|
|
while (iswspace(*pszFooter))
|
|
{
|
|
pszFooter++;
|
|
}
|
|
|
|
hr = _strFooterDocument.Copy( pszFooter );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT W3_METADATA::SetExpire(WCHAR *pszExpire)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the expire header to be used on all responses
|
|
|
|
Arguments:
|
|
|
|
pszExpire: the string containing the description. It could have the form
|
|
"n" : no expire
|
|
"s, some-date" : expire on this date"
|
|
"d, some-number" : expire after this many seconds
|
|
|
|
Returns:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
while (iswspace(*pszExpire))
|
|
{
|
|
pszExpire++;
|
|
}
|
|
|
|
LPWSTR pszParam;
|
|
if ((pszParam = wcschr(pszExpire, L',')) == NULL)
|
|
{
|
|
if (*pszExpire == L'\0' ||
|
|
*pszExpire == L'n' ||
|
|
*pszExpire == L'N')
|
|
{
|
|
_dwExpireMode = EXPIRE_MODE_OFF;
|
|
return S_OK;
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
pszParam++;
|
|
while (iswspace(*pszParam))
|
|
{
|
|
pszParam++;
|
|
}
|
|
|
|
HRESULT hr;
|
|
switch (*pszExpire)
|
|
{
|
|
case L's':
|
|
case L'S':
|
|
if (FAILED(hr = _strExpireHeader.CopyWTruncate(pszParam)))
|
|
{
|
|
return hr;
|
|
}
|
|
_dwExpireMode = EXPIRE_MODE_STATIC;
|
|
break;
|
|
|
|
case L'd':
|
|
case L'D':
|
|
LPWSTR endPtr;
|
|
DWORD dwExpire;
|
|
|
|
if (pszParam[0] == L'0' && pszParam[1] == L'x')
|
|
{
|
|
dwExpire = wcstoul(pszParam + 2, &endPtr, 16);
|
|
}
|
|
else
|
|
{
|
|
dwExpire = wcstoul(pszParam, &endPtr, 10);
|
|
}
|
|
|
|
if (!iswspace(*endPtr) &&
|
|
*endPtr != L'\0')
|
|
{
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
if (dwExpire != ULONG_MAX)
|
|
{
|
|
if (dwExpire > MAX_GLOBAL_EXPIRE)
|
|
{
|
|
dwExpire = MAX_GLOBAL_EXPIRE;
|
|
}
|
|
|
|
_dwExpireMode = EXPIRE_MODE_DYNAMIC;
|
|
_dwExpireDelta = dwExpire;
|
|
}
|
|
break;
|
|
|
|
case L'n':
|
|
case L'N':
|
|
_dwExpireMode = EXPIRE_MODE_OFF;
|
|
break;
|
|
|
|
default:
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT W3_METADATA::SetCacheControlHeader()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
If no-cache, max-age or a dynamic expires directive is present, add
|
|
it to Cache-Control header
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
switch (QueryExpireMode())
|
|
{
|
|
case EXPIRE_MODE_NONE:
|
|
_fHaveNoCache = FALSE;
|
|
_fHaveMaxAge = FALSE;
|
|
break;
|
|
|
|
case EXPIRE_MODE_DYNAMIC:
|
|
// If we have a dynamic Expires header, create a max-age directive
|
|
if (_dwExpireDelta != 0)
|
|
{
|
|
_fHaveNoCache = FALSE;
|
|
if (!_fHaveMaxAge)
|
|
{
|
|
_fHaveMaxAge = TRUE;
|
|
_dwMaxAge = _dwExpireDelta;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_fHaveNoCache = TRUE;
|
|
_fHaveMaxAge = FALSE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
BOOL fHaveCCHeader = !_strCacheControlHeader.IsEmpty();
|
|
HRESULT hr;
|
|
if (_fHaveNoCache)
|
|
{
|
|
if (FAILED(hr = _strCacheControlHeader.Append(
|
|
fHaveCCHeader ? ",no-cache" : "no-cache")))
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
else if (_fHaveMaxAge)
|
|
{
|
|
CHAR pszMaxAgeBuffer[16];
|
|
_itoa(_dwMaxAge, pszMaxAgeBuffer, 10);
|
|
|
|
if (FAILED(hr = _strCacheControlHeader.Append(
|
|
fHaveCCHeader ? ",max-age=" : "max-age=")) ||
|
|
FAILED(hr = _strCacheControlHeader.Append(pszMaxAgeBuffer)))
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
META_SCRIPT_MAP::Initialize(
|
|
IN WCHAR * szScriptMapData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize the collection of META_SCRIPT_MAP_ENTRIES from the
|
|
metadata.
|
|
|
|
This routine will modify the multisz it works with (by replacing
|
|
some ',' with '\0' ).
|
|
|
|
Currently it modifies the in parameter, which is kindof icky.
|
|
We could avoid this by copying the buffer.
|
|
|
|
Arguments:
|
|
|
|
szScriptMapData - A multi-sz of script map entries.
|
|
|
|
|
|
Return Value:
|
|
|
|
Notes:
|
|
|
|
Script map is a multi-sz with each string being a comma separated list
|
|
<extension>,<executable>,<flags>,<verb list>
|
|
|
|
<extension>:
|
|
.xyz - Maximum of 128 characters
|
|
* - Star script map - routes all requests though the executable
|
|
|
|
<executable>
|
|
- Extension to invoke
|
|
|
|
<flags>:
|
|
1 - Allow run in script access directory ( MD_SCRIPTMAPFLAG_SCRIPT )
|
|
4 - Check for pathinfo file ( MD_SCRIPTMAPFLAG_CHECK_PATH_INFO )
|
|
|
|
<verb list>:
|
|
<verb>,<verb>,<verb>
|
|
- Allowed verbs
|
|
- If no verbs are listed, a value of "all verbs" is assumed.
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT( szScriptMapData );
|
|
|
|
HRESULT hr = NOERROR;
|
|
|
|
// Iterate over multisz
|
|
WCHAR * pszEntryIterator;
|
|
|
|
// Current mapping
|
|
WCHAR * pszExtension;
|
|
WCHAR * pszExecutable;
|
|
WCHAR * pszFlags;
|
|
DWORD Flags;
|
|
WCHAR * pszVerbs;
|
|
DWORD cchVerbs;
|
|
|
|
//
|
|
// Iterate over each mapping
|
|
//
|
|
|
|
pszEntryIterator = szScriptMapData;
|
|
while( *pszEntryIterator != L'\0' )
|
|
{
|
|
//
|
|
// Get the extension
|
|
//
|
|
|
|
pszExtension = pszEntryIterator;
|
|
|
|
//
|
|
// Get the executable
|
|
//
|
|
|
|
pszEntryIterator = wcschr( pszEntryIterator, L',' );
|
|
if( pszEntryIterator == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
return hr;
|
|
}
|
|
|
|
*pszEntryIterator++ = L'\0';
|
|
|
|
pszExecutable = pszEntryIterator;
|
|
|
|
if( pszExecutable == L'\0' )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Get the flags
|
|
//
|
|
|
|
pszEntryIterator = wcschr( pszEntryIterator, L',' );
|
|
if( pszEntryIterator == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
return hr;
|
|
}
|
|
|
|
*pszEntryIterator++ = L'\0';
|
|
|
|
//
|
|
// We don't need pszFlags here, but we will need it if
|
|
// there is an empty verb list, to reset our iterator.
|
|
//
|
|
pszFlags = pszEntryIterator;
|
|
|
|
Flags = wcstoul( pszFlags, NULL, 10 );
|
|
|
|
//
|
|
// Get the verbs
|
|
//
|
|
|
|
pszEntryIterator = wcschr( pszEntryIterator, L',' );
|
|
if( pszEntryIterator != NULL )
|
|
{
|
|
//
|
|
// There is a list of verbs
|
|
//
|
|
|
|
*pszEntryIterator++ = L'\0';
|
|
|
|
pszVerbs = pszEntryIterator;
|
|
|
|
//
|
|
// Format verb list as a multi-sz for each entry
|
|
//
|
|
|
|
cchVerbs = 1;
|
|
|
|
while( *pszEntryIterator != L'\0')
|
|
{
|
|
if( *pszEntryIterator == L',' )
|
|
{
|
|
*pszEntryIterator = L'\0';
|
|
}
|
|
|
|
cchVerbs++;
|
|
|
|
pszEntryIterator++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Empty Verb List
|
|
//
|
|
|
|
//
|
|
// We've lost our iterator so we need to get it back.
|
|
// Point to the terminator.
|
|
//
|
|
pszEntryIterator = pszFlags + wcslen( pszFlags );
|
|
|
|
pszVerbs = pszEntryIterator;
|
|
cchVerbs = 1;
|
|
}
|
|
|
|
|
|
//
|
|
// Create and add the entry object to our list
|
|
//
|
|
|
|
META_SCRIPT_MAP_ENTRY *
|
|
pNewEntry = new META_SCRIPT_MAP_ENTRY();
|
|
|
|
if( pNewEntry == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
return hr;
|
|
}
|
|
|
|
hr = pNewEntry->Create( pszExtension,
|
|
pszExecutable,
|
|
Flags,
|
|
pszVerbs,
|
|
cchVerbs
|
|
);
|
|
if( FAILED(hr) )
|
|
{
|
|
delete pNewEntry;
|
|
return hr;
|
|
}
|
|
|
|
if (pNewEntry->QueryIsStarScriptMap())
|
|
{
|
|
if (m_StarScriptMapEntry != NULL)
|
|
{
|
|
delete m_StarScriptMapEntry;
|
|
}
|
|
m_StarScriptMapEntry = pNewEntry;
|
|
}
|
|
else
|
|
{
|
|
InsertTailList( &m_ListHead, &pNewEntry->m_ListEntry );
|
|
}
|
|
|
|
//
|
|
// Move to the next entry.
|
|
//
|
|
pszEntryIterator++;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
BOOL
|
|
META_SCRIPT_MAP::FindEntry(
|
|
IN const STRU & strExtension,
|
|
OUT META_SCRIPT_MAP_ENTRY * * ppScriptMapEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
*ppScriptMapEntry = NULL;
|
|
|
|
PLIST_ENTRY pEntry;
|
|
META_SCRIPT_MAP_ENTRY * pScriptMapEntry = NULL;
|
|
|
|
for( pEntry = m_ListHead.Flink;
|
|
pEntry != &m_ListHead;
|
|
pEntry = pEntry->Flink )
|
|
{
|
|
pScriptMapEntry = CONTAINING_RECORD( pEntry,
|
|
META_SCRIPT_MAP_ENTRY,
|
|
m_ListEntry
|
|
);
|
|
|
|
if( strExtension.Equals( pScriptMapEntry->m_strExtension ) )
|
|
{
|
|
*ppScriptMapEntry = pScriptMapEntry;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
VOID
|
|
META_SCRIPT_MAP::Terminate( VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
if (m_StarScriptMapEntry != NULL)
|
|
{
|
|
delete m_StarScriptMapEntry;
|
|
m_StarScriptMapEntry = NULL;
|
|
}
|
|
|
|
META_SCRIPT_MAP_ENTRY * pScriptMapEntry;
|
|
|
|
while( !IsListEmpty( &m_ListHead ) )
|
|
{
|
|
pScriptMapEntry = CONTAINING_RECORD( m_ListHead.Flink,
|
|
META_SCRIPT_MAP_ENTRY,
|
|
m_ListEntry );
|
|
|
|
RemoveEntryList( &pScriptMapEntry->m_ListEntry );
|
|
|
|
delete pScriptMapEntry;
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
META_SCRIPT_MAP_ENTRY::Create(
|
|
IN const WCHAR * szExtension,
|
|
IN const WCHAR * szExecutable,
|
|
IN DWORD Flags,
|
|
IN const WCHAR * szVerbs,
|
|
IN DWORD cchVerbs
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
DWORD cchExecutable;
|
|
|
|
//
|
|
// Capture initialization parameters
|
|
//
|
|
|
|
m_Flags = Flags;
|
|
|
|
hr = m_strExtension.Copy( szExtension );
|
|
if( FAILED(hr) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Lower-case to allow for case insensitive comparisons
|
|
//
|
|
_wcslwr( m_strExtension.QueryStr() );
|
|
|
|
if (szExtension[0] == L'*' && szExtension[1] == L'\0')
|
|
{
|
|
m_fIsStarScriptMapEntry = TRUE;
|
|
}
|
|
|
|
//
|
|
// We treat the executable name as an ExpandSz, so expand it
|
|
//
|
|
WCHAR szExpand[MAX_PATH + 1];
|
|
if (!ExpandEnvironmentStrings(szExecutable,
|
|
szExpand,
|
|
sizeof szExpand/sizeof WCHAR))
|
|
{
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
if (FAILED(hr = m_strExecutable.Copy( szExpand )))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// If the executable is quoted, remove the quotes now
|
|
//
|
|
if ( m_strExecutable.QueryStr()[ 0 ] == L'"' &&
|
|
m_strExecutable.QueryStr()[ m_strExecutable.QueryCCH() - 1 ] == L'"' )
|
|
{
|
|
cchExecutable = m_strExecutable.QueryCCH();
|
|
|
|
memmove( m_strExecutable.QueryStr(),
|
|
m_strExecutable.QueryStr() + 1,
|
|
cchExecutable * sizeof( WCHAR ) );
|
|
|
|
m_strExecutable.SetLen( cchExecutable - 2 );
|
|
}
|
|
|
|
if (m_strExecutable.QueryCCH() > 4)
|
|
{
|
|
if (!_wcsicmp(
|
|
m_strExecutable.QueryStr() + m_strExecutable.QueryCCH() - 4,
|
|
L".dll"))
|
|
{
|
|
m_Gateway = GATEWAY_ISAPI;
|
|
}
|
|
else
|
|
{
|
|
m_Gateway = GATEWAY_CGI;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
if (!m_Verbs.AppendW( szVerbs, cchVerbs ))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
return hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
W3_METADATA_CACHE::Initialize(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Initialize metadata cache
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwData;
|
|
DWORD dwType;
|
|
DWORD cbData = sizeof( DWORD );
|
|
DWORD csecTTL = DEFAULT_W3_METADATA_CACHE_TTL;
|
|
HKEY hKey;
|
|
|
|
//
|
|
// What is the TTL for the URI cache
|
|
//
|
|
|
|
if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
L"System\\CurrentControlSet\\Services\\w3svc\\Parameters",
|
|
0,
|
|
KEY_READ,
|
|
&hKey ) == ERROR_SUCCESS )
|
|
{
|
|
DBG_ASSERT( hKey != NULL );
|
|
|
|
if ( RegQueryValueEx( hKey,
|
|
L"MetadataCacheTTL",
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwData,
|
|
&cbData ) == ERROR_SUCCESS &&
|
|
dwType == REG_DWORD )
|
|
{
|
|
csecTTL = dwData;
|
|
}
|
|
|
|
RegCloseKey( hKey );
|
|
}
|
|
|
|
//
|
|
// We'll use TTL for scavenge period, and expect two inactive periods to
|
|
// flush
|
|
//
|
|
|
|
hr = SetCacheConfiguration( csecTTL * 1000,
|
|
csecTTL * 1000,
|
|
CACHE_INVALIDATION_METADATA,
|
|
NULL );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
return W3_METADATA::Initialize();
|
|
}
|
|
|
|
HRESULT
|
|
W3_METADATA_CACHE::GetMetaData(
|
|
W3_CONTEXT * pW3Context,
|
|
STRU & strUrl,
|
|
W3_METADATA ** ppMetaData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieve a W3_METADATA, creating if necessary
|
|
|
|
Arguments:
|
|
|
|
pW3Context - W3 context
|
|
strUrl - Url
|
|
ppMetaData - Set to point to metadata on success
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
W3_METADATA_KEY metaKey;
|
|
W3_METADATA * pMetaData;
|
|
DWORD dwDataSetNumber;
|
|
HRESULT hr;
|
|
STACK_STRU( strFullPath, 128 );
|
|
MB mb( g_pW3Server->QueryMDObject() );
|
|
HANDLE hToken = NULL;
|
|
|
|
if ( pW3Context == NULL ||
|
|
ppMetaData == NULL )
|
|
{
|
|
DBG_ASSERT( FALSE );
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
|
goto Failed;
|
|
}
|
|
|
|
*ppMetaData = NULL;
|
|
|
|
//
|
|
// Setup a key to lookup by determining data set number
|
|
//
|
|
|
|
hr = GetFullMetadataPath( pW3Context,
|
|
strUrl,
|
|
&strFullPath );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failed;
|
|
}
|
|
|
|
//
|
|
// If the caller is coming from an ISAPI, then the thread may
|
|
// be impersonating. Temporarily discard the impersonation
|
|
// token until we get the metadata.
|
|
//
|
|
|
|
if ( OpenThreadToken( GetCurrentThread(),
|
|
TOKEN_IMPERSONATE,
|
|
TRUE,
|
|
&hToken ) )
|
|
{
|
|
DBG_ASSERT( hToken != NULL );
|
|
DBG_REQUIRE( RevertToSelf() );
|
|
}
|
|
|
|
if ( !mb.GetDataSetNumber( strFullPath.QueryStr(),
|
|
&dwDataSetNumber ) )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
goto Failed;
|
|
}
|
|
|
|
metaKey.SetDataSetNumber( dwDataSetNumber );
|
|
|
|
//
|
|
// Look it up
|
|
//
|
|
|
|
hr = FindCacheEntry( &metaKey, (CACHE_ENTRY**) &pMetaData );
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
DBG_ASSERT( pMetaData != NULL );
|
|
|
|
*ppMetaData = pMetaData;
|
|
|
|
goto Succeeded;
|
|
}
|
|
|
|
//
|
|
// We need to create a metadata entry and add it
|
|
//
|
|
|
|
hr = CreateNewMetaData( pW3Context,
|
|
strUrl,
|
|
strFullPath,
|
|
&pMetaData );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Failed;
|
|
}
|
|
|
|
DBG_ASSERT( pMetaData != NULL );
|
|
|
|
//
|
|
// Add to the cache
|
|
//
|
|
|
|
AddCacheEntry( pMetaData );
|
|
|
|
*ppMetaData = pMetaData;
|
|
|
|
Succeeded:
|
|
|
|
DBG_ASSERT( SUCCEEDED( hr ) );
|
|
|
|
if ( hToken != NULL )
|
|
{
|
|
DBG_REQUIRE( SetThreadToken( NULL, hToken ) );
|
|
DBG_REQUIRE( CloseHandle( hToken ) );
|
|
hToken = NULL;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
Failed:
|
|
|
|
DBG_ASSERT( FAILED( hr ) );
|
|
|
|
if ( hToken != NULL )
|
|
{
|
|
DBG_REQUIRE( SetThreadToken( NULL, hToken ) );
|
|
DBG_REQUIRE( CloseHandle( hToken ) );
|
|
hToken = NULL;
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
HRESULT
|
|
W3_METADATA_CACHE::CreateNewMetaData(
|
|
W3_CONTEXT * pW3Context,
|
|
STRU & strUrl,
|
|
STRU & strFullMetadataPath,
|
|
W3_METADATA ** ppMetaData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create a new W3_METADATA and initializes it
|
|
|
|
Arguments:
|
|
|
|
pW3Context - context
|
|
strUrl - URL
|
|
strFullMetadataPath - Full metabase path to open
|
|
ppMetaData - Set to new metadata entry on success
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr;
|
|
W3_METADATA * pMetaData = NULL;
|
|
|
|
if ( pW3Context == NULL ||
|
|
ppMetaData == NULL )
|
|
{
|
|
DBG_ASSERT( FALSE );
|
|
return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
|
}
|
|
|
|
*ppMetaData = NULL;
|
|
|
|
//
|
|
// Create the metadata object
|
|
//
|
|
|
|
pMetaData = new W3_METADATA( this );
|
|
if ( pMetaData == NULL )
|
|
{
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
//
|
|
// Set full URL for flushing purposes
|
|
//
|
|
|
|
hr = pMetaData->QueryMetadataPath()->Copy( strFullMetadataPath );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
pMetaData->DereferenceCacheEntry();
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Initialize it
|
|
//
|
|
|
|
hr = pMetaData->ReadMetaData( *(pW3Context->QuerySite()->QueryMBRoot()),
|
|
strUrl );
|
|
if( FAILED(hr) )
|
|
{
|
|
pMetaData->DereferenceCacheEntry();
|
|
return hr;
|
|
}
|
|
|
|
*ppMetaData = pMetaData;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
HRESULT
|
|
W3_METADATA_CACHE::GetFullMetadataPath(
|
|
W3_CONTEXT * pW3Context,
|
|
STRU & strUrl,
|
|
STRU * pstrFullPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the full metadata given the URL and site
|
|
|
|
Arguments:
|
|
|
|
pW3Context - Used to get the site
|
|
strUrl - Url
|
|
pstrFullPath - Filled with full path on success
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr;
|
|
WCHAR * pszSource;
|
|
DWORD cchSource;
|
|
|
|
if ( pW3Context == NULL ||
|
|
pstrFullPath == NULL )
|
|
{
|
|
DBG_ASSERT( FALSE );
|
|
return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
|
}
|
|
|
|
//
|
|
// Build up full metabase path (including instance)
|
|
//
|
|
|
|
hr = pstrFullPath->Copy( *(pW3Context->QuerySite()->QueryMBRoot()) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Don't copy two slashes
|
|
//
|
|
|
|
if ( strUrl.QueryStr()[ 0 ] == L'/' )
|
|
{
|
|
pszSource = strUrl.QueryStr() + 1;
|
|
cchSource = strUrl.QueryCCH() - 1;
|
|
}
|
|
else
|
|
{
|
|
pszSource = strUrl.QueryStr();
|
|
cchSource = strUrl.QueryCCH();
|
|
}
|
|
|
|
hr = pstrFullPath->Append( pszSource, cchSource );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|