Source code of Windows XP (NT5)
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.

1750 lines
44 KiB

  1. #include "headers.hxx"
  2. #include "global.hpp"
  3. #include "Analisys.hpp"
  4. #include "AnalisysResults.hpp"
  5. #include "CSVDSReader.hpp"
  6. #include "resource.h"
  7. #include "AdsiHelpers.hpp"
  8. #include "constants.hpp"
  9. #include "dspecup.hpp"
  10. Analisys::Analisys
  11. (
  12. const CSVDSReader& csvReader409_,
  13. const CSVDSReader& csvReaderIntl_,
  14. const String& ldapPrefix_,
  15. const String& rootContainerDn_,
  16. AnalisysResults &res,
  17. const String &reportName_,//=L"",
  18. void *caleeStruct_,//=NULL,
  19. progressFunction stepIt_,//=NULL,
  20. progressFunction totalSteps_//=NULL,
  21. )
  22. :
  23. csvReader409(csvReader409_),
  24. csvReaderIntl(csvReaderIntl_),
  25. ldapPrefix(ldapPrefix_),
  26. rootContainerDn(rootContainerDn_),
  27. results(res),
  28. reportName(reportName_),
  29. caleeStruct(caleeStruct_),
  30. stepIt(stepIt_),
  31. totalSteps(totalSteps_)
  32. {
  33. LOG_CTOR(Analisys);
  34. ASSERT(!ldapPrefix.empty());
  35. ASSERT(!rootContainerDn.empty());
  36. };
  37. // Analisys entry point
  38. HRESULT
  39. Analisys::run()
  40. {
  41. LOG_FUNCTION(Analisys::run);
  42. setReplaceW2KStrs();
  43. HRESULT hr=S_OK;
  44. do
  45. {
  46. LongList locales;
  47. for(long t=0;LOCALEIDS[t]!=0;t++)
  48. {
  49. locales.push_back(LOCALEIDS[t]);
  50. }
  51. locales.push_back(LOCALE409[0]);
  52. if(totalSteps!=NULL)
  53. {
  54. // The cast bellow is for IA64 compilation since we know
  55. // that locales.size() will fit in a long.
  56. totalSteps(static_cast<long>(locales.size()),caleeStruct);
  57. }
  58. BREAK_ON_FAILED_HRESULT(hr);
  59. LongList::iterator begin=locales.begin();
  60. LongList::iterator end=locales.end();
  61. while(begin!=end)
  62. {
  63. long locale=*begin;
  64. bool isPresent;
  65. hr=dealWithContainer(locale,isPresent);
  66. BREAK_ON_FAILED_HRESULT(hr);
  67. if (isPresent)
  68. {
  69. hr=dealWithXPObjects(locale);
  70. BREAK_ON_FAILED_HRESULT(hr);
  71. hr=dealWithW2KObjects(locale);
  72. BREAK_ON_FAILED_HRESULT(hr);
  73. }
  74. if(stepIt!=NULL)
  75. {
  76. stepIt(1,caleeStruct);
  77. }
  78. begin++;
  79. }
  80. BREAK_ON_FAILED_HRESULT(hr);
  81. if(!reportName.empty())
  82. {
  83. hr=createReport(reportName);
  84. BREAK_ON_FAILED_HRESULT(hr);
  85. }
  86. }
  87. while (0);
  88. LOG_HRESULT(hr);
  89. return hr;
  90. }
  91. // add entry to result.createContainers if container is not present
  92. // also returns flag isPresent
  93. HRESULT
  94. Analisys::dealWithContainer(
  95. const long locale,
  96. bool &isPresent)
  97. {
  98. LOG_FUNCTION(Analisys::dealWithContainer);
  99. ASSERT(locale > 0);
  100. ASSERT(!rootContainerDn.empty());
  101. HRESULT hr = S_OK;
  102. do
  103. {
  104. String container = String::format(L"CN=%1!3x!,", locale);
  105. String childContainerDn =ldapPrefix + container + rootContainerDn;
  106. // Attempt to bind to the container.
  107. SmartInterface<IADs> iads(0);
  108. hr = AdsiOpenObject<IADs>(childContainerDn, iads);
  109. if (HRESULT_CODE(hr) == ERROR_DS_NO_SUCH_OBJECT)
  110. {
  111. // The container object does not exist. This is possible because
  112. // the user has manually removed the container, or because it
  113. // was never created due to an aboted post-dcpromo import of the
  114. // display specifiers when the forest root dc was first promoted.
  115. results.createContainers.push_back(locale);
  116. isPresent=false;
  117. hr = S_OK;
  118. break;
  119. }
  120. else if (FAILED(hr))
  121. {
  122. error=String::format(IDS_ERROR_BINDING_TO_CONTAINER,
  123. childContainerDn.c_str());
  124. break;
  125. }
  126. // At this point, the bind succeeded, so the child container exists.
  127. // So now we want to examine objects in that container.
  128. isPresent=true;
  129. }
  130. while (0);
  131. LOG_HRESULT(hr);
  132. return hr;
  133. }
  134. // add entries to results.conflictingXPObjects or
  135. // results.createXPObject as necessary
  136. HRESULT
  137. Analisys::dealWithXPObjects(const long locale)
  138. {
  139. LOG_FUNCTION(Analisys::dealWithXPObjects);
  140. ASSERT(locale > 0);
  141. ASSERT(!rootContainerDn.empty());
  142. HRESULT hr = S_OK;
  143. do
  144. {
  145. for (
  146. int i = 0;
  147. *NEW_XP_OBJECTS[i]!=0;
  148. ++i
  149. )
  150. {
  151. String objectName = NEW_XP_OBJECTS[i];
  152. String objectPath =
  153. ldapPrefix + L"CN=" + objectName + L"," +
  154. String::format(L"CN=%1!3x!,", locale) + rootContainerDn;
  155. SmartInterface<IADs> iads(0);
  156. hr = AdsiOpenObject<IADs>(objectPath, iads);
  157. if (HRESULT_CODE(hr) == ERROR_DS_NO_SUCH_OBJECT)
  158. {
  159. // The object does not exist. This is what we expect. We want
  160. // to add the object in the repair phase.
  161. ObjectId tempObj(locale,objectName);
  162. results.createXPObjects.push_back(tempObj);
  163. hr = S_OK;
  164. continue;
  165. }
  166. else if (SUCCEEDED(hr))
  167. {
  168. // The object already exists. We have a conflict.
  169. ObjectId tempObj(locale,objectName);
  170. results.conflictingXPObjects.push_back(tempObj);
  171. }
  172. else
  173. {
  174. error=String::format(
  175. IDS_ERROR_BINDING_TO_OBJECT,
  176. objectName.c_str(),
  177. objectPath.c_str());
  178. break;
  179. }
  180. }
  181. BREAK_ON_FAILED_HRESULT(hr);
  182. }
  183. while (0);
  184. LOG_HRESULT(hr);
  185. return hr;
  186. }
  187. // add entries to results.createW2KObjects
  188. // and results.objectActions as necessary
  189. HRESULT
  190. Analisys::dealWithW2KObjects(const long locale)
  191. {
  192. LOG_FUNCTION(Analisys::dealWithW2KObjects);
  193. ASSERT(locale >0);
  194. ASSERT(!rootContainerDn.empty());
  195. HRESULT hr = S_OK;
  196. do
  197. {
  198. for(
  199. long i = 0;
  200. *(CHANGE_LIST[i].object)!=0;
  201. ++i
  202. )
  203. {
  204. String objectName = CHANGE_LIST[i].object;
  205. String objectPath =
  206. ldapPrefix + L"CN=" + objectName + L"," +
  207. String::format(L"CN=%1!3x!,", locale) + rootContainerDn;
  208. SmartInterface<IADs> iads(0);
  209. hr = AdsiOpenObject<IADs>(objectPath, iads);
  210. if (HRESULT_CODE(hr) == ERROR_DS_NO_SUCH_OBJECT)
  211. {
  212. // The object does not exist.
  213. ObjectId tempObj(locale,objectName);
  214. results.createW2KObjects.push_back(tempObj);
  215. hr = S_OK;
  216. continue;
  217. }
  218. else if (SUCCEEDED(hr))
  219. {
  220. // At this point, the display specifier object exists. Determine if
  221. // if has been touched since its creation.
  222. SmartInterface<IDirectoryObject> iDirObj;
  223. hr=iDirObj.AcquireViaQueryInterface(iads);
  224. // hr = iads->QueryInterface(IID_IDirectoryObject,(void **)iDirObj);
  225. BREAK_ON_FAILED_HRESULT(hr);
  226. hr = checkChanges(locale,CHANGE_LIST[i],iDirObj);
  227. BREAK_ON_FAILED_HRESULT(hr);
  228. }
  229. else
  230. {
  231. error=String::format(
  232. IDS_ERROR_BINDING_TO_OBJECT,
  233. objectName.c_str(),
  234. objectPath.c_str());
  235. break;
  236. }
  237. }
  238. BREAK_ON_FAILED_HRESULT(hr);
  239. }
  240. while (0);
  241. LOG_HRESULT(hr);
  242. return hr;
  243. }
  244. HRESULT
  245. Analisys::checkChanges(
  246. const long locale,
  247. const sChangeList& changes,
  248. IDirectoryObject *iDirObj)
  249. {
  250. LOG_FUNCTION(Analisys::checkChanges);
  251. wchar_t *object=changes.object;
  252. HRESULT hr=S_OK;
  253. for(
  254. long i = 0;
  255. *(changes.changes[i].property)!=0;
  256. ++i)
  257. {
  258. struct sChange change=changes.changes[i];
  259. switch(change.type)
  260. {
  261. case ADD_ALL_CSV_VALUES:
  262. hr = addAllCsvValues
  263. (
  264. iDirObj,
  265. locale,
  266. object,
  267. change.property
  268. );
  269. if(FAILED(hr))
  270. {
  271. LOG_HRESULT(hr);
  272. return hr;
  273. }
  274. break;
  275. case ADD_VALUE:
  276. hr = addValue
  277. (
  278. iDirObj,
  279. locale,
  280. object,
  281. change.property,
  282. change.value
  283. );
  284. if(FAILED(hr))
  285. {
  286. LOG_HRESULT(hr);
  287. return hr;
  288. }
  289. break;
  290. case REPLACE_W2K_MULTIPLE_VALUE:
  291. hr = replaceW2KMultipleValue
  292. (
  293. iDirObj,
  294. locale,
  295. object,
  296. change.property,
  297. change.value
  298. );
  299. if(FAILED(hr))
  300. {
  301. LOG_HRESULT(hr);
  302. return hr;
  303. }
  304. break;
  305. case REPLACE_W2K_SINGLE_VALUE:
  306. hr = replaceW2KSingleValue
  307. (
  308. iDirObj,
  309. locale,
  310. object,
  311. change.property,
  312. change.value
  313. );
  314. if(FAILED(hr))
  315. {
  316. LOG_HRESULT(hr);
  317. return hr;
  318. }
  319. break;
  320. case ADD_GUID:
  321. hr = addGuid
  322. (
  323. iDirObj,
  324. locale,
  325. object,
  326. change.property,
  327. change.value
  328. );
  329. if(FAILED(hr))
  330. {
  331. LOG_HRESULT(hr);
  332. return hr;
  333. }
  334. break;
  335. case REMOVE_GUID:
  336. hr = removeGuid
  337. (
  338. iDirObj,
  339. locale,
  340. object,
  341. change.property,
  342. change.value
  343. );
  344. if(FAILED(hr))
  345. {
  346. LOG_HRESULT(hr);
  347. return hr;
  348. }
  349. break;
  350. default:
  351. ASSERT(false);
  352. }
  353. }
  354. LOG_HRESULT(S_OK);
  355. return S_OK;
  356. }
  357. // adds ordAndGuid to the property if Guid is not already there.
  358. HRESULT
  359. Analisys::addGuid(
  360. IDirectoryObject *iDirObj,
  361. const int locale,
  362. const wchar_t *object,
  363. const wchar_t *property,
  364. const wchar_t *ordAndGuid)
  365. {
  366. LOG_FUNCTION(Analisys::addGuid);
  367. HRESULT hr = S_OK;
  368. String propertStr(property);
  369. String ordAndGuidStr(ordAndGuid);
  370. do
  371. {
  372. String guidFound;
  373. hr=getADGuid(
  374. iDirObj,
  375. propertStr,
  376. ordAndGuidStr,
  377. guidFound
  378. );
  379. BREAK_ON_FAILED_HRESULT(hr);
  380. if (hr == S_FALSE)
  381. {
  382. ObjectId tempObj(locale,String(object));
  383. ValueActions &act=results.objectActions[tempObj][property];
  384. act.addValues.push_back(ordAndGuidStr);
  385. }
  386. }
  387. while (0);
  388. LOG_HRESULT(hr);
  389. return hr;
  390. }
  391. // adds all csv values still not on the property
  392. HRESULT
  393. Analisys::addAllCsvValues(
  394. IDirectoryObject *iDirObj,
  395. const long locale,
  396. const wchar_t *object,
  397. const wchar_t *property)
  398. {
  399. LOG_FUNCTION(Analisys::addAllCsvValues);
  400. HRESULT hr = S_OK;
  401. const CSVDSReader &csvReader=(locale==0x409)?csvReader409:csvReaderIntl;
  402. do
  403. {
  404. StringList values;
  405. hr=csvReader.getCsvValues(locale,object,property,values);
  406. BREAK_ON_FAILED_HRESULT(hr);
  407. if (values.size()==0)
  408. {
  409. error=String::format(IDS_NO_CSV_VALUE,locale,object);
  410. hr=E_FAIL;
  411. break;
  412. }
  413. StringList::iterator begin=values.begin();
  414. StringList::iterator end=values.end();
  415. while(begin!=end)
  416. {
  417. hr=addValue(iDirObj,locale,object,property,begin->c_str());
  418. BREAK_ON_FAILED_HRESULT(hr);
  419. begin++;
  420. }
  421. BREAK_ON_FAILED_HRESULT(hr);
  422. }
  423. while (0);
  424. LOG_HRESULT(hr);
  425. return hr;
  426. }
  427. // adds value to the property if it is not already there.
  428. HRESULT
  429. Analisys::addValue(
  430. IDirectoryObject *iDirObj,
  431. const int locale,
  432. const wchar_t *object,
  433. const wchar_t *property,
  434. const wchar_t *value)
  435. {
  436. LOG_FUNCTION(Analisys::addValue);
  437. HRESULT hr = S_OK;
  438. String valueStr(value);
  439. String propertyStr(property);
  440. do
  441. {
  442. hr=isADValuePresent (
  443. iDirObj,
  444. propertyStr,
  445. valueStr
  446. );
  447. BREAK_ON_FAILED_HRESULT(hr);
  448. if (hr == S_FALSE)
  449. {
  450. ObjectId tempObj(locale,String(object));
  451. ValueActions &act=results.objectActions[tempObj][property];
  452. act.addValues.push_back(value);
  453. }
  454. }
  455. while (0);
  456. LOG_HRESULT(hr);
  457. return hr;
  458. }
  459. //Auxiliary function for replaceW2KSingleValue
  460. // retrieves csvValue
  461. HRESULT
  462. Analisys::getCsvSingleValue
  463. (
  464. const int locale,
  465. const wchar_t *object,
  466. const wchar_t *property,
  467. String &csvValue
  468. )
  469. {
  470. LOG_FUNCTION(Analisys::getCsvReplacementValue);
  471. const CSVDSReader &csvReader=(locale==0x409)?csvReader409:csvReaderIntl;
  472. HRESULT hr = S_OK;
  473. do
  474. {
  475. StringList XPCsvValues;
  476. hr=csvReader.getCsvValues(locale,object,property,XPCsvValues);
  477. BREAK_ON_FAILED_HRESULT(hr);
  478. // we should have only one value in the csv
  479. // since we can't distinguish the
  480. // value we want to replace from others as
  481. // in REPLACE_W2K_MULTIPLE_VALE
  482. if(XPCsvValues.size() != 1)
  483. {
  484. error=String::format
  485. (
  486. IDS_NOT_ONE_CSV_VALUE,
  487. XPCsvValues.size(),
  488. csvReader.getFileName().c_str(),
  489. locale,
  490. object,
  491. property
  492. );
  493. hr=E_FAIL;
  494. break;
  495. }
  496. csvValue = *XPCsvValues.begin();
  497. } while(0);
  498. LOG_HRESULT(hr);
  499. return hr;
  500. }
  501. // The idea of replaceW2KValue is replacing the W2K value
  502. // for the Whistler. We also make sure we don't extraneous values.
  503. HRESULT
  504. Analisys::replaceW2KSingleValue
  505. (
  506. IDirectoryObject *iDirObj,
  507. const int locale,
  508. const wchar_t *object,
  509. const wchar_t *property,
  510. const wchar_t *value
  511. )
  512. {
  513. LOG_FUNCTION(Analisys::replaceW2KValue);
  514. long index = *value;
  515. String objectStr(object);
  516. String propertyStr(property);
  517. HRESULT hr = S_OK;
  518. do
  519. {
  520. String XPCsvValue;
  521. hr=getCsvSingleValue
  522. (
  523. locale,
  524. object,
  525. property,
  526. XPCsvValue
  527. );
  528. BREAK_ON_FAILED_HRESULT(hr);
  529. // Retrieve W2KCsvValue from replaceW2KStrs
  530. pair<long,long> tmpIndxLoc;
  531. tmpIndxLoc.first=index;
  532. tmpIndxLoc.second=locale;
  533. String &W2KCsvValue=replaceW2KStrs[tmpIndxLoc];
  534. // There is nothing to do if the Whistler csv value
  535. // is the same as it was in W2K
  536. if (XPCsvValue.icompare(W2KCsvValue)==0)
  537. {
  538. break;
  539. }
  540. // Now we might have a replacement to do since the value
  541. // changed from W2K to Whistler
  542. hr=isADValuePresent(iDirObj,propertyStr,XPCsvValue);
  543. BREAK_ON_FAILED_HRESULT(hr);
  544. if(hr == S_OK) // The Whistler value is already there
  545. {
  546. // We will remove any other value than the Whistler
  547. hr=removeExtraneous(iDirObj,locale,objectStr,propertyStr,XPCsvValue);
  548. break;
  549. }
  550. // Now we know that the Whistler value is not present
  551. // and therefore we will add it if the W2K value is present
  552. hr=isADValuePresent(iDirObj,propertyStr,W2KCsvValue);
  553. BREAK_ON_FAILED_HRESULT(hr);
  554. if(hr == S_OK) // The W2K value is there.
  555. {
  556. ObjectId tempObj(locale,String(object));
  557. ValueActions &act=results.objectActions[tempObj][property];
  558. act.addValues.push_back(XPCsvValue);
  559. act.delValues.push_back(W2KCsvValue);
  560. // remove all but the W2K that we removed in the previous line
  561. hr=removeExtraneous(iDirObj,locale,objectStr,propertyStr,W2KCsvValue);
  562. break;
  563. }
  564. // Now we know that neither Whistler nor W2K values are present
  565. // If we have a value we will log that it is a custom value
  566. String ADValue;
  567. hr=getADFirstValue(iDirObj,propertyStr,ADValue);
  568. BREAK_ON_FAILED_HRESULT(hr);
  569. if(hr == S_OK) // We have a value
  570. {
  571. SingleValue tmpCustom(locale,objectStr,propertyStr,ADValue);
  572. results.customizedValues.push_back(tmpCustom);
  573. // We will remove any other value than the one we found
  574. hr=removeExtraneous(iDirObj,locale,objectStr,propertyStr,ADValue);
  575. break;
  576. }
  577. // Now we know that we don't have any values at all.
  578. ObjectId tempObj(locale,String(object));
  579. ValueActions &act=results.objectActions[tempObj][property];
  580. act.addValues.push_back(XPCsvValue);
  581. }
  582. while(0);
  583. LOG_HRESULT(hr);
  584. return hr;
  585. }
  586. //Auxiliary function for replaceW2KMultipleValue
  587. // retrieves csvValue and XPStart
  588. HRESULT
  589. Analisys::getCsvMultipleValue
  590. (
  591. const int locale,
  592. const wchar_t *object,
  593. const wchar_t *property,
  594. const wchar_t *value,
  595. String &csvValue,
  596. String &XPstart
  597. )
  598. {
  599. LOG_FUNCTION(Analisys::getCsvReplacementValue);
  600. const CSVDSReader &csvReader=(locale==0x409)?csvReader409:csvReaderIntl;
  601. HRESULT hr = S_OK;
  602. do
  603. {
  604. String sW2KXP(value+2); // +2 for index and semicollon
  605. StringList lW2KXP;
  606. size_t cnt=sW2KXP.tokenize(back_inserter(lW2KXP),L";");
  607. XPstart=lW2KXP.back();
  608. // We have the W2K and the XP start
  609. ASSERT(cnt==2);
  610. // Search the csv for the value starting with the XP string
  611. hr=csvReader.getCsvValue(
  612. locale,
  613. object,
  614. property,
  615. XPstart.c_str(),
  616. csvValue
  617. );
  618. BREAK_ON_FAILED_HRESULT(hr);
  619. // We should always find a csv value
  620. if(hr == S_FALSE)
  621. {
  622. error=String::format(
  623. IDS_VALUE_NOT_IN_CSV,
  624. XPstart.c_str(),
  625. locale,
  626. object,
  627. property,
  628. csvReader.getFileName().c_str()
  629. );
  630. hr=E_FAIL;
  631. break;
  632. }
  633. } while(0);
  634. LOG_HRESULT(hr);
  635. return hr;
  636. }
  637. // The idea of replaceW2KValue is replacing the W2K value
  638. // for the Whistler. We also make sure we don't extraneous values.
  639. HRESULT
  640. Analisys::replaceW2KMultipleValue
  641. (
  642. IDirectoryObject *iDirObj,
  643. const int locale,
  644. const wchar_t *object,
  645. const wchar_t *property,
  646. const wchar_t *value
  647. )
  648. {
  649. LOG_FUNCTION(Analisys::replaceW2KValue);
  650. long index = *value;
  651. String objectStr(object);
  652. String propertyStr(property);
  653. HRESULT hr = S_OK;
  654. do
  655. {
  656. String XPCsvValue,XPStart;
  657. // Get the Whistler csv value and the start of the Whistler value
  658. hr=getCsvMultipleValue
  659. (
  660. locale,
  661. object,
  662. property,
  663. value,
  664. XPCsvValue,
  665. XPStart
  666. );
  667. BREAK_ON_FAILED_HRESULT(hr);
  668. // Retrieve W2KCsvValue from replaceW2KStrs
  669. pair<long,long> tmpIndxLoc;
  670. tmpIndxLoc.first=index;
  671. tmpIndxLoc.second=locale;
  672. String &W2KCsvValue=replaceW2KStrs[tmpIndxLoc];
  673. // There is nothing to do if the Whistler csv value
  674. // is the same as it was in W2K
  675. if (XPCsvValue.icompare(W2KCsvValue)==0)
  676. {
  677. break;
  678. }
  679. // Now we might have a replacement to do since the value
  680. // changed from W2K to Whistler
  681. // First we should get the beginning of the W2K string
  682. // for use in removeExtraneous calls
  683. size_t pos=W2KCsvValue.find(L',');
  684. String W2KStart;
  685. // We only need to assert since the W2KStrs tool would
  686. // detect any REPLACE_W2K_MULTIPLE_VALUE without a comma
  687. ASSERT(pos != String::npos);
  688. W2KStart=W2KCsvValue.substr(0,pos+1);
  689. hr=isADValuePresent(iDirObj,propertyStr,XPCsvValue);
  690. BREAK_ON_FAILED_HRESULT(hr);
  691. if(hr == S_OK) // The Whistler value is already there
  692. {
  693. hr=removeExtraneous(
  694. iDirObj,
  695. locale,
  696. objectStr,
  697. propertyStr,
  698. XPCsvValue,
  699. XPStart,
  700. W2KStart
  701. );
  702. BREAK_ON_FAILED_HRESULT(hr);
  703. break;
  704. }
  705. // Now we know that the Whistler value is not present
  706. // and therefore we will add it if the W2K value is present
  707. hr=isADValuePresent(iDirObj,propertyStr,W2KCsvValue);
  708. BREAK_ON_FAILED_HRESULT(hr);
  709. if(hr == S_OK) // The W2K value is there.
  710. {
  711. ObjectId tempObj(locale,String(object));
  712. ValueActions &act=results.objectActions[tempObj][property];
  713. act.addValues.push_back(XPCsvValue);
  714. act.delValues.push_back(W2KCsvValue);
  715. // remove all but the W2K that we removed in the previous line
  716. hr=removeExtraneous(
  717. iDirObj,
  718. locale,
  719. objectStr,
  720. propertyStr,
  721. W2KCsvValue,
  722. XPStart,
  723. W2KStart
  724. );
  725. break;
  726. }
  727. // Now we know that neither Whistler nor W2K values are present
  728. // If we have a value starting like the W2K we will log that it
  729. // is a custom value
  730. String ADValue;
  731. hr=isADStartValuePresent(iDirObj,propertyStr,W2KStart,ADValue);
  732. BREAK_ON_FAILED_HRESULT(hr);
  733. if(hr==S_OK) // Something starts like the W2K csv value
  734. {
  735. SingleValue tmpCustom(locale,objectStr,propertyStr,ADValue);
  736. results.customizedValues.push_back(tmpCustom);
  737. // We will keep only the first custom value
  738. hr=removeExtraneous(
  739. iDirObj,
  740. locale,
  741. objectStr,
  742. propertyStr,
  743. ADValue,
  744. XPStart,
  745. W2KStart
  746. );
  747. break;
  748. }
  749. // Now neither Whistler, W2K or W2KStart are present
  750. if ( XPStart.icompare(W2KStart) != 0 )
  751. {
  752. // We have to check the XPStart as well
  753. hr=isADStartValuePresent(iDirObj,propertyStr,XPStart,ADValue);
  754. BREAK_ON_FAILED_HRESULT(hr);
  755. if(hr == S_OK) // Something starts like the Whistler csv value
  756. {
  757. SingleValue tmpCustom(locale,objectStr,propertyStr,ADValue);
  758. results.customizedValues.push_back(tmpCustom);
  759. // We will keep only the first custom value
  760. hr=removeExtraneous(
  761. iDirObj,
  762. locale,
  763. objectStr,
  764. propertyStr,
  765. ADValue,
  766. XPStart,
  767. W2KStart
  768. );
  769. break;
  770. }
  771. }
  772. // Now we know that there are no values starting like
  773. // the Whistler or W2K csv values so we have to add
  774. // the Whistler value
  775. ObjectId tempObj(locale,String(object));
  776. ValueActions &act=results.objectActions[tempObj][property];
  777. act.addValues.push_back(XPCsvValue);
  778. }
  779. while(0);
  780. LOG_HRESULT(hr);
  781. return hr;
  782. }
  783. // removes ordAndGuid from the property if Guid is there.
  784. HRESULT
  785. Analisys::removeGuid(
  786. IDirectoryObject *iDirObj,
  787. const int locale,
  788. const wchar_t *object,
  789. const wchar_t *property,
  790. const wchar_t *ordAndGuid)
  791. {
  792. LOG_FUNCTION(Analisys::removeGuid);
  793. HRESULT hr = S_OK;
  794. String propertStr(property);
  795. String ordAndGuidStr(ordAndGuid);
  796. do
  797. {
  798. String guidFound;
  799. hr=getADGuid(
  800. iDirObj,
  801. propertStr,
  802. ordAndGuidStr,
  803. guidFound
  804. );
  805. BREAK_ON_FAILED_HRESULT(hr);
  806. if (hr == S_OK)
  807. {
  808. ObjectId tempObj(locale,String(object));
  809. ValueActions &act=results.objectActions[tempObj][property];
  810. act.delValues.push_back(guidFound);
  811. }
  812. }
  813. while (0);
  814. LOG_HRESULT(hr);
  815. return hr;
  816. }
  817. //called from RwplaceW2KMultipleValue to remove all values
  818. // starting with start1 or start2 other than keeper
  819. HRESULT
  820. Analisys::removeExtraneous
  821. (
  822. IDirectoryObject *iDirObj,
  823. const int locale,
  824. const String &object,
  825. const String &property,
  826. const String &keeper,
  827. const String &start1,
  828. const String &start2
  829. )
  830. {
  831. LOG_FUNCTION(Analisys::removeExtraneous);
  832. DWORD dwReturn;
  833. ADS_ATTR_INFO *pAttrInfo =NULL;
  834. // GetObjectAttributes swears that pAttrName is an IN argument.
  835. // It should have used a LPCWSTR but now we have to pay the
  836. // casting price
  837. LPWSTR pAttrName[] ={const_cast<LPWSTR>(property.c_str())};
  838. HRESULT hr = S_OK;
  839. do
  840. {
  841. hr = iDirObj->GetObjectAttributes(
  842. pAttrName,
  843. 1,
  844. &pAttrInfo,
  845. &dwReturn
  846. );
  847. BREAK_ON_FAILED_HRESULT(hr);
  848. if(pAttrInfo==NULL)
  849. {
  850. hr = S_FALSE;
  851. break;
  852. }
  853. for (
  854. long val=0;
  855. val < pAttrInfo->dwNumValues;
  856. val++, pAttrInfo->pADsValues++
  857. )
  858. {
  859. wchar_t *valueAD = pAttrInfo->pADsValues->CaseIgnoreString;
  860. if ( _wcsicmp(valueAD,keeper.c_str())!=0 &&
  861. (
  862. _wcsnicmp(valueAD,start1.c_str(),start1.size())==0 ||
  863. _wcsnicmp(valueAD,start2.c_str(),start2.size())==0
  864. )
  865. )
  866. {
  867. String value=pAttrInfo->pADsValues->CaseIgnoreString;
  868. ObjectId tempObj(locale,String(object));
  869. ValueActions &act=results.extraneousValues[tempObj][property];
  870. act.delValues.push_back(value);
  871. }
  872. }
  873. }
  874. while (0);
  875. LOG_HRESULT(hr);
  876. return hr;
  877. }
  878. // called from RwplaceW2KSingleValue to remove all values
  879. // other than keeper
  880. HRESULT
  881. Analisys::removeExtraneous
  882. (
  883. IDirectoryObject *iDirObj,
  884. const int locale,
  885. const String &object,
  886. const String &property,
  887. const String &keeper
  888. )
  889. {
  890. LOG_FUNCTION(Analisys::removeExtraneous);
  891. DWORD dwReturn;
  892. ADS_ATTR_INFO *pAttrInfo =NULL;
  893. // GetObjectAttributes swears that pAttrName is an IN argument.
  894. // It should have used a LPCWSTR but now we have to pay the
  895. // casting price
  896. LPWSTR pAttrName[] ={const_cast<LPWSTR>(property.c_str())};
  897. HRESULT hr = S_OK;
  898. do
  899. {
  900. hr = iDirObj->GetObjectAttributes(
  901. pAttrName,
  902. 1,
  903. &pAttrInfo,
  904. &dwReturn
  905. );
  906. BREAK_ON_FAILED_HRESULT(hr);
  907. if(pAttrInfo==NULL)
  908. {
  909. hr = S_FALSE;
  910. break;
  911. }
  912. for (
  913. long val=0;
  914. val < pAttrInfo->dwNumValues;
  915. val++, pAttrInfo->pADsValues++
  916. )
  917. {
  918. wchar_t *valueAD = pAttrInfo->pADsValues->CaseIgnoreString;
  919. if ( _wcsicmp(valueAD,keeper.c_str())!=0 )
  920. {
  921. String value=pAttrInfo->pADsValues->CaseIgnoreString;
  922. ObjectId tempObj(locale,String(object));
  923. ValueActions &act=results.extraneousValues[tempObj][property];
  924. act.delValues.push_back(value);
  925. }
  926. }
  927. }
  928. while (0);
  929. LOG_HRESULT(hr);
  930. return hr;
  931. }
  932. // if any value exists in the AD with the same guid as guidValue
  933. // it is returned in guidFound, otherwise S_FALSE is returned
  934. HRESULT
  935. Analisys::getADGuid
  936. (
  937. IDirectoryObject *iDirObj,
  938. const String &property,
  939. const String &guidValue,
  940. String &guidFound
  941. )
  942. {
  943. LOG_FUNCTION(Analisys::getADGuid);
  944. DWORD dwReturn;
  945. ADS_ATTR_INFO *pAttrInfo =NULL;
  946. // GetObjectAttributes swears that pAttrName is an IN argument.
  947. // It should have used a LPCWSTR but now we have to pay the
  948. // casting price
  949. LPWSTR pAttrName[] ={const_cast<LPWSTR>(property.c_str())};
  950. size_t pos=guidValue.find(L',');
  951. ASSERT(pos!=String::npos);
  952. String guid=guidValue.substr(pos+1);
  953. HRESULT hr = S_OK;
  954. do
  955. {
  956. hr = iDirObj->GetObjectAttributes(
  957. pAttrName,
  958. 1,
  959. &pAttrInfo,
  960. &dwReturn
  961. );
  962. BREAK_ON_FAILED_HRESULT(hr);
  963. // If there are no values we finish the search
  964. hr=S_FALSE;
  965. if(pAttrInfo==NULL)
  966. {
  967. break;
  968. }
  969. for (
  970. long val=0;
  971. val < pAttrInfo->dwNumValues;
  972. val++, pAttrInfo->pADsValues++
  973. )
  974. {
  975. wchar_t *guidAD=wcschr(pAttrInfo->pADsValues->CaseIgnoreString,L',');
  976. if(guidAD != NULL)
  977. {
  978. guidAD++;
  979. if (_wcsicmp(guid.c_str(),guidAD)==0)
  980. {
  981. guidFound=pAttrInfo->pADsValues->CaseIgnoreString;
  982. hr=S_OK;
  983. break;
  984. }
  985. }
  986. }
  987. }
  988. while (0);
  989. LOG_HRESULT(hr);
  990. return hr;
  991. }
  992. // returns S_OK if value is present or S_FALSE otherwise
  993. HRESULT
  994. Analisys::isADValuePresent
  995. (
  996. IDirectoryObject *iDirObj,
  997. const String &property,
  998. const String &value
  999. )
  1000. {
  1001. LOG_FUNCTION(Analisys::isADValuePresent);
  1002. DWORD dwReturn;
  1003. ADS_ATTR_INFO *pAttrInfo =NULL;
  1004. // GetObjectAttributes swears that pAttrName is an IN argument.
  1005. // It should have used a LPCWSTR but now we have to pay the
  1006. // casting price
  1007. LPWSTR pAttrName[] ={const_cast<LPWSTR>(property.c_str())};
  1008. HRESULT hr = S_OK;
  1009. do
  1010. {
  1011. hr = iDirObj->GetObjectAttributes(
  1012. pAttrName,
  1013. 1,
  1014. &pAttrInfo,
  1015. &dwReturn
  1016. );
  1017. BREAK_ON_FAILED_HRESULT(hr);
  1018. hr=S_FALSE;
  1019. // If there are no values we finish the search
  1020. if(pAttrInfo==NULL)
  1021. {
  1022. break;
  1023. }
  1024. for (
  1025. long val=0;
  1026. val < pAttrInfo->dwNumValues;
  1027. val++, pAttrInfo->pADsValues++
  1028. )
  1029. {
  1030. wchar_t *valueAD=pAttrInfo->pADsValues->CaseIgnoreString;
  1031. if (_wcsicmp(value.c_str(),valueAD)==0)
  1032. {
  1033. hr=S_OK;
  1034. break;
  1035. }
  1036. }
  1037. }
  1038. while (0);
  1039. LOG_HRESULT(hr);
  1040. return hr;
  1041. }
  1042. // retrieves the first value starting with valueStart
  1043. // from the Active Directory
  1044. // If no value is found S_FALSE is returned.
  1045. HRESULT
  1046. Analisys::isADStartValuePresent
  1047. (
  1048. IDirectoryObject *iDirObj,
  1049. const String &property,
  1050. const String &valueStart,
  1051. String &value
  1052. )
  1053. {
  1054. LOG_FUNCTION(Analisys::isADStartValuePresent);
  1055. DWORD dwReturn;
  1056. ADS_ATTR_INFO *pAttrInfo =NULL;
  1057. // GetObjectAttributes swears that pAttrName is an IN argument.
  1058. // It should have used a LPCWSTR but now we have to pay the
  1059. // casting price
  1060. LPWSTR pAttrName[] ={const_cast<LPWSTR>(property.c_str())};
  1061. HRESULT hr = S_OK;
  1062. do
  1063. {
  1064. hr = iDirObj->GetObjectAttributes(
  1065. pAttrName,
  1066. 1,
  1067. &pAttrInfo,
  1068. &dwReturn
  1069. );
  1070. BREAK_ON_FAILED_HRESULT(hr);
  1071. value.erase();
  1072. hr = S_FALSE;
  1073. // If there are no values we finish the search
  1074. if(pAttrInfo==NULL)
  1075. {
  1076. break;
  1077. }
  1078. for (
  1079. long val=0;
  1080. (val < pAttrInfo->dwNumValues);
  1081. val++, pAttrInfo->pADsValues++
  1082. )
  1083. {
  1084. wchar_t *valueAD=pAttrInfo->pADsValues->CaseIgnoreString;
  1085. if (_wcsnicmp(valueStart.c_str(),valueAD,valueStart.size())==0)
  1086. {
  1087. value=pAttrInfo->pADsValues->CaseIgnoreString;
  1088. hr=S_OK;
  1089. break;
  1090. }
  1091. }
  1092. }
  1093. while (0);
  1094. LOG_HRESULT(hr);
  1095. return hr;
  1096. }
  1097. // retrieves the first value starting with valueStart
  1098. // from the Active Directory
  1099. // If no value is found S_FALSE is returned.
  1100. HRESULT
  1101. Analisys::getADFirstValue
  1102. (
  1103. IDirectoryObject *iDirObj,
  1104. const String &property,
  1105. String &value
  1106. )
  1107. {
  1108. LOG_FUNCTION(Analisys::getADFirstValue);
  1109. DWORD dwReturn;
  1110. ADS_ATTR_INFO *pAttrInfo =NULL;
  1111. // GetObjectAttributes swears that pAttrName is an IN argument.
  1112. // It should have used a LPCWSTR but now we have to pay the
  1113. // casting price
  1114. LPWSTR pAttrName[] ={const_cast<LPWSTR>(property.c_str())};
  1115. HRESULT hr = S_OK;
  1116. do
  1117. {
  1118. hr = iDirObj->GetObjectAttributes(
  1119. pAttrName,
  1120. 1,
  1121. &pAttrInfo,
  1122. &dwReturn
  1123. );
  1124. BREAK_ON_FAILED_HRESULT(hr);
  1125. // If there are no values we finish the search
  1126. if(pAttrInfo==NULL)
  1127. {
  1128. hr = S_FALSE;
  1129. break;
  1130. }
  1131. value=pAttrInfo->pADsValues->CaseIgnoreString;
  1132. }
  1133. while (0);
  1134. LOG_HRESULT(hr);
  1135. return hr;
  1136. }
  1137. // auxiliary in the createReport to
  1138. // enumerate an ObjectIdList
  1139. HRESULT
  1140. Analisys::reportObjects
  1141. (
  1142. HANDLE file,
  1143. const ObjectIdList &list,
  1144. const String &header
  1145. )
  1146. {
  1147. LOG_FUNCTION(Analisys::reportObjects);
  1148. HRESULT hr=S_OK;
  1149. do
  1150. {
  1151. if(list.size()==0) break;
  1152. hr=FS::WriteLine(file,header);
  1153. BREAK_ON_FAILED_HRESULT(hr);
  1154. ObjectIdList::const_iterator begin,end;
  1155. begin=list.begin();
  1156. end=list.end();
  1157. while(begin!=end)
  1158. {
  1159. hr=FS::WriteLine(
  1160. file,
  1161. String::format
  1162. (
  1163. IDS_RPT_OBJECT_FORMAT,
  1164. begin->object.c_str(),
  1165. begin->locale
  1166. )
  1167. );
  1168. BREAK_ON_FAILED_HRESULT(hr);
  1169. begin++;
  1170. }
  1171. BREAK_ON_FAILED_HRESULT(hr);
  1172. }
  1173. while(0);
  1174. LOG_HRESULT(hr);
  1175. return hr;
  1176. }
  1177. // auxiliary in the createReport to
  1178. // enumerate a LongList
  1179. HRESULT
  1180. Analisys::reportContainers
  1181. (
  1182. HANDLE file,
  1183. const LongList &list,
  1184. const String &header
  1185. )
  1186. {
  1187. LOG_FUNCTION(Analisys::reportContainers);
  1188. HRESULT hr=S_OK;
  1189. do
  1190. {
  1191. if(list.size()==0) break;
  1192. hr=FS::WriteLine(file,header);
  1193. BREAK_ON_FAILED_HRESULT(hr);
  1194. LongList::const_iterator begin,end;
  1195. begin=list.begin();
  1196. end=list.end();
  1197. while(begin!=end)
  1198. {
  1199. hr=FS::WriteLine(
  1200. file,
  1201. String::format
  1202. (
  1203. IDS_RPT_CONTAINER_FORMAT,
  1204. *begin
  1205. )
  1206. );
  1207. BREAK_ON_FAILED_HRESULT(hr);
  1208. begin++;
  1209. }
  1210. BREAK_ON_FAILED_HRESULT(hr);
  1211. }
  1212. while(0);
  1213. LOG_HRESULT(hr);
  1214. return hr;
  1215. }
  1216. // auxiliary in the createReport to
  1217. // enumerate a SingleValueList
  1218. HRESULT
  1219. Analisys::reportValues
  1220. (
  1221. HANDLE file,
  1222. const SingleValueList &list,
  1223. const String &header
  1224. )
  1225. {
  1226. LOG_FUNCTION(Analisys::reportContainers);
  1227. HRESULT hr=S_OK;
  1228. do
  1229. {
  1230. if(list.size()==0) break;
  1231. hr=FS::WriteLine(file,header);
  1232. BREAK_ON_FAILED_HRESULT(hr);
  1233. SingleValueList::const_iterator begin,end;
  1234. begin=list.begin();
  1235. end=list.end();
  1236. while(begin!=end)
  1237. {
  1238. hr=FS::WriteLine(
  1239. file,
  1240. String::format
  1241. (
  1242. IDS_RPT_VALUE_FORMAT,
  1243. begin->value.c_str(),
  1244. begin->locale,
  1245. begin->object.c_str(),
  1246. begin->property.c_str()
  1247. )
  1248. );
  1249. BREAK_ON_FAILED_HRESULT(hr);
  1250. begin++;
  1251. }
  1252. BREAK_ON_FAILED_HRESULT(hr);
  1253. }
  1254. while(0);
  1255. LOG_HRESULT(hr);
  1256. return hr;
  1257. }
  1258. // auxiliary in the createReport to
  1259. // enumerate ObjectActions
  1260. HRESULT
  1261. Analisys::reportActions
  1262. (
  1263. HANDLE file,
  1264. const ObjectActions &list,
  1265. const String &header
  1266. )
  1267. {
  1268. LOG_FUNCTION(Analisys::reportActions);
  1269. HRESULT hr=S_OK;
  1270. do
  1271. {
  1272. if(list.size()==0) break;
  1273. hr=FS::WriteLine(file,header);
  1274. BREAK_ON_FAILED_HRESULT(hr);
  1275. ObjectActions::const_iterator beginObj=list.begin();
  1276. ObjectActions::const_iterator endObj=list.end();
  1277. while(beginObj!=endObj)
  1278. {
  1279. hr=FS::WriteLine
  1280. (
  1281. file,
  1282. String::format
  1283. (
  1284. IDS_RPT_OBJECT_FORMAT,
  1285. beginObj->first.object.c_str(),
  1286. beginObj->first.locale
  1287. )
  1288. );
  1289. BREAK_ON_FAILED_HRESULT(hr);
  1290. PropertyActions::iterator beginAct=beginObj->second.begin();
  1291. PropertyActions::iterator endAct=beginObj->second.end();
  1292. while(beginAct!=endAct)
  1293. {
  1294. StringList::iterator
  1295. beginDel = beginAct->second.delValues.begin();
  1296. StringList::iterator
  1297. endDel = beginAct->second.delValues.end();
  1298. while(beginDel!=endDel)
  1299. {
  1300. hr=FS::WriteLine
  1301. (
  1302. file,
  1303. String::format
  1304. (
  1305. IDS_RPT_DEL_VALUE_FORMAT,
  1306. beginAct->first.c_str(),
  1307. beginDel->c_str()
  1308. )
  1309. );
  1310. BREAK_ON_FAILED_HRESULT(hr);
  1311. beginDel++;
  1312. }
  1313. BREAK_ON_FAILED_HRESULT(hr); // break on if internal while broke
  1314. StringList::iterator
  1315. beginAdd = beginAct->second.addValues.begin();
  1316. StringList::iterator
  1317. endAdd = beginAct->second.addValues.end();
  1318. while(beginAdd!=endAdd)
  1319. {
  1320. hr=FS::WriteLine
  1321. (
  1322. file,
  1323. String::format
  1324. (
  1325. IDS_RPT_ADD_VALUE_FORMAT,
  1326. beginAct->first.c_str(),
  1327. beginAdd->c_str()
  1328. )
  1329. );
  1330. BREAK_ON_FAILED_HRESULT(hr);
  1331. beginAdd++;
  1332. }
  1333. BREAK_ON_FAILED_HRESULT(hr); // break on if internal while broke
  1334. beginAct++;
  1335. } // while(beginAct!=endAct)
  1336. BREAK_ON_FAILED_HRESULT(hr); // break on if internal while broke
  1337. beginObj++;
  1338. } // while(beginObj!=endObj)
  1339. BREAK_ON_FAILED_HRESULT(hr);
  1340. }
  1341. while(0);
  1342. LOG_HRESULT(hr);
  1343. return hr;
  1344. }
  1345. // Create the report from the AnalisysResults
  1346. HRESULT
  1347. Analisys::createReport(const String& reportName)
  1348. {
  1349. LOG_FUNCTION(Analisys::createReport);
  1350. HRESULT hr=S_OK;
  1351. do
  1352. {
  1353. HANDLE file;
  1354. hr=FS::CreateFile(reportName,
  1355. file,
  1356. GENERIC_WRITE);
  1357. if (FAILED(hr))
  1358. {
  1359. error=String::format(IDS_COULD_NOT_CREATE_FILE,reportName.c_str());
  1360. break;
  1361. }
  1362. do
  1363. {
  1364. hr=FS::WriteLine(file,String::load(IDS_RPT_HEADER));
  1365. BREAK_ON_FAILED_HRESULT(hr);
  1366. hr=reportActions (
  1367. file,
  1368. results.extraneousValues,
  1369. String::load(IDS_RPT_EXTRANEOUS)
  1370. );
  1371. BREAK_ON_FAILED_HRESULT(hr);
  1372. hr=reportValues (
  1373. file,
  1374. results.customizedValues,
  1375. String::load(IDS_RPT_CUSTOMIZED)
  1376. );
  1377. BREAK_ON_FAILED_HRESULT(hr);
  1378. hr=reportObjects (
  1379. file,
  1380. results.conflictingXPObjects,
  1381. String::load(IDS_RPT_CONFLICTINGXP)
  1382. );
  1383. BREAK_ON_FAILED_HRESULT(hr);
  1384. hr=reportActions (
  1385. file,
  1386. results.objectActions,
  1387. String::load(IDS_RPT_ACTIONS)
  1388. );
  1389. BREAK_ON_FAILED_HRESULT(hr);
  1390. hr=reportObjects (
  1391. file,
  1392. results.createW2KObjects,
  1393. String::load(IDS_RPT_CREATEW2K)
  1394. );
  1395. BREAK_ON_FAILED_HRESULT(hr);
  1396. hr=reportObjects (
  1397. file,
  1398. results.createXPObjects,
  1399. String::load(IDS_RPT_CREATEXP)
  1400. );
  1401. BREAK_ON_FAILED_HRESULT(hr);
  1402. hr=reportContainers(
  1403. file,
  1404. results.createContainers,
  1405. String::load(IDS_RPT_CONTAINERS)
  1406. );
  1407. BREAK_ON_FAILED_HRESULT(hr);
  1408. } while(0);
  1409. CloseHandle(file);
  1410. BREAK_ON_FAILED_HRESULT(hr);
  1411. } while(0);
  1412. LOG_HRESULT(hr);
  1413. return hr;
  1414. }