#include "headers.hxx" #include "global.hpp" #include "Analysis.hpp" #include "AnalysisResults.hpp" #include "CSVDSReader.hpp" #include "resourceDspecup.h" #include "AdsiHelpers.hpp" #include "constants.hpp" #include "dspecup.hpp" Analysis::Analysis ( const GUID guid_, const CSVDSReader& csvReader409_, const CSVDSReader& csvReaderIntl_, const String& ldapPrefix_, const String& rootContainerDn_, AnalysisResults &res, const String &reportName_,//=L"", void *caleeStruct_,//=NULL, progressFunction stepIt_,//=NULL, progressFunction totalSteps_//=NULL, ) : guid(guid_), csvReader409(csvReader409_), csvReaderIntl(csvReaderIntl_), ldapPrefix(ldapPrefix_), rootContainerDn(rootContainerDn_), results(res), reportName(reportName_), caleeStruct(caleeStruct_), stepIt(stepIt_), totalSteps(totalSteps_) { LOG_CTOR(Analysis); ASSERT(!ldapPrefix.empty()); ASSERT(!rootContainerDn.empty()); }; // Analysis entry point HRESULT Analysis::run() { LOG_FUNCTION(Analysis::run); if(changes.size()==0) { setChanges(); } HRESULT hr=S_OK; do { LongList locales; for(long t=0;LOCALEIDS[t]!=0;t++) { locales.push_back(LOCALEIDS[t]); } locales.push_back(LOCALE409[0]); if(totalSteps!=NULL) { // The cast bellow is for IA64 compilation since we know // that locales.size() will fit in a long. totalSteps(static_cast(locales.size()),caleeStruct); } BREAK_ON_FAILED_HRESULT(hr); LongList::iterator begin=locales.begin(); LongList::iterator end=locales.end(); while(begin!=end) { long locale=*begin; bool isPresent; hr=dealWithContainer(locale,isPresent); BREAK_ON_FAILED_HRESULT(hr); if (isPresent) { hr=dealWithW2KObjects(locale); BREAK_ON_FAILED_HRESULT(hr); } if(stepIt!=NULL) { stepIt(1,caleeStruct); } begin++; } BREAK_ON_FAILED_HRESULT(hr); if(!reportName.empty()) { hr=createReport(reportName); BREAK_ON_FAILED_HRESULT(hr); } } while (0); LOG_HRESULT(hr); return hr; } // add entry to result.createContainers if container is not present // also returns flag isPresent HRESULT Analysis::dealWithContainer( const long locale, bool &isPresent) { LOG_FUNCTION(Analysis::dealWithContainer); ASSERT(locale > 0); ASSERT(!rootContainerDn.empty()); HRESULT hr = S_OK; do { String container = String::format(L"CN=%1!3x!,", locale); String childContainerDn =ldapPrefix + container + rootContainerDn; // Attempt to bind to the container. SmartInterface iads(0); hr = AdsiOpenObject(childContainerDn, iads); if (HRESULT_CODE(hr) == ERROR_DS_NO_SUCH_OBJECT) { // The container object does not exist. This is possible because // the user has manually removed the container, or because it // was never created due to an aboted post-dcpromo import of the // display specifiers when the forest root dc was first promoted. // NTRAID#NTBUG9-726839-2002/10/31-lucios // We are only recovering the 409 container since recovering // an international locale will overwrite possible 409 customizations if (locale == 0x409) results.createContainers.push_back(locale); isPresent=false; hr = S_OK; break; } else if (FAILED(hr)) { error=String::format(IDS_ERROR_BINDING_TO_CONTAINER, childContainerDn.c_str()); break; } // At this point, the bind succeeded, so the child container exists. // So now we want to examine objects in that container. isPresent=true; } while (0); LOG_HRESULT(hr); return hr; } // sets iDirObj with the Active Directory object // corresponding to the locale and object HRESULT Analysis::getADObj ( const long locale, const String& object, SmartInterface &iDirObj ) { HRESULT hr = S_OK; do { String objectPath = ldapPrefix + L"CN=" + object + L"," + String::format(L"CN=%1!3x!,", locale) + rootContainerDn; SmartInterface iads(0); hr = AdsiOpenObject(objectPath, iads); if (HRESULT_CODE(hr) == ERROR_DS_NO_SUCH_OBJECT) { // The object does not exist. hr = S_FALSE; break; } if (FAILED(hr)) { // Unexpected error error=String::format ( IDS_ERROR_BINDING_TO_OBJECT, object.c_str(), objectPath.c_str() ); break; } // At this point, the display specifier object exists. hr=iDirObj.AcquireViaQueryInterface(iads); BREAK_ON_FAILED_HRESULT(hr); } while (0); LOG_HRESULT(hr); return hr; } // add entries to results.createW2KObjects // and results.objectActions as necessary HRESULT Analysis::dealWithW2KObjects(const long locale) { LOG_FUNCTION(Analysis::dealWithW2KObjects); ASSERT(locale > 0); HRESULT hr = S_OK; do { hr=checkChanges(locale,changes[guid][locale]); BREAK_ON_FAILED_HRESULT(hr); hr=checkChanges(locale,changes[guid][-1]); BREAK_ON_FAILED_HRESULT(hr); } while (0); LOG_HRESULT(hr); return hr; } HRESULT Analysis::checkChanges ( const long locale, const changeList& changes ) { LOG_FUNCTION(Analysis::checkChanges); HRESULT hr=S_OK; do { changeList::const_iterator curChange,endChange; for ( curChange=changes.begin(),endChange=changes.end(); curChange!=endChange; curChange++ ) { const String &object=curChange->object; const String &property=curChange->property; const String &firstArg=curChange->firstArg; const String &secondArg=curChange->secondArg; SmartInterface iDirObj; hr=getADObj(locale,object,iDirObj); BREAK_ON_FAILED_HRESULT(hr); if(hr==S_FALSE) // object doesn't exist { ObjectId tempObj(locale,String(object)); if(curChange->type==ADD_OBJECT) { results.createWhistlerObjects.push_back(tempObj); } else { // NTRAID#NTBUG9-726839-2002/10/31-lucios // We are only recovering objects in the 409 container // since recovering an object in an international locale // will overwrite possible 409 customizations if ( (locale == 0x409) && find ( results.createW2KObjects.begin(), results.createW2KObjects.end(), tempObj ) == results.createW2KObjects.end() ) { results.createW2KObjects.push_back(tempObj); } } hr=S_OK; continue; } else { ObjectId tempObj(locale,String(object)); if(curChange->type==ADD_OBJECT) { results.conflictingWhistlerObjects.push_back(tempObj); } } switch(curChange->type) { case ADD_ALL_CSV_VALUES: hr = addAllCsvValues ( iDirObj, locale, object, property ); break; case ADD_VALUE: hr = addValue ( iDirObj, locale, object, property, firstArg ); break; case REPLACE_W2K_MULTIPLE_VALUE: hr = replaceW2KMultipleValue ( iDirObj, locale, object, property, firstArg, secondArg ); break; case REPLACE_W2K_SINGLE_VALUE: hr = replaceW2KSingleValue ( iDirObj, locale, object, property, firstArg, secondArg ); break; case ADD_GUID: hr = addGuid ( iDirObj, locale, object, property, firstArg ); break; case REMOVE_GUID: hr = removeGuid ( iDirObj, locale, object, property, firstArg ); break; case REPLACE_GUID: hr = replaceGuid ( iDirObj, locale, object, property, firstArg, secondArg ); break; case ADD_OBJECT: break; // dealt with in the beginning of the function default: ASSERT(false); } BREAK_ON_FAILED_HRESULT(hr); } BREAK_ON_FAILED_HRESULT(hr); } while(0); LOG_HRESULT(hr); return hr; } // adds ordAndGuid to the property if Guid is not already there. HRESULT Analysis::addGuid ( IDirectoryObject *iDirObj, const int locale, const String &object, const String &property, const String &ordAndGuid ) { LOG_FUNCTION(Analysis::addGuid); HRESULT hr = S_OK; do { String guidFound; hr=getADGuid( iDirObj, property, ordAndGuid, guidFound ); BREAK_ON_FAILED_HRESULT(hr); if (hr == S_FALSE) { ObjectId tempObj(locale,String(object)); ValueActions &act=results.objectActions[tempObj][property]; act.addValues.push_back(ordAndGuid); } } while (0); LOG_HRESULT(hr); return hr; } // replaces ordAndGuidWin2K for ordAndGuidWhistler. HRESULT Analysis::replaceGuid ( IDirectoryObject *iDirObj, const int locale, const String &object, const String &property, const String &ordAndGuidWin2K, const String &ordAndGuidWhistler ) { LOG_FUNCTION(Analysis::replaceGuid); HRESULT hr = S_OK; do { String guidFound; hr=getADGuid( iDirObj, property, ordAndGuidWhistler, guidFound ); BREAK_ON_FAILED_HRESULT(hr); if (hr == S_OK) // The Whistler GUID was found { hr=removeExtraneousGUID ( iDirObj, locale, object, property, guidFound, ordAndGuidWin2K, ordAndGuidWhistler ); break; } // The Whistler GUID is not present hr=getADGuid( iDirObj, property, ordAndGuidWin2K, guidFound ); BREAK_ON_FAILED_HRESULT(hr); if (hr == S_OK) // The Win2K GUID was found { size_t posFound=guidFound.find(L','); ASSERT(posFound != String::npos); size_t posWhistler=ordAndGuidWhistler.find(L','); ASSERT(posWhistler != String::npos); String guidToAdd = guidFound.substr(0,posFound) + ordAndGuidWhistler.substr(posWhistler); ObjectId tempObj(locale,String(object)); ValueActions &act=results.objectActions[tempObj][property]; act.delValues.push_back(guidFound); act.addValues.push_back(guidToAdd); hr=removeExtraneousGUID ( iDirObj, locale, object, property, guidFound, ordAndGuidWin2K, ordAndGuidWhistler ); break; } // Neither the Win2K nor the Whistler GUIDs were found // Since the customer did not wan't the Win2K GUID // he probably will not want the Whistler GUID either, // so we do nothing. } while(0); LOG_HRESULT(hr); return hr; } // removes ordAndGuid from the property if Guid is there. HRESULT Analysis::removeGuid ( IDirectoryObject *iDirObj, const int locale, const String &object, const String &property, const String &ordAndGuid) { LOG_FUNCTION(Analysis::removeGuid); HRESULT hr = S_OK; do { String guidFound; hr=getADGuid( iDirObj, property, ordAndGuid, guidFound ); BREAK_ON_FAILED_HRESULT(hr); if (hr == S_OK) { ObjectId tempObj(locale,String(object)); ValueActions &act=results.objectActions[tempObj][property]; act.delValues.push_back(guidFound); } } while (0); LOG_HRESULT(hr); return hr; } // adds all csv values still not on the property HRESULT Analysis::addAllCsvValues ( IDirectoryObject *iDirObj, const long locale, const String &object, const String &property ) { LOG_FUNCTION(Analysis::addAllCsvValues); HRESULT hr = S_OK; const CSVDSReader &csvReader=(locale==0x409)?csvReader409:csvReaderIntl; do { StringList values; hr=csvReader.getCsvValues(locale,object.c_str(),property.c_str(),values); BREAK_ON_FAILED_HRESULT(hr); if (values.size()==0) { error=String::format(IDS_NO_CSV_VALUE,locale,object.c_str()); hr=E_FAIL; break; } StringList::iterator begin=values.begin(); StringList::iterator end=values.end(); while(begin!=end) { hr=addValue(iDirObj,locale,object,property,begin->c_str()); BREAK_ON_FAILED_HRESULT(hr); begin++; } BREAK_ON_FAILED_HRESULT(hr); } while (0); LOG_HRESULT(hr); return hr; } // adds value to the property if it is not already there. HRESULT Analysis::addValue( IDirectoryObject *iDirObj, const long locale, const String &object, const String &property, const String &value) { LOG_FUNCTION(Analysis::addValue); HRESULT hr = S_OK; do { hr=isADValuePresent ( iDirObj, property, value ); BREAK_ON_FAILED_HRESULT(hr); if (hr == S_FALSE) { ObjectId tempObj(locale,String(object)); ValueActions &act=results.objectActions[tempObj][property]; act.addValues.push_back(value); } } while (0); LOG_HRESULT(hr); return hr; } // The idea of replaceW2KValue is replacing the W2K value // for the Whistler. We also make sure we don't extraneous values. HRESULT Analysis::replaceW2KSingleValue ( IDirectoryObject *iDirObj, const int locale, const String &object, const String &property, const String &W2KCsvValue, const String &WhistlerCsvValue ) { LOG_FUNCTION(Analysis::replaceW2KSingleValue); HRESULT hr = S_OK; do { hr=isADValuePresent(iDirObj,property,WhistlerCsvValue); BREAK_ON_FAILED_HRESULT(hr); if(hr == S_OK) // The Whistler value is already there { // We will remove any other value than the Whistler hr=removeExtraneous ( iDirObj, locale, object, property, WhistlerCsvValue ); break; } // Now we know that the Whistler value is not present // and therefore we will add it if the W2K value is present hr=isADValuePresent(iDirObj,property,W2KCsvValue); BREAK_ON_FAILED_HRESULT(hr); if(hr == S_OK) // The W2K value is there. { ObjectId tempObj(locale,String(object)); ValueActions &act=results.objectActions[tempObj][property]; act.addValues.push_back(WhistlerCsvValue); act.delValues.push_back(W2KCsvValue); // remove all but the W2K that we removed in the previous line hr=removeExtraneous ( iDirObj, locale, object, property, W2KCsvValue ); break; } // Now we know that neither Whistler nor W2K values are present // If we have a value we will log that it is a custom value String ADValue; hr=getADFirstValue(iDirObj,property,ADValue); BREAK_ON_FAILED_HRESULT(hr); if(hr == S_OK) // We have a value { SingleValue tmpCustom(locale,object,property,ADValue); results.customizedValues.push_back(tmpCustom); // We will remove any other value than the one we found hr=removeExtraneous(iDirObj,locale,object,property,ADValue); break; } // Now we know that we don't have any values at all. ObjectId tempObj(locale,String(object)); ValueActions &act=results.objectActions[tempObj][property]; act.addValues.push_back(WhistlerCsvValue); } while(0); LOG_HRESULT(hr); return hr; } // The idea of replaceW2KValue is replacing the W2K value // for the Whistler. We also make sure we don't ahve extraneous values. HRESULT Analysis::replaceW2KMultipleValue ( IDirectoryObject *iDirObj, const int locale, const String &object, const String &property, const String &W2KCsvValue, const String &WhistlerCsvValue ) { LOG_FUNCTION(Analysis::replaceW2KMultipleValue); // First we should get the beginning of the W2K // snd Whistler strings for use in removeExtraneous calls size_t pos=W2KCsvValue.find(L','); ASSERT(pos != String::npos); // W2KRepl ensures the comma String W2KStart=W2KCsvValue.substr(0,pos+1); pos=WhistlerCsvValue.find(L','); ASSERT(pos != String::npos); // W2KRepl ensures the comma String WhistlerStart=WhistlerCsvValue.substr(0,pos+1); HRESULT hr = S_OK; do { hr=isADValuePresent(iDirObj,property,WhistlerCsvValue); BREAK_ON_FAILED_HRESULT(hr); if(hr == S_OK) // The Whistler value is already there { hr=removeExtraneous( iDirObj, locale, object, property, WhistlerCsvValue, WhistlerStart, W2KStart ); BREAK_ON_FAILED_HRESULT(hr); break; } // Now we know that the Whistler value is not present // and therefore we will add it if the W2K value is present hr=isADValuePresent(iDirObj,property,W2KCsvValue); BREAK_ON_FAILED_HRESULT(hr); if(hr == S_OK) // The W2K value is there. { ObjectId tempObj(locale,String(object)); ValueActions &act=results.objectActions[tempObj][property]; act.addValues.push_back(WhistlerCsvValue); act.delValues.push_back(W2KCsvValue); // remove all but the W2K that we removed in the previous line hr=removeExtraneous( iDirObj, locale, object, property, W2KCsvValue, WhistlerStart, W2KStart ); break; } // Now we know that neither Whistler nor W2K values are present // If we have a value starting like the W2K we will log that it // is a custom value String ADValue; hr=isADStartValuePresent(iDirObj,property,W2KStart,ADValue); BREAK_ON_FAILED_HRESULT(hr); if(hr==S_OK) // Something starts like the W2K csv value { SingleValue tmpCustom(locale,object,property,ADValue); results.customizedValues.push_back(tmpCustom); // We will keep only the first custom value hr=removeExtraneous( iDirObj, locale, object, property, ADValue, WhistlerStart, W2KStart ); break; } // Now neither Whistler, W2K or W2KStart are present if ( WhistlerStart == W2KStart ) { // We have to check the WhistlerStart as well hr=isADStartValuePresent(iDirObj,property,WhistlerStart,ADValue); BREAK_ON_FAILED_HRESULT(hr); if(hr == S_OK) // Something starts like the Whistler csv value { SingleValue tmpCustom(locale,object,property,ADValue); results.customizedValues.push_back(tmpCustom); // We will keep only the first custom value hr=removeExtraneous( iDirObj, locale, object, property, ADValue, WhistlerStart, W2KStart ); break; } } // Now we know that there are no values starting like // the Whistler or W2K csv values so we have to add // the Whistler value ObjectId tempObj(locale,String(object)); ValueActions &act=results.objectActions[tempObj][property]; act.addValues.push_back(WhistlerCsvValue); } while(0); LOG_HRESULT(hr); return hr; } //called from RwplaceW2KMultipleValue to remove all values // starting with start1 or start2 other than keeper HRESULT Analysis::removeExtraneous ( IDirectoryObject *iDirObj, const int locale, const String &object, const String &property, const String &keeper, const String &start1, const String &start2 ) { LOG_FUNCTION(Analysis::removeExtraneous); HRESULT hr = S_OK; DWORD dwReturn=0; ADS_ATTR_INFO *pAttrInfo =NULL; // iDirObj->GetObjectAttributes swears that pAttrName is an IN argument. // It should have used a LPCWSTR but now we have to pay the // casting price LPWSTR pAttrName[] ={const_cast(property.c_str())}; do { hr = iDirObj->GetObjectAttributes( pAttrName, 1, &pAttrInfo, &dwReturn ); do { BREAK_ON_FAILED_HRESULT(hr); if(pAttrInfo==NULL) { hr = S_FALSE; break; } for ( DWORD val=0; val < pAttrInfo->dwNumValues; val++ ) { ASSERT ( pAttrInfo->pADsValues[val].dwType == ADSTYPE_CASE_IGNORE_STRING ); wchar_t *valueAD = pAttrInfo->pADsValues[val].CaseIgnoreString; if ( wcscmp(valueAD,keeper.c_str())!=0 && ( wcsncmp(valueAD,start1.c_str(),start1.size())==0 || wcsncmp(valueAD,start2.c_str(),start2.size())==0 ) ) { String value=valueAD; ObjectId tempObj(locale,String(object)); ValueActions &act=results.extraneousValues[tempObj][property]; act.delValues.push_back(value); } } } while(0); if (pAttrInfo!=NULL) FreeADsMem(pAttrInfo); } while (0); LOG_HRESULT(hr); return hr; } // called from RwplaceW2KSingleValue to remove all values // other than keeper HRESULT Analysis::removeExtraneous ( IDirectoryObject *iDirObj, const int locale, const String &object, const String &property, const String &keeper ) { LOG_FUNCTION(Analysis::removeExtraneous); HRESULT hr = S_OK; DWORD dwReturn=0; ADS_ATTR_INFO *pAttrInfo =NULL; // iDirObj->GetObjectAttributes swears that pAttrName is an IN argument. // It should have used a LPCWSTR but now we have to pay the // casting price LPWSTR pAttrName[] ={const_cast(property.c_str())}; do { hr = iDirObj->GetObjectAttributes( pAttrName, 1, &pAttrInfo, &dwReturn ); do { BREAK_ON_FAILED_HRESULT(hr); if(pAttrInfo==NULL) { hr = S_FALSE; break; } for ( DWORD val=0; val < pAttrInfo->dwNumValues; val++ ) { ASSERT ( pAttrInfo->pADsValues[val].dwType == ADSTYPE_CASE_IGNORE_STRING ); wchar_t *valueAD = pAttrInfo->pADsValues[val].CaseIgnoreString; if ( wcscmp(valueAD,keeper.c_str())!=0 ) { String value=valueAD; ObjectId tempObj(locale,String(object)); ValueActions &act=results.extraneousValues[tempObj][property]; act.delValues.push_back(value); } } } while(0); if (pAttrInfo!=NULL) FreeADsMem(pAttrInfo); } while (0); LOG_HRESULT(hr); return hr; } // called from replaceGUID to remove all values // starting with the GUID in ordAndGuid1 // or the GUID in ordAndGuid2 other than keeper HRESULT Analysis::removeExtraneousGUID ( IDirectoryObject *iDirObj, const int locale, const String &object, const String &property, const String &keeper, const String &ordAndGuid1, const String &ordAndGuid2 ) { LOG_FUNCTION(Analysis::removeExtraneousGUID); HRESULT hr = S_OK; size_t pos=ordAndGuid1.find(L','); ASSERT(pos != String::npos); String guid1=ordAndGuid1.substr(pos+1); pos=ordAndGuid2.find(L','); ASSERT(pos != String::npos); String guid2=ordAndGuid2.substr(pos+1); DWORD dwReturn=0; ADS_ATTR_INFO *pAttrInfo =NULL; // iDirObj->GetObjectAttributes swears that pAttrName is an IN argument. // It should have used a LPCWSTR but now we have to pay the // casting price LPWSTR pAttrName[] ={const_cast(property.c_str())}; do { hr = iDirObj->GetObjectAttributes( pAttrName, 1, &pAttrInfo, &dwReturn ); do { BREAK_ON_FAILED_HRESULT(hr); if(pAttrInfo==NULL) { hr = S_FALSE; break; } for ( DWORD val=0; val < pAttrInfo->dwNumValues; val++ ) { ASSERT ( pAttrInfo->pADsValues[val].dwType == ADSTYPE_CASE_IGNORE_STRING ); wchar_t *valueAD = pAttrInfo->pADsValues[val].CaseIgnoreString; if (keeper.icompare(valueAD)!=0) { String valueStr=valueAD; pos=valueStr.find(L','); if (pos!=String::npos) { String guid=valueStr.substr(pos+1); if(guid1.icompare(guid)==0 || guid2.icompare(guid)==0) { ObjectId tempObj(locale,String(object)); ValueActions &act=results.extraneousValues[tempObj][property]; act.delValues.push_back(valueStr); } } } } } while(0); if (pAttrInfo!=NULL) FreeADsMem(pAttrInfo); } while (0); LOG_HRESULT(hr); return hr; } // if any value exists in the AD with the same guid as guidValue // it is returned in guidFound, otherwise S_FALSE is returned HRESULT Analysis::getADGuid ( IDirectoryObject *iDirObj, const String &property, const String &guidValue, String &guidFound ) { LOG_FUNCTION(Analysis::getADGuid); DWORD dwReturn=0; ADS_ATTR_INFO *pAttrInfo =NULL; // iDirObj->GetObjectAttributes swears that pAttrName is an IN argument. // It should have used a LPCWSTR but now we have to pay the // casting price LPWSTR pAttrName[] ={const_cast(property.c_str())}; size_t pos=guidValue.find(L','); ASSERT(pos!=String::npos); String guid=guidValue.substr(pos+1); HRESULT hr = S_OK; do { hr = iDirObj->GetObjectAttributes( pAttrName, 1, &pAttrInfo, &dwReturn ); do { BREAK_ON_FAILED_HRESULT(hr); // If there are no values we finish the search hr=S_FALSE; if(pAttrInfo==NULL) { break; } for ( DWORD val=0; val < pAttrInfo->dwNumValues; val++ ) { ASSERT ( pAttrInfo->pADsValues[val].dwType == ADSTYPE_CASE_IGNORE_STRING ); wchar_t *guidAD=wcschr(pAttrInfo->pADsValues[val].CaseIgnoreString,L','); if(guidAD != NULL) { guidAD++; if (guid.icompare(guidAD)==0) { guidFound=pAttrInfo->pADsValues[val].CaseIgnoreString; hr=S_OK; break; } } } } while(0); if (pAttrInfo!=NULL) FreeADsMem(pAttrInfo); } while (0); LOG_HRESULT(hr); return hr; } // returns S_OK if value is present or S_FALSE otherwise HRESULT Analysis::isADValuePresent ( IDirectoryObject *iDirObj, const String &property, const String &value ) { LOG_FUNCTION(Analysis::isADValuePresent); DWORD dwReturn=0; ADS_ATTR_INFO *pAttrInfo =NULL; // iDirObj->GetObjectAttributes swears that pAttrName is an IN argument. // It should have used a LPCWSTR but now we have to pay the // casting price LPWSTR pAttrName[] ={const_cast(property.c_str())}; HRESULT hr = S_OK; do { hr = iDirObj->GetObjectAttributes( pAttrName, 1, &pAttrInfo, &dwReturn ); do { BREAK_ON_FAILED_HRESULT(hr); hr=S_FALSE; // If there are no values we finish the search if(pAttrInfo==NULL) { break; } for ( DWORD val=0; val < pAttrInfo->dwNumValues; val++ ) { ASSERT ( pAttrInfo->pADsValues[val].dwType == ADSTYPE_CASE_IGNORE_STRING ); wchar_t *valueAD=pAttrInfo->pADsValues[val].CaseIgnoreString; if (wcscmp(value.c_str(),valueAD)==0) { hr=S_OK; break; } } } while(0); if (pAttrInfo!=NULL) FreeADsMem(pAttrInfo); } while (0); LOG_HRESULT(hr); return hr; } // retrieves the first value starting with valueStart // from the Active Directory // If no value is found S_FALSE is returned. HRESULT Analysis::isADStartValuePresent ( IDirectoryObject *iDirObj, const String &property, const String &valueStart, String &value ) { LOG_FUNCTION(Analysis::isADStartValuePresent); DWORD dwReturn=0; ADS_ATTR_INFO *pAttrInfo =NULL; // iDirObj->GetObjectAttributes swears that pAttrName is an IN argument. // It should have used a LPCWSTR but now we have to pay the // casting price LPWSTR pAttrName[] ={const_cast(property.c_str())}; HRESULT hr = S_OK; do { hr = iDirObj->GetObjectAttributes( pAttrName, 1, &pAttrInfo, &dwReturn ); do { BREAK_ON_FAILED_HRESULT(hr); value.erase(); hr = S_FALSE; // If there are no values we finish the search if(pAttrInfo==NULL) { break; } for ( DWORD val=0; (val < pAttrInfo->dwNumValues); val++ ) { ASSERT ( pAttrInfo->pADsValues[val].dwType == ADSTYPE_CASE_IGNORE_STRING ); wchar_t *valueAD=pAttrInfo->pADsValues[val].CaseIgnoreString; if (wcsncmp(valueStart.c_str(),valueAD,valueStart.size())==0) { value=pAttrInfo->pADsValues[val].CaseIgnoreString; hr=S_OK; break; } } } while(0); if (pAttrInfo!=NULL) FreeADsMem(pAttrInfo); } while (0); LOG_HRESULT(hr); return hr; } // retrieves the first value // from the Active Directory // If no value is found S_FALSE is returned. HRESULT Analysis::getADFirstValue ( IDirectoryObject *iDirObj, const String &property, String &value ) { LOG_FUNCTION(Analysis::getADFirstValue); DWORD dwReturn=0; ADS_ATTR_INFO *pAttrInfo =NULL; // iDirObj->GetObjectAttributes swears that pAttrName is an IN argument. // It should have used a LPCWSTR but now we have to pay the // casting price LPWSTR pAttrName[] ={const_cast(property.c_str())}; HRESULT hr = S_OK; do { hr = iDirObj->GetObjectAttributes( pAttrName, 1, &pAttrInfo, &dwReturn ); do { BREAK_ON_FAILED_HRESULT(hr); // If there are no values we finish the search if(pAttrInfo==NULL) { hr = S_FALSE; break; } ASSERT(pAttrInfo->pADsValues->dwType==ADSTYPE_CASE_IGNORE_STRING); value=pAttrInfo->pADsValues->CaseIgnoreString; } while(0); if (pAttrInfo!=NULL) FreeADsMem(pAttrInfo); } while (0); LOG_HRESULT(hr); return hr; } // auxiliary in the createReport to // enumerate an ObjectIdList HRESULT Analysis::reportObjects ( HANDLE file, const ObjectIdList &list, const String &header ) { LOG_FUNCTION(Analysis::reportObjects); HRESULT hr=S_OK; do { if(list.size()==0) break; hr=FS::WriteLine(file,header); BREAK_ON_FAILED_HRESULT(hr); ObjectIdList::const_iterator begin,end; begin=list.begin(); end=list.end(); while(begin!=end) { hr=FS::WriteLine( file, String::format ( IDS_RPT_OBJECT_FORMAT, begin->object.c_str(), begin->locale ) ); BREAK_ON_FAILED_HRESULT(hr); begin++; } BREAK_ON_FAILED_HRESULT(hr); } while(0); LOG_HRESULT(hr); return hr; } // auxiliary in the createReport to // enumerate a LongList HRESULT Analysis::reportContainers ( HANDLE file, const LongList &list, const String &header ) { LOG_FUNCTION(Analysis::reportContainers); HRESULT hr=S_OK; do { if(list.size()==0) break; hr=FS::WriteLine(file,header); BREAK_ON_FAILED_HRESULT(hr); LongList::const_iterator begin,end; begin=list.begin(); end=list.end(); while(begin!=end) { hr=FS::WriteLine( file, String::format ( IDS_RPT_CONTAINER_FORMAT, *begin ) ); BREAK_ON_FAILED_HRESULT(hr); begin++; } BREAK_ON_FAILED_HRESULT(hr); } while(0); LOG_HRESULT(hr); return hr; } // auxiliary in the createReport to // enumerate a SingleValueList HRESULT Analysis::reportValues ( HANDLE file, const SingleValueList &list, const String &header ) { LOG_FUNCTION(Analysis::reportValues); HRESULT hr=S_OK; do { if(list.size()==0) break; hr=FS::WriteLine(file,header); BREAK_ON_FAILED_HRESULT(hr); SingleValueList::const_iterator begin,end; begin=list.begin(); end=list.end(); while(begin!=end) { hr=FS::WriteLine( file, String::format ( IDS_RPT_VALUE_FORMAT, begin->value.c_str(), begin->locale, begin->object.c_str(), begin->property.c_str() ) ); BREAK_ON_FAILED_HRESULT(hr); begin++; } BREAK_ON_FAILED_HRESULT(hr); } while(0); LOG_HRESULT(hr); return hr; } // auxiliary in the createReport to // enumerate ObjectActions HRESULT Analysis::reportActions ( HANDLE file, const ObjectActions &list, const String &header ) { LOG_FUNCTION(Analysis::reportActions); HRESULT hr=S_OK; do { if(list.size()==0) break; hr=FS::WriteLine(file,header); BREAK_ON_FAILED_HRESULT(hr); ObjectActions::const_iterator beginObj=list.begin(); ObjectActions::const_iterator endObj=list.end(); while(beginObj!=endObj) { hr=FS::WriteLine ( file, String::format ( IDS_RPT_OBJECT_FORMAT, beginObj->first.object.c_str(), beginObj->first.locale ) ); BREAK_ON_FAILED_HRESULT(hr); PropertyActions::iterator beginAct=beginObj->second.begin(); PropertyActions::iterator endAct=beginObj->second.end(); while(beginAct!=endAct) { StringList::iterator beginDel = beginAct->second.delValues.begin(); StringList::iterator endDel = beginAct->second.delValues.end(); while(beginDel!=endDel) { hr=FS::WriteLine ( file, String::format ( IDS_RPT_DEL_VALUE_FORMAT, beginAct->first.c_str(), beginDel->c_str() ) ); BREAK_ON_FAILED_HRESULT(hr); beginDel++; } BREAK_ON_FAILED_HRESULT(hr); StringList::iterator beginAdd = beginAct->second.addValues.begin(); StringList::iterator endAdd = beginAct->second.addValues.end(); while(beginAdd!=endAdd) { hr=FS::WriteLine ( file, String::format ( IDS_RPT_ADD_VALUE_FORMAT, beginAct->first.c_str(), beginAdd->c_str() ) ); BREAK_ON_FAILED_HRESULT(hr); beginAdd++; } BREAK_ON_FAILED_HRESULT(hr); beginAct++; } // while(beginAct!=endAct) BREAK_ON_FAILED_HRESULT(hr); beginObj++; } // while(beginObj!=endObj) BREAK_ON_FAILED_HRESULT(hr); } while(0); LOG_HRESULT(hr); return hr; } // Create the report from the AnalysisResults HRESULT Analysis::createReport(const String& reportName) { LOG_FUNCTION(Analysis::createReport); HRESULT hr=S_OK; do { HANDLE file; hr=FS::CreateFile(reportName, file, GENERIC_WRITE); if (FAILED(hr)) { error=String::format(IDS_COULD_NOT_CREATE_FILE,reportName.c_str()); break; } do { hr=FS::WriteLine(file,String::load(IDS_RPT_HEADER)); BREAK_ON_FAILED_HRESULT(hr); hr=reportActions ( file, results.extraneousValues, String::load(IDS_RPT_EXTRANEOUS) ); BREAK_ON_FAILED_HRESULT(hr); hr=reportValues ( file, results.customizedValues, String::load(IDS_RPT_CUSTOMIZED) ); BREAK_ON_FAILED_HRESULT(hr); hr=reportObjects ( file, results.conflictingWhistlerObjects, String::load ( IDS_RPT_CONFLICTING_WITH_NEW_WHISTLER_OBJECTS ) ); BREAK_ON_FAILED_HRESULT(hr); hr=reportActions ( file, results.objectActions, String::load(IDS_RPT_ACTIONS) ); BREAK_ON_FAILED_HRESULT(hr); hr=reportObjects ( file, results.createW2KObjects, String::load(IDS_RPT_CREATEW2K) ); BREAK_ON_FAILED_HRESULT(hr); hr=reportObjects ( file, results.createWhistlerObjects, String::load(IDS_RPT_CREATE_WHISTLER) ); BREAK_ON_FAILED_HRESULT(hr); hr=reportContainers( file, results.createContainers, String::load(IDS_RPT_CONTAINERS) ); BREAK_ON_FAILED_HRESULT(hr); } while(0); CloseHandle(file); BREAK_ON_FAILED_HRESULT(hr); } while(0); LOG_HRESULT(hr); return hr; }