#include "headers.hxx" #include "global.hpp" #include "Analisys.hpp" #include "AnalisysResults.hpp" #include "CSVDSReader.hpp" #include "resource.h" #include "AdsiHelpers.hpp" #include "constants.hpp" #include "dspecup.hpp" Analisys::Analisys ( const CSVDSReader& csvReader409_, const CSVDSReader& csvReaderIntl_, const String& ldapPrefix_, const String& rootContainerDn_, AnalisysResults &res, const String &reportName_,//=L"", void *caleeStruct_,//=NULL, progressFunction stepIt_,//=NULL, progressFunction totalSteps_//=NULL, ) : csvReader409(csvReader409_), csvReaderIntl(csvReaderIntl_), ldapPrefix(ldapPrefix_), rootContainerDn(rootContainerDn_), results(res), reportName(reportName_), caleeStruct(caleeStruct_), stepIt(stepIt_), totalSteps(totalSteps_) { LOG_CTOR(Analisys); ASSERT(!ldapPrefix.empty()); ASSERT(!rootContainerDn.empty()); }; // Analisys entry point HRESULT Analisys::run() { LOG_FUNCTION(Analisys::run); setReplaceW2KStrs(); 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=dealWithXPObjects(locale); BREAK_ON_FAILED_HRESULT(hr); 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 Analisys::dealWithContainer( const long locale, bool &isPresent) { LOG_FUNCTION(Analisys::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. 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; } // add entries to results.conflictingXPObjects or // results.createXPObject as necessary HRESULT Analisys::dealWithXPObjects(const long locale) { LOG_FUNCTION(Analisys::dealWithXPObjects); ASSERT(locale > 0); ASSERT(!rootContainerDn.empty()); HRESULT hr = S_OK; do { for ( int i = 0; *NEW_XP_OBJECTS[i]!=0; ++i ) { String objectName = NEW_XP_OBJECTS[i]; String objectPath = ldapPrefix + L"CN=" + objectName + 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. This is what we expect. We want // to add the object in the repair phase. ObjectId tempObj(locale,objectName); results.createXPObjects.push_back(tempObj); hr = S_OK; continue; } else if (SUCCEEDED(hr)) { // The object already exists. We have a conflict. ObjectId tempObj(locale,objectName); results.conflictingXPObjects.push_back(tempObj); } else { error=String::format( IDS_ERROR_BINDING_TO_OBJECT, objectName.c_str(), objectPath.c_str()); break; } } BREAK_ON_FAILED_HRESULT(hr); } while (0); LOG_HRESULT(hr); return hr; } // add entries to results.createW2KObjects // and results.objectActions as necessary HRESULT Analisys::dealWithW2KObjects(const long locale) { LOG_FUNCTION(Analisys::dealWithW2KObjects); ASSERT(locale >0); ASSERT(!rootContainerDn.empty()); HRESULT hr = S_OK; do { for( long i = 0; *(CHANGE_LIST[i].object)!=0; ++i ) { String objectName = CHANGE_LIST[i].object; String objectPath = ldapPrefix + L"CN=" + objectName + 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. ObjectId tempObj(locale,objectName); results.createW2KObjects.push_back(tempObj); hr = S_OK; continue; } else if (SUCCEEDED(hr)) { // At this point, the display specifier object exists. Determine if // if has been touched since its creation. SmartInterface iDirObj; hr=iDirObj.AcquireViaQueryInterface(iads); // hr = iads->QueryInterface(IID_IDirectoryObject,(void **)iDirObj); BREAK_ON_FAILED_HRESULT(hr); hr = checkChanges(locale,CHANGE_LIST[i],iDirObj); BREAK_ON_FAILED_HRESULT(hr); } else { error=String::format( IDS_ERROR_BINDING_TO_OBJECT, objectName.c_str(), objectPath.c_str()); break; } } BREAK_ON_FAILED_HRESULT(hr); } while (0); LOG_HRESULT(hr); return hr; } HRESULT Analisys::checkChanges( const long locale, const sChangeList& changes, IDirectoryObject *iDirObj) { LOG_FUNCTION(Analisys::checkChanges); wchar_t *object=changes.object; HRESULT hr=S_OK; for( long i = 0; *(changes.changes[i].property)!=0; ++i) { struct sChange change=changes.changes[i]; switch(change.type) { case ADD_ALL_CSV_VALUES: hr = addAllCsvValues ( iDirObj, locale, object, change.property ); if(FAILED(hr)) { LOG_HRESULT(hr); return hr; } break; case ADD_VALUE: hr = addValue ( iDirObj, locale, object, change.property, change.value ); if(FAILED(hr)) { LOG_HRESULT(hr); return hr; } break; case REPLACE_W2K_MULTIPLE_VALUE: hr = replaceW2KMultipleValue ( iDirObj, locale, object, change.property, change.value ); if(FAILED(hr)) { LOG_HRESULT(hr); return hr; } break; case REPLACE_W2K_SINGLE_VALUE: hr = replaceW2KSingleValue ( iDirObj, locale, object, change.property, change.value ); if(FAILED(hr)) { LOG_HRESULT(hr); return hr; } break; case ADD_GUID: hr = addGuid ( iDirObj, locale, object, change.property, change.value ); if(FAILED(hr)) { LOG_HRESULT(hr); return hr; } break; case REMOVE_GUID: hr = removeGuid ( iDirObj, locale, object, change.property, change.value ); if(FAILED(hr)) { LOG_HRESULT(hr); return hr; } break; default: ASSERT(false); } } LOG_HRESULT(S_OK); return S_OK; } // adds ordAndGuid to the property if Guid is not already there. HRESULT Analisys::addGuid( IDirectoryObject *iDirObj, const int locale, const wchar_t *object, const wchar_t *property, const wchar_t *ordAndGuid) { LOG_FUNCTION(Analisys::addGuid); HRESULT hr = S_OK; String propertStr(property); String ordAndGuidStr(ordAndGuid); do { String guidFound; hr=getADGuid( iDirObj, propertStr, ordAndGuidStr, 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(ordAndGuidStr); } } while (0); LOG_HRESULT(hr); return hr; } // adds all csv values still not on the property HRESULT Analisys::addAllCsvValues( IDirectoryObject *iDirObj, const long locale, const wchar_t *object, const wchar_t *property) { LOG_FUNCTION(Analisys::addAllCsvValues); HRESULT hr = S_OK; const CSVDSReader &csvReader=(locale==0x409)?csvReader409:csvReaderIntl; do { StringList values; hr=csvReader.getCsvValues(locale,object,property,values); BREAK_ON_FAILED_HRESULT(hr); if (values.size()==0) { error=String::format(IDS_NO_CSV_VALUE,locale,object); 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 Analisys::addValue( IDirectoryObject *iDirObj, const int locale, const wchar_t *object, const wchar_t *property, const wchar_t *value) { LOG_FUNCTION(Analisys::addValue); HRESULT hr = S_OK; String valueStr(value); String propertyStr(property); do { hr=isADValuePresent ( iDirObj, propertyStr, valueStr ); 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; } //Auxiliary function for replaceW2KSingleValue // retrieves csvValue HRESULT Analisys::getCsvSingleValue ( const int locale, const wchar_t *object, const wchar_t *property, String &csvValue ) { LOG_FUNCTION(Analisys::getCsvReplacementValue); const CSVDSReader &csvReader=(locale==0x409)?csvReader409:csvReaderIntl; HRESULT hr = S_OK; do { StringList XPCsvValues; hr=csvReader.getCsvValues(locale,object,property,XPCsvValues); BREAK_ON_FAILED_HRESULT(hr); // we should have only one value in the csv // since we can't distinguish the // value we want to replace from others as // in REPLACE_W2K_MULTIPLE_VALE if(XPCsvValues.size() != 1) { error=String::format ( IDS_NOT_ONE_CSV_VALUE, XPCsvValues.size(), csvReader.getFileName().c_str(), locale, object, property ); hr=E_FAIL; break; } csvValue = *XPCsvValues.begin(); } 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 Analisys::replaceW2KSingleValue ( IDirectoryObject *iDirObj, const int locale, const wchar_t *object, const wchar_t *property, const wchar_t *value ) { LOG_FUNCTION(Analisys::replaceW2KValue); long index = *value; String objectStr(object); String propertyStr(property); HRESULT hr = S_OK; do { String XPCsvValue; hr=getCsvSingleValue ( locale, object, property, XPCsvValue ); BREAK_ON_FAILED_HRESULT(hr); // Retrieve W2KCsvValue from replaceW2KStrs pair tmpIndxLoc; tmpIndxLoc.first=index; tmpIndxLoc.second=locale; String &W2KCsvValue=replaceW2KStrs[tmpIndxLoc]; // There is nothing to do if the Whistler csv value // is the same as it was in W2K if (XPCsvValue.icompare(W2KCsvValue)==0) { break; } // Now we might have a replacement to do since the value // changed from W2K to Whistler hr=isADValuePresent(iDirObj,propertyStr,XPCsvValue); 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,objectStr,propertyStr,XPCsvValue); 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,propertyStr,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(XPCsvValue); act.delValues.push_back(W2KCsvValue); // remove all but the W2K that we removed in the previous line hr=removeExtraneous(iDirObj,locale,objectStr,propertyStr,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,propertyStr,ADValue); BREAK_ON_FAILED_HRESULT(hr); if(hr == S_OK) // We have a value { SingleValue tmpCustom(locale,objectStr,propertyStr,ADValue); results.customizedValues.push_back(tmpCustom); // We will remove any other value than the one we found hr=removeExtraneous(iDirObj,locale,objectStr,propertyStr,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(XPCsvValue); } while(0); LOG_HRESULT(hr); return hr; } //Auxiliary function for replaceW2KMultipleValue // retrieves csvValue and XPStart HRESULT Analisys::getCsvMultipleValue ( const int locale, const wchar_t *object, const wchar_t *property, const wchar_t *value, String &csvValue, String &XPstart ) { LOG_FUNCTION(Analisys::getCsvReplacementValue); const CSVDSReader &csvReader=(locale==0x409)?csvReader409:csvReaderIntl; HRESULT hr = S_OK; do { String sW2KXP(value+2); // +2 for index and semicollon StringList lW2KXP; size_t cnt=sW2KXP.tokenize(back_inserter(lW2KXP),L";"); XPstart=lW2KXP.back(); // We have the W2K and the XP start ASSERT(cnt==2); // Search the csv for the value starting with the XP string hr=csvReader.getCsvValue( locale, object, property, XPstart.c_str(), csvValue ); BREAK_ON_FAILED_HRESULT(hr); // We should always find a csv value if(hr == S_FALSE) { error=String::format( IDS_VALUE_NOT_IN_CSV, XPstart.c_str(), locale, object, property, csvReader.getFileName().c_str() ); hr=E_FAIL; break; } } 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 Analisys::replaceW2KMultipleValue ( IDirectoryObject *iDirObj, const int locale, const wchar_t *object, const wchar_t *property, const wchar_t *value ) { LOG_FUNCTION(Analisys::replaceW2KValue); long index = *value; String objectStr(object); String propertyStr(property); HRESULT hr = S_OK; do { String XPCsvValue,XPStart; // Get the Whistler csv value and the start of the Whistler value hr=getCsvMultipleValue ( locale, object, property, value, XPCsvValue, XPStart ); BREAK_ON_FAILED_HRESULT(hr); // Retrieve W2KCsvValue from replaceW2KStrs pair tmpIndxLoc; tmpIndxLoc.first=index; tmpIndxLoc.second=locale; String &W2KCsvValue=replaceW2KStrs[tmpIndxLoc]; // There is nothing to do if the Whistler csv value // is the same as it was in W2K if (XPCsvValue.icompare(W2KCsvValue)==0) { break; } // Now we might have a replacement to do since the value // changed from W2K to Whistler // First we should get the beginning of the W2K string // for use in removeExtraneous calls size_t pos=W2KCsvValue.find(L','); String W2KStart; // We only need to assert since the W2KStrs tool would // detect any REPLACE_W2K_MULTIPLE_VALUE without a comma ASSERT(pos != String::npos); W2KStart=W2KCsvValue.substr(0,pos+1); hr=isADValuePresent(iDirObj,propertyStr,XPCsvValue); BREAK_ON_FAILED_HRESULT(hr); if(hr == S_OK) // The Whistler value is already there { hr=removeExtraneous( iDirObj, locale, objectStr, propertyStr, XPCsvValue, XPStart, 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,propertyStr,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(XPCsvValue); act.delValues.push_back(W2KCsvValue); // remove all but the W2K that we removed in the previous line hr=removeExtraneous( iDirObj, locale, objectStr, propertyStr, W2KCsvValue, XPStart, 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,propertyStr,W2KStart,ADValue); BREAK_ON_FAILED_HRESULT(hr); if(hr==S_OK) // Something starts like the W2K csv value { SingleValue tmpCustom(locale,objectStr,propertyStr,ADValue); results.customizedValues.push_back(tmpCustom); // We will keep only the first custom value hr=removeExtraneous( iDirObj, locale, objectStr, propertyStr, ADValue, XPStart, W2KStart ); break; } // Now neither Whistler, W2K or W2KStart are present if ( XPStart.icompare(W2KStart) != 0 ) { // We have to check the XPStart as well hr=isADStartValuePresent(iDirObj,propertyStr,XPStart,ADValue); BREAK_ON_FAILED_HRESULT(hr); if(hr == S_OK) // Something starts like the Whistler csv value { SingleValue tmpCustom(locale,objectStr,propertyStr,ADValue); results.customizedValues.push_back(tmpCustom); // We will keep only the first custom value hr=removeExtraneous( iDirObj, locale, objectStr, propertyStr, ADValue, XPStart, 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(XPCsvValue); } while(0); LOG_HRESULT(hr); return hr; } // removes ordAndGuid from the property if Guid is there. HRESULT Analisys::removeGuid( IDirectoryObject *iDirObj, const int locale, const wchar_t *object, const wchar_t *property, const wchar_t *ordAndGuid) { LOG_FUNCTION(Analisys::removeGuid); HRESULT hr = S_OK; String propertStr(property); String ordAndGuidStr(ordAndGuid); do { String guidFound; hr=getADGuid( iDirObj, propertStr, ordAndGuidStr, 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; } //called from RwplaceW2KMultipleValue to remove all values // starting with start1 or start2 other than keeper HRESULT Analisys::removeExtraneous ( IDirectoryObject *iDirObj, const int locale, const String &object, const String &property, const String &keeper, const String &start1, const String &start2 ) { LOG_FUNCTION(Analisys::removeExtraneous); DWORD dwReturn; ADS_ATTR_INFO *pAttrInfo =NULL; // 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 ); BREAK_ON_FAILED_HRESULT(hr); if(pAttrInfo==NULL) { hr = S_FALSE; break; } for ( long val=0; val < pAttrInfo->dwNumValues; val++, pAttrInfo->pADsValues++ ) { wchar_t *valueAD = pAttrInfo->pADsValues->CaseIgnoreString; if ( _wcsicmp(valueAD,keeper.c_str())!=0 && ( _wcsnicmp(valueAD,start1.c_str(),start1.size())==0 || _wcsnicmp(valueAD,start2.c_str(),start2.size())==0 ) ) { String value=pAttrInfo->pADsValues->CaseIgnoreString; ObjectId tempObj(locale,String(object)); ValueActions &act=results.extraneousValues[tempObj][property]; act.delValues.push_back(value); } } } while (0); LOG_HRESULT(hr); return hr; } // called from RwplaceW2KSingleValue to remove all values // other than keeper HRESULT Analisys::removeExtraneous ( IDirectoryObject *iDirObj, const int locale, const String &object, const String &property, const String &keeper ) { LOG_FUNCTION(Analisys::removeExtraneous); DWORD dwReturn; ADS_ATTR_INFO *pAttrInfo =NULL; // 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 ); BREAK_ON_FAILED_HRESULT(hr); if(pAttrInfo==NULL) { hr = S_FALSE; break; } for ( long val=0; val < pAttrInfo->dwNumValues; val++, pAttrInfo->pADsValues++ ) { wchar_t *valueAD = pAttrInfo->pADsValues->CaseIgnoreString; if ( _wcsicmp(valueAD,keeper.c_str())!=0 ) { String value=pAttrInfo->pADsValues->CaseIgnoreString; ObjectId tempObj(locale,String(object)); ValueActions &act=results.extraneousValues[tempObj][property]; act.delValues.push_back(value); } } } 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 Analisys::getADGuid ( IDirectoryObject *iDirObj, const String &property, const String &guidValue, String &guidFound ) { LOG_FUNCTION(Analisys::getADGuid); DWORD dwReturn; ADS_ATTR_INFO *pAttrInfo =NULL; // 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 ); BREAK_ON_FAILED_HRESULT(hr); // If there are no values we finish the search hr=S_FALSE; if(pAttrInfo==NULL) { break; } for ( long val=0; val < pAttrInfo->dwNumValues; val++, pAttrInfo->pADsValues++ ) { wchar_t *guidAD=wcschr(pAttrInfo->pADsValues->CaseIgnoreString,L','); if(guidAD != NULL) { guidAD++; if (_wcsicmp(guid.c_str(),guidAD)==0) { guidFound=pAttrInfo->pADsValues->CaseIgnoreString; hr=S_OK; break; } } } } while (0); LOG_HRESULT(hr); return hr; } // returns S_OK if value is present or S_FALSE otherwise HRESULT Analisys::isADValuePresent ( IDirectoryObject *iDirObj, const String &property, const String &value ) { LOG_FUNCTION(Analisys::isADValuePresent); DWORD dwReturn; ADS_ATTR_INFO *pAttrInfo =NULL; // 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 ); BREAK_ON_FAILED_HRESULT(hr); hr=S_FALSE; // If there are no values we finish the search if(pAttrInfo==NULL) { break; } for ( long val=0; val < pAttrInfo->dwNumValues; val++, pAttrInfo->pADsValues++ ) { wchar_t *valueAD=pAttrInfo->pADsValues->CaseIgnoreString; if (_wcsicmp(value.c_str(),valueAD)==0) { hr=S_OK; break; } } } 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 Analisys::isADStartValuePresent ( IDirectoryObject *iDirObj, const String &property, const String &valueStart, String &value ) { LOG_FUNCTION(Analisys::isADStartValuePresent); DWORD dwReturn; ADS_ATTR_INFO *pAttrInfo =NULL; // 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 ); BREAK_ON_FAILED_HRESULT(hr); value.erase(); hr = S_FALSE; // If there are no values we finish the search if(pAttrInfo==NULL) { break; } for ( long val=0; (val < pAttrInfo->dwNumValues); val++, pAttrInfo->pADsValues++ ) { wchar_t *valueAD=pAttrInfo->pADsValues->CaseIgnoreString; if (_wcsnicmp(valueStart.c_str(),valueAD,valueStart.size())==0) { value=pAttrInfo->pADsValues->CaseIgnoreString; hr=S_OK; break; } } } 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 Analisys::getADFirstValue ( IDirectoryObject *iDirObj, const String &property, String &value ) { LOG_FUNCTION(Analisys::getADFirstValue); DWORD dwReturn; ADS_ATTR_INFO *pAttrInfo =NULL; // 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 ); BREAK_ON_FAILED_HRESULT(hr); // If there are no values we finish the search if(pAttrInfo==NULL) { hr = S_FALSE; break; } value=pAttrInfo->pADsValues->CaseIgnoreString; } while (0); LOG_HRESULT(hr); return hr; } // auxiliary in the createReport to // enumerate an ObjectIdList HRESULT Analisys::reportObjects ( HANDLE file, const ObjectIdList &list, const String &header ) { LOG_FUNCTION(Analisys::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 Analisys::reportContainers ( HANDLE file, const LongList &list, const String &header ) { LOG_FUNCTION(Analisys::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 Analisys::reportValues ( HANDLE file, const SingleValueList &list, const String &header ) { LOG_FUNCTION(Analisys::reportContainers); 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 Analisys::reportActions ( HANDLE file, const ObjectActions &list, const String &header ) { LOG_FUNCTION(Analisys::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); // break on if internal while broke 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); // break on if internal while broke beginAct++; } // while(beginAct!=endAct) BREAK_ON_FAILED_HRESULT(hr); // break on if internal while broke beginObj++; } // while(beginObj!=endObj) BREAK_ON_FAILED_HRESULT(hr); } while(0); LOG_HRESULT(hr); return hr; } // Create the report from the AnalisysResults HRESULT Analisys::createReport(const String& reportName) { LOG_FUNCTION(Analisys::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.conflictingXPObjects, String::load(IDS_RPT_CONFLICTINGXP) ); 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.createXPObjects, String::load(IDS_RPT_CREATEXP) ); 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; }