/*--------------------------------------------------------------------------- File: ProcessExtensions.cpp Comments: implementation of the CProcessExtensions class. (c) Copyright 1999, Mission Critical Software, Inc., All Rights Reserved Proprietary and confidential to Mission Critical Software, Inc. REVISION LOG ENTRY Revision By: Sham Chauthani Revised on 07/02/99 12:40:00 --------------------------------------------------------------------------- */ #include "stdafx.h" #include "Err.hpp" #include "ErrDct.hpp" #include "workobj.h" #include "TReg.hpp" #include "ProcExts.h" #include "ResStr.h" #include "DCTStat.h" #include "TxtSid.h" #include "ARExt_i.c" #include "folders.h" using namespace nsFolders; //#import "\bin\AdsProp.tlb" no_namespace #import "AdsProp.tlb" no_namespace #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif const _bstr_t sKeyExtension = REGKEY_EXTENSIONS; const _bstr_t sKeyBase = REGKEY_ADMT; extern TErrorDct err; // Sort function for the list of interface pointers int TExtNodeSortBySequence(TNode const * t1, TNode const * t2) { TNodeInterface const * p1 = (TNodeInterface const *)t1; TNodeInterface const * p2 = (TNodeInterface const *)t2; if ( p1->GetSequence() < p2->GetSequence() ) return -1; else if ( p1->GetSequence() > p2->GetSequence() ) return 1; else return 0; } ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------------- // CONSTRUCTOR : The constructor looks up all the registered COM extensions // from the registry. For each one it creates a com object and // puts it into a list as a IExtendAccountMigration *. //--------------------------------------------------------------------------- CProcessExtensions::CProcessExtensions( IVarSetPtr pVs //in -Pointer to the Varset with main settings. ) { // Store the varset that has the main settings. m_pVs = pVs; // GUI told us to run all the Extensions. // Now look through the registry to get all the registered extension object ClassIDs // for each one create a object and store the interface pointer in an array. TRegKey key; TCHAR sName[300]; // key name TCHAR sValue[300]; // value name DWORD valuelen; // value length DWORD type; // value type DWORD retval = 0; // Loop sentinel CLSID clsid; HRESULT hr; IExtendAccountMigration * pExtTemp; retval = 0; // Open the Extensions registry key DWORD rc = key.Open(sKeyExtension); // if no extensions then we can leave now. if ( rc != ERROR_SUCCESS ) { err.SysMsgWrite(ErrE, rc, DCT_MSG_REG_KEY_OPEN_FAILED_SD, (PCWSTR)sKeyExtension, rc); _com_issue_error(HRESULT_FROM_WIN32(rc)); } valuelen = sizeof(sValue); // Go through all Name-Value pairs and try to create those objects // if successful then put it into the list to be processed. long ndx = 0; while (!retval) { retval = key.ValueEnum(ndx, sName, sizeof(sName)/sizeof(sName[0]), sValue, &valuelen, &type); if ( !retval ) { // each name in here is a Object name for the class ID. we are going to use this to // Create the object and then put the IExtendAccountRepl * in the list member0 ::CLSIDFromProgID(sName, &clsid); hr = ::CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IExtendAccountMigration, (void **) &pExtTemp); if ( SUCCEEDED(hr) ) { TNodeInterface * pNode = new TNodeInterface(pExtTemp); long num; hr = pExtTemp->get_SequenceNumber(&num); if ((pNode) && (SUCCEEDED(hr))) { pNode->SetSequence(num); } if (pNode) { m_listInterface.InsertBottom(pNode); } else { pExtTemp->Release(); _com_issue_error(E_OUTOFMEMORY); } } else { err.SysMsgWrite(ErrE, hr, DCT_MSG_CANNOT_CREATE_EXTENSION_S, sName); _com_issue_error(hr); } } if ((retval != ERROR_SUCCESS) && (retval != ERROR_NO_MORE_ITEMS)) { err.SysMsgWrite(ErrE, retval, DCT_MSG_CANNOT_ENUM_REGISTRY_VALUES_S, (PCWSTR)sKeyExtension); _com_issue_error(HRESULT_FROM_WIN32(retval)); } ndx++; } m_listInterface.Sort(&TExtNodeSortBySequence); } //--------------------------------------------------------------------------- // DESTRUCTOR : Clears the list of interfaces. //--------------------------------------------------------------------------- CProcessExtensions::~CProcessExtensions() { TNodeInterface * pNode; TNodeInterface * tempNode; pNode = (TNodeInterface *) m_listInterface.Head(); while ( pNode ) { tempNode = (TNodeInterface *)pNode->Next(); delete pNode; pNode = tempNode; } } //--------------------------------------------------------------------------- // Process: This function is called by the account replicator for every // object that is copied. This function sets up the parameters and // for every registered extension object it calls the Process method // on that extension. //--------------------------------------------------------------------------- HRESULT CProcessExtensions::Process( TAcctReplNode * pAcctNode, //in- Account replication node _bstr_t sTargetDomain, //in- Name of the target domain Options * pOptions, //in- Options as set by the user BOOL bPreMigration //in- Flag, whether to call pre or post task ) { IExtendAccountMigration * pExt; TNodeInterface * pNode = NULL; HRESULT hr; IUnknown * pSUnk = NULL; IUnknown * pTUnk = NULL; IUnknown * pMain = NULL; IUnknown * pProps = NULL; IVarSetPtr pVar(__uuidof(VarSet)); IObjPropBuilderPtr pProp(__uuidof(ObjPropBuilder)); IADs * pSource = NULL; IADs * pTarget = NULL; _variant_t var; IDispatch * pDisp = NULL; // Get the IADs to both source and target accounts. hr = ADsGetObject(const_cast(pAcctNode->GetSourcePath()), IID_IADs, (void**) &pSource); if ( FAILED(hr)) pSource = NULL; hr = ADsGetObject(const_cast(pAcctNode->GetTargetPath()), IID_IADs, (void**) &pTarget); if ( FAILED(hr)) pTarget = NULL; // Get IUnknown * s to everything... Need to marshal it that way if ( pSource != NULL ) pSource->QueryInterface(IID_IUnknown, (void **) &pSUnk); else pSUnk = NULL; if ( pTarget != NULL ) pTarget->QueryInterface(IID_IUnknown, (void **) &pTUnk); else pTUnk = NULL; pVar->QueryInterface(IID_IUnknown, (void **) &pProps); m_pVs->QueryInterface(IID_IUnknown, (void **) &pMain); if ( pOptions->bSameForest ) m_pVs->put(GET_BSTR(DCTVS_Options_IsIntraforest),GET_BSTR(IDS_YES)); else m_pVs->put(GET_BSTR(DCTVS_Options_IsIntraforest),GET_BSTR(IDS_No)); m_pVs->put(L"Options.SourceDomainVersion",(long)pOptions->srcDomainVer); m_pVs->put(L"Options.TargetDomainVersion",(long)pOptions->tgtDomainVer); // AccountNode into the Varset. PutAccountNodeInVarset(pAcctNode, pTarget, m_pVs); // Put the DB manager into the Varset pOptions->pDb->QueryInterface(IID_IDispatch, (void**)&pDisp); var.vt = VT_DISPATCH; var.pdispVal = pDisp; m_pVs->putObject(GET_BSTR(DCTVS_DBManager), var); // Call the Process Object method on all registered objects.that we created pNode = (TNodeInterface *) m_listInterface.Head(); while ( pNode ) { try { if ( pOptions->pStatus ) { LONG status = 0; HRESULT hr = pOptions->pStatus->get_Status(&status); if ( SUCCEEDED(hr) && status == DCT_STATUS_ABORTING ) break; } pExt = pNode->GetInterface(); if ( pOptions->bUndo ) { EAMAccountStats eamAccountStats = { 0 }; hr = pExt->ProcessUndo(pSUnk, pTUnk, pMain, &pProps, &eamAccountStats); BatchMark(eamAccountStats); } else { BSTR sName; pExt->get_sName(&sName); if ( bPreMigration ) { EAMAccountStats eamAccountStats = { 0 }; hr = pExt->PreProcessObject(pSUnk, pTUnk, pMain, &pProps, &eamAccountStats); BatchMark(eamAccountStats); if (hr == ERROR_OBJECT_ALREADY_EXISTS) pAcctNode->SetHr(hr); } else { /* we need to run the DisAcct extension last, so don't run it in this loop run it in the next loop by itself */ //if not DisAcct extension, process this extension if (wcscmp((WCHAR*)sName, L"Disable Accounts")) { EAMAccountStats eamAccountStats = { 0 }; hr = pExt->ProcessObject(pSUnk, pTUnk, pMain, &pProps, &eamAccountStats); BatchMark(eamAccountStats); } } } } catch (...) { BSTR sName; pExt->get_sName(&sName); err.LogOpen(pOptions->logFile,1); err.MsgWrite(ErrE, DCT_MSG_Extension_Exception_SS, (WCHAR*) sName, pAcctNode->GetTargetName()); err.LogClose(); hr = S_OK; } pNode = (TNodeInterface *)pNode->Next(); } /* now run the DisAcct extension here to ensure it is run last, if not undo or premigration */ if ((!pOptions->bUndo) && (!bPreMigration)) { bool bDone = false; pNode = (TNodeInterface *) m_listInterface.Head(); while ((pNode) && (!bDone)) { try { if ( pOptions->pStatus ) { LONG status = 0; HRESULT hr = pOptions->pStatus->get_Status(&status); if ( SUCCEEDED(hr) && status == DCT_STATUS_ABORTING ) break; } pExt = pNode->GetInterface(); BSTR sName; pExt->get_sName(&sName); if (!wcscmp((WCHAR*)sName, L"Disable Accounts")) { bDone = true; EAMAccountStats eamAccountStats = { 0 }; hr = pExt->ProcessObject(pSUnk, pTUnk, pMain, &pProps, &eamAccountStats); BatchMark(eamAccountStats); } } catch (...) { BSTR sName; pExt->get_sName(&sName); err.LogOpen(pOptions->logFile,1); err.MsgWrite(ErrE, DCT_MSG_Extension_Exception_SS, (WCHAR*) sName, pAcctNode->GetTargetName()); err.LogClose(); hr = S_OK; } pNode = (TNodeInterface *)pNode->Next(); }//end while not done and more }//end if not undo or premigration // Now we have the varset with all the settings that the user wants us to set. // So we can call the SetPropsFromVarset method in out GetProps object to set these // properties. hr = pProp->SetPropertiesFromVarset(pAcctNode->GetTargetPath(), /*sTargetDomain,*/ pProps, ADS_ATTR_UPDATE); // Update the AccountNode with any changes made by the extensions UpdateAccountNodeFromVarset(pAcctNode, pTarget, m_pVs); // Cleanup time ... if ( pSUnk ) pSUnk->Release(); if ( pTUnk ) pTUnk->Release(); if ( pProps ) pProps->Release(); if ( pMain ) pMain->Release(); if ( pSource ) pSource->Release(); if ( pTarget ) pTarget->Release(); return hr; } //--------------------------------------------------------------------------- // PutAccountNodeInVarset : Transfers all the account node info into the // varset. //--------------------------------------------------------------------------- void CProcessExtensions::PutAccountNodeInVarset( TAcctReplNode *pNode, //in -Replicated account node to get info IADs * pTarget, //in -IADs pointer to the target object for the GUID IVarSet * pVS //out-Varset to put the information in ) { _variant_t var = L""; BSTR sGUID; DWORD lVal = 0; HRESULT hr; WCHAR strSid[MAX_PATH]; DWORD lenStrSid = DIM(strSid); pVS->put(GET_WSTR(DCTVS_CopiedAccount_SourceName),pNode->GetName()); pVS->put(GET_WSTR(DCTVS_CopiedAccount_SourcePath),pNode->GetSourcePath()); pVS->put(GET_WSTR(DCTVS_CopiedAccount_SourceProfile),pNode->GetSourceProfile()); pVS->put(GET_WSTR(DCTVS_CopiedAccount_SourceRID),(long)pNode->GetSourceRid()); pVS->put(GET_WSTR(DCTVS_CopiedAccount_SourceSam),pNode->GetSourceSam()); pVS->put(GET_WSTR(DCTVS_CopiedAccount_Status),(long)pNode->GetStatus()); pVS->put(GET_WSTR(DCTVS_CopiedAccount_TargetName),pNode->GetTargetName()); pVS->put(GET_WSTR(DCTVS_CopiedAccount_TargetPath),pNode->GetTargetPath()); pVS->put(GET_WSTR(DCTVS_CopiedAccount_TargetProfile),pNode->GetTargetProfile()); pVS->put(GET_WSTR(DCTVS_CopiedAccount_TargetRID),(long)pNode->GetTargetRid()); pVS->put(GET_WSTR(DCTVS_CopiedAccount_TargetSam),pNode->GetTargetSam()); pVS->put(GET_WSTR(DCTVS_CopiedAccount_Type),pNode->GetType()); pVS->put(GET_WSTR(DCTVS_CopiedAccount_GroupType),(long)pNode->GetGroupType()); pVS->put(GET_WSTR(DCTVS_CopiedAccount_Operations),(long)pNode->operations); pVS->put(GET_WSTR(DCTVS_CopiedAccount_ExpDate),pNode->lExpDate); pVS->put(GET_WSTR(DCTVS_CopiedAccount_UserFlags), pNode->lFlags); pVS->put(GET_WSTR(DCTVS_CopiedAccount_SourceUPN),pNode->GetSourceUPN()); GetTextualSid(pNode->GetSourceSid(),strSid,&lenStrSid); pVS->put(GET_WSTR(DCTVS_CopiedAccount_SourceDomainSid),strSid); // Get the GUID if ( pTarget ) { hr = pTarget->get_GUID(&sGUID); if ( SUCCEEDED(hr) ) { var = sGUID; SysFreeString(sGUID); } } pVS->put(GET_WSTR(DCTVS_CopiedAccount_GUID), var); // Get the status lVal = pNode->GetStatus(); var.Clear(); var.vt = VT_UI4; var.lVal = lVal; pVS->put(GET_WSTR(DCTVS_CopiedAccount_Status), var); } //--------------------------------------------------------------------------- // UpdateAccountNodeFromVarset : Updates the account node info with the data in the Transfers all the account node info into the // varset. //--------------------------------------------------------------------------- void CProcessExtensions::UpdateAccountNodeFromVarset( TAcctReplNode *pNode, //in -Replicated account node to get info IADs * pTarget, //in -IADs pointer to the target object for the GUID IVarSet * pVS //out-Varset to put the information in ) { _variant_t var = L""; DWORD lVal = 0; _bstr_t text; long val; text = pVS->get(GET_WSTR(DCTVS_CopiedAccount_SourceName)); pNode->SetName(text); text = pVS->get(GET_WSTR(DCTVS_CopiedAccount_SourcePath)); pNode->SetSourcePath(text); text = pVS->get(GET_WSTR(DCTVS_CopiedAccount_SourceProfile)); pNode->SetSourceProfile(text); val = pVS->get(GET_WSTR(DCTVS_CopiedAccount_SourceRID)); pNode->SetSourceRid(val); text = pVS->get(GET_WSTR(DCTVS_CopiedAccount_SourceSam)); pNode->SetSourceSam(text); val = pVS->get(GET_WSTR(DCTVS_CopiedAccount_Status)); pNode->SetStatus(val); text = pVS->get(GET_WSTR(DCTVS_CopiedAccount_TargetName)); pNode->SetTargetName(text); text = pVS->get(GET_WSTR(DCTVS_CopiedAccount_TargetPath)); pNode->SetTargetPath(text); text = pVS->get(GET_WSTR(DCTVS_CopiedAccount_TargetProfile)); pNode->SetTargetProfile(text); val = pVS->get(GET_WSTR(DCTVS_CopiedAccount_TargetRID)); pNode->SetTargetRid(val); text = pVS->get(GET_WSTR(DCTVS_CopiedAccount_TargetSam)); pNode->SetTargetSam(text); text = pVS->get(GET_WSTR(DCTVS_CopiedAccount_Type)); pNode->SetType(text); val = pVS->get(GET_WSTR(DCTVS_CopiedAccount_Operations)); pNode->operations = val; val = pVS->get(GET_WSTR(DCTVS_CopiedAccount_ExpDate)); pNode->lExpDate = val; val = pVS->get(GET_WSTR(DCTVS_CopiedAccount_UserFlags)); pNode->lFlags = val; text = pVS->get(GET_WSTR(DCTVS_CopiedAccount_SourceDomainSid)); pNode->SetSourceSid(SidFromString((WCHAR*)text)); }