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.

1285 lines
40 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 2001.
  5. //
  6. // File: ida.cxx
  7. //
  8. // Contents: Parser for an IDQ file
  9. //
  10. // History: 96/Jan/3 DwightKr Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. #include <fsciexps.hxx>
  16. //
  17. // Constants
  18. //
  19. static WCHAR const wcsPRootVar[] = L"PROOT_";
  20. unsigned const ccPRootVar = sizeof(wcsPRootVar)/sizeof(WCHAR) - 1;
  21. static WCHAR const wcsIndexVar[] = L"INDEX_";
  22. unsigned const ccIndexVar = sizeof(wcsIndexVar)/sizeof(WCHAR) - 1;
  23. static WCHAR const wcsNNTP[] = L"NNTP_";
  24. unsigned const ccNNTP = sizeof(wcsNNTP)/sizeof(WCHAR) - 1;
  25. static WCHAR const wcsIMAP[] = L"IMAP_";
  26. unsigned const ccIMAP = sizeof(wcsIMAP)/sizeof(WCHAR) - 1;
  27. static WCHAR const wcsScanVar[] = L"SCAN_";
  28. unsigned const ccScanVar = sizeof(wcsScanVar)/sizeof(WCHAR) - 1;
  29. unsigned const ccStringizedGuid = 36;
  30. BOOL ParseGuid( WCHAR const * pwcsGuid, GUID & guid );
  31. //+---------------------------------------------------------------------------
  32. //
  33. // Member: CIDAFile::CIDAFile - public constructor
  34. //
  35. // Synopsis: Builds a CIDAFile object, initializes values
  36. //
  37. // Arguments: [wcsFileName] -- full path to IDQ file
  38. //
  39. // History: 13-Apr-96 KyleP Created.
  40. //
  41. //----------------------------------------------------------------------------
  42. CIDAFile::CIDAFile( WCHAR const * wcsFileName, UINT codePage )
  43. : _eOperation( CIDAFile::CiState ),
  44. _wcsCatalog(0),
  45. _wcsHTXFileName( 0 ),
  46. _wcsLocale(0),
  47. _cReplaceableParameters(0),
  48. _refCount(0),
  49. _codePage(codePage)
  50. {
  51. ULONG cwc = wcslen(wcsFileName);
  52. if ( cwc >= sizeof(_wcsIDAFileName)/sizeof(WCHAR) )
  53. {
  54. ciGibDebugOut(( DEB_WARN, "Too long a path (%ws)\n", wcsFileName ));
  55. THROW( CException( STATUS_INVALID_PARAMETER ));
  56. }
  57. RtlCopyMemory( _wcsIDAFileName, wcsFileName, (cwc+1) * sizeof(WCHAR) );
  58. }
  59. //+---------------------------------------------------------------------------
  60. //
  61. // Member: CIDAFile::~CIDAFile - public destructor
  62. //
  63. // History: 13-Apr-96 KyleP Created.
  64. //
  65. //----------------------------------------------------------------------------
  66. CIDAFile::~CIDAFile()
  67. {
  68. Win4Assert( _refCount == 0 );
  69. delete [] _wcsCatalog;
  70. delete [] _wcsHTXFileName;
  71. delete [] _wcsLocale;
  72. }
  73. //+---------------------------------------------------------------------------
  74. //
  75. // Member: CIDAFile::ParseFile, private
  76. //
  77. // Synopsis: Parses the given file and sets up the necessary variables
  78. //
  79. // History: 13-Apr-96 KyleP Created.
  80. // 23-Jul-96 DwightKr Use mapped file I/O which checks
  81. // ACLs and throws ACCESS_DENIED if
  82. // not available.
  83. //
  84. //----------------------------------------------------------------------------
  85. void CIDAFile::ParseFile()
  86. {
  87. //
  88. // Parse the query parameters
  89. //
  90. XPtr<CFileMapView> xMapView;
  91. TRY
  92. {
  93. xMapView.Set( new CFileMapView( _wcsIDAFileName ) );
  94. xMapView->Init();
  95. }
  96. CATCH( CException, e )
  97. {
  98. if ( HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) == e.GetErrorCode() )
  99. {
  100. THROW( CIDQException( MSG_CI_IDQ_NOT_FOUND, 0 ) );
  101. }
  102. else
  103. {
  104. RETHROW();
  105. }
  106. }
  107. END_CATCH
  108. CFileBuffer idaFile( xMapView.GetReference(), _codePage );
  109. //
  110. // Process a line at a time, look for the [Admin] section and
  111. // process lines within that section.
  112. //
  113. BOOL fAdminSection = FALSE;
  114. int iLine = 0; // Start counting at line #1
  115. for( ;; )
  116. {
  117. iLine++;
  118. XGrowable<WCHAR> xLine;
  119. ULONG cwcChar = idaFile.fgetsw( xLine );
  120. if( 0 == cwcChar )
  121. {
  122. break;
  123. }
  124. WCHAR *pwcLine = xLine.Get();
  125. //
  126. // Skip ahead until we find a [Admin] section
  127. //
  128. if ( L'[' == *pwcLine )
  129. {
  130. if ( _wcsnicmp(pwcLine+1, L"Admin]", 6) == 0 )
  131. fAdminSection = TRUE;
  132. else
  133. fAdminSection = FALSE;
  134. continue;
  135. }
  136. //
  137. // Ignore comments.
  138. //
  139. else if ( L'#' == *pwcLine )
  140. continue;
  141. if ( fAdminSection )
  142. {
  143. CQueryScanner scanner( pwcLine, FALSE );
  144. ParseOneLine( scanner, iLine );
  145. }
  146. }
  147. //
  148. // Verify that the minimum set of parameters are specified.
  149. //
  150. //
  151. // We must have all of the following:
  152. //
  153. // - a HTX file name
  154. //
  155. if ( 0 == _wcsHTXFileName )
  156. {
  157. // Report an error
  158. ciGibDebugOut(( DEB_IERROR, "Template not found in IDA file.\n" ));
  159. THROW( CIDQException(MSG_CI_IDQ_MISSING_TEMPLATEFILE, 0) );
  160. }
  161. //
  162. // If no catalog was specified, use the default catalog in the registry
  163. //
  164. if ( 0 == _wcsCatalog )
  165. {
  166. ciGibDebugOut(( DEB_ITRACE, "Using default catalog\n" ));
  167. WCHAR awcTmp[ MAX_PATH ];
  168. ULONG cwcRequired = TheIDQRegParams.GetISDefaultCatalog( awcTmp,
  169. MAX_PATH );
  170. if ( cwcRequired > MAX_PATH )
  171. THROW( CException(STATUS_INVALID_PARAMETER) );
  172. cwcRequired++; // make room for termination
  173. _wcsCatalog = new WCHAR[ cwcRequired ];
  174. RtlCopyMemory( _wcsCatalog, awcTmp, cwcRequired * sizeof WCHAR );
  175. }
  176. }
  177. //+---------------------------------------------------------------------------
  178. //
  179. // Member: CIDAFile::ParseOneLine, private
  180. //
  181. // Synopsis: Parses one line of the IDQ file
  182. //
  183. // Arguments: [scan] -- scanner initialized with the current line
  184. // [iLine] -- current line number
  185. //
  186. // History: 13-Apr-96 KyleP Created.
  187. //
  188. //----------------------------------------------------------------------------
  189. void CIDAFile::ParseOneLine( CQueryScanner & scan, unsigned iLine )
  190. {
  191. //
  192. // Is this a comment line (does it start with #) or an empty line?
  193. //
  194. if ( scan.LookAhead() == PROP_REGEX_TOKEN || scan.LookAhead() == EOS_TOKEN )
  195. {
  196. return;
  197. }
  198. if ( scan.LookAhead() != TEXT_TOKEN ) // Better be a word
  199. {
  200. // Report an error
  201. THROW( CIDQException( MSG_CI_IDQ_EXPECTING_NAME, iLine ) );
  202. }
  203. XPtrST<WCHAR> wcsAttribute( scan.AcqWord() );
  204. if( wcsAttribute.GetPointer() == 0 ) // Better find a word
  205. {
  206. THROW( CIDQException( MSG_CI_IDQ_EXPECTING_TYPE, iLine ) );
  207. }
  208. scan.Accept();
  209. if ( scan.LookAhead() != EQUAL_TOKEN )
  210. {
  211. // Report an error
  212. THROW( CIDQException( MSG_CI_IDQ_EXPECTING_EQUAL, iLine ) );
  213. }
  214. scan.Accept();
  215. if ( 0 == _wcsicmp( wcsAttribute.GetPointer(), ISAPI_CI_CATALOG ) )
  216. GetStringValue( scan, iLine, &_wcsCatalog );
  217. else if ( 0 == _wcsicmp( wcsAttribute.GetPointer(), ISAPI_CI_TEMPLATE ) )
  218. GetStringValue( scan, iLine, &_wcsHTXFileName );
  219. else if ( 0 == _wcsicmp( wcsAttribute.GetPointer(), ISAPI_CI_ADMIN_OPERATION ) )
  220. {
  221. WCHAR * pwcsTemp = 0;
  222. GetStringValue( scan, iLine, &pwcsTemp );
  223. XPtrST<WCHAR> xwcsTemp( pwcsTemp );
  224. if ( 0 == pwcsTemp )
  225. {
  226. THROW( CIDQException( MSG_CI_IDA_INVALID_OPERATION, iLine ) );
  227. }
  228. else if ( 0 == _wcsicmp( pwcsTemp, wcsOpGetState ) )
  229. _eOperation = CIDAFile::CiState;
  230. else if ( 0 == _wcsicmp( pwcsTemp, wcsOpForceMerge ) )
  231. _eOperation = CIDAFile::ForceMerge;
  232. else if ( 0 == _wcsicmp( pwcsTemp, wcsOpScanRoots ) )
  233. _eOperation = CIDAFile::ScanRoots;
  234. else if ( 0 == _wcsicmp( pwcsTemp, wcsOpUpdateCache ) )
  235. _eOperation = CIDAFile::UpdateCache;
  236. else
  237. {
  238. THROW( CIDQException( MSG_CI_IDA_INVALID_OPERATION, iLine ) );
  239. }
  240. }
  241. else if ( 0 == _wcsicmp( wcsAttribute.GetPointer(), ISAPI_CI_LOCALE ) )
  242. {
  243. GetStringValue( scan, iLine, &_wcsLocale );
  244. }
  245. else
  246. {
  247. //
  248. // We've found a keyword/attribute that we don't support.
  249. // Don't report an error. This will allow this version of the
  250. // parser to work with newer .IDA file versions with new parameters.
  251. //
  252. ciGibDebugOut(( DEB_ERROR, "Invalid string in IDQ file: %ws\n", wcsAttribute.GetPointer() ));
  253. }
  254. }
  255. //+---------------------------------------------------------------------------
  256. //
  257. // Member: CIDAFile::GetStringValue - private
  258. //
  259. // Synopsis: Gets the string value on the currenct line
  260. //
  261. // Arguments: [scan] -- scanner initialized with the current line
  262. // [iLine] -- current line number
  263. // [pwcsStringValue] -- value to put string into
  264. //
  265. // History: 13-Apr-96 KyleP Created.
  266. //
  267. //----------------------------------------------------------------------------
  268. void CIDAFile::GetStringValue( CQueryScanner & scan,
  269. unsigned iLine,
  270. WCHAR ** pwcsStringValue )
  271. {
  272. if ( 0 != *pwcsStringValue )
  273. {
  274. ciGibDebugOut(( DEB_IWARN,
  275. "Duplicate CiXX=value in IDA file on line #%d\n",
  276. iLine ));
  277. THROW( CIDQException(MSG_CI_IDQ_DUPLICATE_ENTRY, iLine) );
  278. }
  279. *pwcsStringValue = scan.AcqLine();
  280. if ( IsAReplaceableParameter( *pwcsStringValue ) != eIsSimpleString )
  281. {
  282. _cReplaceableParameters++;
  283. }
  284. }
  285. //+---------------------------------------------------------------------------
  286. //
  287. // Function: FindEntry, public
  288. //
  289. // Synopsis: Helper function for admin variable parsing.
  290. //
  291. // Arguments: [pwcsName] -- Variable name
  292. // [fScan] -- TRUE for SCAN, FALSE for INDEX
  293. // [pwcsBuf] -- Buffer for search token
  294. //
  295. // History: 10-Oct-96 KyleP Created.
  296. //
  297. //----------------------------------------------------------------------------
  298. BOOL FindEntry( WCHAR const * * ppwcsName, BOOL fScan, WCHAR * pwcsBuf )
  299. {
  300. if ( 0 != _wcsnicmp( *ppwcsName, wcsPRootVar, ccPRootVar ) )
  301. return FALSE;
  302. //
  303. // Scan or Index?
  304. //
  305. WCHAR const * pwcsOutputTag;
  306. unsigned ccOutputTag;
  307. if ( fScan )
  308. {
  309. pwcsOutputTag = wcsScanVar;
  310. ccOutputTag = ccScanVar;
  311. }
  312. else
  313. {
  314. pwcsOutputTag = wcsIndexVar;
  315. ccOutputTag = ccIndexVar;
  316. }
  317. //
  318. // IMAP, NNTP or W3?
  319. //
  320. unsigned ccPrefix = ccOutputTag;
  321. BOOL fW3 = FALSE;
  322. BOOL fNNTP = FALSE;
  323. BOOL fIMAP = FALSE;
  324. if ( 0 == _wcsnicmp( *ppwcsName + ccPRootVar, wcsNNTP, ccNNTP ) )
  325. {
  326. fNNTP = TRUE;
  327. *ppwcsName += ccNNTP;
  328. ccPrefix += ccNNTP;
  329. }
  330. else if ( 0 == _wcsnicmp( *ppwcsName + ccPRootVar, wcsIMAP, ccIMAP ) )
  331. {
  332. fIMAP = TRUE;
  333. *ppwcsName += ccIMAP;
  334. ccPrefix += ccIMAP;
  335. }
  336. else
  337. {
  338. fW3 = TRUE;
  339. }
  340. *ppwcsName += ccPRootVar;
  341. //
  342. // Length check.
  343. //
  344. unsigned ccName = wcslen( *ppwcsName ) + 1;
  345. if ( ccName + ccPrefix > (MAX_PATH + ccIndexVar + ccNNTP + 1) )
  346. {
  347. ciGibDebugOut(( DEB_WARN, "Path %ws too long for admin\n", *ppwcsName ));
  348. return FALSE;
  349. }
  350. if ( ccName + ccPrefix > (MAX_PATH + ccIndexVar + ccIMAP + 1) )
  351. {
  352. ciGibDebugOut(( DEB_WARN, "Path %ws too long for admin\n", *ppwcsName ));
  353. return FALSE;
  354. }
  355. //
  356. // Build output name
  357. //
  358. RtlCopyMemory( pwcsBuf, pwcsOutputTag, ccOutputTag * sizeof(WCHAR) );
  359. if ( fNNTP )
  360. RtlCopyMemory( pwcsBuf + ccOutputTag, wcsNNTP, ccNNTP * sizeof(WCHAR) );
  361. else if ( fIMAP )
  362. RtlCopyMemory( pwcsBuf + ccOutputTag, wcsIMAP, ccIMAP * sizeof(WCHAR) );
  363. RtlCopyMemory( pwcsBuf + ccPrefix, *ppwcsName, ccName * sizeof(WCHAR) );
  364. return TRUE;
  365. }
  366. //+---------------------------------------------------------------------------
  367. //
  368. // Function: DoAdmin, public
  369. //
  370. // Synopsis: Executes an administrative change.
  371. //
  372. // Arguments: [wcsIDAFile] -- Virtual path to .IDA file
  373. // [VarSet] -- Query variables
  374. // [OutputFormat] -- Output format
  375. // [vsResults] -- On success (non exception) result page
  376. // written here.
  377. //
  378. // History: 13-Apr-96 KyleP Created.
  379. // 22-Jul-96 DwightKr Make CiLocale replaceable & visible
  380. // in HTX files
  381. // 11-Jun-97 KyleP Use web server in Output Format
  382. //
  383. //----------------------------------------------------------------------------
  384. void DoAdmin( WCHAR const * wcsIDAFile,
  385. CVariableSet & VarSet,
  386. COutputFormat & OutputFormat,
  387. CVirtualString & vsResults )
  388. {
  389. //
  390. // Parse .IDA file. We don't bother to cache these.
  391. //
  392. XPtr<CIDAFile> xIDAFile( new CIDAFile(wcsIDAFile, OutputFormat.CodePage()) );
  393. xIDAFile->ParseFile();
  394. ULONG cwcOut;
  395. XPtrST<WCHAR> wcsLocaleID( ReplaceParameters( xIDAFile->GetLocale(),
  396. VarSet,
  397. OutputFormat,
  398. cwcOut ) );
  399. XArray<WCHAR> wcsLocale;
  400. LCID locale = GetQueryLocale( wcsLocaleID.GetPointer(),
  401. VarSet,
  402. OutputFormat,
  403. wcsLocale );
  404. if ( OutputFormat.GetLCID() != locale )
  405. {
  406. ciGibDebugOut(( DEB_ITRACE,
  407. "Wrong codePage used for loading IDA file, used 0x%x retrying with 0x%x\n",
  408. OutputFormat.CodePage(),
  409. LocaleToCodepage(locale) ));
  410. //
  411. // We've parsed the IDA file with the wrong locale.
  412. //
  413. delete xIDAFile.Acquire();
  414. OutputFormat.LoadNumberFormatInfo( locale );
  415. xIDAFile.Set( new CIDAFile(wcsIDAFile, OutputFormat.CodePage()) );
  416. xIDAFile->ParseFile();
  417. }
  418. SetupDefaultCiVariables( VarSet );
  419. SetupDefaultISAPIVariables( VarSet );
  420. SetCGIVariables( VarSet, OutputFormat );
  421. //
  422. // Get the catalog.
  423. //
  424. XPtrST<WCHAR> wcsCiCatalog( ReplaceParameters( xIDAFile->GetCatalog(),
  425. VarSet,
  426. OutputFormat,
  427. cwcOut ) );
  428. //
  429. // Verify that the wcsCatalog is valid
  430. //
  431. if ( !IsAValidCatalog( wcsCiCatalog.GetPointer(), cwcOut ) )
  432. {
  433. THROW( CIDQException(MSG_CI_IDQ_NO_SUCH_CATALOG, 0) );
  434. }
  435. //
  436. // Get the catalog and machine from the URL style catalog.
  437. //
  438. XPtrST<WCHAR> wcsMachine( 0 );
  439. XPtrST<WCHAR> wcsCatalog( 0 );
  440. SCODE sc = ParseCatalogURL( wcsCiCatalog.GetPointer(),
  441. wcsCatalog,
  442. wcsMachine );
  443. if (FAILED(sc))
  444. {
  445. THROW( CException(sc) );
  446. }
  447. Win4Assert ( 0 != wcsMachine.GetPointer() );
  448. //
  449. // Check that the client is allowed to perform administration
  450. //
  451. CheckAdminSecurity( wcsMachine.GetPointer() );
  452. //
  453. // Build the HTX page for [success] output
  454. //
  455. XPtrST<WCHAR> wcsTemplate( ReplaceParameters( xIDAFile->GetHTXFileName(),
  456. VarSet,
  457. OutputFormat,
  458. cwcOut ) );
  459. WCHAR wcsPhysicalName[_MAX_PATH];
  460. if ( OutputFormat.IsValid() )
  461. {
  462. OutputFormat.GetPhysicalPath( wcsTemplate.GetPointer(),
  463. wcsPhysicalName,
  464. _MAX_PATH );
  465. }
  466. else
  467. {
  468. if ( !GetFullPathName( wcsTemplate.GetPointer(),
  469. MAX_PATH,
  470. wcsPhysicalName,
  471. 0 ) )
  472. {
  473. THROW( CException() );
  474. }
  475. }
  476. //
  477. // Note: Parsing of HTX file needs to be done in different locations
  478. // to ensure variables added to variable set by admin operations
  479. // are added before parse. But we also don't want to fail the
  480. // parse *after* doing a dangerous operation (like force merge).
  481. //
  482. CSecurityIdentity securityStub;
  483. CHTXFile SuccessHTX( wcsTemplate,
  484. OutputFormat.CodePage(),
  485. securityStub,
  486. OutputFormat.GetServerInstance() );
  487. switch ( xIDAFile->Operation() )
  488. {
  489. case CIDAFile::ScanRoots:
  490. {
  491. SuccessHTX.ParseFile( wcsPhysicalName, VarSet, OutputFormat );
  492. if ( SuccessHTX.DoesDetailSectionExist() )
  493. {
  494. THROW( CIDQException(MSG_CI_IDA_TEMPLATE_DETAIL_SECTION, 0) );
  495. }
  496. //
  497. // Execute the changes. 'Entries' have the following format:
  498. // Variable: P<virtual root> = physical root for <virtual root>
  499. // Variable: S<virtual root> = "on" / existence means root is scanned
  500. // Variable: T<virtual root> = "on" / existence means full scan
  501. //
  502. CVariableSetIter iter( VarSet );
  503. while ( !iter.AtEnd() )
  504. {
  505. CVariable * pVar = iter.Get();
  506. WCHAR const * pwcsName = pVar->GetName();
  507. WCHAR wcsScanName[MAX_PATH + ccScanVar + __max( ccNNTP, ccIMAP ) + 10 ];
  508. if ( FindEntry( &pwcsName, // Starting variable
  509. TRUE, // SCAN
  510. wcsScanName )) // Matching search string returned here
  511. {
  512. PROPVARIANT * ppvPRoot = pVar->GetValue();
  513. CVariable * pScanVar = VarSet.Find( wcsScanName );
  514. if ( 0 != pScanVar )
  515. {
  516. WCHAR const * pwszScanType = pScanVar->GetStringValueRAW();
  517. if ( 0 != pwszScanType &&
  518. ( 0 == _wcsicmp( pwszScanType, L"FullScan" ) ||
  519. 0 == _wcsicmp( pwszScanType, L"IncrementalScan")
  520. ) )
  521. {
  522. BOOL fFull = (0 == _wcsicmp( pwszScanType, L"FullScan" ));
  523. SCODE sc = UpdateContentIndex( ppvPRoot->pwszVal,
  524. wcsCatalog.GetPointer(),
  525. wcsMachine.GetPointer(),
  526. fFull );
  527. if ( FAILED(sc) )
  528. {
  529. ciGibDebugOut(( DEB_ERROR,
  530. "Error 0x%x scanning virtual scope %ws\n",
  531. pwcsName ));
  532. THROW( CException( sc ) );
  533. }
  534. }
  535. }
  536. }
  537. iter.Next();
  538. }
  539. break;
  540. }
  541. case CIDAFile::UpdateCache:
  542. {
  543. SuccessHTX.ParseFile( wcsPhysicalName, VarSet, OutputFormat );
  544. if ( SuccessHTX.DoesDetailSectionExist() )
  545. {
  546. THROW( CIDQException(MSG_CI_IDA_TEMPLATE_DETAIL_SECTION, 0) );
  547. }
  548. //
  549. // Execute the changes. 'Entries' have the following format:
  550. // Variable: CACHESIZE_<guid>_NAME_<name> = Size for named entry
  551. // Variable: CACHESIZE_<guid>_PROPID_<propid> = Size for numbered entry
  552. // Variable: CACHETYPE_<guid>_NAME_<name> = Type for named entry
  553. // Variable: CACHETYPE_<guid>_PROPID_<propid> = Type for numbered entry
  554. //
  555. CVariableSetIter iter( VarSet );
  556. BOOL fSawOne = FALSE;
  557. ULONG_PTR ulToken;
  558. SCODE sc = BeginCacheTransaction( &ulToken,
  559. wcsCatalog.GetPointer(),
  560. wcsCatalog.GetPointer(),
  561. wcsMachine.GetPointer() );
  562. if ( FAILED(sc) )
  563. {
  564. ciGibDebugOut(( DEB_ERROR, "Error 0x%x setting up cache transaction.\n", sc ));
  565. THROW( CException( sc ) );
  566. }
  567. while ( !iter.AtEnd() )
  568. {
  569. CVariable * pVar = iter.Get();
  570. WCHAR const * pwcsName = pVar->GetName();
  571. //
  572. // We write out last prop twice, 2nd time to commit everything.
  573. //
  574. //
  575. // Constants.
  576. //
  577. static WCHAR const wcsSizeVar[] = L"CACHESIZE_";
  578. unsigned ccSizeVar = sizeof(wcsSizeVar)/sizeof(WCHAR) - 1;
  579. static WCHAR const wcsTypeVar[] = L"CACHETYPE_";
  580. unsigned ccTypeVar = sizeof(wcsTypeVar)/sizeof(WCHAR) - 1;
  581. if ( 0 == _wcsnicmp( pwcsName, wcsSizeVar, ccSizeVar ) )
  582. {
  583. CFullPropSpec ps;
  584. //
  585. // Parse the GUID.
  586. //
  587. unsigned cc = wcslen( pwcsName );
  588. GUID guid;
  589. if ( cc <= ccSizeVar || !ParseGuid( pwcsName + ccSizeVar, guid ) )
  590. {
  591. ciGibDebugOut(( DEB_WARN, "Improperly formatted CACHESIZE entry %ws\n", pwcsName ));
  592. iter.Next();
  593. continue;
  594. }
  595. ps.SetPropSet( guid );
  596. //
  597. // PROPID or string?
  598. //
  599. static WCHAR const wcsName[] = L"_NAME_";
  600. unsigned ccName = sizeof(wcsName)/sizeof(WCHAR) - 1;
  601. static WCHAR const wcsPropid[] = L"_PROPID_";
  602. unsigned ccPropid = sizeof(wcsPropid)/sizeof(WCHAR) - 1;
  603. if ( 0 == _wcsnicmp( pwcsName + ccSizeVar + ccStringizedGuid, wcsPropid, ccPropid ) )
  604. {
  605. CQueryScanner scan( pwcsName + ccSizeVar + ccStringizedGuid + ccPropid, FALSE );
  606. PROPID propid;
  607. BOOL fEnd;
  608. if ( !scan.GetNumber( propid, fEnd ) )
  609. {
  610. ciGibDebugOut(( DEB_WARN, "Improperly formatted CACHESIZE entry %ws\n", pwcsName ));
  611. iter.Next();
  612. continue;
  613. }
  614. ps.SetProperty( propid );
  615. }
  616. else if ( 0 == _wcsnicmp( pwcsName + ccSizeVar + ccStringizedGuid, wcsName, ccName ) )
  617. {
  618. ps.SetProperty( pwcsName + ccSizeVar + ccStringizedGuid + ccName );
  619. }
  620. else
  621. {
  622. ciGibDebugOut(( DEB_WARN, "Improperly formatted CACHESIZE entry %ws\n", pwcsName ));
  623. iter.Next();
  624. continue;
  625. }
  626. //
  627. // Get value.
  628. //
  629. PROPVARIANT * ppvSize = pVar->GetValue();
  630. ULONG cb;
  631. if ( ppvSize->vt == VT_LPWSTR )
  632. {
  633. CQueryScanner scan( ppvSize->pwszVal, FALSE );
  634. BOOL fEnd;
  635. if ( !scan.GetNumber( cb, fEnd ) )
  636. {
  637. ciGibDebugOut(( DEB_WARN, "Improper CACHESIZE size: \"%ws\".\n", ppvSize->pwszVal ));
  638. iter.Next();
  639. continue;
  640. }
  641. }
  642. else
  643. {
  644. ciGibDebugOut(( DEB_IWARN, "Improper CACHESIZE size (type = %d).\n", ppvSize->vt ));
  645. iter.Next();
  646. continue;
  647. }
  648. if ( 0 == cb )
  649. {
  650. //
  651. // Delete property from cache (if it was even there).
  652. //
  653. //
  654. // If IDA were the future...
  655. // Need to allow primary or secondary store to be chosen!
  656. // Also allow the ability to set true/false for prop meta info
  657. // modifiability.
  658. //
  659. SCODE sc = SetupCacheEx( ps.CastToStruct(),
  660. 0,
  661. 0,
  662. ulToken,
  663. TRUE,
  664. PRIMARY_STORE,
  665. wcsCatalog.GetPointer(),
  666. wcsCatalog.GetPointer(),
  667. wcsMachine.GetPointer() );
  668. if ( FAILED(sc) )
  669. {
  670. ciGibDebugOut(( DEB_ERROR, "Error 0x%x modifying cache\n", sc ));
  671. THROW( CException( sc ) );
  672. }
  673. fSawOne = TRUE;
  674. iter.Next();
  675. continue;
  676. }
  677. //
  678. // At this point, we have a non-zero size. The property will
  679. // be added to the cache.
  680. //
  681. //
  682. // Fetch data type
  683. //
  684. XArray<WCHAR> xVar(cc+1);
  685. RtlCopyMemory( xVar.GetPointer(), pwcsName, (cc+1) * sizeof(WCHAR) );
  686. RtlCopyMemory( xVar.GetPointer(), wcsTypeVar, ccTypeVar * sizeof(WCHAR) );
  687. CVariable * pVarType = VarSet.Find( xVar.GetPointer() );
  688. if ( 0 == pVarType )
  689. {
  690. ciGibDebugOut(( DEB_WARN, "Missing CACHETYPE value.\n" ));
  691. iter.Next();
  692. continue;
  693. }
  694. PROPVARIANT * ppvType = pVarType->GetValue();
  695. ULONG type;
  696. if ( ppvType->vt == VT_LPWSTR )
  697. {
  698. CQueryScanner scan( ppvType->pwszVal, FALSE );
  699. BOOL fEnd;
  700. if ( !scan.GetNumber( type, fEnd ) )
  701. {
  702. ciGibDebugOut(( DEB_WARN, "Improper CACHETYPE type: \"%ws\".\n", ppvType->pwszVal ));
  703. iter.Next();
  704. continue;
  705. }
  706. }
  707. else
  708. {
  709. ciGibDebugOut(( DEB_WARN, "Improper CACHETYPE size (type = %d).\n", ppvType->vt ));
  710. iter.Next();
  711. continue;
  712. }
  713. ciGibDebugOut(( DEB_WARN, "Add/change %ws\n", pwcsName ));
  714. //
  715. // If IDA were the future...
  716. // Need to allow primary or secondary store to be chosen!
  717. // Also allow the ability to set true/false for prop meta info
  718. // modifiability.
  719. //
  720. SCODE sc = SetupCacheEx( ps.CastToStruct(),
  721. type,
  722. cb,
  723. ulToken,
  724. TRUE,
  725. SECONDARY_STORE,
  726. wcsCatalog.GetPointer(),
  727. wcsCatalog.GetPointer(),
  728. wcsMachine.GetPointer() );
  729. if ( FAILED(sc) )
  730. {
  731. ciGibDebugOut(( DEB_ERROR, "Error 0x%x modifying cache\n", sc ));
  732. THROW( CException( sc ) );
  733. }
  734. fSawOne = TRUE;
  735. }
  736. iter.Next();
  737. }
  738. sc = EndCacheTransaction( ulToken,
  739. fSawOne,
  740. wcsCatalog.GetPointer(),
  741. wcsCatalog.GetPointer(),
  742. wcsMachine.GetPointer() );
  743. if ( FAILED(sc) )
  744. {
  745. ciGibDebugOut(( DEB_ERROR, "Error 0x%x completing cache transaction.\n", sc ));
  746. THROW( CException( sc ) );
  747. }
  748. break;
  749. }
  750. case CIDAFile::CiState:
  751. {
  752. //
  753. // Populate the variable set.
  754. //
  755. CStorageVariant var;
  756. var.SetUI4( TheWebQueryCache.Hits() );
  757. VarSet.SetVariable( ISAPI_CI_ADMIN_CACHE_HITS, var, 0 );
  758. var.SetUI4( TheWebQueryCache.Misses() );
  759. VarSet.SetVariable( ISAPI_CI_ADMIN_CACHE_MISSES, var, 0 );
  760. var.SetUI4( TheWebQueryCache.Running() );
  761. VarSet.SetVariable( ISAPI_CI_ADMIN_CACHE_ACTIVE, var, 0 );
  762. var.SetUI4( TheWebQueryCache.Cached() );
  763. VarSet.SetVariable( ISAPI_CI_ADMIN_CACHE_COUNT, var, 0 );
  764. var.SetUI4( TheWebPendingRequestQueue.Count() );
  765. VarSet.SetVariable( ISAPI_CI_ADMIN_CACHE_PENDING, var, 0 );
  766. var.SetUI4( TheWebQueryCache.Rejected() );
  767. VarSet.SetVariable( ISAPI_CI_ADMIN_CACHE_REJECTED, var, 0 );
  768. var.SetUI4( TheWebQueryCache.Total() );
  769. VarSet.SetVariable( ISAPI_CI_ADMIN_CACHE_TOTAL, var, 0 );
  770. var.SetUI4( TheWebQueryCache.QPM() );
  771. VarSet.SetVariable( ISAPI_CI_ADMIN_CACHE_QPM, var, 0 );
  772. //
  773. // Fetch CI state.
  774. //
  775. CI_STATE sState;
  776. sState.cbStruct = sizeof(sState);
  777. SCODE sc = CIState ( wcsCatalog.GetPointer(),
  778. wcsMachine.GetPointer(),
  779. &sState );
  780. if ( FAILED(sc) )
  781. {
  782. ciGibDebugOut(( DEB_ERROR, "Error 0x%x getting CI state.\n", sc ));
  783. THROW( CException( sc ) );
  784. }
  785. var.SetUI4( sState.cWordList );
  786. VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_COUNT_WORDLISTS, var, 0 );
  787. var.SetUI4( sState.cPersistentIndex );
  788. VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_COUNT_PERSINDEX, var, 0 );
  789. var.SetUI4( sState.cQueries );
  790. VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_COUNT_QUERIES, var, 0 );
  791. var.SetUI4( sState.cDocuments );
  792. VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_COUNT_TOFILTER, var, 0 );
  793. var.SetUI4( sState.cFreshTest );
  794. VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_COUNT_FRESHTEST, var, 0 );
  795. var.SetUI4( sState.dwMergeProgress );
  796. VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_MERGE_PROGRESS, var, 0 );
  797. var.SetUI4( sState.cPendingScans );
  798. VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_COUNT_PENDINGSCANS, var, 0 );
  799. var.SetUI4( sState.cFilteredDocuments );
  800. VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_COUNT_FILTERED, var, 0 );
  801. var.SetUI4( sState.cTotalDocuments );
  802. VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_COUNT_TOTAL, var, 0 );
  803. var.SetUI4( sState.cUniqueKeys );
  804. VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_COUNT_UNIQUE, var, 0 );
  805. var.SetUI4( sState.dwIndexSize );
  806. VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_SIZE, var, 0 );
  807. if ( sState.eState & CI_STATE_SHADOW_MERGE )
  808. var.SetBOOL( VARIANT_TRUE );
  809. else
  810. var.SetBOOL( VARIANT_FALSE );
  811. VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_STATE_SHADOWMERGE, var, 0 );
  812. if ( sState.eState & CI_STATE_MASTER_MERGE )
  813. var.SetBOOL( VARIANT_TRUE );
  814. else
  815. var.SetBOOL( VARIANT_FALSE );
  816. VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_STATE_MASTERMERGE, var, 0 );
  817. if ( sState.eState & CI_STATE_ANNEALING_MERGE )
  818. var.SetBOOL( VARIANT_TRUE );
  819. else
  820. var.SetBOOL( VARIANT_FALSE );
  821. VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_STATE_ANNEALINGMERGE, var, 0 );
  822. if ( sState.eState & CI_STATE_CONTENT_SCAN_REQUIRED )
  823. var.SetBOOL( VARIANT_TRUE );
  824. else
  825. var.SetBOOL( VARIANT_FALSE );
  826. VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_STATE_SCANREQUIRED, var, 0 );
  827. if ( sState.eState & CI_STATE_SCANNING )
  828. var.SetBOOL( VARIANT_TRUE );
  829. else
  830. var.SetBOOL( VARIANT_FALSE );
  831. VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_STATE_SCANNING, var, 0 );
  832. if ( sState.eState & CI_STATE_RECOVERING )
  833. var.SetBOOL( VARIANT_TRUE );
  834. else
  835. var.SetBOOL( VARIANT_FALSE );
  836. VarSet.SetVariable( ISAPI_CI_ADMIN_INDEX_STATE_RECOVERING, var, 0 );
  837. //
  838. // Now that we've got the variables, we can parse the file.
  839. //
  840. SuccessHTX.ParseFile( wcsPhysicalName, VarSet, OutputFormat );
  841. if ( SuccessHTX.DoesDetailSectionExist() )
  842. {
  843. THROW( CIDQException(MSG_CI_IDA_TEMPLATE_DETAIL_SECTION, 0) );
  844. }
  845. break;
  846. }
  847. case CIDAFile::ForceMerge:
  848. {
  849. SuccessHTX.ParseFile( wcsPhysicalName, VarSet, OutputFormat );
  850. if ( SuccessHTX.DoesDetailSectionExist() )
  851. {
  852. THROW( CIDQException(MSG_CI_IDA_TEMPLATE_DETAIL_SECTION, 0) );
  853. }
  854. SCODE sc = ForceMasterMerge( wcsCatalog.GetPointer(), // Drive
  855. wcsCatalog.GetPointer(), // Catalog
  856. wcsMachine.GetPointer(), // Machine
  857. 1 ); // Partition
  858. if ( FAILED(sc) )
  859. {
  860. ciGibDebugOut(( DEB_ERROR, "Error 0x%x calling ForceMerge for %ws\n",
  861. sc, wcsCatalog.GetPointer() ));
  862. THROW( CException( sc ) );
  863. }
  864. break;
  865. }
  866. }
  867. //
  868. // Set CiQueryTime
  869. //
  870. ULONG cwcQueryTime = 40;
  871. SYSTEMTIME QueryTime;
  872. GetLocalTime( &QueryTime );
  873. XArray<WCHAR> wcsQueryTime(cwcQueryTime+1);
  874. cwcQueryTime = OutputFormat.FormatTime( QueryTime,
  875. wcsQueryTime.GetPointer(),
  876. cwcQueryTime );
  877. //
  878. // SetCiQueryDate
  879. //
  880. ULONG cwcQueryDate = 40;
  881. XArray<WCHAR> wcsQueryDate(cwcQueryDate+1);
  882. cwcQueryDate = OutputFormat.FormatDate( QueryTime,
  883. wcsQueryDate.GetPointer(),
  884. cwcQueryDate );
  885. VarSet.AcquireStringValue( ISAPI_CI_QUERY_TIME, wcsQueryTime.GetPointer(), 0 );
  886. wcsQueryTime.Acquire();
  887. VarSet.AcquireStringValue( ISAPI_CI_QUERY_DATE, wcsQueryDate.GetPointer(), 0 );
  888. wcsQueryDate.Acquire();
  889. //
  890. // Set CiQueryTimeZone
  891. //
  892. TIME_ZONE_INFORMATION TimeZoneInformation;
  893. DWORD dwResult = GetTimeZoneInformation( &TimeZoneInformation );
  894. LPWSTR pwszTimeZoneName = 0;
  895. if ( TIME_ZONE_ID_DAYLIGHT == dwResult )
  896. {
  897. pwszTimeZoneName = TimeZoneInformation.DaylightName;
  898. }
  899. else if ( 0xFFFFFFFF == dwResult )
  900. {
  901. # if CIDBG == 1
  902. DWORD dwError = GetLastError();
  903. ciGibDebugOut(( DEB_ERROR, "Error %d from GetTimeZoneInformation.\n", dwError ));
  904. THROW(CException( HRESULT_FROM_WIN32(dwError) ));
  905. # else
  906. THROW( CException() );
  907. # endif
  908. }
  909. else
  910. {
  911. pwszTimeZoneName = TimeZoneInformation.StandardName;
  912. }
  913. VarSet.CopyStringValue( ISAPI_CI_QUERY_TIMEZONE, pwszTimeZoneName, 0);
  914. //
  915. // Set CiCatalog, CiLocale and CiTemplate
  916. //
  917. VarSet.AcquireStringValue( ISAPI_CI_CATALOG, wcsCiCatalog.GetPointer(), 0 );
  918. wcsCiCatalog.Acquire();
  919. VarSet.AcquireStringValue( ISAPI_CI_LOCALE, wcsLocale.GetPointer(), 0 );
  920. wcsLocale.Acquire();
  921. VarSet.CopyStringValue( ISAPI_CI_TEMPLATE, SuccessHTX.GetVirtualName(), 0 );
  922. //
  923. // If we got here, then all changes succeeded and we build success page.
  924. //
  925. SuccessHTX.GetHeader( vsResults, VarSet, OutputFormat );
  926. SuccessHTX.GetFooter( vsResults, VarSet, OutputFormat );
  927. }
  928. BOOL ParseGuid( WCHAR const * pwcsGuid, GUID & guid )
  929. {
  930. unsigned cc = wcslen( pwcsGuid );
  931. if ( cc < ccStringizedGuid ||
  932. L'-' != pwcsGuid[8] ||
  933. L'-' != pwcsGuid[13] ||
  934. L'-' != pwcsGuid[18] ||
  935. L'-' != pwcsGuid[23] )
  936. {
  937. ciGibDebugOut(( DEB_WARN, "Improperly formatted guid %ws\n", pwcsGuid ));
  938. return FALSE;
  939. }
  940. //
  941. // Copy into local, editable, storage
  942. //
  943. WCHAR wcsGuid[ccStringizedGuid + 1];
  944. RtlCopyMemory( wcsGuid, pwcsGuid, (ccStringizedGuid + 1) * sizeof(WCHAR) );
  945. wcsGuid[ccStringizedGuid] = 0;
  946. wcsGuid[8] = 0;
  947. WCHAR * pwcStart = &wcsGuid[0];
  948. WCHAR * pwcEnd;
  949. guid.Data1 = wcstoul( pwcStart, &pwcEnd, 16 );
  950. if ( (pwcEnd-pwcStart) != 8 ) // The 1st number MUST be 8 digits long
  951. return FALSE;
  952. wcsGuid[13] = 0;
  953. pwcStart = &wcsGuid[9];
  954. guid.Data2 = (USHORT)wcstoul( pwcStart, &pwcEnd, 16 );
  955. if ( (pwcEnd-pwcStart) != 4 ) // The 2nd number MUST be 4 digits long
  956. return FALSE;
  957. wcsGuid[18] = 0;
  958. pwcStart = &wcsGuid[14];
  959. guid.Data3 = (USHORT)wcstoul( pwcStart, &pwcEnd, 16 );
  960. if ( (pwcEnd-pwcStart) != 4 ) // The 3rd number MUST be 4 digits long
  961. return FALSE;
  962. WCHAR wc = wcsGuid[21];
  963. wcsGuid[21] = 0;
  964. pwcStart = &wcsGuid[19];
  965. guid.Data4[0] = (unsigned char)wcstoul( pwcStart, &pwcEnd, 16 );
  966. if ( (pwcEnd-pwcStart) != 2 ) // The 4th number MUST be 4 digits long
  967. return FALSE;
  968. wcsGuid[21] = wc;
  969. wcsGuid[23] = 0;
  970. pwcStart = &wcsGuid[21];
  971. guid.Data4[1] = (unsigned char)wcstoul( pwcStart, &pwcEnd, 16 );
  972. if ( (pwcEnd-pwcStart) != 2 ) // The 4th number MUST be 4 digits long
  973. return FALSE;
  974. for ( unsigned i = 0; i < 6; i++ )
  975. {
  976. wc = wcsGuid[26+i*2];
  977. wcsGuid[26+i*2] = 0;
  978. pwcStart = &wcsGuid[24+i*2];
  979. guid.Data4[2+i] = (unsigned char)wcstoul( pwcStart, &pwcEnd, 16 );
  980. if ( pwcStart == pwcEnd )
  981. return FALSE;
  982. wcsGuid[26+i*2] = wc;
  983. }
  984. return TRUE;
  985. }
  986. //+---------------------------------------------------------------------------
  987. //
  988. // Function: CheckAdminSecurity, public
  989. //
  990. // Synopsis: Checks to see if the client has administrative access.
  991. //
  992. // Arguments: [pwszMachine] - machine name
  993. //
  994. // Returns: Nothing, throws if access is denied.
  995. //
  996. // Notes: The ACL on the HKEY_CURRENT_MACHINE\system\CurrentControlSet\
  997. // Control\ContentIndex registry key is used to determine if
  998. // access is permitted.
  999. //
  1000. // The access check is only done when the administrative operation
  1001. // is local. Otherwise, it will be checked in the course of doing
  1002. // the administrative operation.
  1003. //
  1004. // History: 26 Jun 96 AlanW Created.
  1005. //
  1006. //----------------------------------------------------------------------------
  1007. void CheckAdminSecurity( WCHAR const * pwszMachine )
  1008. {
  1009. HKEY hNewKey = (HKEY) INVALID_HANDLE_VALUE;
  1010. if ( 0 != wcscmp( pwszMachine, CATURL_LOCAL_MACHINE ) )
  1011. return;
  1012. LONG dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1013. wcsRegAdminSubKey,
  1014. 0,
  1015. KEY_WRITE,
  1016. &hNewKey );
  1017. if ( ERROR_SUCCESS == dwError )
  1018. {
  1019. RegCloseKey( hNewKey );
  1020. }
  1021. else if ( ERROR_ACCESS_DENIED == dwError )
  1022. {
  1023. THROW(CException( STATUS_ACCESS_DENIED ) );
  1024. }
  1025. else
  1026. {
  1027. ciGibDebugOut(( DEB_ERROR,
  1028. "Can not open reg key %ws, error %d\n",
  1029. wcsRegAdminSubKey, dwError ));
  1030. THROW(CException( HRESULT_FROM_WIN32( dwError ) ) );
  1031. }
  1032. }