windows-nt/Source/XPSP1/NT/inetsrv/query/web/dll/ida.cxx

1286 lines
39 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 2001.
//
// File: ida.cxx
//
// Contents: Parser for an IDQ file
//
// History: 96/Jan/3 DwightKr Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <fsciexps.hxx>
//
// Constants
//
static WCHAR const wcsPRootVar[] = L"PROOT_";
unsigned const ccPRootVar = sizeof(wcsPRootVar)/sizeof(WCHAR) - 1;
static WCHAR const wcsIndexVar[] = L"INDEX_";
unsigned const ccIndexVar = sizeof(wcsIndexVar)/sizeof(WCHAR) - 1;
static WCHAR const wcsNNTP[] = L"NNTP_";
unsigned const ccNNTP = sizeof(wcsNNTP)/sizeof(WCHAR) - 1;
static WCHAR const wcsIMAP[] = L"IMAP_";
unsigned const ccIMAP = sizeof(wcsIMAP)/sizeof(WCHAR) - 1;
static WCHAR const wcsScanVar[] = L"SCAN_";
unsigned const ccScanVar = sizeof(wcsScanVar)/sizeof(WCHAR) - 1;
unsigned const ccStringizedGuid = 36;
BOOL ParseGuid( WCHAR const * pwcsGuid, GUID & guid );
//+---------------------------------------------------------------------------
//
// Member: CIDAFile::CIDAFile - public constructor
//
// Synopsis: Builds a CIDAFile object, initializes values
//
// Arguments: [wcsFileName] -- full path to IDQ file
//
// History: 13-Apr-96 KyleP Created.
//
//----------------------------------------------------------------------------
CIDAFile::CIDAFile( WCHAR const * wcsFileName, UINT codePage )
: _eOperation( CIDAFile::CiState ),
_wcsCatalog(0),
_wcsHTXFileName( 0 ),
_wcsLocale(0),
_cReplaceableParameters(0),
_refCount(0),
_codePage(codePage)
{
ULONG cwc = wcslen(wcsFileName);
if ( cwc >= sizeof(_wcsIDAFileName)/sizeof(WCHAR) )
{
ciGibDebugOut(( DEB_WARN, "Too long a path (%ws)\n", wcsFileName ));
THROW( CException( STATUS_INVALID_PARAMETER ));
}
RtlCopyMemory( _wcsIDAFileName, wcsFileName, (cwc+1) * sizeof(WCHAR) );
}
//+---------------------------------------------------------------------------
//
// Member: CIDAFile::~CIDAFile - public destructor
//
// History: 13-Apr-96 KyleP Created.
//
//----------------------------------------------------------------------------
CIDAFile::~CIDAFile()
{
Win4Assert( _refCount == 0 );
delete [] _wcsCatalog;
delete [] _wcsHTXFileName;
delete [] _wcsLocale;
}
//+---------------------------------------------------------------------------
//
// Member: CIDAFile::ParseFile, private
//
// Synopsis: Parses the given file and sets up the necessary variables
//
// History: 13-Apr-96 KyleP Created.
// 23-Jul-96 DwightKr Use mapped file I/O which checks
// ACLs and throws ACCESS_DENIED if
// not available.
//
//----------------------------------------------------------------------------
void CIDAFile::ParseFile()
{
//
// Parse the query parameters
//
XPtr<CFileMapView> xMapView;
TRY
{
xMapView.Set( new CFileMapView( _wcsIDAFileName ) );
xMapView->Init();
}
CATCH( CException, e )
{
if ( HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) == e.GetErrorCode() )
{
THROW( CIDQException( MSG_CI_IDQ_NOT_FOUND, 0 ) );
}
else
{
RETHROW();
}
}
END_CATCH
CFileBuffer idaFile( xMapView.GetReference(), _codePage );
//
// Process a line at a time, look for the [Admin] section and
// process lines within that section.
//
BOOL fAdminSection = FALSE;
int iLine = 0; // Start counting at line #1
for( ;; )
{
iLine++;
XGrowable<WCHAR> xLine;
ULONG cwcChar = idaFile.fgetsw( xLine );
if( 0 == cwcChar )
{
break;
}
WCHAR *pwcLine = xLine.Get();
//
// Skip ahead until we find a [Admin] section
//
if ( L'[' == *pwcLine )
{
if ( _wcsnicmp(pwcLine+1, L"Admin]", 6) == 0 )
fAdminSection = TRUE;
else
fAdminSection = FALSE;
continue;
}
//
// Ignore comments.
//
else if ( L'#' == *pwcLine )
continue;
if ( fAdminSection )
{
CQueryScanner scanner( pwcLine, FALSE );
ParseOneLine( scanner, iLine );
}
}
//
// Verify that the minimum set of parameters are specified.
//
//
// We must have all of the following:
//
// - a HTX file name
//
if ( 0 == _wcsHTXFileName )
{
// Report an error
ciGibDebugOut(( DEB_IERROR, "Template not found in IDA file.\n" ));
THROW( CIDQException(MSG_CI_IDQ_MISSING_TEMPLATEFILE, 0) );
}
//
// If no catalog was specified, use the default catalog in the registry
//
if ( 0 == _wcsCatalog )
{
ciGibDebugOut(( DEB_ITRACE, "Using default catalog\n" ));
WCHAR awcTmp[ MAX_PATH ];
ULONG cwcRequired = TheIDQRegParams.GetISDefaultCatalog( awcTmp,
MAX_PATH );
if ( cwcRequired > MAX_PATH )
THROW( CException(STATUS_INVALID_PARAMETER) );
cwcRequired++; // make room for termination
_wcsCatalog = new WCHAR[ cwcRequired ];
RtlCopyMemory( _wcsCatalog, awcTmp, cwcRequired * sizeof WCHAR );
}
}
//+---------------------------------------------------------------------------
//
// Member: CIDAFile::ParseOneLine, private
//
// Synopsis: Parses one line of the IDQ file
//
// Arguments: [scan] -- scanner initialized with the current line
// [iLine] -- current line number
//
// History: 13-Apr-96 KyleP Created.
//
//----------------------------------------------------------------------------
void CIDAFile::ParseOneLine( CQueryScanner & scan, unsigned iLine )
{
//
// Is this a comment line (does it start with #) or an empty line?
//
if ( scan.LookAhead() == PROP_REGEX_TOKEN || scan.LookAhead() == EOS_TOKEN )
{
return;
}
if ( scan.LookAhead() != TEXT_TOKEN ) // Better be a word
{
// Report an error
THROW( CIDQException( MSG_CI_IDQ_EXPECTING_NAME, iLine ) );
}
XPtrST<WCHAR> wcsAttribute( scan.AcqWord() );
if( wcsAttribute.GetPointer() == 0 ) // Better find a word
{
THROW( CIDQException( MSG_CI_IDQ_EXPECTING_TYPE, iLine ) );
}
scan.Accept();
if ( scan.LookAhead() != EQUAL_TOKEN )
{
// Report an error
THROW( CIDQException( MSG_CI_IDQ_EXPECTING_EQUAL, iLine ) );
}
scan.Accept();
if ( 0 == _wcsicmp( wcsAttribute.GetPointer(), ISAPI_CI_CATALOG ) )
GetStringValue( scan, iLine, &_wcsCatalog );
else if ( 0 == _wcsicmp( wcsAttribute.GetPointer(), ISAPI_CI_TEMPLATE ) )
GetStringValue( scan, iLine, &_wcsHTXFileName );
else if ( 0 == _wcsicmp( wcsAttribute.GetPointer(), ISAPI_CI_ADMIN_OPERATION ) )
{
WCHAR * pwcsTemp = 0;
GetStringValue( scan, iLine, &pwcsTemp );
XPtrST<WCHAR> xwcsTemp( pwcsTemp );
if ( 0 == pwcsTemp )
{
THROW( CIDQException( MSG_CI_IDA_INVALID_OPERATION, iLine ) );
}
else if ( 0 == _wcsicmp( pwcsTemp, wcsOpGetState ) )
_eOperation = CIDAFile::CiState;
else if ( 0 == _wcsicmp( pwcsTemp, wcsOpForceMerge ) )
_eOperation = CIDAFile::ForceMerge;
else if ( 0 == _wcsicmp( pwcsTemp, wcsOpScanRoots ) )
_eOperation = CIDAFile::ScanRoots;
else if ( 0 == _wcsicmp( pwcsTemp, wcsOpUpdateCache ) )
_eOperation = CIDAFile::UpdateCache;
else
{
THROW( CIDQException( MSG_CI_IDA_INVALID_OPERATION, iLine ) );
}
}
else if ( 0 == _wcsicmp( wcsAttribute.GetPointer(), ISAPI_CI_LOCALE ) )
{
GetStringValue( scan, iLine, &_wcsLocale );
}
else
{
//
// We've found a keyword/attribute that we don't support.
// Don't report an error. This will allow this version of the
// parser to work with newer .IDA file versions with new parameters.
//
ciGibDebugOut(( DEB_ERROR, "Invalid string in IDQ file: %ws\n", wcsAttribute.GetPointer() ));
}
}
//+---------------------------------------------------------------------------
//
// Member: CIDAFile::GetStringValue - private
//
// Synopsis: Gets the string value on the currenct line
//
// Arguments: [scan] -- scanner initialized with the current line
// [iLine] -- current line number
// [pwcsStringValue] -- value to put string into
//
// History: 13-Apr-96 KyleP Created.
//
//----------------------------------------------------------------------------
void CIDAFile::GetStringValue( CQueryScanner & scan,
unsigned iLine,
WCHAR ** pwcsStringValue )
{
if ( 0 != *pwcsStringValue )
{
ciGibDebugOut(( DEB_IWARN,
"Duplicate CiXX=value in IDA file on line #%d\n",
iLine ));
THROW( CIDQException(MSG_CI_IDQ_DUPLICATE_ENTRY, iLine) );
}
*pwcsStringValue = scan.AcqLine();
if ( IsAReplaceableParameter( *pwcsStringValue ) != eIsSimpleString )
{
_cReplaceableParameters++;
}
}
//+---------------------------------------------------------------------------
//
// Function: FindEntry, public
//
// Synopsis: Helper function for admin variable parsing.
//
// Arguments: [pwcsName] -- Variable name
// [fScan] -- TRUE for SCAN, FALSE for INDEX
// [pwcsBuf] -- Buffer for search token
//
// History: 10-Oct-96 KyleP Created.
//
//----------------------------------------------------------------------------
BOOL FindEntry( WCHAR const * * ppwcsName, BOOL fScan, WCHAR * pwcsBuf )
{
if ( 0 != _wcsnicmp( *ppwcsName, wcsPRootVar, ccPRootVar ) )
return FALSE;
//
// Scan or Index?
//
WCHAR const * pwcsOutputTag;
unsigned ccOutputTag;
if ( fScan )
{
pwcsOutputTag = wcsScanVar;
ccOutputTag = ccScanVar;
}
else
{
pwcsOutputTag = wcsIndexVar;
ccOutputTag = ccIndexVar;
}
//
// IMAP, NNTP or W3?
//
unsigned ccPrefix = ccOutputTag;
BOOL fW3 = FALSE;
BOOL fNNTP = FALSE;
BOOL fIMAP = FALSE;
if ( 0 == _wcsnicmp( *ppwcsName + ccPRootVar, wcsNNTP, ccNNTP ) )
{
fNNTP = TRUE;
*ppwcsName += ccNNTP;
ccPrefix += ccNNTP;
}
else if ( 0 == _wcsnicmp( *ppwcsName + ccPRootVar, wcsIMAP, ccIMAP ) )
{
fIMAP = TRUE;
*ppwcsName += ccIMAP;
ccPrefix += ccIMAP;
}
else
{
fW3 = TRUE;
}
*ppwcsName += ccPRootVar;
//
// Length check.
//
unsigned ccName = wcslen( *ppwcsName ) + 1;
if ( ccName + ccPrefix > (MAX_PATH + ccIndexVar + ccNNTP + 1) )
{
ciGibDebugOut(( DEB_WARN, "Path %ws too long for admin\n", *ppwcsName ));
return FALSE;
}
if ( ccName + ccPrefix > (MAX_PATH + ccIndexVar + ccIMAP + 1) )
{
ciGibDebugOut(( DEB_WARN, "Path %ws too long for admin\n", *ppwcsName ));
return FALSE;
}
//
// Build output name
//
RtlCopyMemory( pwcsBuf, pwcsOutputTag, ccOutputTag * sizeof(WCHAR) );
if ( fNNTP )
RtlCopyMemory( pwcsBuf + ccOutputTag, wcsNNTP, ccNNTP * sizeof(WCHAR) );
else if ( fIMAP )
RtlCopyMemory( pwcsBuf + ccOutputTag, wcsIMAP, ccIMAP * sizeof(WCHAR) );
RtlCopyMemory( pwcsBuf + ccPrefix, *ppwcsName, ccName * sizeof(WCHAR) );
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Function: DoAdmin, public
//
// Synopsis: Executes an administrative change.
//
// Arguments: [wcsIDAFile] -- Virtual path to .IDA file
// [VarSet] -- Query variables
// [OutputFormat] -- Output format
// [vsResults] -- On success (non exception) result page
// written here.
//
// History: 13-Apr-96 KyleP Created.
// 22-Jul-96 DwightKr Make CiLocale replaceable & visible
// in HTX files
// 11-Jun-97 KyleP Use web server in Output Format
//
//----------------------------------------------------------------------------
void DoAdmin( WCHAR const * wcsIDAFile,
CVariableSet & VarSet,
COutputFormat & OutputFormat,
CVirtualString & vsResults )
{
//
// Parse .IDA file. We don't bother to cache these.
//
XPtr<CIDAFile> xIDAFile( new CIDAFile(wcsIDAFile, OutputFormat.CodePage()) );
xIDAFile->ParseFile();
ULONG cwcOut;
XPtrST<WCHAR> wcsLocaleID( ReplaceParameters( xIDAFile->GetLocale(),
VarSet,
OutputFormat,
cwcOut ) );
XArray<WCHAR> wcsLocale;
LCID locale = GetQueryLocale( wcsLocaleID.GetPointer(),
VarSet,
OutputFormat,
wcsLocale );
if ( OutputFormat.GetLCID() != locale )
{
ciGibDebugOut(( DEB_ITRACE,
"Wrong codePage used for loading IDA file, used 0x%x retrying with 0x%x\n",
OutputFormat.CodePage(),
LocaleToCodepage(locale) ));
//
// We've parsed the IDA file with the wrong locale.
//
delete xIDAFile.Acquire();
OutputFormat.LoadNumberFormatInfo( locale );
xIDAFile.Set( new CIDAFile(wcsIDAFile, OutputFormat.CodePage()) );
xIDAFile->ParseFile();
}
SetupDefaultCiVariables( VarSet );
SetupDefaultISAPIVariables( VarSet );
SetCGIVariables( VarSet, OutputFormat );
//
// Get the catalog.
//
XPtrST<WCHAR> wcsCiCatalog( ReplaceParameters( xIDAFile->GetCatalog(),
VarSet,
OutputFormat,
cwcOut ) );
//
// Verify that the wcsCatalog is valid
//
if ( !IsAValidCatalog( wcsCiCatalog.GetPointer(), cwcOut ) )
{
THROW( CIDQException(MSG_CI_IDQ_NO_SUCH_CATALOG, 0) );
}
//
// Get the catalog and machine from the URL style catalog.
//
XPtrST<WCHAR> wcsMachine( 0 );
XPtrST<WCHAR> wcsCatalog( 0 );
SCODE sc = ParseCatalogURL( wcsCiCatalog.GetPointer(),
wcsCatalog,
wcsMachine );
if (FAILED(sc))
{
THROW( CException(sc) );
}
Win4Assert ( 0 != wcsMachine.GetPointer() );
//
// Check that the client is allowed to perform administration
//
CheckAdminSecurity( wcsMachine.GetPointer() );
//
// Build the HTX page for [success] output
//
XPtrST<WCHAR> wcsTemplate( ReplaceParameters( xIDAFile->GetHTXFileName(),
VarSet,
OutputFormat,
cwcOut ) );
WCHAR wcsPhysicalName[_MAX_PATH];
if ( OutputFormat.IsValid() )
{
OutputFormat.GetPhysicalPath( wcsTemplate.GetPointer(),
wcsPhysicalName,
_MAX_PATH );
}
else
{
if ( !GetFullPathName( wcsTemplate.GetPointer(),
MAX_PATH,
wcsPhysicalName,
0 ) )
{
THROW( CException() );
}
}
//
// Note: Parsing of HTX file needs to be done in different locations
// to ensure variables added to variable set by admin operations
// are added before parse. But we also don't want to fail the
// parse *after* doing a dangerous operation (like force merge).
//
CSecurityIdentity securityStub;
CHTXFile SuccessHTX( wcsTemplate,
OutputFormat.CodePage(),
securityStub,
OutputFormat.GetServerInstance() );
switch ( xIDAFile->Operation() )
{
case CIDAFile::ScanRoots:
{
SuccessHTX.ParseFile( wcsPhysicalName, VarSet, OutputFormat );
if ( SuccessHTX.DoesDetailSectionExist() )
{
THROW( CIDQException(MSG_CI_IDA_TEMPLATE_DETAIL_SECTION, 0) );
}
//
// Execute the changes. 'Entries' have the following format:
// Variable: P<virtual root> = physical root for <virtual root>
// Variable: S<virtual root> = "on" / existence means root is scanned
// Variable: T<virtual root> = "on" / existence means full scan
//
CVariableSetIter iter( VarSet );
while ( !iter.AtEnd() )
{
CVariable * pVar = iter.Get();
WCHAR const * pwcsName = pVar->GetName();
WCHAR wcsScanName[MAX_PATH + ccScanVar + __max( ccNNTP, ccIMAP ) + 1];
if ( FindEntry( &pwcsName, // Starting variable
TRUE, // SCAN
wcsScanName )) // Matching search string returned here
{
PROPVARIANT * ppvPRoot = pVar->GetValue();
CVariable * pScanVar = VarSet.Find( wcsScanName );
if ( 0 != pScanVar )
{
WCHAR const * pwszScanType = pScanVar->GetStringValueRAW();
if ( 0 != pwszScanType &&
( 0 == _wcsicmp( pwszScanType, L"FullScan" ) ||
0 == _wcsicmp( pwszScanType, L"IncrementalScan")
) )
{
BOOL fFull = (0 == _wcsicmp( pwszScanType, L"FullScan" ));
SCODE sc = UpdateContentIndex( ppvPRoot->pwszVal,
wcsCatalog.GetPointer(),
wcsMachine.GetPointer(),
fFull );
if ( FAILED(sc) )
{
ciGibDebugOut(( DEB_ERROR,
"Error 0x%x scanning virtual scope %ws\n",
pwcsName ));
THROW( CException( sc ) );
}
}
}
}
iter.Next();
}
break;
}
case CIDAFile::UpdateCache:
{
SuccessHTX.ParseFile( wcsPhysicalName, VarSet, OutputFormat );
if ( SuccessHTX.DoesDetailSectionExist() )
{
THROW( CIDQException(MSG_CI_IDA_TEMPLATE_DETAIL_SECTION, 0) );
}
//
// Execute the changes. 'Entries' have the following format:
// Variable: CACHESIZE_<guid>_NAME_<name> = Size for named entry
// Variable: CACHESIZE_<guid>_PROPID_<propid> = Size for numbered entry
// Variable: CACHETYPE_<guid>_NAME_<name> = Type for named entry
// Variable: CACHETYPE_<guid>_PROPID_<propid> = Type for numbered entry
//
CVariableSetIter iter( VarSet );
BOOL fSawOne = FALSE;
ULONG_PTR ulToken;
SCODE sc = BeginCacheTransaction( &ulToken,
wcsCatalog.GetPointer(),
wcsCatalog.GetPointer(),
wcsMachine.GetPointer() );
if ( FAILED(sc) )
{
ciGibDebugOut(( DEB_ERROR, "Error 0x%x setting up cache transaction.\n", sc ));
THROW( CException( sc ) );
}
while ( !iter.AtEnd() )
{
CVariable * pVar = iter.Get();
WCHAR const * pwcsName = pVar->GetName();
//
// We write out last prop twice, 2nd time to commit everything.
//
//
// Constants.
//
static WCHAR const wcsSizeVar[] = L"CACHESIZE_";
unsigned ccSizeVar = sizeof(wcsSizeVar)/sizeof(WCHAR) - 1;
static WCHAR const wcsTypeVar[] = L"CACHETYPE_";
unsigned ccTypeVar = sizeof(wcsTypeVar)/sizeof(WCHAR) - 1;
if ( 0 == _wcsnicmp( pwcsName, wcsSizeVar, ccSizeVar ) )
{
CFullPropSpec ps;
//
// Parse the GUID.
//
unsigned cc = wcslen( pwcsName );
GUID guid;
if ( cc <= ccSizeVar || !ParseGuid( pwcsName + ccSizeVar, guid ) )
{
ciGibDebugOut(( DEB_WARN, "Improperly formatted CACHESIZE entry %ws\n", pwcsName ));
iter.Next();
continue;
}
ps.SetPropSet( guid );
//
// PROPID or string?
//
static WCHAR const wcsName[] = L"_NAME_";
unsigned ccName = sizeof(wcsName)/sizeof(WCHAR) - 1;
static WCHAR const wcsPropid[] = L"_PROPID_";
unsigned ccPropid = sizeof(wcsPropid)/sizeof(WCHAR) - 1;
if ( 0 == _wcsnicmp( pwcsName + ccSizeVar + ccStringizedGuid, wcsPropid, ccPropid ) )
{
CQueryScanner scan( pwcsName + ccSizeVar + ccStringizedGuid + ccPropid, FALSE );
PROPID propid;
BOOL fEnd;
if ( !scan.GetNumber( propid, fEnd ) )
{
ciGibDebugOut(( DEB_WARN, "Improperly formatted CACHESIZE entry %ws\n", pwcsName ));
iter.Next();
continue;
}
ps.SetProperty( propid );
}
else if ( 0 == _wcsnicmp( pwcsName + ccSizeVar + ccStringizedGuid, wcsName, ccName ) )
{
ps.SetProperty( pwcsName + ccSizeVar + ccStringizedGuid + ccName );
}
else
{
ciGibDebugOut(( DEB_WARN, "Improperly formatted CACHESIZE entry %ws\n", pwcsName ));
iter.Next();
continue;
}
//
// Get value.
//
PROPVARIANT * ppvSize = pVar->GetValue();
ULONG cb;
if ( ppvSize->vt == VT_LPWSTR )
{
CQueryScanner scan( ppvSize->pwszVal, FALSE );
BOOL fEnd;
if ( !scan.GetNumber( cb, fEnd ) )
{
ciGibDebugOut(( DEB_WARN, "Improper CACHESIZE size: \"%ws\".\n", ppvSize->pwszVal ));
iter.Next();
continue;
}
}
else
{
ciGibDebugOut(( DEB_IWARN, "Improper CACHESIZE size (type = %d).\n", ppvSize->vt ));
iter.Next();
continue;
}
if ( 0 == cb )
{
//
// Delete property from cache (if it was even there).
//
//
// If IDA were the future...
// Need to allow primary or secondary store to be chosen!
// Also allow the ability to set true/false for prop meta info
// modifiability.
//
SCODE sc = SetupCacheEx( ps.CastToStruct(),
0,
0,
ulToken,
TRUE,
PRIMARY_STORE,
wcsCatalog.GetPointer(),
wcsCatalog.GetPointer(),
wcsMachine.GetPointer() );
if ( FAILED(sc) )
{
ciGibDebugOut(( DEB_ERROR, "Error 0x%x modifying cache\n", sc ));
THROW( CException( sc ) );
}
fSawOne = TRUE;
iter.Next();
continue;
}
//
// At this point, we have a non-zero size. The property will
// be added to the cache.
//
//
// Fetch data type
//
XArray<WCHAR> xVar(cc+1);
RtlCopyMemory( xVar.GetPointer(), pwcsName, (cc+1) * sizeof(WCHAR) );
RtlCopyMemory( xVar.GetPointer(), wcsTypeVar, ccTypeVar * sizeof(WCHAR) );
CVariable * pVarType = VarSet.Find( xVar.GetPointer() );
if ( 0 == pVarType )
{
ciGibDebugOut(( DEB_WARN, "Missing CACHETYPE value.\n" ));
iter.Next();
continue;
}
PROPVARIANT * ppvType = pVarType->GetValue();
ULONG type;
if ( ppvType->vt == VT_LPWSTR )
{
CQueryScanner scan( ppvType->pwszVal, FALSE );
BOOL fEnd;
if ( !scan.GetNumber( type, fEnd ) )
{
ciGibDebugOut(( DEB_WARN, "Improper CACHETYPE type: \"%ws\".\n", ppvType->pwszVal ));
iter.Next();
continue;
}
}
else
{
ciGibDebugOut(( DEB_WARN, "Improper CACHETYPE size (type = %d).\n", ppvType->vt ));
iter.Next();
continue;
}
ciGibDebugOut(( DEB_WARN, "Add/change %ws\n", pwcsName ));
//
// If IDA were the future...
// Need to allow primary or secondary store to be chosen!
// Also allow the ability to set true/false for prop meta info
// modifiability.
//
SCODE sc = SetupCacheEx( ps.CastToStruct(),
type,
cb,
ulToken,
TRUE,
SECONDARY_STORE,
wcsCatalog.GetPointer(),
wcsCatalog.GetPointer(),
wcsMachine.GetPointer() );
if ( FAILED(sc) )
{
ciGibDebugOut(( DEB_ERROR, "Error 0x%x modifying cache\n", sc ));
THROW( CException( sc ) );
}
fSawOne = TRUE;
}
iter.Next();
}
sc = EndCacheTransaction( ulToken,
fSawOne,
wcsCatalog.GetPointer(),
wcsCatalog.GetPointer(),
wcsMachine.GetPointer() );
if ( FAILED(sc) )
{
ciGibDebugOut(( DEB_ERROR, "Error 0x%x completing cache transaction.\n", sc ));
THROW( CException( sc ) );
}
break;
}
case CIDAFile::CiState:
{
//
// Populate the variable set.
//
CStorageVariant var;
var.SetUI4( TheWebQueryCache.Hits() );
VarSet.SetVariable( ISAPI_CI_ADMIN_CACHE_HITS, var, 0 );
var.SetUI4( TheWebQueryCache.Misses() );
VarSet.SetVariable( ISAPI_CI_ADMIN_CACHE_MISSES, var, 0 );
var.SetUI4( TheWebQueryCache.Running() );
VarSet.SetVariable( ISAPI_CI_ADMIN_CACHE_ACTIVE, var, 0 );
var.SetUI4( TheWebQueryCache.Cached() );
VarSet.SetVariable( ISAPI_CI_ADMIN_CACHE_COUNT, var, 0 );
var.SetUI4( TheWebPendingRequestQueue.Count() );
VarSet.SetVariable( ISAPI_CI_ADMIN_CACHE_PENDING, var, 0 );
var.SetUI4( TheWebQueryCache.Rejected() );
VarSet.SetVariable( ISAPI_CI_ADMIN_CACHE_REJECTED, var, 0 );
var.SetUI4( TheWebQueryCache.Total() );
VarSet.SetVariable( ISAPI_CI_ADMIN_CACHE_TOTAL, var, 0 );
var.SetUI4( TheWebQueryCache.QPM() );
VarSet.SetVariable( ISAPI_CI_ADMIN_CACHE_QPM, var, 0 );
//
// Fetch CI state.
//
CI_STATE sState;
sState.cbStruct = sizeof(sState);
SCODE sc = CIState ( wcsCatalog.GetPointer(),
wcsMachine.GetPointer(),
&sState );
if ( FAILED(sc) )
{
ciGibDebugOut(( DEB_ERROR, "Error 0x%x getting CI state.\n", sc ));
THROW( CException( sc ) );
}
var.SetUI4( sState.cWordList );
VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_COUNT_WORDLISTS, var, 0 );
var.SetUI4( sState.cPersistentIndex );
VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_COUNT_PERSINDEX, var, 0 );
var.SetUI4( sState.cQueries );
VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_COUNT_QUERIES, var, 0 );
var.SetUI4( sState.cDocuments );
VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_COUNT_TOFILTER, var, 0 );
var.SetUI4( sState.cFreshTest );
VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_COUNT_FRESHTEST, var, 0 );
var.SetUI4( sState.dwMergeProgress );
VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_MERGE_PROGRESS, var, 0 );
var.SetUI4( sState.cPendingScans );
VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_COUNT_PENDINGSCANS, var, 0 );
var.SetUI4( sState.cFilteredDocuments );
VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_COUNT_FILTERED, var, 0 );
var.SetUI4( sState.cTotalDocuments );
VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_COUNT_TOTAL, var, 0 );
var.SetUI4( sState.cUniqueKeys );
VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_COUNT_UNIQUE, var, 0 );
var.SetUI4( sState.dwIndexSize );
VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_SIZE, var, 0 );
if ( sState.eState & CI_STATE_SHADOW_MERGE )
var.SetBOOL( VARIANT_TRUE );
else
var.SetBOOL( VARIANT_FALSE );
VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_STATE_SHADOWMERGE, var, 0 );
if ( sState.eState & CI_STATE_MASTER_MERGE )
var.SetBOOL( VARIANT_TRUE );
else
var.SetBOOL( VARIANT_FALSE );
VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_STATE_MASTERMERGE, var, 0 );
if ( sState.eState & CI_STATE_ANNEALING_MERGE )
var.SetBOOL( VARIANT_TRUE );
else
var.SetBOOL( VARIANT_FALSE );
VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_STATE_ANNEALINGMERGE, var, 0 );
if ( sState.eState & CI_STATE_CONTENT_SCAN_REQUIRED )
var.SetBOOL( VARIANT_TRUE );
else
var.SetBOOL( VARIANT_FALSE );
VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_STATE_SCANREQUIRED, var, 0 );
if ( sState.eState & CI_STATE_SCANNING )
var.SetBOOL( VARIANT_TRUE );
else
var.SetBOOL( VARIANT_FALSE );
VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_STATE_SCANNING, var, 0 );
if ( sState.eState & CI_STATE_RECOVERING )
var.SetBOOL( VARIANT_TRUE );
else
var.SetBOOL( VARIANT_FALSE );
VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_STATE_RECOVERING, var, 0 );
//
// Now that we've got the variables, we can parse the file.
//
SuccessHTX.ParseFile( wcsPhysicalName, VarSet, OutputFormat );
if ( SuccessHTX.DoesDetailSectionExist() )
{
THROW( CIDQException(MSG_CI_IDA_TEMPLATE_DETAIL_SECTION, 0) );
}
break;
}
case CIDAFile::ForceMerge:
{
SuccessHTX.ParseFile( wcsPhysicalName, VarSet, OutputFormat );
if ( SuccessHTX.DoesDetailSectionExist() )
{
THROW( CIDQException(MSG_CI_IDA_TEMPLATE_DETAIL_SECTION, 0) );
}
SCODE sc = ForceMasterMerge( wcsCatalog.GetPointer(), // Drive
wcsCatalog.GetPointer(), // Catalog
wcsMachine.GetPointer(), // Machine
1 ); // Partition
if ( FAILED(sc) )
{
ciGibDebugOut(( DEB_ERROR, "Error 0x%x calling ForceMerge for %ws\n",
sc, wcsCatalog.GetPointer() ));
THROW( CException( sc ) );
}
break;
}
}
//
// Set CiQueryTime
//
ULONG cwcQueryTime = 40;
SYSTEMTIME QueryTime;
GetLocalTime( &QueryTime );
XArray<WCHAR> wcsQueryTime(cwcQueryTime-1);
cwcQueryTime = OutputFormat.FormatTime( QueryTime,
wcsQueryTime.GetPointer(),
cwcQueryTime );
//
// SetCiQueryDate
//
ULONG cwcQueryDate = 40;
XArray<WCHAR> wcsQueryDate(cwcQueryDate-1);
cwcQueryDate = OutputFormat.FormatDate( QueryTime,
wcsQueryDate.GetPointer(),
cwcQueryDate );
VarSet.AcquireStringValue( ISAPI_CI_QUERY_TIME, wcsQueryTime.GetPointer(), 0 );
wcsQueryTime.Acquire();
VarSet.AcquireStringValue( ISAPI_CI_QUERY_DATE, wcsQueryDate.GetPointer(), 0 );
wcsQueryDate.Acquire();
//
// Set CiQueryTimeZone
//
TIME_ZONE_INFORMATION TimeZoneInformation;
DWORD dwResult = GetTimeZoneInformation( &TimeZoneInformation );
LPWSTR pwszTimeZoneName = 0;
if ( TIME_ZONE_ID_DAYLIGHT == dwResult )
{
pwszTimeZoneName = TimeZoneInformation.DaylightName;
}
else if ( 0xFFFFFFFF == dwResult )
{
# if CIDBG == 1
DWORD dwError = GetLastError();
ciGibDebugOut(( DEB_ERROR, "Error %d from GetTimeZoneInformation.\n", dwError ));
THROW(CException( HRESULT_FROM_WIN32(dwError) ));
# else
THROW( CException() );
# endif
}
else
{
pwszTimeZoneName = TimeZoneInformation.StandardName;
}
VarSet.CopyStringValue( ISAPI_CI_QUERY_TIMEZONE, pwszTimeZoneName, 0);
//
// Set CiCatalog, CiLocale and CiTemplate
//
VarSet.AcquireStringValue( ISAPI_CI_CATALOG, wcsCiCatalog.GetPointer(), 0 );
wcsCiCatalog.Acquire();
VarSet.AcquireStringValue( ISAPI_CI_LOCALE, wcsLocale.GetPointer(), 0 );
wcsLocale.Acquire();
VarSet.CopyStringValue( ISAPI_CI_TEMPLATE, SuccessHTX.GetVirtualName(), 0 );
//
// If we got here, then all changes succeeded and we build success page.
//
SuccessHTX.GetHeader( vsResults, VarSet, OutputFormat );
SuccessHTX.GetFooter( vsResults, VarSet, OutputFormat );
}
BOOL ParseGuid( WCHAR const * pwcsGuid, GUID & guid )
{
unsigned cc = wcslen( pwcsGuid );
if ( cc < ccStringizedGuid ||
L'-' != pwcsGuid[8] ||
L'-' != pwcsGuid[13] ||
L'-' != pwcsGuid[18] ||
L'-' != pwcsGuid[23] )
{
ciGibDebugOut(( DEB_WARN, "Improperly formatted guid %ws\n", pwcsGuid ));
return FALSE;
}
//
// Copy into local, editable, storage
//
WCHAR wcsGuid[ccStringizedGuid + 1];
RtlCopyMemory( wcsGuid, pwcsGuid, (ccStringizedGuid + 1) * sizeof(WCHAR) );
wcsGuid[ccStringizedGuid] = 0;
wcsGuid[8] = 0;
WCHAR * pwcStart = &wcsGuid[0];
WCHAR * pwcEnd;
guid.Data1 = wcstoul( pwcStart, &pwcEnd, 16 );
if ( (pwcEnd-pwcStart) != 8 ) // The 1st number MUST be 8 digits long
return FALSE;
wcsGuid[13] = 0;
pwcStart = &wcsGuid[9];
guid.Data2 = (USHORT)wcstoul( pwcStart, &pwcEnd, 16 );
if ( (pwcEnd-pwcStart) != 4 ) // The 2nd number MUST be 4 digits long
return FALSE;
wcsGuid[18] = 0;
pwcStart = &wcsGuid[14];
guid.Data3 = (USHORT)wcstoul( pwcStart, &pwcEnd, 16 );
if ( (pwcEnd-pwcStart) != 4 ) // The 3rd number MUST be 4 digits long
return FALSE;
WCHAR wc = wcsGuid[21];
wcsGuid[21] = 0;
pwcStart = &wcsGuid[19];
guid.Data4[0] = (unsigned char)wcstoul( pwcStart, &pwcEnd, 16 );
if ( (pwcEnd-pwcStart) != 2 ) // The 4th number MUST be 4 digits long
return FALSE;
wcsGuid[21] = wc;
wcsGuid[23] = 0;
pwcStart = &wcsGuid[21];
guid.Data4[1] = (unsigned char)wcstoul( pwcStart, &pwcEnd, 16 );
if ( (pwcEnd-pwcStart) != 2 ) // The 4th number MUST be 4 digits long
return FALSE;
for ( unsigned i = 0; i < 6; i++ )
{
wc = wcsGuid[26+i*2];
wcsGuid[26+i*2] = 0;
pwcStart = &wcsGuid[24+i*2];
guid.Data4[2+i] = (unsigned char)wcstoul( pwcStart, &pwcEnd, 16 );
if ( pwcStart == pwcEnd )
return FALSE;
wcsGuid[26+i*2] = wc;
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Function: CheckAdminSecurity, public
//
// Synopsis: Checks to see if the client has administrative access.
//
// Arguments: [pwszMachine] - machine name
//
// Returns: Nothing, throws if access is denied.
//
// Notes: The ACL on the HKEY_CURRENT_MACHINE\system\CurrentControlSet\
// Control\ContentIndex registry key is used to determine if
// access is permitted.
//
// The access check is only done when the administrative operation
// is local. Otherwise, it will be checked in the course of doing
// the administrative operation.
//
// History: 26 Jun 96 AlanW Created.
//
//----------------------------------------------------------------------------
void CheckAdminSecurity( WCHAR const * pwszMachine )
{
HKEY hNewKey = (HKEY) INVALID_HANDLE_VALUE;
if ( 0 != wcscmp( pwszMachine, CATURL_LOCAL_MACHINE ) )
return;
LONG dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
wcsRegAdminSubKey,
0,
KEY_WRITE,
&hNewKey );
if ( ERROR_SUCCESS == dwError )
{
RegCloseKey( hNewKey );
}
else if ( ERROR_ACCESS_DENIED == dwError )
{
THROW(CException( STATUS_ACCESS_DENIED ) );
}
else
{
ciGibDebugOut(( DEB_ERROR,
"Can not open reg key %ws, error %d\n",
wcsRegAdminSubKey, dwError ));
THROW(CException( HRESULT_FROM_WIN32( dwError ) ) );
}
}