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.
 
 
 
 
 
 

761 lines
20 KiB

/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
config.cpp
Abstract:
This file implements metabase access routines for virtual directories.
--*/
#include "precomp.h"
StringHandle
VDirConfig::GetFullPath( StringHandle Path )
{
StringHandle ParsedPath;
CHAR *FilePart = NULL;
DWORD BufferLength = MAX_PATH;
while( 1 )
{
CHAR *PathBuffer = ParsedPath.AllocBuffer( BufferLength );
DWORD Result =
GetFullPathName(
Path,
BufferLength,
PathBuffer,
&FilePart );
if ( Result > BufferLength )
{
BufferLength = Result;
continue;
}
if ( !Result )
{
Log( LOG_ERROR, "Unable to get the full path name for %s, error 0x%8.8X",
(const char*)Path, HRESULT_FROM_WIN32( GetLastError() ) );
throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
}
ParsedPath.SetStringSize();
break;
}
return ParsedPath;
}
VDirConfig::VDirConfig(
StringHandle Path,
SmartMetabasePointer AdminBase
) :
m_Refs(1)
{
//
// Read in all the metabase configuration for the virtual directory.
//
HRESULT Hr;
METADATA_HANDLE MdVDirKey = NULL;
GetSystemTimeAsFileTime( &m_LastLookup );
try
{
m_Path = Path;
StringHandleW UnicodePath = Path;
Hr = AdminBase->OpenKey(
METADATA_MASTER_ROOT_HANDLE,
(const WCHAR*)UnicodePath,
METADATA_PERMISSION_READ,
METABASE_OPEN_KEY_TIMEOUT,
&MdVDirKey );
if ( FAILED(Hr) )
throw ServerException( Hr );
m_PhysicalPath =
GetMetaDataString(
AdminBase.Get(),
MdVDirKey,
NULL,
MD_VR_PATH,
"" );
m_PhysicalPath = GetFullPath( m_PhysicalPath );
DWORD UploadEnabled =
GetMetaDataDWORD(
AdminBase.Get(),
MdVDirKey,
NULL,
g_PropertyMan->GetPropertyMetabaseID( MD_BITS_UPLOAD_ENABLED ),
0);
m_UploadEnabled = UploadEnabled ? true : false;
m_ConnectionsDir =
GetMetaDataString(
AdminBase.Get(),
MdVDirKey,
NULL,
g_PropertyMan->GetPropertyMetabaseID( MD_BITS_CONNECTION_DIR ),
MD_DEFAULT_BITS_CONNECTION_DIRA );
m_SessionDir = m_PhysicalPath + StringHandle( "\\" ) + m_ConnectionsDir;
m_RequestsDir = m_SessionDir + StringHandle( "\\" ) + StringHandle( REQUESTS_DIR_NAME );
m_RepliesDir = m_SessionDir + StringHandle( "\\" ) + StringHandle( REPLIES_DIR_NAME );
m_NoProgressTimeout =
GetMetaDataDWORD(
AdminBase.Get(),
MdVDirKey,
NULL,
g_PropertyMan->GetPropertyMetabaseID( MD_BITS_NO_PROGRESS_TIMEOUT ),
MD_DEFAULT_NO_PROGESS_TIMEOUT );
StringHandle MaxFilesizeString =
GetMetaDataString(
AdminBase.Get(),
MdVDirKey,
NULL,
g_PropertyMan->GetPropertyMetabaseID( MD_BITS_MAX_FILESIZE ),
MD_DEFAULT_BITS_MAX_FILESIZEA );
if ( MaxFilesizeString.Size() == 0 )
{
m_MaxFileSize = 0xFFFFFFFFFFFFFFFF;
}
else
{
UINT64 MaxFileSize;
int ScanRet = sscanf( (const char*)MaxFilesizeString, "%I64u", &MaxFileSize );
if ( 1 != ScanRet )
throw ServerException( E_INVALIDARG );
m_MaxFileSize = MaxFileSize;
}
DWORD NotificationType =
GetMetaDataDWORD(
AdminBase.Get(),
MdVDirKey,
NULL,
g_PropertyMan->GetPropertyMetabaseID( MD_BITS_NOTIFICATION_URL_TYPE ),
MD_DEFAULT_BITS_NOTIFICATION_URL_TYPE );
if ( NotificationType > BITS_NOTIFICATION_TYPE_MAX )
throw ServerException( E_INVALIDARG );
m_NotificationType = (BITS_SERVER_NOTIFICATION_TYPE)NotificationType;
m_NotificationURL =
GetMetaDataString(
AdminBase.Get(),
MdVDirKey,
NULL,
g_PropertyMan->GetPropertyMetabaseID( MD_BITS_NOTIFICATION_URL ),
MD_DEFAULT_BITS_NOTIFICATION_URLA );
m_HostId =
GetMetaDataString(
AdminBase.Get(),
MdVDirKey,
NULL,
g_PropertyMan->GetPropertyMetabaseID( MD_BITS_HOSTID ),
MD_DEFAULT_BITS_HOSTIDA );
m_HostIdFallbackTimeout =
GetMetaDataDWORD(
AdminBase.Get(),
MdVDirKey,
NULL,
g_PropertyMan->GetPropertyMetabaseID( MD_BITS_HOSTID_FALLBACK_TIMEOUT ),
MD_DEFAULT_HOSTID_FALLBACK_TIMEOUT );
m_ExecutePermissions =
GetMetaDataDWORD(
AdminBase.Get(),
MdVDirKey,
NULL,
MD_ACCESS_PERM,
MD_ACCESS_READ );
#if defined( ALLOW_OVERWRITES )
m_AllowOverwrites =
!!GetMetaDataDWORD(
AdminBase.Get(),
MdVDirKey,
NULL,
g_PropertyMan->GetPropertyMetabaseID( MD_BITS_ALLOW_OVERWRITES ),
MD_DEFAULT_BITS_ALLOW_OVERWRITES );
#else
m_AllowOverwrites = false;
#endif
AdminBase->CloseKey( MdVDirKey );
}
catch( const ComError & )
{
if ( MdVDirKey )
AdminBase->CloseKey( MdVDirKey );
throw;
}
}
ConfigurationManager::ConfigurationManager()
{
bool CSInitialize = false;
memset( m_PathCacheEntries, 0, sizeof( m_PathCacheEntries ) );
memset( m_MapCacheEntries, 0, sizeof( m_MapCacheEntries ) );
HRESULT Hr =
CoInitializeEx( NULL, COINIT_MULTITHREADED );
if ( FAILED(Hr) )
throw ServerException( Hr );
try
{
if ( !InitializeCriticalSectionAndSpinCount( &m_CacheCS, 0x80000100 ) )
throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
CSInitialize = true;
Hr =
CoCreateInstance(
GETAdminBaseCLSID(TRUE),
NULL,
CLSCTX_SERVER,
__uuidof( IMSAdminBase ),
(LPVOID*)m_IISAdminBase.GetRecvPointer() );
if ( FAILED(Hr) )
throw ServerException( Hr );
Hr = m_IISAdminBase->GetSystemChangeNumber( &m_ChangeNumber );
if ( FAILED(Hr))
throw ServerException( Hr );
CoUninitialize();
}
catch( const ComError & )
{
if ( CSInitialize )
DeleteCriticalSection( &m_CacheCS );
CoUninitialize();
throw;
}
}
ConfigurationManager::~ConfigurationManager()
{
FlushCache();
DeleteCriticalSection( &m_CacheCS );
}
void
ConfigurationManager::FlushCache()
{
for( unsigned int i = 0; i < PATH_CACHE_ENTRIES; i++ )
{
if ( m_PathCacheEntries[i] )
m_PathCacheEntries[i].Clear();
}
for( unsigned int i = 0; i < MAP_CACHE_ENTRIES; i++ )
{
delete m_MapCacheEntries[i];
m_MapCacheEntries[i] = NULL;
}
}
SmartVDirConfig
ConfigurationManager::Lookup(
StringHandle Path )
{
for( unsigned int i=0; i < PATH_CACHE_ENTRIES; i++ )
{
if ( m_PathCacheEntries[i] )
{
if ( _stricmp( (const char*)m_PathCacheEntries[i]->m_Path, (const char*)Path) == 0 )
{
SmartVDirConfig ReturnVal = m_PathCacheEntries[i];
GetSystemTimeAsFileTime( &ReturnVal->m_LastLookup );
return ReturnVal;
}
}
}
return SmartVDirConfig();
}
void
ConfigurationManager::Insert(
SmartVDirConfig NewConfig )
{
//
// Insert a new virtual directory configuration into the
// virtual directory cache. Expire an old entry if needed.
//
int BestSlot = 0;
FILETIME WorstTime;
memset( &WorstTime, 0xFF, sizeof( WorstTime ) );
for( unsigned int i=0; i < PATH_CACHE_ENTRIES; i++ )
{
if ( !m_PathCacheEntries[i] )
{
BestSlot = i;
break;
}
else if ( CompareFileTime( &m_PathCacheEntries[i]->m_LastLookup, &WorstTime ) < 0 )
{
WorstTime = m_PathCacheEntries[i]->m_LastLookup;
BestSlot = i;
}
}
m_PathCacheEntries[BestSlot] = NewConfig;
}
SmartVDirConfig
ConfigurationManager::Lookup(
StringHandle InstanceMetabasePath,
StringHandle URL,
DWORD *pURLDepth )
{
//
// Find the virtual directories configuration in the cache.
//
for( unsigned int i=0; i < MAP_CACHE_ENTRIES; i++ )
{
MapCacheEntry* CacheEntry = m_MapCacheEntries[i];
if ( CacheEntry )
{
if ( ( _stricmp( (const char*)CacheEntry->m_InstanceMetabasePath,
(const char*)InstanceMetabasePath) == 0 ) &&
( _stricmp( (const char*)CacheEntry->m_URL,
(const char*)URL ) == 0 ) )
{
GetSystemTimeAsFileTime( &CacheEntry->m_LastLookup );
*pURLDepth = CacheEntry->m_URLDepth;
return CacheEntry->m_Config;
}
}
}
return SmartVDirConfig();
}
SmartVDirConfig
ConfigurationManager::GetVDirConfig(
StringHandle Path )
{
SmartVDirConfig Config = Lookup( Path );
if ( !Config.Get() )
{
*Config.GetRecvPointer() = new VDirConfig( Path, m_IISAdminBase );
Insert( Config );
}
return Config;
}
SmartVDirConfig
ConfigurationManager::Insert(
StringHandle InstanceMetabasePath,
StringHandle URL,
StringHandle Path,
DWORD URLDepth )
{
SmartVDirConfig Config = GetVDirConfig( Path );
MapCacheEntry* CacheEntry =
new MapCacheEntry(
InstanceMetabasePath,
URL,
Config,
URLDepth );
int BestSlot = 0;
FILETIME WorstTime;
memset( &WorstTime, 0xFF, sizeof( WorstTime ) );
for( unsigned int i=0; i < MAP_CACHE_ENTRIES; i++ )
{
if ( !m_MapCacheEntries[i] )
{
BestSlot = i;
break;
}
else if ( CompareFileTime( &m_MapCacheEntries[i]->m_LastLookup, &WorstTime ) < 0 )
{
WorstTime = m_MapCacheEntries[i]->m_LastLookup;
BestSlot = i;
}
}
if ( m_MapCacheEntries[BestSlot] )
delete m_MapCacheEntries[BestSlot];
m_MapCacheEntries[BestSlot] = CacheEntry;
return Config;
}
StringHandle
ConfigurationManager::GetVDirPath(
StringHandle InstanceMetabasePath,
StringHandle URL,
DWORD *pURLDepth )
{
//
// Find the virtual directory that coresponds to the URL.
// Do this by matching the URL up with the metabase keys. Keep
// pruning off the URL untill the longest metabase path is found
// that is a virtual directory.
//
StringHandleW InstanceMetabasePathW = InstanceMetabasePath;
StringHandleW URLW = URL;
WCHAR *Path = NULL;
METADATA_HANDLE MdVDirKey = NULL;
*pURLDepth = 0;
try
{
WCHAR *PathEnd = NULL;
WCHAR *CurrentEnd = NULL;
WCHAR RootString[] = L"/Root";
SIZE_T InstancePathSize = InstanceMetabasePathW.Size();
SIZE_T URLSize = URLW.Size();
SIZE_T RootStringSize = ( sizeof( RootString ) / sizeof( *RootString ) ) - 1;
Path = new WCHAR[ InstancePathSize + URLSize + RootStringSize + 1 ];
memcpy( Path, (const WCHAR*)InstanceMetabasePathW, InstancePathSize * sizeof( WCHAR ) );
PathEnd = Path + InstancePathSize;
memcpy( PathEnd, RootString, RootStringSize * sizeof( WCHAR ) );
memcpy( PathEnd + RootStringSize, (const WCHAR*)URLW, ( URLSize + 1 )* sizeof( WCHAR ) );
CurrentEnd = PathEnd + RootStringSize + URLSize;
while( 1 )
{
HRESULT Hr =
m_IISAdminBase->OpenKey(
METADATA_MASTER_ROOT_HANDLE, //metabase handle.
Path, //path to the key, relative to hMDHandle.
METADATA_PERMISSION_READ, //specifies read and write permissions.
METABASE_OPEN_KEY_TIMEOUT, //the time, in milliseconds, before the method times out.
&MdVDirKey //receives the handle to the opened key.
);
if ( SUCCEEDED( Hr ) )
{
//
// Check if this is a virtual directory
//
WCHAR NodeName[ 255 ];
DWORD RequiredDataLen;
METADATA_RECORD MDRecord;
MDRecord.dwMDIdentifier = MD_KEY_TYPE;
MDRecord.dwMDAttributes = METADATA_NO_ATTRIBUTES;
MDRecord.dwMDUserType = IIS_MD_UT_SERVER;
MDRecord.dwMDDataType = STRING_METADATA;
MDRecord.dwMDDataLen = sizeof( NodeName );
MDRecord.pbMDData = (unsigned char*)NodeName;
MDRecord.dwMDDataTag = 0;
Hr = m_IISAdminBase->GetData(
MdVDirKey,
NULL,
&MDRecord,
&RequiredDataLen );
if ( FAILED(Hr) && ( Hr != MD_ERROR_DATA_NOT_FOUND ) &&
( Hr != HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) ) )
throw ServerException( Hr );
if ( SUCCEEDED( Hr ) && wcscmp( L"IIsWebVirtualDir", NodeName ) == 0 )
{
// Found the path, so return the data
StringHandle VDirPath = Path;
delete[] Path;
m_IISAdminBase->CloseKey( MdVDirKey );
return VDirPath;
}
}
else if ( Hr != HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) )
{
throw ServerException( Hr );
}
//
// If this is the end of the URL, then nothing else can be done
//
if ( CurrentEnd == PathEnd )
throw ServerException( E_INVALIDARG );
m_IISAdminBase->CloseKey( MdVDirKey );
MdVDirKey = NULL;
// Chop off the rightmost subpart
while( CurrentEnd != PathEnd && *CurrentEnd != L'/' &&
*CurrentEnd != L'\\' )
CurrentEnd--;
if ( *CurrentEnd == L'/' || *CurrentEnd == L'\\' )
*CurrentEnd = L'\0';
(*pURLDepth)++;
// Attempt another round
}
}
catch( const ComError & )
{
delete[] Path;
if ( MdVDirKey )
m_IISAdminBase->CloseKey( MdVDirKey );
throw;
}
}
bool
ConfigurationManager::HandleCacheConsistency()
{
//
// Handle cache consistency. This is done my calling IIS to check the change number.
// If the current change number is different then the change number for the last lookup,
// then flush the cache.
//
DWORD ChangeNumber;
HRESULT Hr = m_IISAdminBase->GetSystemChangeNumber( &ChangeNumber );
if ( FAILED(Hr) )
{
throw ServerException( Hr );
}
if ( ChangeNumber == m_ChangeNumber )
return true; // cache is consistent
FlushCache();
m_ChangeNumber = ChangeNumber;
return false; // cache was flushed.
}
SmartVDirConfig
ConfigurationManager::GetConfig2(
StringHandle InstanceMetabasePath,
StringHandle URL,
DWORD * pURLDepth )
{
//
// Toplevel function to do everything to lookup the configuration to use for an URL.
//
METADATA_HANDLE MdVDirKey = NULL;
SmartVDirConfig Config;
HANDLE ImpersonationToken = NULL;
bool DidRevertToSelf = false;
try
{
EnterCriticalSection( &m_CacheCS );
if ( HandleCacheConsistency() )
{
// The cache was consistent. Chances are good
// that the lookup will succeed
Config = Lookup( InstanceMetabasePath, URL, pURLDepth );
if ( Config.Get() )
{
LeaveCriticalSection( &m_CacheCS );
return Config;
}
}
StringHandle Path = GetVDirPath( InstanceMetabasePath, URL, pURLDepth );
Config = Insert( InstanceMetabasePath, URL, Path, *pURLDepth );
LeaveCriticalSection( &m_CacheCS );
return Config;
}
catch( const ComError & )
{
if ( MdVDirKey )
m_IISAdminBase->CloseKey( MdVDirKey );
LeaveCriticalSection( &m_CacheCS );
throw;
}
}
SmartVDirConfig
ConfigurationManager::GetConfig(
StringHandle InstanceMetabasePath,
StringHandle URL,
DWORD * pURLDepth )
{
bool DidRevertToSelf = false;
bool ComInitialized = false;
HANDLE ImpersonationToken = NULL;
SmartVDirConfig ReturnVal;
HRESULT Hr =
CoInitializeEx( NULL, COINIT_MULTITHREADED );
if ( FAILED(Hr) )
throw ServerException( Hr );
ComInitialized = true;
try
{
// Need to revert to the system process
// to address the metabase
if ( !OpenThreadToken(
GetCurrentThread(),
TOKEN_ALL_ACCESS,
TRUE,
&ImpersonationToken ) )
{
DWORD dwError = GetLastError();
if (dwError != ERROR_NO_TOKEN)
throw ServerException( HRESULT_FROM_WIN32( dwError ) );
}
else
{
if ( !RevertToSelf() )
throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
DidRevertToSelf = true;
}
ReturnVal =
GetConfig2(
InstanceMetabasePath,
URL,
pURLDepth );
if ( DidRevertToSelf )
{
BITSSetCurrentThreadToken( ImpersonationToken );
}
if ( ImpersonationToken )
CloseHandle( ImpersonationToken );
CoUninitialize();
return ReturnVal;
}
catch( ComError & )
{
if ( DidRevertToSelf )
BITSSetCurrentThreadToken( ImpersonationToken );
if ( ImpersonationToken )
CloseHandle( ImpersonationToken );
throw;
}
}