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.
448 lines
18 KiB
448 lines
18 KiB
/*---------------------------------------------------------------------------
|
|
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<WCHAR *>(pAcctNode->GetSourcePath()), IID_IADs, (void**) &pSource);
|
|
if ( FAILED(hr))
|
|
pSource = NULL;
|
|
|
|
hr = ADsGetObject(const_cast<WCHAR *>(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));
|
|
}
|