windows-nt/Source/XPSP1/NT/admin/admt/disp/ddisp.cpp
2020-09-26 16:20:57 +08:00

1723 lines
56 KiB
C++

/*---------------------------------------------------------------------------
File: DCTDispatcher.cpp
Comments: Implementation of dispatcher COM object. Remotely installs and
launches the DCT Agent on remote computers.
The CDCTDispatcher class implements the COM interface for the dispatcher.
It takes a varset, containing a list of machines, and dispatches agents to
each specified machine.
A job file (varset persisted to a file) is created for each agent, and
necessary initialization configuration (such as building an account mapping file for
security translation) is done. The DCDTDispatcher class instantiates a
thread pool (CPooledDispatch), and uses the CDCTInstaller class to remotely
install and start the agent service on each machine.
(c) Copyright 1999, Mission Critical Software, Inc., All Rights Reserved
Proprietary and confidential to Mission Critical Software, Inc.
REVISION LOG ENTRY
Revision By: Christy Boles
Revised on 02/15/99 11:23:57
---------------------------------------------------------------------------
*/// DCTDispatcher.cpp : Implementation of CDCTDispatcher
#include "stdafx.h"
#include "resource.h"
#include <locale.h>
//#include "..\Common\Include\McsDispatcher.h"
#include "Dispatch.h"
#include "DDisp.h"
#include "DInst.h"
#include "Common.hpp"
#include "ErrDct.hpp"
#include "UString.hpp"
#include "EaLen.hpp"
#include "Cipher.hpp"
#include "TNode.hpp"
#include "TPool.h" // Thread pool for dispatching jobs
#include "LSAUtils.h"
#include "TxtSid.h"
#include "sd.hpp"
#include "SecObj.hpp"
#include "BkupRstr.hpp"
#include "TReg.hpp"
#include "ResStr.h"
#include "TaskChk.h"
#include "CommaLog.hpp"
#include "TInst.h"
#include <lm.h>
#include "AdmtAccount.h"
/////////////////////////////////////////////////////////////////////////////
// CDCTDispatcher
//#import "\bin\McsEADCTAgent.tlb" named_guids
//#include "..\AgtSvc\AgSvc.h"
#import "Engine.tlb" named_guids
#include "AgSvc.h"
#include "AgSvc_c.c"
#include "AgRpcUtl.h"
//#import "\bin\McsDctWorkerObjects.tlb"
//#include "..\Common\Include\McsPI.h"
#import "WorkObj.tlb"
#include "McsPI.h"
#include "McsPI_i.c"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
TErrorDct errLog; // used to write dispatch log that is read by the agent monitor
TErrorDct errTrace;
TCriticalSection gCS;
BOOL gbCacheFileBuilt = FALSE;
// TServerNodes make up an internally used list of machines to install to
class TServerNode : public TNode
{
WCHAR sourceName[LEN_Computer];
WCHAR targetName[LEN_Computer];
BOOL bTranslate;
BOOL bChangeDomain;
BOOL bReboot;
DWORD dwRebootDelay;
public:
TServerNode() { sourceName[0] = 0; targetName[0] = 0; bTranslate = FALSE; bChangeDomain = FALSE; bReboot= FALSE; dwRebootDelay = 0; }
WCHAR const * SourceName() { return sourceName; }
WCHAR const * TargetName() { return targetName; }
BOOL Translate() { return bTranslate; }
BOOL Reboot() { return bReboot; }
BOOL ChangeDomain() { return bChangeDomain; }
DWORD RebootDelay() { return dwRebootDelay; }
void SourceName(WCHAR const * src) { safecopy(sourceName,src); }
void TargetName(WCHAR const * tgt) { safecopy(targetName,tgt); }
void Translate(BOOL v) { bTranslate = v; }
void ChangeDomain(BOOL v) { bChangeDomain = v; }
void Reboot(BOOL v) { bReboot = v; }
void RebootDelay(DWORD d) { dwRebootDelay = d; }
};
extern
TErrorDct err;
// defined in CkPlugIn.cpp
BOOL IsValidPlugIn(IMcsDomPlugIn * pPlugIn);
BOOL // ret - TRUE if need to dump debug information
DumpDebugInfo(
WCHAR * filename // out - where to dump debug information
)
{
DWORD rc = 0;
BOOL bFound = FALSE;
TRegKey key;
rc = key.OpenRead(GET_STRING(IDS_HKLM_DomainAdmin_Key),HKEY_LOCAL_MACHINE);
if ( ! rc )
{
rc = key.ValueGetStr(L"DispatchVarSet",filename,MAX_PATH);
if ( ! rc )
{
if ( *filename )
bFound = TRUE;
}
}
return bFound;
}
void
BuildPlugInFileList(
TNodeList * pList, // i/o- list that files needed by plug-ins wil be added to
IVarSet * pVarSet // in - varset containing list of plug-ins to query
)
{
// for now, build a list of all plug-ins, and add it to the varset
MCSDCTWORKEROBJECTSLib::IPlugInInfoPtr pPtr;
SAFEARRAY * pArray = NULL;
HRESULT hr;
LONG bound;
LONG ndx[1];
WCHAR key[LEN_Path];
hr = pPtr.CreateInstance(__uuidof(MCSDCTWORKEROBJECTSLib::PlugInInfo));
_bstr_t bStrGuid;
swprintf(key,GET_STRING(IDS_DCTVS_Fmt_PlugIn_D),0);
bStrGuid = pVarSet->get(key);
if (! bStrGuid.length() )
{
// if no plug-ins are specified, use the ones in the plug-ins directory
if ( SUCCEEDED(hr) )
{
hr = pPtr->raw_EnumeratePlugIns(&pArray);
}
if ( SUCCEEDED(hr) )
{
SafeArrayGetUBound(pArray,1,&bound);
for ( ndx[0] = 0 ; ndx[0] <= bound ; ndx[0]++ )
{
BSTR val = NULL;
SafeArrayGetElement(pArray,ndx,&val);
swprintf(key,GET_STRING(IDS_DCTVS_Fmt_PlugIn_D),ndx[0]);
pVarSet->put(key,val);
SysFreeString(val);
}
SafeArrayDestroy(pArray);
pArray = NULL;
}
}
// enumerate the plug-ins specified in the varset, and make a list of their needed files
int nRegFiles = 0;
for ( int i = 0 ; ; i++ )
{
swprintf(key,GET_STRING(IDS_DCTVS_Fmt_PlugIn_D),i);
bStrGuid = pVarSet->get(key);
if ( bStrGuid.length() == 0 )
break;
IMcsDomPlugIn * pPlugIn = NULL;
SAFEARRAY * pFileArray = NULL;
TFileNode * pNode;
CLSID clsid;
hr = CLSIDFromString(bStrGuid,&clsid);
if ( SUCCEEDED(hr) )
{
hr = CoCreateInstance(clsid,NULL,CLSCTX_ALL,IID_IMcsDomPlugIn,(void**)&pPlugIn);
}
if ( SUCCEEDED(hr) )
{
if ( IsValidPlugIn(pPlugIn) )
{
hr = pPlugIn->GetRequiredFiles(&pFileArray);
if ( SUCCEEDED(hr) )
{
SafeArrayGetUBound(pFileArray,1,&bound);
for ( ndx[0] = 0 ; ndx[0] <= bound ; ndx[0]++ )
{
BSTR val = NULL;
SafeArrayGetElement(pFileArray,ndx,&val);
pNode = new TFileNode(val);
pList->InsertBottom(pNode);
SysFreeString(val);
}
SafeArrayDestroy(pFileArray);
pFileArray = NULL;
}
hr = pPlugIn->GetRegisterableFiles(&pFileArray);
if ( SUCCEEDED(hr) )
{
SafeArrayGetUBound(pFileArray,1,&bound);
for (ndx[0] = 0; ndx[0] <= bound ; ndx[0]++ )
{
BSTR val = NULL;
SafeArrayGetElement(pFileArray,ndx,&val);
swprintf(key,GET_STRING(IDS_DCTVSFmt_PlugIn_RegisterFiles_D),nRegFiles);
pVarSet->put(key,val);
SysFreeString(val);
nRegFiles++;
}
SafeArrayDestroy(pFileArray);
pFileArray = NULL;
}
}
pPlugIn->Release();
}
}
}
// InstallJobInfo defines a Domain Migration 'job' to be installed and launched
struct InstallJobInfo
{
IVarSetPtr pVarSetList; // varset defining the server list
IVarSetPtr pVarSet; // VarSet defining the job to run
_bstr_t serverName; // computer to install and run on
long ndx; // index of this server in the server list
TNodeList * pPlugInFileList; // list of files to install for plug-ins
std::vector<CComBSTR>* pStartFailedVector;
std::vector<CComBSTR>* pFailureDescVector;
std::vector<CComBSTR>* pStartedVector;
std::vector<CComBSTR>* pJobidVector;
HANDLE hMutex;
_bstr_t jobfile; // uses the specified job file instead of creating one
int nErrCount;
};
// WaitInfo is used to pass information to a thread that waits and does cleanup
// after all the Dispatcher's work is done
struct WaitInfo
{
IUnknown * pUnknown; // IUnknown interface to the DCTDisptacher object
TJobDispatcher **ppPool; // pointer to thread pool performing the tasks (installations)
TNodeList * pPlugInFileList; // pointer to plug-in files list that will need to be freed
};
WCHAR gComputerName[LEN_Computer] = L""; // name of local computer
// Calls DCTAgentService to start the Domain Migration Job on a remote computer
DWORD // ret- OS return code
StartJob(
WCHAR const * serverName, // in - computer to start job on
WCHAR const * password, // in - password for "Options.Credentials" account (used for writing results back to console machine)
WCHAR const * fullname, // in - full path (including filename) to file containing the job's VarSet
WCHAR const * filename, // in - filename of file containing the varset for the job
_bstr_t& strJobid
)
{
DWORD rc = 0;
handle_t hBinding = NULL;
WCHAR * sBinding = NULL;
WCHAR jobGUID[LEN_Guid];
WCHAR passwordW[LEN_Password];
safecopy(passwordW,password);
rc = EaxBindCreate(serverName,&hBinding,&sBinding,TRUE);
if ( rc )
{
err.SysMsgWrite(ErrE,rc,DCT_MSG_AGENT_BIND_FAILED_SD, serverName,rc);
}
if( ! rc )
{
RpcTryExcept
{
// the job file has been copied to the remote computer
// during the installation
rc = EaxcSubmitJob(hBinding,filename,passwordW,jobGUID);
if ( ! rc )
{
err.MsgWrite(0,DCT_MSG_AGENT_JOB_STARTED_SSS,serverName,filename,jobGUID);
strJobid = jobGUID;
}
else
{
err.SysMsgWrite(ErrE,rc,DCT_MSG_AGENT_JOB_START_FAILED_SSD,serverName,filename,rc);
}
}
RpcExcept(1)
{
rc = RpcExceptionCode();
if ( rc != RPC_S_SERVER_UNAVAILABLE )
{
err.SysMsgWrite(ErrE,rc,DCT_MSG_AGENT_JOB_START_FAILED_SSD,serverName,filename,rc);
}
}
RpcEndExcept
if ( rc == RPC_S_SERVER_UNAVAILABLE )
{
// maybe the agent hasn't started up yet for some reason
for ( int tries = 0 ; tries < 6 ; tries++ )
{
Sleep(5000); // wait a few seconds and try again
RpcTryExcept
{
rc = EaxcSubmitJob(hBinding,filename,passwordW,jobGUID);
if ( ! rc )
{
err.MsgWrite(0,DCT_MSG_AGENT_JOB_STARTED_SSS,serverName,filename,jobGUID);
strJobid = jobGUID;
break;
}
else
{
if ( tries == 5 )
err.SysMsgWrite(ErrE,rc,DCT_MSG_AGENT_JOB_START_FAILED_SSD,serverName,filename,rc);
}
}
RpcExcept(1)
{
rc = RpcExceptionCode();
if ( tries == 5 )
err.SysMsgWrite(ErrE,rc,DCT_MSG_AGENT_JOB_START_FAILED_SSD,serverName,filename,rc);
}
RpcEndExcept
}
}
}
if ( ! rc )
{
// if the job was started successfully, remove the job file
if ( ! MoveFileEx(fullname,NULL, MOVEFILE_DELAY_UNTIL_REBOOT) )
{
// DWORD rc2 = GetLastError();
}
}
// this indicates whether the server was started
if ( ! rc )
{
errLog.DbgMsgWrite(0,L"%ls\t%ls\t%ld,%ls,%ls",serverName,L"Start",rc,filename,jobGUID);
}
else
{
errLog.DbgMsgWrite(0,L"%ls\t%ls\t%ld",serverName,L"Start",rc);
}
return rc;
}
// Gets the domain sid for the specified domain
BOOL // ret- TRUE if successful
GetSidForDomain(
LPWSTR DomainName, // in - name of domain to get SID for
PSID * pDomainSid // out- SID for domain, free with FreeSid
)
{
PSID pSid = NULL;
// DWORD lenSid = 200;
DWORD rc = 0;
WCHAR * domctrl = NULL;
if ( DomainName[0] != L'\\' )
{
rc = NetGetDCName(NULL,DomainName,(LPBYTE*)&domctrl);
}
if ( ! rc )
{
rc = GetDomainSid(domctrl,&pSid);
NetApiBufferFree(domctrl);
}
(*pDomainSid) = pSid;
return ( pSid != NULL);
}
// Set parameters in the varset that are specific to this particular computer
void
SetupVarSetForJob(
InstallJobInfo * pInfo, // structure defining job
IVarSet * pVarSet, // varset describing job
WCHAR const * uncname, // UNC path for results directory
WCHAR const * filename // UNC path for results file for this job
)
{
WCHAR uncresult[MAX_PATH];
WCHAR serverName[MAX_PATH];
WCHAR shareName[MAX_PATH];
_bstr_t text;
// Set server-specific parameters in the varset
swprintf(uncresult,L"%s.result",filename);
swprintf(serverName,L"\\\\%s",gComputerName);
UStrCpy(shareName,uncname + UStrLen(serverName) );
shareName[UStrLen(shareName)-1] = 0;
pVarSet->put(GET_BSTR(DCTVS_Options_ResultFile),uncresult);
pVarSet->put(GET_BSTR(DCTVS_Options_Credentials_Server),serverName);
pVarSet->put(GET_BSTR(DCTVS_Options_Credentials_Share),shareName);
pVarSet->put(GET_BSTR(DCTVS_Options_DeleteFileAfterLoad),GET_BSTR(IDS_YES));
pVarSet->put(GET_BSTR(DCTVS_Options_RemoveAgentOnCompletion),GET_BSTR(IDS_YES));
pVarSet->put(GET_BSTR(DCTVS_Options_LogToTemp),GET_BSTR(IDS_YES));
pVarSet->put(GET_BSTR(DCTVS_Server_Index), CComVariant((long)pInfo->ndx));
text = pVarSet->get(GET_BSTR(DCTVS_GatherInformation_UserRights));
if ( !UStrICmp(text,GET_STRING(IDS_YES)) )
{
swprintf(uncresult,L"%s.userrights",filename);
pVarSet->put(GET_BSTR(DCTVS_GatherInformation_UserRights),uncresult);
}
text = pVarSet->get(GET_BSTR(DCTVS_Security_ReportAccountReferences));
if ( ! UStrICmp(text,GET_STRING(IDS_YES)) )
{
swprintf(uncresult,L"%s.secrefs",filename);
pVarSet->put(GET_BSTR(DCTVS_Security_ReportAccountReferences),uncresult);
}
pVarSet->put(GET_BSTR(DCTVS_Options_LocalProcessingOnly),GET_BSTR(IDS_YES));
}
// Entry point for thread, waits until all agents are installed and started,
// then cleans up and exits
ULONG __stdcall // ret- returns 0
Wait(
void * arg // in - WaitInfo structure containing needed pointers
)
{
WaitInfo * w = (WaitInfo*)arg;
SetThreadLocale(LOCALE_SYSTEM_DEFAULT);
// wait for all jobs to finish
(*(w->ppPool))->WaitForCompletion();
if ( w->pUnknown )
w->pUnknown->Release();
// delete the plug-in file list
TNodeListEnum tEnum;
TFileNode * fNode;
TFileNode * fNext;
for ( fNode = (TFileNode*)tEnum.OpenFirst(w->pPlugInFileList); fNode; fNode = fNext )
{
fNext = (TFileNode*)tEnum.Next();
w->pPlugInFileList->Remove(fNode);
delete fNode;
}
tEnum.Close();
delete w->pPlugInFileList;
delete *(w->ppPool);
*(w->ppPool) = NULL;
err.MsgWrite(0,DCT_MSG_DISPATCHER_DONE);
errLog.DbgMsgWrite(0,L"%ls\t%ls\t%ld",L"All",L"Finished",0);
err.LogClose();
errLog.LogClose();
return 0;
}
// Thread entry point, installs and starts agent on a single computer
ULONG __stdcall // ret- HRESULT error code
DoInstall(
void * arg // in - InstallJobInfo structure
)
{
SetThreadLocale(LOCALE_SYSTEM_DEFAULT);
HRESULT hr = S_OK;
InstallJobInfo * pInfo = (InstallJobInfo*)arg;
_bstr_t strJobid;
_bstr_t strFailureDesc(GET_STRING(IDS_START_FAILED));
if(pInfo->nErrCount == 0)
hr = CoInitializeEx(0,COINIT_MULTITHREADED );
#ifdef OFA
HKEY hkeyLocal;
LONG lRes;
bool bVersionSupported = true;
// Check version info
lRes = RegConnectRegistry(
pInfo->serverName,
// address of name of remote computer
HKEY_LOCAL_MACHINE, // predefined registry handle
&hkeyLocal // address of buffer for remote registry handle
);
if(lRes == ERROR_SUCCESS)
{
HKEY hkeyWin;
lRes = ::RegOpenKey(hkeyLocal, GET_STRING(IDS_HKLM_WINDOWS_NT), &hkeyWin);
if(lRes == ERROR_SUCCESS)
{
DWORD nMaxLen = 20;
BSTR strVersion = SysAllocStringLen(0, nMaxLen), strSP = SysAllocStringLen(0, nMaxLen);
strVersion[0] = L'\0'; strSP[0] = L'\0';
DWORD type;
DWORD nTemp = nMaxLen*2;
lRes = RegQueryValueEx(hkeyWin, GET_STRING(IDS_CurrentVersion), 0, &type, (LPBYTE)strVersion, &nTemp);
if(!lRes)
{
nTemp = nMaxLen*2;
lRes = RegQueryValueEx(hkeyWin, GET_STRING(IDS_CSDVersion), 0, &type, (LPBYTE)strSP, &nTemp);
lRes = 0;
}
if(!lRes)
{
// write out the version info
err.MsgWrite(ErrI,DCT_MSG_AGENT_OSVERSION,(WCHAR*)pInfo->serverName,strVersion, strSP);
TCHAR cSP = 0;
if(strVersion[0] == L'4' && wcslen(strSP))
cSP = strSP[wcslen(strSP) - 1];
if(strVersion[0] < L'4' || (strVersion[0] == L'4' &&
cSP < L'3') )
bVersionSupported = false;
}
::RegCloseKey(hkeyWin);
::SysFreeString(strVersion); ::SysFreeString(strSP);
}
else
{
lRes = ::RegOpenKey(hkeyLocal, GET_STRING(IDS_HKLM_MICROSOFT), &hkeyWin);
if(!lRes)
{
bVersionSupported = false;
err.MsgWrite(ErrI, lRes, DCT_MSG_AGENT_OSVERSION_NOT_WINNT,(WCHAR*)pInfo->serverName);
}
::RegCloseKey(hkeyWin);
}
::RegCloseKey(hkeyLocal);
}
if(lRes)
err.SysMsgWrite(ErrI, lRes, DCT_MSG_AGENT_OSVERSION_NOT_FOUND,(WCHAR*)pInfo->serverName, lRes);
else if(!bVersionSupported)
{
err.MsgWrite(ErrI,DCT_MSG_AGENT_OSVERSION_NOTSUPPORTED,(WCHAR*)pInfo->serverName);
strFailureDesc = GET_STRING(IDS_UNSOUPPORTED_OS);
hr = E_FAIL;
}
#endif
if ( SUCCEEDED(hr) )
{
IWorkNode * pInstaller = NULL;
IVarSetPtr pVarSet(CLSID_VarSet);
WCHAR filename[MAX_PATH];
WCHAR tempdir[MAX_PATH];
WCHAR key[MAX_PATH];
if ( pVarSet == NULL )
{
if(pInfo->nErrCount == 0)
CoUninitialize();
return E_FAIL;
}
DWORD uniqueNumber = (LONG)pInfo->pVarSet->get(GET_BSTR(DCTVS_Options_UniqueNumberForResultsFile));
_bstr_t bstrResultPath = pInfo->pVarSet->get(GET_BSTR(DCTVS_Dispatcher_ResultPath));
_bstr_t bstrPassword = pInfo->pVarSet->get(GET_BSTR(DCTVS_Options_Credentials_Password));
// Copy the common information from the source varset
gCS.Enter();
// pInfo->pVarSet contains all the information except the server list
// we don't want to copy the server list each time, so we create our new varset from pInfo->pVarSet
pVarSet->ImportSubTree("",pInfo->pVarSet);
gCS.Leave();
// Set the server-specific data in the varset
swprintf(key,GET_BSTR(IDS_DCTVSFmt_Servers_RenameTo_D),pInfo->ndx);
// pInfo->pVarSetList contains the entire varset including the server list
_bstr_t text = pInfo->pVarSetList->get(key);
if ( text.length() )
{
pVarSet->put(GET_BSTR(DCTVS_LocalServer_RenameTo),text);
}
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_ChangeDomain_D),pInfo->ndx);
text = pInfo->pVarSetList->get(key);
if ( text.length() )
{
pVarSet->put(GET_BSTR(DCTVS_LocalServer_ChangeDomain),text);
}
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_MigrateOnly_D),pInfo->ndx);
text = pInfo->pVarSetList->get(key);
pVarSet->put(GET_BSTR(DCTVS_LocalServer_MigrateOnly),text);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_Reboot_D),pInfo->ndx);
text = pInfo->pVarSetList->get(key);
if ( text.length() )
{
pVarSet->put(GET_BSTR(DCTVS_LocalServer_Reboot),text);
LONG delay;
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_RebootDelay_D),pInfo->ndx);
delay = pInfo->pVarSetList->get(key);
if ( delay )
{
pVarSet->put(GET_BSTR(DCTVS_LocalServer_RebootDelay),delay);
}
}
// remove the password from the varset, so that we are not writing it
// to a file in plain text. Instead, it will be passed to the agent service
// when the job is submitted
pVarSet->put(GET_BSTR(DCTVS_Options_Credentials_Password),"");
pVarSet->put(GET_BSTR(DCTVS_AccountOptions_SidHistoryCredentials_Password),"");
if ( ! uniqueNumber )
{
uniqueNumber = GetTickCount();
}
MCSASSERT(bstrResultPath.length());
safecopy(tempdir,(WCHAR*)bstrResultPath);
pInstaller = new CComObject<CDCTInstaller>;
if (!pInstaller)
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
pInstaller->AddRef();
((CDCTInstaller*)pInstaller)->SetFileList(pInfo->pPlugInFileList);
if ( SUCCEEDED(hr) )
{
swprintf(filename,L"%s%s%ld",tempdir,(WCHAR*)pInfo->serverName + 2,uniqueNumber);
if ( !pInfo->jobfile.length() )
{
SetupVarSetForJob(pInfo,pVarSet,tempdir,filename);
// Save the input varset to a file
IPersistStoragePtr ps = NULL;
IStoragePtr store = NULL;
hr = pVarSet->QueryInterface(IID_IPersistStorage,(void**)&ps);
if ( SUCCEEDED(hr) )
{
hr = StgCreateDocfile(filename,STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE |STGM_FAILIFTHERE,0,&store);
if ( SUCCEEDED(hr) )
{
hr = OleSave(ps,store,FALSE);
}
}
}
else
{
safecopy(filename,(WCHAR*)pInfo->jobfile);
}
IUnknown * pWorkItem = NULL;
if ( SUCCEEDED(hr) )
{
pVarSet->put(GET_BSTR(DCTVS_ConfigurationFile),filename);
pVarSet->put(GET_BSTR(DCTVS_InstallToServer),pInfo->serverName);
hr = pVarSet->QueryInterface(IID_IUnknown,(void**)&pWorkItem);
}
if ( SUCCEEDED(hr) )
{
// Do the installation to the server
hr = pInstaller->Process(pWorkItem);
if(hr == 0x88070040)
strFailureDesc = GET_STRING(IDS_AGENT_RUNNING);
pWorkItem->Release();
if ( SUCCEEDED(hr) )
{
err.MsgWrite(0,DCT_MSG_AGENT_INSTALLED_S,(WCHAR*)pInfo->serverName);
// try to start the job
DWORD rc = StartJob(pInfo->serverName,bstrPassword,filename,filename + UStrLen(tempdir), strJobid );
if ( rc )
{
hr = HRESULT_FROM_WIN32(rc);
// if we couldn't start the job, then try to stop the service
TDCTInstall x( pInfo->serverName, NULL );
x.SetServiceInformation(GET_STRING(IDS_DISPLAY_NAME),GET_STRING(IDS_SERVICE_NAME),L"EXE",NULL);
DWORD rcOs = x.ScmOpen();
if ( ! rcOs )
{
x.ServiceStop();
}
}
}
}
pInstaller->Release();
}
}
if(pInfo->nErrCount == 0)
CoUninitialize();
if ( hr )
{
if ( hr == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) )
{
err.MsgWrite(ErrE,DCT_MSG_AGENT_SERVICE_NOT_STARTED_SS,(WCHAR*)pInfo->serverName,(WCHAR*)pInfo->serverName);
}
else
{
err.SysMsgWrite(ErrE,hr,DCT_MSG_AGENT_LAUNCH_FAILED_SD,(WCHAR*)pInfo->serverName,hr);
}
if(hr == 0x80070040 && pInfo->nErrCount < 10)
{
Sleep(1000);
pInfo->nErrCount++;
err.DbgMsgWrite(0,L"Retrying install...");
DoInstall((LPVOID)pInfo);
}
else if (hr == CO_E_NOT_SUPPORTED)
{
err.MsgWrite(ErrI,DCT_MSG_AGENT_ALPHA_NOTSUPPORTED,(WCHAR*)pInfo->serverName);
strFailureDesc = GET_STRING(IDS_UNSOUPPORTED_OS);
::WaitForSingleObject(pInfo->hMutex, 30000);
pInfo->pStartFailedVector->push_back((BSTR)pInfo->serverName);
pInfo->pFailureDescVector->push_back((BSTR)strFailureDesc);
::ReleaseMutex(pInfo->hMutex);
}
else
{
::WaitForSingleObject(pInfo->hMutex, 30000);
pInfo->pStartFailedVector->push_back((BSTR)pInfo->serverName);
pInfo->pFailureDescVector->push_back((BSTR)strFailureDesc);
::ReleaseMutex(pInfo->hMutex);
}
}
else
{
// DWORD res = ::WaitForSingleObject(pInfo->hMutex, 30000);
::WaitForSingleObject(pInfo->hMutex, 30000);
pInfo->pStartedVector->push_back((BSTR)pInfo->serverName);
_ASSERTE(strJobid != _bstr_t(L""));
pInfo->pJobidVector->push_back((BSTR)strJobid);
::ReleaseMutex(pInfo->hMutex);
}
if(pInfo->nErrCount == 0)
delete pInfo;
return hr;
}
// DispatchToServers
// VarSet input:
//
STDMETHODIMP // ret- HRESULT
CDCTDispatcher::DispatchToServers(
IUnknown ** ppData // i/o- pointer to varset
)
{
HRESULT hr;
SetThreadLocale(LOCALE_SYSTEM_DEFAULT);
//Sleep(60000); //delay for debugging
(*ppData)->AddRef();
hr = Process(*ppData,NULL,NULL);
return hr;
}
// Sets share level permissions
DWORD // OS return code
CDCTDispatcher::SetSharePermissions(
WCHAR const * domain, // in - domain for user account
WCHAR const * user, // in - user account to grant permissions to
WCHAR const * share, // in - name of share
WCHAR const * directory // in - path of shared directory
)
{
DWORD rc = 0;
WCHAR domainname[LEN_Domain];
WCHAR * server = NULL;
WCHAR sharename[MAX_PATH];
WCHAR dirname[MAX_PATH];
BYTE * sid = (BYTE*)malloc(200);
DWORD lenSid = 200;
DWORD lenDomain = DIM(domainname);
SID_NAME_USE snu;
BOOL bGotSid = FALSE;
if (!sid)
return ERROR_NOT_ENOUGH_MEMORY;
safecopy(sharename,share);
safecopy(dirname,directory);
// Set the share permissions
TShareSD sd(sharename);
// Get a domain controller for domain
if ( UStrICmp(domain,gComputerName) )
{
rc = NetGetDCName(NULL,domain,(LPBYTE*)&server);
}
if ( ! rc )
{
// get the SID for the user account
if ( ! LookupAccountName(server,user,sid,&lenSid,domainname,&lenDomain,&snu) )
{
rc = GetLastError();
}
else
{
bGotSid = TRUE;
if (! UStrICmp(domainname,domain) )
{
// we found the correct account
// grant permissions to this user
if ( sd.GetSecurity() != NULL )
{
TACE ace(ACCESS_ALLOWED_ACE_TYPE,0,DACL_FULLCONTROL_MASK,sid);
PACL acl = sd.GetSecurity()->GetDacl();
sd.GetSecurity()->ACLAddAce(&acl,&ace,-1);
sd.GetSecurity()->SetDacl(acl,TRUE);
sd.WriteSD();
}
}
}
NetApiBufferFree(server);
}
if ( rc )
{
err.SysMsgWrite(ErrW,rc,DCT_MSG_CANNOT_FIND_ACCOUNT_SSD,domain,user,rc);
}
GetBkupRstrPriv();
// Set NTFS permissions for the results directory
TFileSD * fsd = new TFileSD(dirname);
if (!fsd)
return ERROR_NOT_ENOUGH_MEMORY;
if ( bGotSid && fsd->GetSecurity() != NULL )
{
BYTE inherit = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
TACE ace(ACCESS_ALLOWED_ACE_TYPE,0,DACL_FULLCONTROL_MASK,sid);
TACE ace2(ACCESS_ALLOWED_ACE_TYPE,0,DACL_FULLCONTROL_MASK,sid);
TACE ace3(ACCESS_ALLOWED_ACE_TYPE,0,DACL_FULLCONTROL_MASK,GetWellKnownSid(1/*ADMINISTRATORS*/));
TACE ace4(ACCESS_ALLOWED_ACE_TYPE,0,DACL_FULLCONTROL_MASK,GetWellKnownSid(1/*ADMINISTRATORS*/));
PACL acl = NULL;
ace2.SetFlags(inherit);
ace4.SetFlags(inherit);
fsd->GetSecurity()->ACLAddAce(&acl,&ace,0);
fsd->GetSecurity()->ACLAddAce(&acl,&ace2,1);
fsd->GetSecurity()->ACLAddAce(&acl,&ace3,2);
fsd->GetSecurity()->ACLAddAce(&acl,&ace4,3);
fsd->GetSecurity()->SetDacl(acl,TRUE);
fsd->WriteSD();
}
return rc;
}
// DoesAccountHaveAccessToShare Function
//
// Checks if the specified account's SID is in the specified folder's DACL. This function only
// verifies the existence of the SID in the DACL.
bool DoesAccountHaveAccessToShare(LPCTSTR pszDomainName, LPCTSTR pszAccountName, LPCTSTR pszResultFolder)
{
bool bAccess = false;
try
{
// maximum SID size in bytes
// Revision 1
// SubAuthorityCount 1
// IdentifierAuthority 6
// SubAuthority[15] 60
// Total 68
BYTE bytSid[128];
PSID pSid = (PSID)bytSid;
DWORD cbSid = sizeof(bytSid);
_TCHAR szDomainName[128];
DWORD cchDomainName = sizeof(szDomainName) / sizeof(szDomainName[0]);
SID_NAME_USE snu;
LookupAccountName(NULL, pszAccountName, pSid, &cbSid, szDomainName, &cchDomainName, &snu);
// verify that the domains match
if (_tcsicmp(szDomainName, pszDomainName) == 0)
{
// add backup/restore privilege to current process/thread token
GetBkupRstrPriv();
// search for SID in DACL of result folder
TFileSD sdFile((const LPTSTR)(pszResultFolder));
TSD* psd = sdFile.GetSecurity();
if (psd && psd->IsDaclPresent())
{
int c = psd->GetNumDaclAces();
for (int i = 0; i < c; i++)
{
TACE ace(psd->GetDaclAce(i));
if (EqualSid(ace.GetSid(), pSid))
{
bAccess = true;
break;
}
}
}
}
}
catch (...)
{
;
}
return bAccess;
}
// creates a share on the local machine for the results directory
// the name of the share is determined by RESULT_SHARE_NAME, and a number
//
// VarSet input:
// Dispatcher.ResultPath - name of directory to share
// Options.Credentials.Domain - domain for user account
// Options.Credentials.UserName - user account to grant permissions to
//
HRESULT // ret- HRESULT
CDCTDispatcher::ShareResultDirectory(
IVarSet * pVarSet // in - varset containing credentials
)
{
DWORD rc = 0;
_bstr_t bstrResultDir = pVarSet->get(GET_BSTR(DCTVS_Dispatcher_ResultPath));
_bstr_t bstrDomain = pVarSet->get(GET_BSTR(DCTVS_Options_Credentials_Domain));
_bstr_t bstrAccount = pVarSet->get(GET_BSTR(DCTVS_Options_Credentials_UserName));
_bstr_t bstrShareName = pVarSet->get(_bstr_t((BSTR)L"Options.ShareName"));
WCHAR resultPath[MAX_PATH];
WCHAR uncResultPath[MAX_PATH];
WCHAR shareName[MAX_PATH];
if ( bstrResultDir.length() )
{
safecopy(resultPath,(WCHAR*)bstrResultDir);
}
else
{
GetTempPath(DIM(resultPath),resultPath);
}
// create a share for the results directory
if ( bstrShareName.length() )
{
safecopy(shareName,(WCHAR*)bstrShareName);
}
else
{
swprintf(shareName,L"%s$",GET_STRING(IDS_RESULT_SHARE_NAME));
}
SHARE_INFO_2 shareInfo;
memset(&shareInfo,0,(sizeof shareInfo));
// remove the trailing backslash from the path
if ( resultPath[UStrLen(resultPath)-1] == L'\\' )
resultPath[UStrLen(resultPath)-1] = 0;
shareInfo.shi2_netname = shareName;
shareInfo.shi2_remark = GET_BSTR(IDS_RESULT_SHARE_REMARK);
shareInfo.shi2_path = resultPath;
shareInfo.shi2_max_uses = -1;
shareInfo.shi2_type = STYPE_DISKTREE;
swprintf(uncResultPath,L"\\\\%s\\%s\\",gComputerName,shareName);
pVarSet->put(GET_BSTR(DCTVS_Dispatcher_ResultPath),uncResultPath);
rc = NetShareAdd(NULL,2,(LPBYTE)&shareInfo,NULL);
if ( ! rc )
{
// remove trailing backslash
uncResultPath[UStrLen(uncResultPath)-1] = 0;
// update the permissions for the share
rc = SetSharePermissions((WCHAR*)bstrDomain,(WCHAR*)bstrAccount,uncResultPath,resultPath);
}
else if ( rc == NERR_DuplicateShare )
{
SHARE_INFO_2 * shInfo = NULL;
DWORD parmErr;
// make sure the share is pointing to the right directory
rc = NetShareGetInfo(NULL,shareName,2,(LPBYTE*)&shInfo);
if ( ! rc )
{
if ( UStrICmp(resultPath,shInfo->shi2_path) )
{
rc = NetShareDel(NULL, shareName, 0);
if(!rc)
{
rc = NetShareAdd(NULL,2,(LPBYTE)&shareInfo,NULL);
if ( ! rc )
{
// remove trailing backslash
uncResultPath[UStrLen(uncResultPath)-1] = 0;
// update the permissions for the share
rc = SetSharePermissions((WCHAR*)bstrDomain,(WCHAR*)bstrAccount,uncResultPath,resultPath);
}
}
else
{
// the share points to the wrong place
shInfo->shi2_netname = shareName;
rc = NetShareSetInfo(NULL,shareName,2,(LPBYTE)&shInfo,&parmErr);
}
}
else
{
if (DoesAccountHaveAccessToShare(bstrDomain, bstrAccount, resultPath) == false)
{
uncResultPath[UStrLen(uncResultPath) - 1] = 0;
SetSharePermissions(bstrDomain, bstrAccount, uncResultPath, resultPath);
}
}
NetApiBufferFree(shInfo);
}
}
if ( ! rc )
{
err.MsgWrite(0,DCT_MSG_CREATED_RESULT_SHARE_SS,resultPath,uncResultPath);
errLog.DbgMsgWrite(0,L"%ls : %ls",resultPath,uncResultPath);
}
return HRESULT_FROM_WIN32(rc);
}
// BuildInputFile constructs a cache file to be used for security translation
// VarSet input:
// Options.UniqueNumberForResultsFile -unique number to append
// Dispatcher.ResultPath -directory to write file to
//
HRESULT // ret- HRESULT
CDCTDispatcher::BuildInputFile(
IVarSet * pVarSet // in - varset containing data
)
{
IVarSetPtr pVarSetST(CLSID_VarSet); // varset to use to run security translator
IVarSetPtr pVarSetTemp;
HRESULT hr = S_OK;
_bstr_t key = GET_BSTR(DCTVS_Options);
WCHAR tempdir[MAX_PATH];
WCHAR resultPath[MAX_PATH];
WCHAR logfile[MAX_PATH];
DWORD uniqueNumber = (LONG)pVarSet->get(GET_BSTR(DCTVS_Options_UniqueNumberForResultsFile));
_bstr_t bstrResultDir = pVarSet->get(GET_BSTR(DCTVS_Dispatcher_ResultPath));
_bstr_t temp = pVarSet->get(GET_BSTR(DCTVS_Security_AlternateCacheFile));
if ( pVarSetST == NULL )
{
return E_FAIL;
}
if ( ! NeedToUseST(pVarSet,TRUE) )
{
return S_OK;
}
// construct a filename for the cache
if ( ! uniqueNumber )
{
uniqueNumber = GetTickCount();
}
if ( bstrResultDir.length() )
{
safecopy(tempdir,(WCHAR*)bstrResultDir);
}
else
{
// if no result path specified, use temp directory
hr = GetTempPath(DIM(tempdir),tempdir);
}
swprintf(resultPath,L"%s%s",tempdir,GET_STRING(IDS_CACHE_FILE_NAME));
// if a cache file is specified, use it instead of building a new one
if ( temp.length() )
{
CopyFile(temp,resultPath,FALSE);
pVarSet->put(GET_BSTR(DCTVS_Accounts_InputFile),GET_BSTR(IDS_CACHE_FILE_NAME));
pVarSet->put(GET_BSTR(DCTVS_Accounts_WildcardSpec),"");
gbCacheFileBuilt = TRUE;
return S_OK;
}
// copy 'Options' settings to ST varset
hr = pVarSet->raw_getReference(key,&pVarSetTemp);
if ( SUCCEEDED(hr) )
{
pVarSetST->ImportSubTree(key,pVarSetTemp);
}
// copy 'Accounts' settings to ST varset
key = GET_BSTR(DCTVS_Accounts);
hr = pVarSet->raw_getReference(key,&pVarSetTemp);
if ( SUCCEEDED(hr) )
{
pVarSetST->ImportSubTree(key,pVarSetTemp);
}
pVarSetST->put(GET_BSTR(DCTVS_Security_TranslationMode),GET_BSTR(IDS_Replace));
pVarSetST->put(GET_BSTR(DCTVS_Options_NoChange),GET_BSTR(IDS_YES));
pVarSetST->put(GET_BSTR(DCTVS_Options_LogLevel),(LONG)0);
pVarSetST->put(GET_BSTR(DCTVS_Security_BuildCacheFile),resultPath);
// change the log file - the building of the cache file happens behind the scenes
// so we won't put it in the regular log file because it would cause confusion
swprintf(logfile,L"%s%s",tempdir,L"BuildCacheFileLog.txt");
pVarSetST->put(GET_BSTR(DCTVS_Options_Logfile),logfile);
//are we using a sID mapping file to perform security translation
pVarSetST->put(GET_BSTR(DCTVS_AccountOptions_SecurityInputMOT),
pVarSet->get(GET_BSTR(DCTVS_AccountOptions_SecurityInputMOT)));
pVarSetST->put(GET_BSTR(DCTVS_AccountOptions_SecurityMapFile),
pVarSet->get(GET_BSTR(DCTVS_AccountOptions_SecurityMapFile)));
MCSEADCTAGENTLib::IDCTAgentPtr pAgent(MCSEADCTAGENTLib::CLSID_DCTAgent);
try {
if ( pAgent == NULL )
return E_FAIL;
_bstr_t jobID;
BSTR b = NULL;
hr = pAgent->raw_SubmitJob(pVarSetST,&b);
if ( SUCCEEDED(hr) )
{
jobID = b;
IVarSetPtr pVarSetStatus; // used to retrieve status of running job
_bstr_t jobStatus;
IUnknown * pUnk;
// loop until the agent is finished
do {
Sleep(1000);
hr = pAgent->QueryJobStatus(jobID,&pUnk);
if ( SUCCEEDED(hr) )
{
pVarSetStatus = pUnk;
jobStatus = pVarSetStatus->get(GET_BSTR(DCTVS_JobStatus));
pUnk->Release();
}
else
{
break;
}
} while ( UStrICmp(jobStatus,GET_STRING(IDS_DCT_Status_Completed)) );
}
}
catch(...)
{
hr = E_FAIL;
}
if ( SUCCEEDED(hr) )
{
pVarSet->put(GET_BSTR(DCTVS_Accounts_InputFile),GET_BSTR(IDS_CACHE_FILE_NAME));
pVarSet->put(GET_BSTR(DCTVS_Accounts_WildcardSpec),"");
err.MsgWrite(0,DCT_MSG_CACHE_FILE_BUILT_S,(WCHAR*)GET_STRING(IDS_CACHE_FILE_NAME));
gbCacheFileBuilt = TRUE;
}
return hr;
}
// These are TNodeListSortable sorting functions
int ServerNodeCompare(TNode const * t1,TNode const * t2)
{
TServerNode * n1 = (TServerNode *)t1;
TServerNode * n2 = (TServerNode *)t2;
return UStrICmp(n1->SourceName(),n2->SourceName());
}
int ServerValueCompare(TNode const * t1, void const * val)
{
TServerNode * n1 = (TServerNode *)t1;
WCHAR const * name = (WCHAR const *) val;
return UStrICmp(n1->SourceName(),name);
}
// MergeServerList combines the security translation server list in Servers.* with the computer migration
// server list in MigrateServers.*
// The combined list is stored in the varset under Servers.* with subkeys specifying which actions to take for
// each computer
void
CDCTDispatcher::MergeServerList(
IVarSet * pVarSet // in - varset containing list of servers to migrate and translate on
)
{
int ndx = 0;
WCHAR key[1000];
_bstr_t text;
int lastndx = -1;
long totalsrvs;
//get the number of servers in the varset
totalsrvs = pVarSet->get(GET_BSTR(DCTVS_Servers_NumItems));
// if there are computers being migrated
if (totalsrvs > 0)
{
//add code to move varset server entries, with SkipDispatch set, to the bottom
//of the server list and decrease the number of server items by each server
//to be skipped
//check each server in the list moving all to be skipped to the end of the list and
//decreasing the server count for each to be skipped
for (ndx = 0; ndx < totalsrvs; ndx++)
{
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_SkipDispatch_D),ndx);
text = pVarSet->get(key);
//if the server is not to be skipped, we may have to move it above
//a server that is being skipped
if (!UStrICmp(text,GET_STRING(IDS_No)))
{
//if the last server looked at is not being skipped then we don't
//need to swap any servers in the list and we can increment the
//last server not being skipped
if (lastndx == (ndx - 1))
{
lastndx = ndx;
}
else //else swap servers in the varset so skipped server comes after
{ //the one not being skipped
_bstr_t tempName, tempNewName, tempChngDom, tempReboot, tempMigOnly;
long tempRebootDelay;
_bstr_t skipName, skipNewName, skipChngDom, skipReboot, skipMigOnly;
long skipRebootDelay;
lastndx++; //move to the skipped server that we will swap with
//copy skipped server's values to temp
swprintf(key,GET_STRING(DCTVSFmt_Servers_D),lastndx);
skipName = pVarSet->get(key);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_RenameTo_D),lastndx);
skipNewName = pVarSet->get(key);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_ChangeDomain_D),lastndx);
skipChngDom = pVarSet->get(key);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_Reboot_D),lastndx);
skipReboot = pVarSet->get(key);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_MigrateOnly_D),lastndx);
skipMigOnly = pVarSet->get(key);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_RebootDelay_D),lastndx);
skipRebootDelay = pVarSet->get(key);
//copy current, non-skipped, server valuesto second temp
swprintf(key,GET_STRING(DCTVSFmt_Servers_D),ndx);
tempName = pVarSet->get(key);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_RenameTo_D),ndx);
tempNewName = pVarSet->get(key);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_ChangeDomain_D),ndx);
tempChngDom = pVarSet->get(key);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_Reboot_D),ndx);
tempReboot = pVarSet->get(key);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_MigrateOnly_D),ndx);
tempMigOnly = pVarSet->get(key);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_RebootDelay_D),ndx);
tempRebootDelay = pVarSet->get(key);
//place current server's values in place of values for the one
//being skipped
swprintf(key,GET_STRING(DCTVSFmt_Servers_D),lastndx);
pVarSet->put(key,tempName);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_RenameTo_D),lastndx);
pVarSet->put(key,tempNewName);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_ChangeDomain_D),lastndx);
pVarSet->put(key,tempChngDom);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_Reboot_D),lastndx);
pVarSet->put(key,tempReboot);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_MigrateOnly_D),lastndx);
pVarSet->put(key,tempMigOnly);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_RebootDelay_D),lastndx);
pVarSet->put(key,tempRebootDelay);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_SkipDispatch_D),lastndx);
pVarSet->put(key,GET_BSTR(IDS_No));
//place skipped server's values in place of values for current server
swprintf(key,GET_STRING(DCTVSFmt_Servers_D),ndx);
pVarSet->put(key,skipName);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_RenameTo_D),ndx);
pVarSet->put(key,skipNewName);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_ChangeDomain_D),ndx);
pVarSet->put(key,skipChngDom);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_Reboot_D),ndx);
pVarSet->put(key,skipReboot);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_MigrateOnly_D),ndx);
pVarSet->put(key,skipMigOnly);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_RebootDelay_D),ndx);
pVarSet->put(key,skipRebootDelay);
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_SkipDispatch_D),ndx);
pVarSet->put(key,GET_BSTR(IDS_YES));
}//end else need to swap with skipped server
}//end if not skipping dispatch for this server
}//end for each server in the server list
//exclude servers to be skipped for dispatch from being included in the server count
pVarSet->put(GET_BSTR(DCTVS_Servers_NumItems),(long)++lastndx);
}
}
STDMETHODIMP // ret- HRESULT
CDCTDispatcher::Process(
IUnknown * pWorkItem, // in - varset containing job information and list of servers
IUnknown ** ppResponse, // out- not used
UINT * pDisposition // out- not used
)
{
// initialize output parameters
if ( ppResponse )
{
(*ppResponse) = NULL;
}
HRESULT hr = S_OK;
IVarSetPtr pVarSetIn = pWorkItem;
LONG nThreads;
WCHAR key[100];
_bstr_t serverName;
LONG nServers = 0;
_bstr_t log;
_bstr_t useTempCredentials;
BOOL bFatalError = FALSE;
_bstr_t text;
WCHAR debugLog[MAX_PATH];
long bAppend = 0;
_bstr_t skip;
_bstr_t sWizard, text2;
BOOL bSkipSourceSid;
if ( DumpDebugInfo(debugLog) )
{
if ( pVarSetIn != NULL )
{
// temporarily remove the password fromthe varset, so that we don't write it to the file
_bstr_t password = pVarSetIn->get(GET_BSTR(DCTVS_Options_Credentials_Password));
pVarSetIn->put(GET_BSTR(DCTVS_Options_Credentials_Password),L"");
pVarSetIn->DumpToFile(debugLog);
pVarSetIn->put(GET_BSTR(DCTVS_Options_Credentials_Password),password);
}
}
//get the wizard being run
sWizard = pVarSetIn->get(GET_BSTR(DCTVS_Options_Wizard));
text2 = pVarSetIn->get(GET_BSTR(DCTVS_AccountOptions_SecurityInputMOT));
if ((!UStrICmp(sWizard, L"security")) && (!UStrICmp(text2,GET_STRING(IDS_YES))))
bSkipSourceSid = TRUE;
else
bSkipSourceSid = FALSE;
nThreads = pVarSetIn->get(GET_BSTR(DCTVS_Options_MaxThreads));
log = pVarSetIn->get(GET_BSTR(DCTVS_Options_DispatchCSV));
errLog.LogOpen((WCHAR*)log,0);
text = pVarSetIn->get(GET_BSTR(DCTVS_Options_AppendToLogs));
if (! UStrICmp(text,GET_STRING(IDS_YES)) )
{
bAppend = 1;
}
log = pVarSetIn->get(GET_BSTR(DCTVS_Options_DispatchLog));
err.LogOpen((WCHAR*)log,bAppend);
errLog.DbgMsgWrite(0,L"%ls",(WCHAR*)log);
// default to 20 threads if the client doesn't specify
if ( ! nThreads )
{
nThreads = 20;
}
// set credentials used to access share
_bstr_t strAdmtAccountDomain;
_bstr_t strAdmtAccountUserName;
_bstr_t strAdmtAccountPassword;
hr = GetOptionsCredentials(strAdmtAccountDomain, strAdmtAccountUserName, strAdmtAccountPassword);
pVarSetIn->put(GET_BSTR(DCTVS_Options_Credentials_Domain), _variant_t(strAdmtAccountDomain));
pVarSetIn->put(GET_BSTR(DCTVS_Options_Credentials_UserName), _variant_t(strAdmtAccountUserName));
pVarSetIn->put(GET_BSTR(DCTVS_Options_Credentials_Password), _variant_t(strAdmtAccountPassword));
if (FAILED(hr))
{
err.SysMsgWrite(ErrE, HRESULT_CODE(hr), DCT_MSG_COULDNT_GET_OPTIONS_CREDENTIALS);
}
// Get the name of the local computer
DWORD dim = DIM(gComputerName);
GetComputerName(gComputerName,&dim);
m_pThreadPool = new TJobDispatcher(nThreads);
if (!m_pThreadPool)
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
hr = ShareResultDirectory(pVarSetIn);
if ( FAILED(hr) )
{
err.SysMsgWrite(ErrE,HRESULT_CODE(hr),DCT_MSG_RESULT_SHARE_CREATION_FAILED);
bFatalError = TRUE;
}
// Build an input file for the ST cache, to send to each server
hr = BuildInputFile(pVarSetIn);
if ( FAILED(hr) )
{
err.SysMsgWrite(ErrE,HRESULT_CODE(hr),DCT_MSG_CACHE_CONSTRUCTION_FAILED);
bFatalError = TRUE;
}
// Split out the remotable tasks for each server
// Get the sids for the source and target domains
PSID pSidSrc = NULL;
PSID pSidTgt = NULL;
_bstr_t source = pVarSetIn->get(GET_BSTR(DCTVS_Options_SourceDomain));
_bstr_t target = pVarSetIn->get(GET_BSTR(DCTVS_Options_TargetDomain));
//if security translation, retrieve source sid and convert so
//that it can be convert back below
if (bSkipSourceSid)
{
_bstr_t sSid = pVarSetIn->get(GET_BSTR(DCTVS_Options_SourceDomainSid));
pSidSrc = SidFromString((WCHAR*)sSid);
}
else //else get the sid now
GetSidForDomain((WCHAR*)source,&pSidSrc);
GetSidForDomain((WCHAR*)target,&pSidTgt);
if ( pSidSrc && pSidTgt )
{
WCHAR txtSid[200];
DWORD lenTxt = DIM(txtSid);
if ( GetTextualSid(pSidSrc,txtSid,&lenTxt) )
{
pVarSetIn->put(GET_BSTR(DCTVS_Options_SourceDomainSid),txtSid);
}
lenTxt = DIM(txtSid);
if ( GetTextualSid(pSidTgt,txtSid,&lenTxt) )
{
pVarSetIn->put(GET_BSTR(DCTVS_Options_TargetDomainSid),txtSid);
}
FreeSid(pSidSrc);
FreeSid(pSidTgt);
}
/* if ( pSidSrc )
{
WCHAR txtSid[200];
DWORD lenTxt = DIM(txtSid);
if ( GetTextualSid(pSidSrc,txtSid,&lenTxt) )
{
pVarSetIn->put(GET_BSTR(DCTVS_Options_SourceDomainSid),txtSid);
}
}
if ( pSidTgt )
{
WCHAR txtSid[200];
DWORD lenTxt = DIM(txtSid);
if ( GetTextualSid(pSidTgt,txtSid,&lenTxt) )
{
pVarSetIn->put(GET_BSTR(DCTVS_Options_TargetDomainSid),txtSid);
}
}
*/ else
// if (!((pSidSrc) && (pSidTgt)))
{
// if ((source.length()) && (!pSidSrc) && (!bSkipSourceSid))
if ( source.length() && ! pSidSrc )
{
err.MsgWrite(ErrE,DCT_MSG_DOMAIN_SID_NOT_FOUND_S,(WCHAR*)source);
bFatalError = TRUE;
}
else if ( target.length() && ! pSidTgt )
{
err.MsgWrite(ErrE,DCT_MSG_DOMAIN_SID_NOT_FOUND_S,(WCHAR*)target);
bFatalError = TRUE;
}
}
MergeServerList(pVarSetIn);
LONG nServerCount = pVarSetIn->get(GET_BSTR(DCTVS_Servers_NumItems));
if ( nServerCount && ! bFatalError )
{
err.MsgWrite(0,DCT_MSG_DISPATCH_SERVER_COUNT_D,nServerCount);
}
errLog.DbgMsgWrite(0,L"%ld",nServerCount);
TNodeList * fileList = new TNodeList;
if (!fileList)
{
delete m_pThreadPool;
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
}
// Build list of files to install for plug-ins (if any)
BuildPlugInFileList(fileList,pVarSetIn);
// Make a copy of the varset with the server lists removed,
// so we don't have to copy the entire server list for each agent
gCS.Enter();
IVarSet * pTemp = NULL;
IVarSetPtr pVarSetTemp(CLSID_VarSet);
hr = pVarSetTemp->ImportSubTree(_bstr_t(L""),pVarSetIn);
if ( SUCCEEDED(hr) )
{
hr = pVarSetTemp->raw_getReference(SysAllocString(L"MigrateServers"),&pTemp);
if ( SUCCEEDED(hr) )
{
pTemp->Clear();
pTemp->Release();
pTemp = NULL;
}
hr = pVarSetTemp->raw_getReference(SysAllocString(L"Servers"),&pTemp);
if ( SUCCEEDED(hr) )
{
pTemp->Clear();
pTemp->Release();
pTemp = NULL;
}
}
else
{
bFatalError = TRUE;
}
gCS.Leave();
m_startFailedVector.clear();
do
{
if ( bFatalError )
{
break;
}
swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_SkipDispatch_D),nServers);
skip = pVarSetIn->get(key);
swprintf(key,GET_STRING(DCTVSFmt_Servers_D),nServers);
serverName = pVarSetIn->get(key);
if ((serverName.length()) && (UStrICmp(skip,GET_STRING(IDS_YES))))
{
IVarSetPtr pVS(CLSID_VarSet);
InstallJobInfo * pInfo = new InstallJobInfo;
if (!pInfo)
{
delete fileList;
delete m_pThreadPool;
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
}
if ( pVS == NULL )
{
return E_FAIL;
}
UStrCpy(key+UStrLen(key),L".JobFile");
_bstr_t file = pVarSetIn->get(key);
// Set up job structure
pInfo->pVarSetList = pVarSetIn;
pInfo->pVarSet = pVarSetTemp;
pInfo->serverName = serverName;
pInfo->ndx = nServers;
pInfo->pPlugInFileList = fileList;
pInfo->pStartFailedVector = &m_startFailedVector;
pInfo->pFailureDescVector = &m_failureDescVector;
pInfo->pStartedVector = &m_startedVector;
pInfo->pJobidVector = &m_jobidVector;
pInfo->hMutex = m_hMutex;
pInfo->nErrCount = 0;
if ( file.length() )
{
pInfo->jobfile = file;
}
err.MsgWrite(0,DCT_MSG_DISPATCHING_TO_SERVER_S,(WCHAR*)pInfo->serverName);
errLog.DbgMsgWrite(0,L"%ls\t%ls\t%ld",(WCHAR*)pInfo->serverName,L"WillInstall",0);
m_pThreadPool->SubmitJob(&DoInstall,(void *)pInfo);
}
nServers++;
if ( nServers == nServerCount )
break;
} while ( serverName.length() );
// launch a thread to wait for all jobs to finish, then clean up and exit
WaitInfo* wInfo = new WaitInfo;
if (!wInfo)
{
delete fileList;
delete m_pThreadPool;
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
}
wInfo->ppPool = &m_pThreadPool;
wInfo->pUnknown = NULL;
wInfo->pPlugInFileList = fileList;
QueryInterface(IID_IUnknown,(LPVOID*)&(wInfo->pUnknown));
DWORD id = 0;
HANDLE waitHandle = CreateThread(NULL,0,&Wait,(void *)wInfo,0,&id);
CloseHandle(waitHandle);
return hr;
}
STDMETHODIMP CDCTDispatcher::AllAgentsStarted(long *bAllAgentsStarted)
{
*bAllAgentsStarted = m_pThreadPool == NULL;
return S_OK;
}
SAFEARRAY* MakeSafeArray(std::vector<CComBSTR>& stVector)
{
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = stVector.size();
SAFEARRAY FAR* psa = SafeArrayCreate(VT_BSTR, 1, rgsabound);
std::vector<CComBSTR>::iterator iter = stVector.begin();
for(long i=0; iter != stVector.end(); ++iter, ++i)
{
_ASSERTE(*iter && *iter != L"");
SafeArrayPutElement(psa, &i, (void*)(*iter).Copy());
}
stVector.clear();
return psa;
}
STDMETHODIMP CDCTDispatcher::GetStartedAgentsInfo(long* bAllAgentsStarted, SAFEARRAY** ppbstrStartedAgents, SAFEARRAY** ppbstrJobid, SAFEARRAY** ppbstrFailedAgents, SAFEARRAY** ppbstrFailureDesc)
{
*bAllAgentsStarted = m_pThreadPool == NULL;
// DWORD res = ::WaitForSingleObject(m_hMutex, 30000);
::WaitForSingleObject(m_hMutex, 30000);
*ppbstrFailedAgents = MakeSafeArray(m_startFailedVector);
*ppbstrFailureDesc = MakeSafeArray(m_failureDescVector);
_ASSERTE(m_startedVector.size() == m_jobidVector.size());
*ppbstrStartedAgents = MakeSafeArray(m_startedVector);
*ppbstrJobid = MakeSafeArray(m_jobidVector);
::ReleaseMutex(m_hMutex);
return S_OK;
}