|
|
#include "StdAfx.h"
#include "ADMTScript.h"
#include "MigrationBase.h"
#include <LM.h>
#include "Error.h"
#include "VarSetAccounts.h"
#include "VarSetServers.h"
#include "FixHierarchy.h"
using namespace _com_util;
namespace MigrationBase {
void GetNamesFromData(VARIANT& vntData, StringSet& setNames); void GetNamesFromVariant(VARIANT* pvnt, StringSet& setNames); void GetNamesFromString(BSTR bstr, StringSet& setNames); void GetNamesFromStringArray(SAFEARRAY* psa, StringSet& setNames); void GetNamesFromVariantArray(SAFEARRAY* psa, StringSet& setNames);
void GetNamesFromFile(VARIANT& vntData, StringSet& setNames); void GetNamesFromFile(LPCTSTR pszFileName, StringSet& setNames); void GetNamesFromStringA(LPCSTR pchString, DWORD cchString, StringSet& setNames); void GetNamesFromStringW(LPCWSTR pchString, DWORD cchString, StringSet& setNames);
_bstr_t RemoveTrailingDollarSign(LPCTSTR pszName);
}
using namespace MigrationBase;
//---------------------------------------------------------------------------
// MigrationBase Class
//---------------------------------------------------------------------------
// Constructor
CMigrationBase::CMigrationBase() : m_nRecurseMaintain(0), m_Mutex(ADMT_MUTEX) { }
// Destructor
CMigrationBase::~CMigrationBase() { }
// InitSourceDomainAndContainer Method
void CMigrationBase::InitSourceDomainAndContainer() { m_SourceDomain.Initialize(m_spInternal->SourceDomain); m_SourceContainer = m_SourceDomain.GetContainer(m_spInternal->SourceOu); }
// InitTargetDomainAndContainer Method
void CMigrationBase::InitTargetDomainAndContainer() { m_TargetDomain.Initialize(m_spInternal->TargetDomain); m_TargetContainer = m_TargetDomain.GetContainer(m_spInternal->TargetOu);
// verify target domain is in native mode
if (m_TargetDomain.NativeMode() == false) { AdmtThrowError( GUID_NULL, GUID_NULL, E_INVALIDARG, IDS_E_TARGET_DOMAIN_NOT_NATIVE_MODE, (LPCTSTR)m_TargetDomain.Name() ); }
VerifyTargetContainerPathLength(); }
// VerifyInterIntraForest Method
void CMigrationBase::VerifyInterIntraForest() { // if the source and target domains have the same forest name then they are intra-forest
bool bIntraForest = m_spInternal->IntraForest ? true : false;
if (m_SourceDomain.ForestName() == m_TargetDomain.ForestName()) { // intra-forest must be set to true to match the domains
if (!bIntraForest) { AdmtThrowError( GUID_NULL, GUID_NULL, E_INVALIDARG, IDS_E_NOT_INTER_FOREST, (LPCTSTR)m_SourceDomain.Name(), (LPCTSTR)m_TargetDomain.Name() ); } } else { // intra-forest must be set to false to match the domains
if (bIntraForest) { AdmtThrowError( GUID_NULL, GUID_NULL, E_INVALIDARG, IDS_E_NOT_INTRA_FOREST, (LPCTSTR)m_SourceDomain.Name(), (LPCTSTR)m_TargetDomain.Name() ); } } }
// DoOption Method
void CMigrationBase::DoOption(long lOptions, VARIANT& vntInclude, VARIANT& vntExclude) { m_setIncludeNames.clear(); m_setExcludeNames.clear();
InitRecurseMaintainOption(lOptions);
GetExcludeNames(vntExclude, m_setExcludeNames);
switch (lOptions & 0xFF) { case admtNone: { DoNone(); break; } case admtData: { GetNamesFromData(vntInclude, m_setIncludeNames); DoNames(); break; } case admtFile: { GetNamesFromFile(vntInclude, m_setIncludeNames); DoNames(); break; } case admtDomain: { m_setIncludeNames.clear(); DoDomain(); break; } default: { AdmtThrowError(GUID_NULL, GUID_NULL, E_INVALIDARG, IDS_E_INVALID_OPTION); break; } } }
// DoNone Method
void CMigrationBase::DoNone() { }
// DoNames Method
void CMigrationBase::DoNames() { }
// DoDomain Method
void CMigrationBase::DoDomain() { }
// InitRecurseMaintainOption Method
void CMigrationBase::InitRecurseMaintainOption(long lOptions) { switch (lOptions & 0xFF) { case admtData: case admtFile: { if (lOptions & 0xFF00) { AdmtThrowError(GUID_NULL, GUID_NULL, E_INVALIDARG, IDS_E_DATA_OPTION_FLAGS_NOT_ALLOWED); }
m_nRecurseMaintain = 0; break; } case admtDomain: { m_nRecurseMaintain = 0;
if (lOptions & admtRecurse) { ++m_nRecurseMaintain;
if (lOptions & admtMaintainHierarchy) { ++m_nRecurseMaintain; } } break; } default: { m_nRecurseMaintain = 0; break; } } }
// GetExcludeNames Method
void CMigrationBase::GetExcludeNames(VARIANT& vntExclude, StringSet& setExcludeNames) { try { switch (V_VT(&vntExclude)) { case VT_EMPTY: case VT_ERROR: { setExcludeNames.clear(); break; } case VT_BSTR: { GetNamesFromFile(V_BSTR(&vntExclude), setExcludeNames); break; } case VT_BSTR|VT_BYREF: { BSTR* pbstr = V_BSTRREF(&vntExclude);
if (pbstr) { GetNamesFromFile(*pbstr, setExcludeNames); } break; } case VT_BSTR|VT_ARRAY: { GetNamesFromStringArray(V_ARRAY(&vntExclude), setExcludeNames); break; } case VT_BSTR|VT_ARRAY|VT_BYREF: { SAFEARRAY** ppsa = V_ARRAYREF(&vntExclude);
if (ppsa) { GetNamesFromStringArray(*ppsa, setExcludeNames); } break; } case VT_VARIANT|VT_BYREF: { VARIANT* pvnt = V_VARIANTREF(&vntExclude);
if (pvnt) { GetExcludeNames(*pvnt, setExcludeNames); } break; } case VT_VARIANT|VT_ARRAY: { GetNamesFromVariantArray(V_ARRAY(&vntExclude), setExcludeNames); break; } case VT_VARIANT|VT_ARRAY|VT_BYREF: { SAFEARRAY** ppsa = V_ARRAYREF(&vntExclude);
if (ppsa) { GetNamesFromVariantArray(*ppsa, setExcludeNames); } break; } default: { _com_issue_error(E_INVALIDARG); break; } } } catch (_com_error& ce) { AdmtThrowError(GUID_NULL, GUID_NULL, ce.Error(), IDS_E_INVALID_EXCLUDE_DATA_TYPE); } catch (...) { AdmtThrowError(GUID_NULL, GUID_NULL, E_FAIL, IDS_E_INVALID_EXCLUDE_DATA_TYPE); } }
// FillInVarSetForUsers Method
void CMigrationBase::FillInVarSetForUsers(CDomainAccounts& rUsers, CVarSet& rVarSet) { CVarSetAccounts aAccounts(rVarSet);
for (CDomainAccounts::iterator it = rUsers.begin(); it != rUsers.end(); it++) { aAccounts.AddAccount(_T("User"), it->GetADsPath(), it->GetName(), it->GetUserPrincipalName()); } }
// FillInVarSetForGroups Method
void CMigrationBase::FillInVarSetForGroups(CDomainAccounts& rGroups, CVarSet& rVarSet) { CVarSetAccounts aAccounts(rVarSet);
for (CDomainAccounts::iterator it = rGroups.begin(); it != rGroups.end(); it++) { aAccounts.AddAccount(_T("Group"), it->GetADsPath(), it->GetName()); } }
// FillInVarSetForComputers Method
void CMigrationBase::FillInVarSetForComputers(CDomainAccounts& rComputers, bool bMigrateOnly, bool bMoveToTarget, bool bReboot, long lRebootDelay, CVarSet& rVarSet) { CVarSetAccounts aAccounts(rVarSet); CVarSetServers aServers(rVarSet);
for (CDomainAccounts::iterator it = rComputers.begin(); it != rComputers.end(); it++) { // remove trailing '$'
// ADMT doesn't accept true SAM account name
_bstr_t strName = RemoveTrailingDollarSign(it->GetSamAccountName());
aAccounts.AddAccount(_T("Computer"), strName); aServers.AddServer(strName, bMigrateOnly, bMoveToTarget, bReboot, lRebootDelay); } }
// VerifyRenameConflictPrefixSuffixValid Method
void CMigrationBase::VerifyRenameConflictPrefixSuffixValid() { int nTotalPrefixSuffixLength = 0;
long lRenameOption = m_spInternal->RenameOption;
if ((lRenameOption == admtRenameWithPrefix) || (lRenameOption == admtRenameWithSuffix)) { _bstr_t strPrefixSuffix = m_spInternal->RenamePrefixOrSuffix;
nTotalPrefixSuffixLength += strPrefixSuffix.length(); }
long lConflictOption = m_spInternal->ConflictOptions & 0x0F;
if ((lConflictOption == admtRenameConflictingWithSuffix) || (lConflictOption == admtRenameConflictingWithPrefix)) { _bstr_t strPrefixSuffix = m_spInternal->ConflictPrefixOrSuffix;
nTotalPrefixSuffixLength += strPrefixSuffix.length(); }
if (nTotalPrefixSuffixLength > MAXIMUM_PREFIX_SUFFIX_LENGTH) { AdmtThrowError(GUID_NULL, GUID_NULL, E_INVALIDARG, IDS_E_PREFIX_SUFFIX_TOO_LONG, MAXIMUM_PREFIX_SUFFIX_LENGTH); } }
// VerifyCanAddSidHistory Method
void CMigrationBase::VerifyCanAddSidHistory() { #define F_WORKS 0x00000000
#define F_WRONGOS 0x00000001
#define F_NO_REG_KEY 0x00000002
#define F_NO_AUDITING_SOURCE 0x00000004
#define F_NO_AUDITING_TARGET 0x00000008
#define F_NO_LOCAL_GROUP 0x00000010
try { long lErrorFlags = 0;
IAccessCheckerPtr spAccessChecker(__uuidof(AccessChecker));
spAccessChecker->CanUseAddSidHistory(m_SourceDomain.Name(), m_TargetDomain.Name(), &lErrorFlags);
if (lErrorFlags != 0) { _bstr_t strError;
CComBSTR str;
if (lErrorFlags & F_NO_AUDITING_SOURCE) { str.LoadString(IDS_E_NO_AUDITING_SOURCE); strError += str.operator BSTR(); }
if (lErrorFlags & F_NO_AUDITING_TARGET) { str.LoadString(IDS_E_NO_AUDITING_TARGET); strError += str.operator BSTR(); }
if (lErrorFlags & F_NO_LOCAL_GROUP) { str.LoadString(IDS_E_NO_SID_HISTORY_LOCAL_GROUP); strError += str.operator BSTR(); }
if (lErrorFlags & F_NO_REG_KEY) { str.LoadString(IDS_E_NO_SID_HISTORY_REGISTRY_ENTRY); strError += str.operator BSTR(); }
AdmtThrowError(GUID_NULL, GUID_NULL, E_FAIL, IDS_E_SID_HISTORY_CONFIGURATION, (LPCTSTR)strError); } } catch (_com_error& ce) { AdmtThrowError(GUID_NULL, GUID_NULL, ce, IDS_E_CAN_ADD_SID_HISTORY); } catch (...) { AdmtThrowError(GUID_NULL, GUID_NULL, E_FAIL, IDS_E_CAN_ADD_SID_HISTORY); } }
// VerifyTargetContainerPathLength Method
void CMigrationBase::VerifyTargetContainerPathLength() { _bstr_t strPath = GetTargetContainer().GetPath();
if (strPath.length() > 999) { AdmtThrowError(GUID_NULL, GUID_NULL, E_INVALIDARG, IDS_E_TARGET_CONTAINER_PATH_TOO_LONG); } }
// VerifyPasswordServer Method
void CMigrationBase::VerifyPasswordOption() { if (m_spInternal->PasswordOption == admtCopyPassword) { _bstr_t strServer = m_spInternal->PasswordServer;
// a password server must be specified for copy password option
if (strServer.length() == 0) { AdmtThrowError(GUID_NULL, GUID_NULL, E_INVALIDARG, IDS_E_PASSWORD_DC_NOT_SPECIFIED); }
//
// verify that password server exists and is a domain controller
//
_bstr_t strPrefixedServer;
if (_tcsncmp(strServer, _T("\\\\"), 2) == 0) { strPrefixedServer = strServer; } else { strPrefixedServer = _T("\\\\") + strServer; }
PSERVER_INFO_101 psiInfo;
NET_API_STATUS nasStatus = NetServerGetInfo(strPrefixedServer, 101, (LPBYTE*)&psiInfo);
if (nasStatus != NERR_Success) { AdmtThrowError(GUID_NULL, GUID_NULL, HRESULT_FROM_WIN32(nasStatus), IDS_E_PASSWORD_DC_NOT_FOUND, (LPCTSTR)strServer); }
UINT uMsgId = 0;
if (psiInfo->sv101_platform_id != PLATFORM_ID_NT) { uMsgId = IDS_E_PASSWORD_DC_NOT_NT; } else if (!(psiInfo->sv101_type & SV_TYPE_DOMAIN_CTRL) && !(psiInfo->sv101_type & SV_TYPE_DOMAIN_BAKCTRL)) { uMsgId = IDS_E_PASSWORD_DC_NOT_DC; }
NetApiBufferFree(psiInfo);
if (uMsgId) { AdmtThrowError(GUID_NULL, GUID_NULL, E_INVALIDARG, uMsgId, (LPCTSTR)strServer); }
//
// verify that password server is configured properly
//
IPasswordMigrationPtr spPasswordMigration(__uuidof(PasswordMigration));
spPasswordMigration->EstablishSession(strServer, m_TargetDomain.DomainControllerName()); } }
// PerformMigration Method
void CMigrationBase::PerformMigration(CVarSet& rVarSet) { IPerformMigrationTaskPtr spMigrator(__uuidof(Migrator));
try { spMigrator->PerformMigrationTask(IUnknownPtr(rVarSet.GetInterface()), 0); } catch (_com_error& ce) { if (ce.Error() == MIGRATOR_E_PROCESSES_STILL_RUNNING) { AdmtThrowError(GUID_NULL, GUID_NULL, ce.Error(), IDS_E_ADMT_PROCESS_RUNNING); } else { throw; } } }
// FixObjectsInHierarchy Method
void CMigrationBase::FixObjectsInHierarchy(LPCTSTR pszType) { CFixObjectsInHierarchy fix;
fix.SetObjectType(pszType);
long lOptions = m_spInternal->ConflictOptions; long lOption = lOptions & 0x0F; long lFlags = lOptions & 0xF0;
fix.SetFixReplaced((lOption == admtReplaceConflicting) && (lFlags & admtMoveReplacedAccounts));
fix.SetSourceContainerPath(m_SourceContainer.GetPath()); fix.SetTargetContainerPath(m_TargetContainer.GetPath());
fix.FixObjects(); }
//---------------------------------------------------------------------------
namespace MigrationBase {
// GetNamesFromData Method
void GetNamesFromData(VARIANT& vntData, StringSet& setNames) { try { GetNamesFromVariant(&vntData, setNames); } catch (_com_error& ce) { AdmtThrowError(GUID_NULL, GUID_NULL, ce.Error(), IDS_E_INVALID_DATA_OPTION_DATA_TYPE); } catch (...) { AdmtThrowError(GUID_NULL, GUID_NULL, E_FAIL, IDS_E_INVALID_DATA_OPTION_DATA_TYPE); } }
// GetNamesFromVariant Method
void GetNamesFromVariant(VARIANT* pvntData, StringSet& setNames) { switch (V_VT(pvntData)) { case VT_BSTR: { GetNamesFromString(V_BSTR(pvntData), setNames); break; } case VT_BSTR|VT_BYREF: { BSTR* pbstr = V_BSTRREF(pvntData);
if (pbstr) { GetNamesFromString(*pbstr, setNames); } break; } case VT_BSTR|VT_ARRAY: { GetNamesFromStringArray(V_ARRAY(pvntData), setNames); break; } case VT_BSTR|VT_ARRAY|VT_BYREF: { SAFEARRAY** ppsa = V_ARRAYREF(pvntData);
if (ppsa) { GetNamesFromStringArray(*ppsa, setNames); } break; } case VT_VARIANT|VT_BYREF: { VARIANT* pvnt = V_VARIANTREF(pvntData);
if (pvnt) { GetNamesFromVariant(pvnt, setNames); } break; } case VT_VARIANT|VT_ARRAY: { GetNamesFromVariantArray(V_ARRAY(pvntData), setNames); break; } case VT_VARIANT|VT_ARRAY|VT_BYREF: { SAFEARRAY** ppsa = V_ARRAYREF(pvntData);
if (ppsa) { GetNamesFromVariantArray(*ppsa, setNames); } break; } case VT_EMPTY: { // ignore empty variants
break; } default: { _com_issue_error(E_INVALIDARG); break; } } }
// GetNamesFromString Method
void GetNamesFromString(BSTR bstr, StringSet& setNames) { if (bstr) { UINT cch = SysStringLen(bstr);
if (cch > 0) { GetNamesFromStringW(bstr, cch, setNames); } } }
// GetNamesFromStringArray Method
void GetNamesFromStringArray(SAFEARRAY* psa, StringSet& setNames) { BSTR* pbstr;
HRESULT hr = SafeArrayAccessData(psa, (void**)&pbstr);
if (SUCCEEDED(hr)) { try { UINT uDimensionCount = psa->cDims;
for (UINT uDimension = 0; uDimension < uDimensionCount; uDimension++) { UINT uElementCount = psa->rgsabound[uDimension].cElements;
for (UINT uElement = 0; uElement < uElementCount; uElement++) { setNames.insert(_bstr_t(*pbstr++)); } }
SafeArrayUnaccessData(psa); } catch (...) { SafeArrayUnaccessData(psa); throw; } } }
// GetNamesFromVariantArray Method
void GetNamesFromVariantArray(SAFEARRAY* psa, StringSet& setNames) { VARIANT* pvnt;
HRESULT hr = SafeArrayAccessData(psa, (void**)&pvnt);
if (SUCCEEDED(hr)) { try { UINT uDimensionCount = psa->cDims;
for (UINT uDimension = 0; uDimension < uDimensionCount; uDimension++) { UINT uElementCount = psa->rgsabound[uDimension].cElements;
for (UINT uElement = 0; uElement < uElementCount; uElement++) { GetNamesFromVariant(pvnt++, setNames); } }
SafeArrayUnaccessData(psa); } catch (...) { SafeArrayUnaccessData(psa); throw; } } }
// GetNamesFromFile Method
//
// - the maximum file size this implementation can handle is 4,294,967,295 bytes
void GetNamesFromFile(VARIANT& vntData, StringSet& setNames) { bool bInvalidArg = false;
switch (V_VT(&vntData)) { case VT_BSTR: { BSTR bstr = V_BSTR(&vntData);
if (bstr) { GetNamesFromFile(bstr, setNames); } else { bInvalidArg = true; } break; } case VT_BSTR|VT_BYREF: { BSTR* pbstr = V_BSTRREF(&vntData);
if (pbstr && *pbstr) { GetNamesFromFile(*pbstr, setNames); } else { bInvalidArg = true; } break; } case VT_VARIANT|VT_BYREF: { VARIANT* pvnt = V_VARIANTREF(&vntData);
if (pvnt) { GetNamesFromFile(*pvnt, setNames); } else { bInvalidArg = true; } break; } default: { bInvalidArg = true; break; } }
if (bInvalidArg) { AdmtThrowError(GUID_NULL, GUID_NULL, E_INVALIDARG, IDS_E_INVALID_FILE_OPTION_DATA_TYPE); } }
// GetNamesFromFile Method
//
// - the maximum file size this implementation can handle is 4,294,967,295 bytes
void GetNamesFromFile(LPCTSTR pszFileName, StringSet& setNames) { HRESULT hr = S_OK;
if (pszFileName) { HANDLE hFile = CreateFile(pszFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hFile != INVALID_HANDLE_VALUE) { DWORD dwFileSize = GetFileSize(hFile, NULL);
if (dwFileSize > 0) { HANDLE hFileMappingObject = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (hFileMappingObject != NULL) { LPVOID pvBase = MapViewOfFile(hFileMappingObject, FILE_MAP_READ, 0, 0, 0);
if (pvBase != NULL) { // if Unicode signature assume Unicode file
// otherwise it must be an ANSI file
LPCWSTR pwcs = (LPCWSTR)pvBase;
if ((dwFileSize >= 2) && (*pwcs == L'\xFEFF')) { GetNamesFromStringW(pwcs + 1, dwFileSize / sizeof(WCHAR) - 1, setNames); } else { GetNamesFromStringA((LPCSTR)pvBase, dwFileSize, setNames); }
UnmapViewOfFile(pvBase); } else { hr = HRESULT_FROM_WIN32(GetLastError()); }
CloseHandle(hFileMappingObject); } else { hr = HRESULT_FROM_WIN32(GetLastError()); } }
CloseHandle(hFile); } else { hr = HRESULT_FROM_WIN32(GetLastError()); } } else { hr = E_INVALIDARG; }
if (FAILED(hr)) { AdmtThrowError(GUID_NULL, GUID_NULL, hr, IDS_E_INCLUDE_NAMES_FILE, pszFileName); } }
// GetNamesFromStringA Method
void GetNamesFromStringA(LPCSTR pchString, DWORD cchString, StringSet& setNames) { static const CHAR chSeparators[] = "\t\n\r";
LPCSTR pchStringEnd = &pchString[cchString];
for (LPCSTR pch = pchString; pch < pchStringEnd; pch++) { // skip space characters
while ((pch < pchStringEnd) && (*pch == ' ')) { ++pch; }
// beginning of name
LPCSTR pchBeg = pch;
// scan for separator saving pointer to last non-whitespace character
LPCSTR pchEnd = pch;
while ((pch < pchStringEnd) && (strchr(chSeparators, *pch) == NULL)) { if (*pch++ != ' ') { pchEnd = pch; } }
// insert name which doesn't contain any leading or trailing whitespace characters
if (pchEnd > pchBeg) { size_t cchName = pchEnd - pchBeg; LPSTR pszName = (LPSTR) _alloca((cchName + 1) * sizeof(CHAR)); strncpy(pszName, pchBeg, cchName); pszName[cchName] = '\0';
setNames.insert(_bstr_t(pszName)); } } }
// GetNamesFromStringW Method
void GetNamesFromStringW(LPCWSTR pchString, DWORD cchString, StringSet& setNames) { static const WCHAR chSeparators[] = L"\t\n\r";
LPCWSTR pchStringEnd = &pchString[cchString];
for (LPCWSTR pch = pchString; pch < pchStringEnd; pch++) { // skip space characters
while ((pch < pchStringEnd) && (*pch == L' ')) { ++pch; }
// beginning of name
LPCWSTR pchBeg = pch;
// scan for separator saving pointer to last non-whitespace character
LPCWSTR pchEnd = pch;
while ((pch < pchStringEnd) && (wcschr(chSeparators, *pch) == NULL)) { if (*pch++ != L' ') { pchEnd = pch; } }
// insert name which doesn't contain any leading or trailing whitespace characters
if (pchEnd > pchBeg) { _bstr_t strName(SysAllocStringLen(pchBeg, pchEnd - pchBeg), false);
setNames.insert(strName); } } }
// RemoveTrailingDollarSign Method
_bstr_t RemoveTrailingDollarSign(LPCTSTR pszName) { LPTSTR psz = _T("");
if (pszName) { size_t cch = _tcslen(pszName);
if (cch > 0) { psz = reinterpret_cast<LPTSTR>(_alloca((cch + 1) * sizeof(_TCHAR)));
_tcscpy(psz, pszName);
LPTSTR p = &psz[cch - 1];
if (*p == _T('$')) { *p = _T('\0'); } } }
return psz; }
} // namespace
|