//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996 - 2001. // // File: ida.cxx // // Contents: Parser for an IDQ file // // History: 96/Jan/3 DwightKr Created // //---------------------------------------------------------------------------- #include #pragma hdrstop #include // // 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 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 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 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 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 xIDAFile( new CIDAFile(wcsIDAFile, OutputFormat.CodePage()) ); xIDAFile->ParseFile(); ULONG cwcOut; XPtrST wcsLocaleID( ReplaceParameters( xIDAFile->GetLocale(), VarSet, OutputFormat, cwcOut ) ); XArray 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 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 wcsMachine( 0 ); XPtrST 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 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 = physical root for // Variable: S = "on" / existence means root is scanned // Variable: T = "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 ) + 10 ]; 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__NAME_ = Size for named entry // Variable: CACHESIZE__PROPID_ = Size for numbered entry // Variable: CACHETYPE__NAME_ = Type for named entry // Variable: CACHETYPE__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 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 wcsQueryTime(cwcQueryTime+1); cwcQueryTime = OutputFormat.FormatTime( QueryTime, wcsQueryTime.GetPointer(), cwcQueryTime ); // // SetCiQueryDate // ULONG cwcQueryDate = 40; XArray 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 ) ) ); } }