Source code of Windows XP (NT5)
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.

1849 lines
59 KiB

  1. /*---------------------------------------------------------------------------
  2. File: Migrator.cpp
  3. Comments: Implementation of McsMigrationDriver COM object.
  4. This object encapsulates the knowledge of when to call the local engine,
  5. and when to call the dispatcher.
  6. It will also provide a description of the tasks to be performed, for display
  7. on the last page of each migration wizard, and will be responsible for calculating
  8. the actions required to undo an operation (this is not yet implemented).
  9. (c) Copyright 1999, Mission Critical Software, Inc., All Rights Reserved
  10. Proprietary and confidential to Mission Critical Software, Inc.
  11. REVISION LOG ENTRY
  12. Revision By: Christy Boles
  13. ---------------------------------------------------------------------------
  14. */// Migrator.cpp : Implementation of CMcsMigrationDriverApp and DLL registration.
  15. #include "stdafx.h"
  16. #include "MigDrvr.h"
  17. //#import "\bin\McsVarSetMin.tlb" no_namespace, named_guids
  18. //#import "\bin\McsEADCTAgent.tlb" no_namespace, named_guids
  19. //#import "\bin\McsDispatcher.tlb" no_namespace, named_guids
  20. //#import "\bin\DBManager.tlb" no_namespace, named_guids
  21. //#import "\bin\McsDctWorkerObjects.tlb"
  22. //#import "\bin\NetEnum.tlb" no_namespace
  23. #import "VarSet.tlb" no_namespace, named_guids rename("property", "aproperty")
  24. //#import "Engine.tlb" no_namespace, named_guids //#imported via DetDlg.h below
  25. #import "Dispatch.tlb" no_namespace, named_guids
  26. #import "WorkObj.tlb"
  27. #import "NetEnum.tlb" no_namespace
  28. #include <iads.h>
  29. #include <adshlp.h>
  30. #include <dsgetdc.h>
  31. #include <Ntdsapi.h>
  32. #include <lm.h>
  33. #include <Psapi.h>
  34. #pragma comment(lib, "Psapi.lib")
  35. #include "Migrator.h"
  36. #include "TaskChk.h"
  37. #include "ResStr.h"
  38. // dialogs used
  39. #include "DetDlg.h"
  40. #include "MonDlg.h"
  41. #include "SetDlg.h"
  42. #include "MainDlg.h"
  43. #include "Working.h"
  44. #include "ErrDct.hpp"
  45. #include "TReg.hpp"
  46. #include "EaLen.hpp"
  47. #include <MigrationMutex.h>
  48. //#define MAX_DB_FIELD 255
  49. typedef HRESULT (CALLBACK * DSGETDCNAME)(LPWSTR, LPWSTR, GUID*, LPWSTR, DWORD, PDOMAIN_CONTROLLER_INFO*);
  50. // Opertation flags to be performed on the Account
  51. #define OPS_Create_Account (0x00000001)
  52. #define OPS_Copy_Properties (0x00000002)
  53. #define OPS_Process_Members (0x00000004)
  54. #define OPS_Process_MemberOf (0x00000008)
  55. #define OPS_Call_Extensions (0x00000010)
  56. #define OPS_All OPS_Create_Account | OPS_Copy_Properties | OPS_Process_Members | OPS_Process_MemberOf | OPS_Call_Extensions
  57. #define OPS_Copy OPS_Create_Account | OPS_Copy_Properties
  58. BOOL gbCancelled = FALSE;
  59. bool __stdcall IsAgentOrDispatcherProcessRunning();
  60. void __stdcall SetDomainControllers(IVarSetPtr& spVarSet);
  61. /////////////////////////////////////////////////////////////////////////////
  62. //
  63. BOOL // ret - TRUE if found program directory in the registry
  64. GetProgramDirectory(
  65. WCHAR * filename // out - buffer that will contain path to program directory
  66. )
  67. {
  68. DWORD rc = 0;
  69. BOOL bFound = FALSE;
  70. TRegKey key;
  71. rc = key.OpenRead(GET_STRING(IDS_HKLM_DomainAdmin_Key),HKEY_LOCAL_MACHINE);
  72. if ( ! rc )
  73. {
  74. rc = key.ValueGetStr(L"Directory",filename,MAX_PATH);
  75. if ( ! rc )
  76. {
  77. if ( *filename )
  78. bFound = TRUE;
  79. }
  80. }
  81. if ( ! bFound )
  82. {
  83. UStrCpy(filename,L"C:\\"); // if all else fails, default to the C: drive
  84. }
  85. return bFound;
  86. }
  87. BOOL // ret - TRUE if found program directory in the registry
  88. GetLogLevel(
  89. DWORD * level // out - value that should be used for log level
  90. )
  91. {
  92. DWORD rc = 0;
  93. BOOL bFound = FALSE;
  94. TRegKey key;
  95. rc = key.OpenRead(GET_STRING(IDS_HKLM_DomainAdmin_Key),HKEY_LOCAL_MACHINE);
  96. if ( ! rc )
  97. {
  98. rc = key.ValueGetDWORD(L"TranslationLogLevel",level);
  99. if ( ! rc )
  100. {
  101. bFound = TRUE;
  102. }
  103. }
  104. return bFound;
  105. }
  106. HRESULT CMigrator::ViewPreviousDispatchResults()
  107. {
  108. _bstr_t logFile;
  109. if ( logFile.length() == 0 )
  110. {
  111. WCHAR path[MAX_PATH];
  112. GetProgramDirectory(path);
  113. logFile = path;
  114. logFile += L"Logs\\Dispatcher.csv";
  115. }
  116. // reset the stats, so that we don't see anything left over from the previous run
  117. gData.Initialize();
  118. CPropertySheet mdlg;
  119. CAgentMonitorDlg listDlg;
  120. CMainDlg summaryDlg;
  121. CLogSettingsDlg settingsDlg;
  122. listDlg.m_psp.dwFlags |= PSP_PREMATURE | PSP_HASHELP;
  123. summaryDlg.m_psp.dwFlags |= PSP_PREMATURE | PSP_HASHELP;
  124. settingsDlg.m_psp.dwFlags |= PSP_PREMATURE | PSP_HASHELP;
  125. mdlg.AddPage(&summaryDlg);
  126. mdlg.AddPage(&listDlg);
  127. mdlg.AddPage(&settingsDlg);
  128. settingsDlg.SetImmediateStart(TRUE);
  129. settingsDlg.SetDispatchLog(logFile);
  130. mdlg.SetActivePage(&listDlg);
  131. // UINT nResponse = mdlg.DoModal();
  132. UINT_PTR nResponse = mdlg.DoModal();
  133. return S_OK;
  134. }
  135. // WaitForAgentsToFinish Method
  136. //
  137. // Waits for dispatcher and all dispatched agents to complete
  138. // their tasks.
  139. // Used when ADMT is run from script or command line.
  140. static void WaitForAgentsToFinish(_bstr_t strLogPath)
  141. {
  142. gData.SetLogPath(strLogPath);
  143. CloseHandle(CreateThread(NULL, 0, &ResultMonitorFn, NULL, 0, NULL));
  144. CloseHandle(CreateThread(NULL, 0, &LogReaderFn, NULL, 0, NULL));
  145. CloseHandle(CreateThread(NULL, 0, &MonitorRunningAgents, NULL, 0, NULL));
  146. LARGE_INTEGER liDueTime;
  147. liDueTime.QuadPart = -50000000; // 5 sec
  148. HANDLE hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
  149. for (int nState = 0; nState < 3;)
  150. {
  151. SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, FALSE);
  152. if (WaitForSingleObject(hTimer, INFINITE) == WAIT_OBJECT_0)
  153. {
  154. BOOL bDone = FALSE;
  155. switch (nState)
  156. {
  157. case 0: // first pass of dispatcher log
  158. {
  159. gData.GetFirstPassDone(&bDone);
  160. break;
  161. }
  162. case 1: // dispatcher finished
  163. {
  164. gData.GetLogDone(&bDone);
  165. break;
  166. }
  167. case 2: // agents finished
  168. {
  169. ComputerStats stats;
  170. gData.GetComputerStats(&stats);
  171. if (stats.numRunning == 0)
  172. {
  173. bDone = TRUE;
  174. }
  175. break;
  176. }
  177. }
  178. if (bDone)
  179. {
  180. ++nState;
  181. }
  182. }
  183. else
  184. {
  185. break;
  186. }
  187. }
  188. CloseHandle(hTimer);
  189. gData.SetDone(TRUE);
  190. }
  191. STDMETHODIMP CMigrator::PerformMigrationTask(IUnknown* punkVarSet, LONG_PTR hWnd)
  192. {
  193. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  194. HRESULT hr = S_OK;
  195. IVarSetPtr pVS = punkVarSet;
  196. BSTR jobID = NULL;
  197. CWnd wnd;
  198. long lActionID = -2;
  199. IIManageDBPtr pDb;
  200. _bstr_t wizard = pVS->get(L"Options.Wizard");
  201. _bstr_t undo;
  202. _bstr_t viewPreviousResults = pVS->get(L"MigrationDriver.ViewPreviousResults");
  203. bool bAnyToDispatch = true;
  204. long lAutoCloseHideDialogs = pVS->get(GET_BSTR(DCTVS_Options_AutoCloseHideDialogs));
  205. // if agent or dispatcher process still running...
  206. if (IsAgentOrDispatcherProcessRunning())
  207. {
  208. // return error result
  209. return MIGRATOR_E_PROCESSES_STILL_RUNNING;
  210. }
  211. hr = pDb.CreateInstance(__uuidof(IManageDB));
  212. if (FAILED(hr))
  213. {
  214. return hr;
  215. }
  216. gbCancelled = FALSE;
  217. // This provides an easy way to view the previous dispatch results
  218. if ( !UStrICmp(viewPreviousResults,GET_STRING(IDS_YES)) )
  219. {
  220. ViewPreviousDispatchResults();
  221. return S_OK;
  222. }
  223. if (_bstr_t(pVS->get(GET_BSTR(DCTVS_Options_DontBeginNewLog))) != GET_BSTR(IDS_YES))
  224. {
  225. // begin a new log
  226. TError err;
  227. err.LogOpen(_bstr_t(pVS->get(GET_BSTR(DCTVS_Options_Logfile))), 0, 0, true);
  228. err.LogClose();
  229. }
  230. // update the log level, if needed
  231. DWORD level = 0;
  232. if( GetLogLevel(&level) )
  233. {
  234. pVS->put(GET_BSTR(DCTVS_Options_LogLevel),(long)level);
  235. }
  236. undo = pVS->get(GET_BSTR(DCTVS_Options_Undo));
  237. //* if ( !_wcsicmp((WCHAR*) undo, L"Yes") )
  238. if ( !_wcsicmp((WCHAR*) undo, GET_STRING(IDS_YES)) )
  239. {
  240. hr = pDb->raw_GetCurrentActionID(&lActionID);
  241. if ( SUCCEEDED(hr) )
  242. pVS->put(L"UndoAction", lActionID);
  243. hr = pDb->raw_GetNextActionID(&lActionID);
  244. hr = 0;
  245. }
  246. else
  247. {
  248. hr = pDb->raw_GetNextActionID(&lActionID);
  249. if ( SUCCEEDED(hr) )
  250. {
  251. pVS->put(L"ActionID",lActionID);
  252. _bstr_t password1 = pVS->get(GET_BSTR(DCTVS_Options_Credentials_Password));
  253. _bstr_t password2 = pVS->get(GET_BSTR(DCTVS_AccountOptions_SidHistoryCredentials_Password));
  254. pVS->put(GET_BSTR(DCTVS_Options_Credentials_Password),L"");
  255. pVS->put(GET_BSTR(DCTVS_AccountOptions_SidHistoryCredentials_Password),L"");
  256. hr = pDb->raw_SetActionHistory(lActionID, punkVarSet);
  257. pVS->put(GET_BSTR(DCTVS_Options_Credentials_Password),password1);
  258. pVS->put(GET_BSTR(DCTVS_AccountOptions_SidHistoryCredentials_Password),password2);
  259. if ( FAILED(hr) )
  260. {
  261. // log a message, but don't abort the whole operation
  262. hr = S_OK;
  263. //return hr;
  264. }
  265. }
  266. }
  267. // This sets up any varset keys needed internally for reports to be generated
  268. PreProcessForReporting(pVS);
  269. wnd.Attach((HWND)hWnd);
  270. //for scripting, we need to make sure we have the source domain sid in the varset
  271. RetrieveSrcDomainSid(pVS, pDb);
  272. // set preferred domain controllers to be used
  273. // by the account replicator and dispatched agents
  274. SetDomainControllers(pVS);
  275. // Run the local agent first, if needed to copy any accounts
  276. if ( NeedToRunLocalAgent(pVS) )
  277. {
  278. IDCTAgentPtr pAgent;
  279. hr = pAgent.CreateInstance(__uuidof(DCTAgent));
  280. if (SUCCEEDED(hr))
  281. {
  282. hr = pAgent->raw_SubmitJob(punkVarSet,&jobID);
  283. if ( SUCCEEDED(hr) )
  284. {
  285. CAgentDetailDlg detailDlg(&wnd);
  286. detailDlg.SetJobID(jobID);
  287. detailDlg.SetFormat(1); // acct repl stats
  288. // if we're only copying a few accounts, default the refresh rate to a lower value, since the
  289. // process may finish before the refresh can happen
  290. long nAccounts = pVS->get(GET_BSTR(DCTVS_Accounts_NumItems));
  291. if ( nAccounts <= 20 )
  292. {
  293. detailDlg.SetRefreshInterval(1);
  294. }
  295. else
  296. {
  297. detailDlg.SetRefreshInterval(5);
  298. }
  299. _bstr_t logfile = pVS->get(GET_BSTR(DCTVS_Options_Logfile));
  300. detailDlg.SetLogFile((WCHAR*)logfile);
  301. detailDlg.SetAutoCloseHide(lAutoCloseHideDialogs);
  302. UINT_PTR nResponse = detailDlg.DoModal();
  303. }
  304. }
  305. }
  306. if ( gbCancelled )
  307. {
  308. // if the local operation was cancelled, don't dispatch the agents
  309. wnd.Detach();
  310. return S_OK;
  311. }
  312. // now run the dispatcher
  313. if ( SUCCEEDED(hr) )
  314. {
  315. // there's no need to dispatch agents to do translation or migration
  316. // if we were not able to copy the accounts
  317. if ( NeedToDispatch(pVS) )
  318. {
  319. IDCTDispatcherPtr pDispatcher;
  320. hr = pDispatcher.CreateInstance(CLSID_DCTDispatcher);
  321. if ( SUCCEEDED(hr) )
  322. {
  323. // Call the dispatch preprocessor.
  324. PreProcessDispatcher(pVS);
  325. // make sure we're not going to lock out any computers by migrating them to a domain where they
  326. // don't have a good computer account
  327. TrimMigratingComputerList(pVS, &bAnyToDispatch);
  328. if (bAnyToDispatch)
  329. {
  330. CWorking tempDlg(IDS_DISPATCHING);
  331. if (lAutoCloseHideDialogs == 0)
  332. {
  333. tempDlg.Create(IDD_PLEASEWAIT);
  334. tempDlg.ShowWindow(SW_SHOW);
  335. }
  336. // give the dialog a change to process messages
  337. CWnd * wnd = AfxGetMainWnd();
  338. MSG msg;
  339. // Call the dispatch preprocessor.
  340. // PreProcessDispatcher(pVS);
  341. while ( wnd && PeekMessage( &msg, wnd->m_hWnd, 0, 0, PM_NOREMOVE ) )
  342. {
  343. if ( ! AfxGetApp()->PumpMessage() )
  344. {
  345. break;
  346. }
  347. }
  348. AfxGetApp()->DoWaitCursor(0);
  349. _bstr_t logFile = pVS->get(GET_BSTR(DCTVS_Options_DispatchCSV));
  350. WCHAR path[MAX_PATH] = L"";
  351. GetProgramDirectory(path);
  352. if ( logFile.length() == 0 )
  353. {
  354. logFile = path;
  355. logFile += L"Logs\\Dispatcher.csv";
  356. pVS->put(GET_BSTR(DCTVS_Options_DispatchCSV),logFile);
  357. }
  358. // clear the CSV log file if it exists, so we will not get old information in it
  359. if ( ! DeleteFile(logFile) )
  360. {
  361. hr = GetLastError();
  362. }
  363. // set up the location for the agents to write back their results
  364. logFile = path;
  365. logFile += L"Logs\\Agents";
  366. _bstr_t logsPath = path;
  367. logsPath += L"Logs";
  368. CreateDirectory(logsPath,NULL);
  369. if ( ! CreateDirectory(logFile,NULL) )
  370. {
  371. DWORD rc = GetLastError();
  372. }
  373. pVS->put(GET_BSTR(DCTVS_Dispatcher_ResultPath),logFile);
  374. // if (bAnyToDispatch)
  375. // {
  376. punkVarSet->AddRef();
  377. hr = pDispatcher->raw_DispatchToServers(&punkVarSet);
  378. if (lAutoCloseHideDialogs == 0)
  379. {
  380. tempDlg.ShowWindow(SW_HIDE);
  381. }
  382. if ( SUCCEEDED(hr) )
  383. {
  384. // reset the stats, so that we don't see anything left over from the previous run
  385. gData.Initialize();
  386. logFile = pVS->get(GET_BSTR(DCTVS_Options_DispatchCSV));
  387. if (lAutoCloseHideDialogs == 0)
  388. {
  389. CPropertySheet mdlg;
  390. CAgentMonitorDlg listDlg;
  391. CMainDlg summaryDlg;
  392. CLogSettingsDlg settingsDlg;
  393. CString title;
  394. title.LoadString(IDS_MainWindowTitle);
  395. listDlg.m_psp.dwFlags |= PSP_PREMATURE | PSP_HASHELP;
  396. summaryDlg.m_psp.dwFlags |= PSP_PREMATURE | PSP_HASHELP;
  397. settingsDlg.m_psp.dwFlags |= PSP_PREMATURE | PSP_HASHELP;
  398. mdlg.AddPage(&summaryDlg);
  399. mdlg.AddPage(&listDlg);
  400. mdlg.AddPage(&settingsDlg);
  401. settingsDlg.SetImmediateStart(TRUE);
  402. settingsDlg.SetDispatchLog(logFile);
  403. // this determines whether the stats for security translation will be displayed in the agent detail
  404. if ( NeedToUseST(pVS,TRUE) )
  405. {
  406. listDlg.SetSecurityTranslationFlag(TRUE);
  407. }
  408. else
  409. {
  410. listDlg.SetSecurityTranslationFlag(FALSE);
  411. }
  412. if( !UStrICmp(wizard,L"reporting") )
  413. {
  414. listDlg.SetReportingFlag(TRUE);
  415. }
  416. mdlg.SetActivePage(&listDlg);
  417. mdlg.SetTitle(title);
  418. UINT_PTR nResponse = mdlg.DoModal();
  419. }
  420. else
  421. {
  422. WaitForAgentsToFinish(logFile);
  423. }
  424. // store results to database
  425. TNodeListEnum e;
  426. TServerNode * pNode;
  427. // if we are retrying an operation, don't save it to the database again!
  428. for ( pNode = (TServerNode*)e.OpenFirst(gData.GetUnsafeServerList()) ; pNode ; pNode = (TServerNode*)e.Next() )
  429. {
  430. if ( UStrICmp(wizard,L"retry") )
  431. {
  432. hr = pDb->raw_AddDistributedAction(SysAllocString(pNode->GetServer()),SysAllocString(pNode->GetJobPath()),pNode->GetStatus(),pNode->GetMessageText());
  433. if ( FAILED(hr) )
  434. {
  435. hr = S_OK;
  436. }
  437. }
  438. else
  439. {
  440. hr = pDb->raw_SetDistActionStatus(-1,pNode->GetJobPath(),pNode->GetStatus(),pNode->GetMessageText());
  441. if ( FAILED(hr) )
  442. {
  443. hr = S_OK;
  444. }
  445. }
  446. }
  447. }
  448. }
  449. // Call the Dispatcher post processor
  450. PostProcessDispatcher(pVS);
  451. }
  452. }
  453. if ( NeedToRunReports(pVS) )
  454. {
  455. RunReports(pVS);
  456. }
  457. }
  458. wnd.Detach();
  459. // Reset the undo flag so that next wizard does not have to deal with it.
  460. //* pVS->put(GET_BSTR(DCTVS_Options_Undo), L"No");
  461. pVS->put(GET_BSTR(DCTVS_Options_Undo), GET_BSTR(IDS_No));
  462. return hr;
  463. }
  464. STDMETHODIMP CMigrator::GetTaskDescription(IUnknown *pVarSet,/*[out]*/BSTR * pDescription)
  465. {
  466. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  467. IVarSetPtr pVS = pVarSet;
  468. CString str;
  469. _bstr_t wizard = pVS->get(L"Options.Wizard");
  470. _bstr_t undo = pVS->get(GET_BSTR(DCTVS_Options_Undo));
  471. //* if ( !_wcsicmp((WCHAR*) undo, L"Yes") )
  472. if ( !_wcsicmp((WCHAR*) undo, GET_STRING(IDS_YES)) )
  473. {
  474. str.FormatMessage(IDS_Undo);
  475. BuildGeneralDesc(pVS, str);
  476. BuildUndoDesc(pVS,str);
  477. }
  478. else if ( !UStrICmp(wizard,L"user") )
  479. {
  480. str.FormatMessage(IDS_UserMigration);
  481. BuildGeneralDesc(pVS,str);
  482. BuildAcctReplDesc(pVS,str);
  483. }
  484. else if ( !UStrICmp(wizard,L"group") )
  485. {
  486. str.FormatMessage(IDS_GroupMigration);
  487. BuildGeneralDesc(pVS,str);
  488. BuildAcctReplDesc(pVS,str);
  489. }
  490. else if ( !UStrICmp(wizard,L"computer") )
  491. {
  492. str.FormatMessage(IDS_ComputerMigration);
  493. BuildGeneralDesc(pVS,str);
  494. BuildAcctReplDesc(pVS,str);
  495. BuildSecTransDesc(pVS,str,TRUE);
  496. BuildDispatchDesc(pVS,str);
  497. }
  498. else if ( !UStrICmp(wizard,L"security") )
  499. {
  500. str.FormatMessage(IDS_SecurityTranslation);
  501. BuildSecTransDesc(pVS,str,TRUE);
  502. BuildDispatchDesc(pVS,str);
  503. }
  504. else if ( !UStrICmp(wizard,L"reporting") )
  505. {
  506. str.FormatMessage(IDS_ReportGeneration);
  507. BuildReportDesc(pVS,str);
  508. }
  509. else if ( !UStrICmp(wizard,L"retry") )
  510. {
  511. str.FormatMessage(IDS_RetryTasks);
  512. }
  513. else if ( ! UStrICmp(wizard,L"service") )
  514. {
  515. str.FormatMessage(IDS_Service);
  516. }
  517. else if ( ! UStrICmp(wizard,L"trust") )
  518. {
  519. str.FormatMessage(IDS_TrustManagement);
  520. }
  521. else if ( !UStrICmp(wizard,L"exchangeDir") )
  522. {
  523. BuildSecTransDesc(pVS,str,TRUE);
  524. }
  525. else if ( !UStrICmp(wizard,L"groupmapping") )
  526. {
  527. BuildGeneralDesc(pVS,str);
  528. BuildAcctReplDesc(pVS,str);
  529. BuildGroupMappingDesc(pVS,str);
  530. }
  531. (*pDescription) = str.AllocSysString();
  532. return S_OK;
  533. }
  534. STDMETHODIMP CMigrator::GetUndoTask(IUnknown * pVarSet,/*[out]*/ IUnknown ** ppVarSetOut)
  535. {
  536. HRESULT hr = S_OK;
  537. IVarSetPtr pVarSetIn = pVarSet;
  538. IVarSetPtr pVarSetOut;
  539. (*ppVarSetOut) = NULL;
  540. hr = pVarSetOut.CreateInstance(CLSID_VarSet);
  541. if ( SUCCEEDED(hr) )
  542. {
  543. hr = ConstructUndoVarSet(pVarSetIn,pVarSetOut);
  544. pVarSetOut->AddRef();
  545. (*ppVarSetOut) = pVarSetOut;
  546. }
  547. return hr;
  548. }
  549. HRESULT CMigrator::ProcessServerListForUndo(IVarSet * pVarSet)
  550. {
  551. HRESULT hr = S_OK;
  552. _bstr_t srcName;
  553. _bstr_t tgtName;
  554. WCHAR keySrc[100];
  555. WCHAR keyTgt[100];
  556. WCHAR keyTmp[100];
  557. long ndx,numItems;
  558. numItems = pVarSet->get(GET_BSTR(DCTVS_Servers_NumItems));
  559. for ( ndx = 0 ; ndx < numItems ; ndx++ )
  560. {
  561. // if the computer was renamed, swap the source and target names
  562. swprintf(keySrc,GET_STRING(DCTVSFmt_Servers_D),ndx);
  563. swprintf(keyTgt,GET_STRING(IDS_DCTVSFmt_Servers_RenameTo_D),ndx);
  564. srcName = pVarSet->get(keySrc);
  565. tgtName = pVarSet->get(keyTgt);
  566. if ( tgtName.length() )
  567. {
  568. if ( ((WCHAR*)tgtName)[0] != L'\\' )
  569. {
  570. // ensure that tgtName has \\ prefix
  571. tgtName = L"\\\\" + tgtName;
  572. }
  573. if ( ((WCHAR*)srcName)[0] == L'\\' )
  574. {
  575. // remove the \\ prefix from the new name
  576. srcName = ((WCHAR*)srcName)+2;
  577. }
  578. pVarSet->put(keySrc,tgtName);
  579. pVarSet->put(keyTgt,srcName);
  580. }
  581. swprintf(keyTmp,GET_STRING(IDS_DCTVSFmt_Servers_ChangeDomain_D),ndx);
  582. pVarSet->put(keyTmp,GET_BSTR(IDS_YES));
  583. swprintf(keyTmp,GET_STRING(IDS_DCTVSFmt_Servers_MigrateOnly_D),ndx);
  584. pVarSet->put(keyTmp,GET_BSTR(IDS_YES));
  585. }
  586. return hr;
  587. }
  588. HRESULT CMigrator::BuildAccountListForUndo(IVarSet * pVarSet,long actionID)
  589. {
  590. HRESULT hr = S_OK;
  591. WCHAR key[200];
  592. long ndx;
  593. _bstr_t srcPath;
  594. IIManageDBPtr pDB;
  595. IVarSetPtr pVarSetTemp(CLSID_VarSet);
  596. IUnknown * pUnk = NULL;
  597. hr = pDB.CreateInstance(CLSID_IManageDB);
  598. if ( SUCCEEDED(hr) )
  599. {
  600. hr = pVarSetTemp.QueryInterface(IID_IUnknown,&pUnk);
  601. if ( SUCCEEDED(hr) )
  602. {
  603. hr = pDB->raw_GetMigratedObjects(actionID,&pUnk);
  604. }
  605. if ( SUCCEEDED(hr) )
  606. {
  607. pUnk->Release();
  608. srcPath = L"Test";
  609. swprintf(key,L"MigratedObjects");
  610. long numMigrated = pVarSetTemp->get(key);
  611. for ( ndx = 0 ; srcPath.length() ; ndx++ )
  612. {
  613. swprintf(key,L"MigratedObjects.%d.%s",ndx,GET_STRING(DB_SourceAdsPath));
  614. srcPath = pVarSetTemp->get(key);
  615. if ( srcPath.length() )
  616. {
  617. // get the object type
  618. swprintf(key,L"MigratedObjects.%d.%s",ndx,GET_STRING(DB_Type));
  619. _bstr_t text = pVarSetTemp->get(key);
  620. swprintf(key,L"Accounts.%ld.Type",ndx);
  621. //work-around a fix that places the sourcepath for an
  622. //NT 4.0 computer migration
  623. if ((text != _bstr_t(L"computer")) || (wcsncmp(L"WinNT://", (WCHAR*)srcPath, 8)))
  624. {
  625. // set the object type in the account list
  626. pVarSet->put(key,text);
  627. // copy the source path to the account list
  628. swprintf(key,L"Accounts.%ld",ndx);
  629. pVarSet->put(key,srcPath);
  630. // set the target path in the account list
  631. swprintf(key,L"MigratedObjects.%d.%s",ndx,GET_STRING(DB_TargetAdsPath));
  632. text = pVarSetTemp->get(key);
  633. swprintf(key,L"Accounts.%ld.TargetName",ndx);
  634. pVarSet->put(key,text);
  635. }
  636. }
  637. }
  638. swprintf(key,GET_STRING(DCTVS_Accounts_NumItems));
  639. pVarSet->put(key,numMigrated);
  640. }
  641. }
  642. return hr;
  643. }
  644. HRESULT CMigrator::ConstructUndoVarSet(IVarSet * pVarSetIn,IVarSet * pVarSetOut)
  645. {
  646. HRESULT hr = S_OK;
  647. IVarSet * pTemp = NULL;
  648. _bstr_t origSource;
  649. _bstr_t origTarget;
  650. _bstr_t origSourceDns;
  651. _bstr_t origTargetDns;
  652. _bstr_t temp;
  653. _bstr_t temp2;
  654. long actionID = pVarSetIn->get(L"ActionID");
  655. // general options
  656. // mark the varset as an undo operation
  657. pVarSetOut->put(GET_BSTR(DCTVS_Options_Undo),GET_BSTR(IDS_YES));
  658. temp = pVarSetIn->get(GET_BSTR(DCTVS_Options_NoChange));
  659. if ( !UStrICmp(temp,GET_STRING(IDS_YES)) )
  660. {
  661. // for a no-change mode operation, there's nothing to undo!
  662. return hr;
  663. }
  664. // swap the source and target domains
  665. origSource = pVarSetIn->get(GET_BSTR(DCTVS_Options_SourceDomain));
  666. origTarget = pVarSetIn->get(GET_BSTR(DCTVS_Options_TargetDomain));
  667. origSourceDns = pVarSetIn->get(GET_BSTR(DCTVS_Options_SourceDomainDns));
  668. origTargetDns = pVarSetIn->get(GET_BSTR(DCTVS_Options_TargetDomainDns));
  669. temp = pVarSetIn->get(GET_BSTR(DCTVS_Options_Logfile));
  670. temp2 = pVarSetIn->get(GET_BSTR(DCTVS_Options_DispatchLog));
  671. pVarSetOut->put(GET_BSTR(DCTVS_Options_Logfile),temp);
  672. // For inter-forest, leave the domain names as they were
  673. pVarSetOut->put(GET_BSTR(DCTVS_Options_SourceDomain),origSource);
  674. pVarSetOut->put(GET_BSTR(DCTVS_Options_TargetDomain),origTarget);
  675. pVarSetOut->put(GET_BSTR(DCTVS_Options_SourceDomainDns),origSourceDns);
  676. pVarSetOut->put(GET_BSTR(DCTVS_Options_TargetDomainDns),origTargetDns);
  677. // copy the account list
  678. hr = pVarSetIn->raw_getReference(GET_BSTR(DCTVS_Accounts),&pTemp);
  679. if ( SUCCEEDED(hr) )
  680. {
  681. hr = pVarSetOut->raw_ImportSubTree(GET_BSTR(DCTVS_Accounts),pTemp);
  682. if ( SUCCEEDED(hr) )
  683. {
  684. BuildAccountListForUndo(pVarSetOut,actionID);
  685. }
  686. pTemp->Release();
  687. }
  688. hr = pVarSetIn->raw_getReference(SysAllocString(L"AccountOptions"),&pTemp);
  689. if ( SUCCEEDED(hr) )
  690. {
  691. hr = pVarSetOut->raw_ImportSubTree(SysAllocString(L"AccountOptions"),pTemp);
  692. pTemp->Release();
  693. }
  694. // and the server list
  695. hr = pVarSetIn->raw_getReference(GET_BSTR(DCTVS_Servers),&pTemp);
  696. if ( SUCCEEDED(hr) )
  697. {
  698. hr = pVarSetOut->raw_ImportSubTree(GET_BSTR(DCTVS_Servers),pTemp);
  699. if ( SUCCEEDED(hr) )
  700. {
  701. ProcessServerListForUndo(pVarSetOut);
  702. pTemp->Release();
  703. }
  704. }
  705. LONG bSameForest = FALSE;
  706. MCSDCTWORKEROBJECTSLib::IAccessCheckerPtr pAccess;
  707. hr = pAccess.CreateInstance(__uuidof(MCSDCTWORKEROBJECTSLib::AccessChecker));
  708. if ( SUCCEEDED(hr) )
  709. {
  710. hr = pAccess->raw_IsInSameForest(origSourceDns,origTargetDns,&bSameForest);
  711. if ( hr == 8250 )
  712. {
  713. hr = 0;
  714. bSameForest = FALSE;
  715. }
  716. }
  717. if ( SUCCEEDED(hr) )
  718. {
  719. // for account migration, need to check whether we're cloning, or moving accounts
  720. if ( ! bSameForest ) // cloning accounts
  721. {
  722. // Since we cloned the accounts we need to delete the target accounts.
  723. // We will call the account replicator to do this. We will also call
  724. // the undo function on all the registered extensions. This way the extensions
  725. // will have a chance to cleanup after themselves in cases of UNDO.
  726. pVarSetOut->put(GET_BSTR(DCTVS_Options_SourceDomain),origSource);
  727. pVarSetOut->put(GET_BSTR(DCTVS_Options_TargetDomain),origTarget);
  728. }
  729. else // moving, using moveObject
  730. {
  731. // swap the source and target, and move them back, using the same options as before
  732. pVarSetOut->put(GET_BSTR(DCTVS_Options_SourceDomain),origTarget);
  733. pVarSetOut->put(GET_BSTR(DCTVS_Options_TargetDomain),origSource);
  734. pVarSetOut->put(GET_BSTR(DCTVS_Options_SourceDomainDns),origTargetDns);
  735. pVarSetOut->put(GET_BSTR(DCTVS_Options_TargetDomainDns),origSourceDns);
  736. }
  737. }
  738. // if migrating computers, swap the source and target domains, and call the dispatcher again to move them back to the source domain
  739. _bstr_t comp = pVarSetIn->get(GET_BSTR(DCTVS_AccountOptions_CopyComputers));
  740. if ( !UStrICmp(comp,GET_STRING(IDS_YES)) )
  741. {
  742. pVarSetOut->put(GET_BSTR(DCTVS_Options_SourceDomain),origTarget);
  743. pVarSetOut->put(GET_BSTR(DCTVS_Options_TargetDomain),origSource);
  744. pVarSetOut->put(GET_BSTR(DCTVS_Options_DispatchLog),temp2);
  745. pVarSetOut->put(GET_BSTR(DCTVS_Options_Wizard),L"computer");
  746. }
  747. // security translation - don't undo
  748. return S_OK;
  749. }
  750. HRESULT CMigrator::SetReportDataInRegistry(WCHAR const * reportName,WCHAR const * filename)
  751. {
  752. TRegKey hKeyReports;
  753. DWORD rc;
  754. rc = hKeyReports.Open(GET_STRING(IDS_REGKEY_REPORTS));
  755. // if the "Reports" registry key does not already exist, create it
  756. if ( rc == ERROR_FILE_NOT_FOUND )
  757. {
  758. rc = hKeyReports.Create(GET_STRING(IDS_REGKEY_REPORTS));
  759. }
  760. if ( ! rc )
  761. {
  762. rc = hKeyReports.ValueSetStr(reportName,filename);
  763. }
  764. return HRESULT_FROM_WIN32(rc);
  765. }
  766. HRESULT CMigrator::RunReports(IVarSet * pVarSet)
  767. {
  768. HRESULT hr = S_OK;
  769. _bstr_t directory = pVarSet->get(GET_BSTR(DCTVS_Reports_Directory));
  770. _bstr_t srcdm = pVarSet->get(GET_BSTR(DCTVS_Options_SourceDomain));
  771. _bstr_t tgtdm = pVarSet->get(GET_BSTR(DCTVS_Options_TargetDomain));
  772. _bstr_t srcdomainDNS = pVarSet->get(GET_BSTR(DCTVS_Options_SourceDomainDns));
  773. long lAutoCloseHideDialogs = pVarSet->get(GET_BSTR(DCTVS_Options_AutoCloseHideDialogs));
  774. IIManageDBPtr pDB;
  775. int ver;
  776. BOOL bNT4Dom = FALSE;
  777. CWorking tempDlg(IDS_NAMECONFLICTS);
  778. CWnd * wnd = NULL;
  779. MSG msg;
  780. if (lAutoCloseHideDialogs == 0)
  781. {
  782. tempDlg.Create(IDD_PLEASEWAIT);
  783. tempDlg.ShowWindow(SW_SHOW);
  784. tempDlg.m_strMessage.LoadString(IDS_STATUS_GeneratingReports);
  785. tempDlg.UpdateData(FALSE);
  786. wnd = AfxGetMainWnd();
  787. while ( wnd && PeekMessage( &msg, wnd->m_hWnd, 0, 0, PM_NOREMOVE ) )
  788. {
  789. if ( ! AfxGetApp()->PumpMessage() )
  790. {
  791. break;
  792. }
  793. }
  794. AfxGetApp()->DoWaitCursor(0);
  795. }
  796. //get the source domain OS version
  797. ver = GetOSVersionForDomain(srcdomainDNS);
  798. if (ver < 5)
  799. bNT4Dom = TRUE;
  800. hr = pDB.CreateInstance(CLSID_IManageDB);
  801. if ( SUCCEEDED(hr) )
  802. {
  803. // Migrated users and groups report
  804. _bstr_t text = pVarSet->get(GET_BSTR(DCTVS_Reports_MigratedAccounts));
  805. if ( !UStrICmp(text,GET_STRING(IDS_YES)) )
  806. {
  807. // run the migrated users and groups report
  808. CString filename;
  809. filename = (WCHAR*)directory;
  810. if ( filename[filename.GetLength()-1] != L'\\' )
  811. filename += L"\\";
  812. filename += L"MigrAcct.htm";
  813. hr = pDB->raw_GenerateReport(SysAllocString(L"MigratedAccounts"),filename.AllocSysString(), srcdm, tgtdm, bNT4Dom);
  814. if ( SUCCEEDED(hr) )
  815. {
  816. SetReportDataInRegistry(L"MigratedAccounts",filename);
  817. }
  818. }
  819. // migrated computers report
  820. text = pVarSet->get(GET_BSTR(DCTVS_Reports_MigratedComputers));
  821. if ( !UStrICmp(text,GET_STRING(IDS_YES)) )
  822. {
  823. // run the migrated computers report
  824. CString filename;
  825. filename = (WCHAR*)directory;
  826. if ( filename[filename.GetLength()-1] != L'\\' )
  827. filename += L"\\";
  828. filename += L"MigrComp.htm";
  829. hr = pDB->raw_GenerateReport(SysAllocString(L"MigratedComputers"),filename.AllocSysString(), srcdm, tgtdm, bNT4Dom);
  830. if ( SUCCEEDED(hr) )
  831. {
  832. SetReportDataInRegistry(L"MigratedComputers",filename);
  833. }
  834. }
  835. // expired computers report
  836. text = pVarSet->get(GET_BSTR(DCTVS_Reports_ExpiredComputers));
  837. if ( !UStrICmp(text,GET_STRING(IDS_YES)) )
  838. {
  839. // run the expired computers report
  840. CString filename;
  841. // clear the extra settings from the varset
  842. pVarSet->put(GET_BSTR(DCTVS_GatherInformation_ComputerPasswordAge),SysAllocString(L""));
  843. filename = (WCHAR*)directory;
  844. if ( filename[filename.GetLength()-1] != L'\\' )
  845. filename += L"\\";
  846. filename += L"ExpComp.htm";
  847. hr = pDB->raw_GenerateReport(SysAllocString(L"ExpiredComputers"),filename.AllocSysString(), srcdm, tgtdm, bNT4Dom);
  848. if ( SUCCEEDED(hr) )
  849. {
  850. SetReportDataInRegistry(L"ExpiredComputers",filename);
  851. }
  852. }
  853. // account references report
  854. text = pVarSet->get(GET_BSTR(DCTVS_Reports_AccountReferences));
  855. if ( !UStrICmp(text,GET_STRING(IDS_YES)) )
  856. {
  857. // run the account references report
  858. CString filename;
  859. filename = (WCHAR*)directory;
  860. if ( filename[filename.GetLength()-1] != L'\\' )
  861. filename += L"\\";
  862. filename += L"AcctRefs.htm";
  863. hr = pDB->raw_GenerateReport(SysAllocString(L"AccountReferences"),filename.AllocSysString(), srcdm, tgtdm, bNT4Dom);
  864. if ( SUCCEEDED(hr) )
  865. {
  866. SetReportDataInRegistry(L"AccountReferences",filename);
  867. }
  868. // clear the extra settings from the varset
  869. pVarSet->put(GET_BSTR(DCTVS_Security_GatherInformation),GET_BSTR(IDS_No));
  870. pVarSet->put(GET_BSTR(DCTVS_Security_ReportAccountReferences),GET_BSTR(IDS_No));
  871. }
  872. // name conflict report
  873. text = pVarSet->get(GET_BSTR(DCTVS_Reports_NameConflicts));
  874. if ( !UStrICmp(text,GET_STRING(IDS_YES)) )
  875. {
  876. if (lAutoCloseHideDialogs == 0)
  877. {
  878. AfxGetApp()->DoWaitCursor(1);
  879. // run the name conflicts report
  880. tempDlg.m_strMessage.LoadString(IDS_STATUS_Gathering_NameConf);
  881. tempDlg.UpdateData(FALSE);
  882. while ( wnd && PeekMessage( &msg, wnd->m_hWnd, 0, 0, PM_NOREMOVE ) )
  883. {
  884. if ( ! AfxGetApp()->PumpMessage() )
  885. {
  886. break;
  887. }
  888. }
  889. }
  890. //fill the account table in the database
  891. PopulateDomainDBs(pVarSet);
  892. if (lAutoCloseHideDialogs == 0)
  893. {
  894. tempDlg.m_strMessage.LoadString(IDS_STATUS_GeneratingReports);
  895. tempDlg.UpdateData(FALSE);
  896. while ( wnd && PeekMessage( &msg, wnd->m_hWnd, 0, 0, PM_NOREMOVE ) )
  897. {
  898. if ( ! AfxGetApp()->PumpMessage() )
  899. {
  900. break;
  901. }
  902. }
  903. AfxGetApp()->DoWaitCursor(0);
  904. }
  905. CString filename = (WCHAR*)directory;
  906. if ( filename[filename.GetLength()-1] != L'\\' )
  907. filename += L"\\";
  908. filename += L"NameConf.htm";
  909. hr = pDB->raw_GenerateReport(SysAllocString(L"NameConflicts"),filename.AllocSysString(), srcdm, tgtdm, bNT4Dom);
  910. if ( SUCCEEDED(hr) )
  911. {
  912. SetReportDataInRegistry(L"NameConflicts",filename);
  913. }
  914. }
  915. if (lAutoCloseHideDialogs == 0)
  916. {
  917. tempDlg.ShowWindow(SW_HIDE);
  918. }
  919. }
  920. if (lAutoCloseHideDialogs == 0)
  921. {
  922. AfxGetApp()->DoWaitCursor(-1);
  923. }
  924. return hr;
  925. }
  926. //--------------------------------------------------------------------------
  927. // PreProcessDispatcher : Pre processor swaps the source and target domains
  928. // in case of UNDO so that the computers can be
  929. // joined back to the source domain.
  930. //--------------------------------------------------------------------------
  931. void CMigrator::PreProcessDispatcher(IVarSet * pVarSet)
  932. {
  933. _bstr_t sUndo = pVarSet->get(L"Options.Wizard");
  934. // In the service account migration wizard, turn off any security translation tasks
  935. if ( !_wcsicmp(sUndo,L"service") )
  936. {
  937. IVarSet * pVS2 = NULL;
  938. HRESULT hr = pVarSet->raw_getReference(L"Security",&pVS2);
  939. if ( SUCCEEDED(hr) )
  940. {
  941. pVS2->Clear();
  942. pVS2->Release();
  943. }
  944. }
  945. }
  946. //--------------------------------------------------------------------------
  947. // PostProcessDispatcher : Swaps the source and target domains back. Also sets
  948. // the Undo option to no.
  949. //--------------------------------------------------------------------------
  950. void CMigrator::PostProcessDispatcher(IVarSet * pVarSet)
  951. {
  952. _bstr_t sUndo = pVarSet->get(L"Options.Wizard");
  953. _bstr_t origSource = pVarSet->get(GET_BSTR(DCTVS_Options_SourceDomain));
  954. _bstr_t origTarget = pVarSet->get(GET_BSTR(DCTVS_Options_TargetDomain));
  955. if ( !_wcsicmp(sUndo, L"undo") )
  956. {
  957. pVarSet->put(GET_BSTR(DCTVS_Options_SourceDomain), origTarget);
  958. pVarSet->put(GET_BSTR(DCTVS_Options_TargetDomain), origSource);
  959. }
  960. }
  961. void CMigrator::PreProcessForReporting(IVarSet * pVarSet)
  962. {
  963. _bstr_t text = pVarSet->get(GET_BSTR(DCTVS_Reports_Generate));
  964. IVarSet * pVs = NULL;
  965. if ( !UStrICmp(text,GET_STRING(IDS_YES)) )
  966. {
  967. // we are generating reports
  968. // some reports require additional information gathering. We will set up the necessary varset
  969. // keys to gather the information
  970. text = pVarSet->get(GET_BSTR(DCTVS_Reports_ExpiredComputers));
  971. if ( !UStrICmp(text,GET_STRING(IDS_YES)))
  972. {
  973. // we need to gather the computer password age from the computers in the domain
  974. pVarSet->put(GET_BSTR(DCTVS_GatherInformation_ComputerPasswordAge),GET_BSTR(IDS_YES));
  975. }
  976. text = pVarSet->get(GET_BSTR(DCTVS_Reports_AccountReferences));
  977. if ( !UStrICmp(text,GET_STRING(IDS_YES)))
  978. {
  979. // clean up all the Security translation flags so that we dont end up doing
  980. // something that we were not supposed to.
  981. HRESULT hr = pVarSet->raw_getReference(GET_BSTR(DCTVS_Security), &pVs);
  982. if ( pVs )
  983. {
  984. pVs->Clear();
  985. pVs->Release();
  986. }
  987. // for this one, we need to gather information from the selected computers
  988. pVarSet->put(GET_BSTR(DCTVS_Security_GatherInformation),GET_BSTR(IDS_YES));
  989. pVarSet->put(GET_BSTR(DCTVS_Security_ReportAccountReferences),GET_BSTR(IDS_YES));
  990. pVarSet->put(GET_BSTR(DCTVS_Security_TranslateFiles),GET_BSTR(IDS_YES));
  991. pVarSet->put(GET_BSTR(DCTVS_Security_TranslateShares),GET_BSTR(IDS_YES));
  992. pVarSet->put(GET_BSTR(DCTVS_Security_TranslatePrinters),GET_BSTR(IDS_YES));
  993. pVarSet->put(GET_BSTR(DCTVS_Security_TranslateLocalGroups),GET_BSTR(IDS_YES));
  994. pVarSet->put(GET_BSTR(DCTVS_Security_TranslateRegistry),GET_BSTR(IDS_YES));
  995. }
  996. }
  997. }
  998. HRESULT CMigrator::TrimMigratingComputerList(IVarSet * pVarSet, bool* bAnyToDispatch)
  999. {
  1000. // this functions checks each computer to be migrated, and does not migrate it if the account was not successfully copied
  1001. HRESULT hr = S_OK;
  1002. _bstr_t text;
  1003. WCHAR key[100];
  1004. long val,i;
  1005. IIManageDBPtr pDB;
  1006. _bstr_t srcDomain;
  1007. _bstr_t tgtDomain;
  1008. _bstr_t computer;
  1009. long actionID = pVarSet->get(L"ActionID");
  1010. CString temp;
  1011. _bstr_t origSource = pVarSet->get(GET_BSTR(DCTVS_Options_SourceDomain));
  1012. _bstr_t origTarget = pVarSet->get(GET_BSTR(DCTVS_Options_TargetDomain));
  1013. *bAnyToDispatch = false;
  1014. text = pVarSet->get(GET_BSTR(DCTVS_Options_Undo));
  1015. if (! UStrICmp(text,GET_STRING(IDS_YES)))
  1016. {
  1017. // don't trim on undo's, just reverse the domain affiliations
  1018. // return S_OK;
  1019. bool bFound = false;
  1020. long numServers = pVarSet->get(GET_BSTR(DCTVS_Servers_NumItems));
  1021. //for each server, see if it is in the account list (only successfully
  1022. //migrated computers are listed in the account list)
  1023. for (i = 0; i < numServers; i++)
  1024. {
  1025. bFound = false;
  1026. //get this servers name
  1027. swprintf(key,GET_STRING(DCTVSFmt_Servers_D),i);
  1028. text = pVarSet->get(key);
  1029. //get rid of leading "\\"
  1030. temp = (WCHAR*)text;
  1031. wcscpy((WCHAR*)text, temp.Right(temp.GetLength()-2));
  1032. long numAccts = pVarSet->get(GET_BSTR(DCTVS_Accounts_NumItems));
  1033. //see if that name is in the accounts list
  1034. _bstr_t text2;
  1035. for (val = 0; ((val < numAccts) && (!bFound)); val++)
  1036. {
  1037. swprintf(key,GET_STRING(DCTVSFmt_Accounts_D),val);
  1038. text2 = pVarSet->get(key);
  1039. //W2K machine accounts are LDAP paths, so check for the actual name
  1040. //in that path and compare with it
  1041. if ( !wcsncmp(L"LDAP://", text2, 7))
  1042. {
  1043. CString sAccount = (WCHAR*)text2;
  1044. int nIndex;
  1045. if ((nIndex = sAccount.Find(L"/CN=")) != -1)//if found
  1046. {
  1047. sAccount = sAccount.Right(sAccount.GetLength() - nIndex - wcslen(L"/CN="));
  1048. if ((nIndex = sAccount.Find(L',')) != -1)
  1049. text2 = sAccount.Left(nIndex);
  1050. }
  1051. }
  1052. if (! UStrICmp((WCHAR*)text,(WCHAR*)text2))
  1053. bFound = true;
  1054. }
  1055. swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_SkipDispatch_D),i);
  1056. if (!bFound)
  1057. pVarSet->put(key,GET_BSTR(IDS_YES));
  1058. else
  1059. {
  1060. *bAnyToDispatch = true;
  1061. pVarSet->put(key,GET_BSTR(IDS_No));
  1062. }
  1063. }
  1064. return S_OK;
  1065. }
  1066. text = pVarSet->get(GET_BSTR(DCTVS_Options_NoChange));
  1067. if (! UStrICmp(text,GET_STRING(IDS_YES)))
  1068. {
  1069. // don't need to trim in nochange mode
  1070. *bAnyToDispatch = true; //say yes run dispatcher if Nochange
  1071. return S_OK;
  1072. }
  1073. hr = pDB.CreateInstance(CLSID_IManageDB);
  1074. if ( FAILED(hr) )
  1075. {
  1076. return hr;
  1077. }
  1078. srcDomain = pVarSet->get(GET_BSTR(DCTVS_Options_SourceDomain));
  1079. tgtDomain = pVarSet->get(GET_BSTR(DCTVS_Options_TargetDomain));
  1080. *bAnyToDispatch = false; //indicate that so far no accounts to dispatch
  1081. val = pVarSet->get(GET_BSTR(DCTVS_Servers_NumItems));
  1082. for ( i = 0 ; i < val ; i++ )
  1083. {
  1084. //init the skipDispath flag to "No"
  1085. swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_SkipDispatch_D),i);
  1086. pVarSet->put(key,GET_BSTR(IDS_No));
  1087. swprintf(key,GET_STRING(DCTVSFmt_Servers_D),i);
  1088. computer = pVarSet->get(key);
  1089. swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_ChangeDomain_D),i);
  1090. text = pVarSet->get(key);
  1091. if (! UStrICmp(text,GET_STRING(IDS_YES)) )
  1092. {
  1093. // we are migrating this computer to a different domain
  1094. // check our database to verify that the computer account has been
  1095. // successfully migrated
  1096. computer += L"$";
  1097. IVarSetPtr pVS(CLSID_VarSet);
  1098. IUnknown * pUnk = NULL;
  1099. hr = pVS->QueryInterface(IID_IUnknown,(void**)&pUnk);
  1100. if ( SUCCEEDED(hr) )
  1101. {
  1102. if ( ((WCHAR*)computer)[0] == L'\\' )
  1103. {
  1104. // leave off the leading \\'s
  1105. hr = pDB->raw_GetAMigratedObject(SysAllocString(((WCHAR*)computer) + 2),srcDomain,tgtDomain,&pUnk);
  1106. }
  1107. else
  1108. {
  1109. hr = pDB->raw_GetAMigratedObject(computer,srcDomain,tgtDomain,&pUnk);
  1110. }
  1111. if ( hr == S_OK )
  1112. {
  1113. // the computer was found in the migrated objects table
  1114. // make sure we are using its correct target name, if it has been renamed
  1115. swprintf(key,L"MigratedObjects.TargetSamName");
  1116. _bstr_t targetName = pVS->get(key);
  1117. swprintf(key,L"MigratedObjects.SourceSamName");
  1118. _bstr_t sourceName = pVS->get(key);
  1119. long id = pVS->get(L"MigratedObjects.ActionID");
  1120. if ( UStrICmp((WCHAR*)sourceName,(WCHAR*)targetName) )
  1121. {
  1122. // the computer is being renamed
  1123. swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_RenameTo_D),i);
  1124. // strip off the $ from the end of the target name, if specified
  1125. WCHAR target[LEN_Account];
  1126. safecopy(target,(WCHAR*)targetName);
  1127. if ( target[UStrLen(target)-1] == L'$' )
  1128. {
  1129. target[UStrLen(target)-1] = 0;
  1130. }
  1131. pVarSet->put(key,target);
  1132. }
  1133. if ( id != actionID )
  1134. {
  1135. // the migration failed, but this computer had been migrated before
  1136. // don't migrate the computer because it's account in the target domain, won't be reset
  1137. // and it will therefore be locked out of the domain
  1138. swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_ChangeDomain_D),i);
  1139. pVarSet->put(key,GET_BSTR(IDS_No));
  1140. swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_Reboot_D),i);
  1141. pVarSet->put(key,GET_BSTR(IDS_No));
  1142. swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_SkipDispatch_D),i);
  1143. pVarSet->put(key,GET_BSTR(IDS_YES));
  1144. }
  1145. else
  1146. *bAnyToDispatch = true; //atleast one server for dispatcher
  1147. }
  1148. else
  1149. {
  1150. // the computer migration failed!
  1151. // don't migrate the computer because it won't have it's account in the target domain,
  1152. // and will therefore be locked out of the domain
  1153. pVarSet->put(key,GET_BSTR(IDS_No));
  1154. swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_Reboot_D),i);
  1155. pVarSet->put(key,GET_BSTR(IDS_No));
  1156. swprintf(key,GET_STRING(IDS_DCTVSFmt_Servers_SkipDispatch_D),i);
  1157. pVarSet->put(key,GET_BSTR(IDS_YES));
  1158. }
  1159. pUnk->Release();
  1160. }
  1161. }
  1162. else
  1163. *bAnyToDispatch = true; //atleast one server for dispatcher
  1164. }
  1165. return hr;
  1166. }
  1167. HRESULT CMigrator::PopulateAccounts(IVarSetPtr pVs)
  1168. {
  1169. _bstr_t origSource = pVs->get(GET_BSTR(DCTVS_Options_SourceDomain));
  1170. _bstr_t origTarget = pVs->get(GET_BSTR(DCTVS_Options_TargetDomain));
  1171. // Check if the source domain is NT4 or win2k
  1172. // if NT4 then call the NetObjEnum to enumerate the domain.
  1173. return S_OK;
  1174. }
  1175. //----------------------------------------------------------------------------
  1176. // PopulateDomainDBs : This function coordinates the populating of the Access
  1177. // DBs for both the source and target domains with the
  1178. // necessary fields from the AD.
  1179. //----------------------------------------------------------------------------
  1180. bool CMigrator::PopulateDomainDBs(
  1181. IVarSet * pVarSet //in- varset with domain names.
  1182. )
  1183. {
  1184. /* local variables */
  1185. _bstr_t srcdomain = pVarSet->get(GET_BSTR(DCTVS_Options_SourceDomain));
  1186. _bstr_t tgtdomain = pVarSet->get(GET_BSTR(DCTVS_Options_TargetDomain));
  1187. _bstr_t srcdomainDNS = pVarSet->get(GET_BSTR(DCTVS_Options_SourceDomainDns));
  1188. _bstr_t tgtdomainDNS = pVarSet->get(GET_BSTR(DCTVS_Options_TargetDomainDns));
  1189. /* function body */
  1190. //populate the DB for the source domain
  1191. PopulateADomainDB(srcdomain, srcdomainDNS, TRUE);
  1192. //populate the DB for the target domain
  1193. PopulateADomainDB(tgtdomain, tgtdomainDNS, FALSE);
  1194. return true;
  1195. }
  1196. //----------------------------------------------------------------------------
  1197. // PopulateADomainDB : This function looks up the necessary fields from the AD,
  1198. // using an MCSNetObjectEnum object, for the given domain
  1199. // and populates the corresponding Access DB with that info.
  1200. //----------------------------------------------------------------------------
  1201. bool CMigrator::PopulateADomainDB(
  1202. WCHAR const *domain, // in- NetBIOS name of domain to enumerate
  1203. WCHAR const *domainDNS, // in- DSN name of domain to enumerate
  1204. BOOL bSource
  1205. )
  1206. {
  1207. INetObjEnumeratorPtr pQuery(__uuidof(NetObjEnumerator));
  1208. IIManageDBPtr pDb;
  1209. WCHAR sPath[MAX_PATH];
  1210. WCHAR sQuery[MAX_PATH];
  1211. LPWSTR sData[] = { L"sAMAccountName", L"ADsPath" };
  1212. HRESULT hr;
  1213. long nElt = DIM(sData);
  1214. // int nobjectType;
  1215. BSTR HUGEP * pData = NULL;
  1216. SAFEARRAY * pszColNames;
  1217. IEnumVARIANT * pEnum = NULL;
  1218. _variant_t var;
  1219. DWORD dwFetch = 1;
  1220. bool bSuccess = false;
  1221. BSTR iterator[] = { L"USER", L"GROUP", L"COMPUTER" };
  1222. int i = 0;
  1223. int ver = 0;
  1224. bool bW2KDom = false;
  1225. // create instance of database manager
  1226. hr = pDb.CreateInstance(__uuidof(IManageDB));
  1227. if (FAILED(hr))
  1228. return false;
  1229. if ( bSource )
  1230. pDb->raw_ClearTable(L"SourceAccounts");
  1231. else
  1232. pDb->raw_ClearTable(L"TargetAccounts");
  1233. pDb->raw_OpenAccountsTable(bSource);
  1234. ver = GetOSVersionForDomain(domainDNS);
  1235. // iterate three times once to get USERS, GROUPS, COMPUTERS (mainly for WinNT)
  1236. while ( i < 3 )
  1237. {
  1238. // Set the LDAP path to the whole domain and then the query everything
  1239. if ( ver > 4 )
  1240. {
  1241. wsprintf(sPath, L"LDAP://%s", domainDNS);
  1242. wsprintf(sQuery, L"(objectClass=%s)", (WCHAR*) iterator[i]);
  1243. bW2KDom = true;
  1244. }
  1245. else
  1246. {
  1247. wsprintf(sPath, L"CN=%sS", (WCHAR*)iterator[i]);
  1248. wcscpy(sQuery, L"(objectClass=*)");
  1249. bW2KDom = false;
  1250. }
  1251. // Set the enumerator query
  1252. hr = pQuery->raw_SetQuery(sPath, const_cast<WCHAR*>(domainDNS), sQuery, ADS_SCOPE_SUBTREE, FALSE);
  1253. if (SUCCEEDED(hr))
  1254. {
  1255. // Create a safearray of columns we need from the enumerator.
  1256. SAFEARRAYBOUND bd = { nElt, 0 };
  1257. pszColNames = ::SafeArrayCreate(VT_BSTR, 1, &bd);
  1258. HRESULT hr = ::SafeArrayAccessData(pszColNames, (void HUGEP **)&pData);
  1259. if ( SUCCEEDED(hr) )
  1260. {
  1261. for( long i = 0; i < nElt; i++)
  1262. {
  1263. pData[i] = SysAllocString(sData[i]);
  1264. }
  1265. hr = ::SafeArrayUnaccessData(pszColNames);
  1266. }
  1267. if (SUCCEEDED(hr))
  1268. {
  1269. // Set the columns on the enumerator object.
  1270. hr = pQuery->raw_SetColumns(pszColNames);
  1271. }
  1272. }
  1273. if (SUCCEEDED(hr))
  1274. {
  1275. // Now execute.
  1276. hr = pQuery->raw_Execute(&pEnum);
  1277. }
  1278. //while we have more enumerated objects, get the enumerated fields
  1279. //for that object, save them in local variables, and add them to
  1280. //the appropriate DB
  1281. HRESULT hrEnum = S_OK;
  1282. while (hrEnum == S_OK && dwFetch > 0)
  1283. {
  1284. //get the enumerated fields for this current object
  1285. hrEnum = pEnum->Next(1, &var, &dwFetch);
  1286. if ( dwFetch > 0 && hrEnum == S_OK && ( var.vt & VT_ARRAY) )
  1287. {
  1288. _bstr_t sAdsPath;
  1289. _bstr_t sDN = L"";
  1290. _bstr_t sSAMName;
  1291. _bstr_t sRDN = L"";
  1292. _bstr_t sCanonicalName = L"";
  1293. _bstr_t sObjectClass;
  1294. BOOL bSave = TRUE;
  1295. // We now have a Variant containing an array of variants so we access the data
  1296. _variant_t * pVar;
  1297. pszColNames = V_ARRAY(&var);
  1298. SafeArrayAccessData(pszColNames, (void HUGEP **)&pVar);
  1299. //get the sAMAccountName field
  1300. sSAMName = pVar[0].bstrVal;
  1301. //create an RDN from the SAM name, will be replaced below with real RDN
  1302. //if not NT4.0 source domain
  1303. sRDN = L"CN=" + sSAMName;
  1304. //get the ADsPath field
  1305. sAdsPath = pVar[1].bstrVal;
  1306. //get the objectClass field
  1307. sObjectClass = (WCHAR*) iterator[i];
  1308. SafeArrayUnaccessData(pszColNames);
  1309. //for W2K domains, computers get enumerated twice, once as a computer
  1310. //and once as a user, so for any item of type computer we will not add
  1311. //it to the database, place the computer account name in a string list,
  1312. //and when we see that name again change it's type from user to computer.
  1313. //this code assumes the enumeration above enumerates users prior to computers
  1314. if (bW2KDom)
  1315. {
  1316. /* for W2K domain, get the RDN and Canonical Name of this object */
  1317. //connect to the object
  1318. IADs * pAds = NULL;
  1319. hr = ADsGetObject(sAdsPath, IID_IADs, (void**)&pAds);
  1320. if ( SUCCEEDED(hr) )
  1321. {
  1322. //get the CN
  1323. BSTR sName = NULL;
  1324. hr = pAds->get_Name(&sName);
  1325. if (SUCCEEDED(hr))
  1326. sRDN = _bstr_t(sName, false);
  1327. //get the DN
  1328. _variant_t varDN;
  1329. hr = pAds->Get(L"distinguishedName", &varDN);
  1330. if (SUCCEEDED(hr))
  1331. sDN = varDN.bstrVal;
  1332. pAds->Release();
  1333. }
  1334. //convert from DN to canonical name
  1335. if (sDN.length())
  1336. {
  1337. HANDLE hDs = NULL;
  1338. //bind to the domain
  1339. hr = DsBind(NULL, domainDNS, &hDs);
  1340. if (SUCCEEDED(hr))
  1341. {
  1342. PDS_NAME_RESULT pNamesOut = NULL;
  1343. WCHAR * pNamesIn[1];
  1344. pNamesIn[0] = (WCHAR *)sDN;
  1345. //convert the name
  1346. hr = DsCrackNames(hDs,
  1347. DS_NAME_FLAG_SYNTACTICAL_ONLY,
  1348. DS_FQDN_1779_NAME,
  1349. DS_CANONICAL_NAME,
  1350. 1,
  1351. pNamesIn,
  1352. &pNamesOut);
  1353. DsUnBind(&hDs); //unbind
  1354. if (SUCCEEDED(hr))
  1355. {
  1356. //if name converted, get it
  1357. if (pNamesOut->rItems[0].status == DS_NAME_NO_ERROR)
  1358. sCanonicalName = pNamesOut->rItems[0].pName;
  1359. DsFreeNameResult(pNamesOut); //release the buffer
  1360. }
  1361. }//end if Bound
  1362. }//end if got DN
  1363. /* adjust for computer issue */
  1364. //if computer, delete from user list so it will not be created again later
  1365. if (!_wcsicmp((WCHAR*)sObjectClass, L"computer"))
  1366. DeleteItemFromList(sSAMName);
  1367. //if user see if the name is in the computer list, if so,
  1368. //don't store in database
  1369. if ((!_wcsicmp((WCHAR*)sObjectClass, L"user")) && (((WCHAR*)sSAMName)[sSAMName.length() - 1] == L'$'))
  1370. {
  1371. //store fields for database entry in struct for later inclusion
  1372. DATABASE_ENTRY aListItem;
  1373. aListItem.m_domain = domain;
  1374. aListItem.m_sSAMName = sSAMName;
  1375. aListItem.m_sObjectClass = sObjectClass;
  1376. aListItem.m_sRDN = sRDN;
  1377. aListItem.m_sCanonicalName = sCanonicalName;
  1378. aListItem.m_bSource = bSource;
  1379. mUserList.AddTail(aListItem); //add item to user list
  1380. bSave = FALSE;
  1381. }
  1382. }
  1383. //use the DBManager Interface to store this object's fields
  1384. //in the appropriate database
  1385. if (bSave)
  1386. {
  1387. hr = pDb->raw_AddSourceObject(const_cast<WCHAR*>(domain), sSAMName, sObjectClass, sRDN, sCanonicalName, bSource);
  1388. if ( FAILED(hr) )
  1389. int x = 0;
  1390. }
  1391. VariantInit(&var);
  1392. }
  1393. }
  1394. if ( pEnum ) pEnum->Release();
  1395. i++;
  1396. } // while
  1397. //add each user in the user list to the database since it was not
  1398. //matched with a computer name already entered
  1399. POSITION pos = mUserList.GetHeadPosition();
  1400. DATABASE_ENTRY aListItem;
  1401. while (pos != NULL)
  1402. {
  1403. aListItem = mUserList.GetNext(pos);
  1404. hr = pDb->raw_AddSourceObject(aListItem.m_domain,
  1405. aListItem.m_sSAMName,
  1406. aListItem.m_sObjectClass,
  1407. aListItem.m_sRDN,
  1408. aListItem.m_sCanonicalName,
  1409. aListItem.m_bSource);
  1410. if ( FAILED(hr) )
  1411. int x = 0;
  1412. }
  1413. mUserList.RemoveAll();
  1414. pDb->raw_CloseAccountsTable();
  1415. return SUCCEEDED(hr);
  1416. }
  1417. DWORD CMigrator::GetOSVersionForDomain(WCHAR const * domain)
  1418. {
  1419. // Load DsGetDcName dynamically
  1420. DOMAIN_CONTROLLER_INFO * pSrcDomCtrlInfo = NULL;
  1421. WKSTA_INFO_100 * pInfo = NULL;
  1422. DWORD retVal = 0;
  1423. DSGETDCNAME DsGetDcName = NULL;
  1424. HMODULE hPro = LoadLibrary(L"NetApi32.dll");
  1425. if ( hPro )
  1426. {
  1427. DsGetDcName = (DSGETDCNAME)GetProcAddress(hPro, "DsGetDcNameW");
  1428. if ( DsGetDcName )
  1429. {
  1430. DWORD rc = DsGetDcName(
  1431. NULL ,// LPCTSTR ComputerName ?
  1432. const_cast<WCHAR*>(domain) ,// LPCTSTR DomainName
  1433. NULL ,// GUID *DomainGuid ?
  1434. NULL ,// LPCTSTR SiteName ?
  1435. 0 ,// ULONG Flags ?
  1436. &pSrcDomCtrlInfo // PDOMAIN_CONTROLLER_INFO *DomainControllerInfo
  1437. );
  1438. if ( !rc )
  1439. {
  1440. rc = NetWkstaGetInfo(pSrcDomCtrlInfo->DomainControllerName,100,(LPBYTE*)&pInfo);
  1441. if ( ! rc )
  1442. {
  1443. retVal = pInfo->wki100_ver_major;
  1444. NetApiBufferFree(pInfo);
  1445. }
  1446. NetApiBufferFree(pSrcDomCtrlInfo);
  1447. }
  1448. }
  1449. FreeLibrary(hPro);
  1450. }
  1451. return retVal;
  1452. }
  1453. BOOL CMigrator::DeleteItemFromList(WCHAR const * aName)
  1454. {
  1455. DATABASE_ENTRY aListItem;
  1456. CString itemName;
  1457. POSITION pos, lastpos;
  1458. BOOL bFound = FALSE;
  1459. pos = mUserList.GetHeadPosition();
  1460. while ((pos != NULL) && (!bFound))
  1461. {
  1462. lastpos = pos;
  1463. aListItem = mUserList.GetNext(pos);
  1464. itemName = (WCHAR*)(aListItem.m_sSAMName);
  1465. if (itemName == aName)
  1466. {
  1467. mUserList.RemoveAt(lastpos);
  1468. bFound = TRUE;
  1469. }
  1470. }
  1471. return bFound;
  1472. }
  1473. /*********************************************************************
  1474. * *
  1475. * Written by: Paul Thompson *
  1476. * Date: 11 OCT 2000 *
  1477. * *
  1478. * This function is responsible for opening the sid mapping file *
  1479. * whether it is anm ANSI or UNICODE file and return the file *
  1480. * pointer. *
  1481. * *
  1482. *********************************************************************/
  1483. //BEGIN RetrieveSrcDomainSid
  1484. void CMigrator::RetrieveSrcDomainSid(
  1485. IVarSet * pVarSet, //in- varset with domain names.
  1486. IIManageDBPtr pDb //in - pointer to the DB manager class
  1487. )
  1488. {
  1489. /* local variables */
  1490. IVarSetPtr pVarSetTemp(CLSID_VarSet);
  1491. IUnknown * pUnk = NULL;
  1492. HRESULT hr;
  1493. WCHAR key[200];
  1494. _bstr_t srcdomain = pVarSet->get(GET_BSTR(DCTVS_Options_SourceDomain));
  1495. _bstr_t sSrcDomain;
  1496. /* function body */
  1497. hr = pVarSetTemp.QueryInterface(IID_IUnknown,&pUnk);
  1498. if ( SUCCEEDED(hr) )
  1499. {
  1500. hr = pDb->raw_GetMigratedObjects(-1,&pUnk);
  1501. }
  1502. if ( SUCCEEDED(hr) )
  1503. {
  1504. pUnk->Release();
  1505. long lCnt = pVarSetTemp->get("MigratedObjects");
  1506. bool bFound = false;
  1507. for ( long l = 0; (l < lCnt) && (!bFound); l++)
  1508. {
  1509. //get the source domain
  1510. swprintf(key,L"MigratedObjects.%ld.%s",l,GET_STRING(DB_SourceDomain));
  1511. sSrcDomain = pVarSetTemp->get(key);
  1512. //if source domain matches, see if the sid was stored
  1513. if (!UStrICmp((WCHAR*)srcdomain, (WCHAR*)sSrcDomain))
  1514. {
  1515. //get the source domain Sid
  1516. swprintf(key,L"MigratedObjects.%ld.%s",l,GET_STRING(DB_SourceDomainSid));
  1517. _variant_t varSid = pVarSetTemp->get(key);
  1518. if (varSid.vt != VT_NULL)
  1519. {
  1520. _bstr_t txtSid = pVarSetTemp->get(key);
  1521. pVarSet->put(GET_BSTR(DCTVS_Options_SourceDomainSid),txtSid);
  1522. bFound = true;
  1523. }
  1524. }
  1525. }
  1526. }
  1527. }//END RetrieveSrcDomainSid
  1528. // IsAgentOrDispatcherProcessRunning
  1529. bool __stdcall IsAgentOrDispatcherProcessRunning()
  1530. {
  1531. bool bIsRunning = true;
  1532. CMigrationMutex mutexAgent(AGENT_MUTEX);
  1533. CMigrationMutex mutexDispatcher(DISPATCHER_MUTEX);
  1534. if (mutexAgent.ObtainOwnership(30000) && mutexDispatcher.ObtainOwnership(30000))
  1535. {
  1536. bIsRunning = false;
  1537. }
  1538. return bIsRunning;
  1539. }
  1540. // SetDomainControllers
  1541. //
  1542. // Sets preferred domain controllers to be used
  1543. // by the account replicator and dispatched agents
  1544. void __stdcall SetDomainControllers(IVarSetPtr& spVarSet)
  1545. {
  1546. // set source domain controller
  1547. _bstr_t strSourceServer = spVarSet->get(GET_BSTR(DCTVS_Options_SourceServerOverride));
  1548. if (strSourceServer.length() == 0)
  1549. {
  1550. _bstr_t strSourceDomain = spVarSet->get(GET_BSTR(DCTVS_Options_SourceDomain));
  1551. PDOMAIN_CONTROLLER_INFO pdci;
  1552. DWORD dwError = DsGetDcName(
  1553. NULL,
  1554. strSourceDomain,
  1555. NULL,
  1556. NULL,
  1557. DS_IS_FLAT_NAME|DS_RETURN_FLAT_NAME,
  1558. &pdci
  1559. );
  1560. if (dwError == ERROR_SUCCESS)
  1561. {
  1562. strSourceServer = pdci->DomainControllerName;
  1563. NetApiBufferFree(pdci);
  1564. }
  1565. }
  1566. spVarSet->put(GET_BSTR(DCTVS_Options_SourceServer), strSourceServer);
  1567. // set target domain controller
  1568. _bstr_t strTargetServer = spVarSet->get(GET_BSTR(DCTVS_Options_TargetServerOverride));
  1569. if (strTargetServer.length() == 0)
  1570. {
  1571. _bstr_t strTargetDomain = spVarSet->get(GET_BSTR(DCTVS_Options_TargetDomain));
  1572. PDOMAIN_CONTROLLER_INFO pdci;
  1573. DWORD dwError = DsGetDcName(
  1574. NULL,
  1575. strTargetDomain,
  1576. NULL,
  1577. NULL,
  1578. DS_IS_FLAT_NAME|DS_RETURN_FLAT_NAME,
  1579. &pdci
  1580. );
  1581. if (dwError == ERROR_SUCCESS)
  1582. {
  1583. strTargetServer = pdci->DomainControllerName;
  1584. NetApiBufferFree(pdci);
  1585. }
  1586. }
  1587. spVarSet->put(GET_BSTR(DCTVS_Options_TargetServer), strTargetServer);
  1588. }