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.

1788 lines
55 KiB

  1. /*Copyright (c) 1995-1999, Mission Critical Software, Inc. All rights reserved.
  2. ===============================================================================
  3. Module - SecTranslator.cpp
  4. System - Domain Consolidation Toolkit.
  5. Author - Christy Boles
  6. Created - 97/06/27
  7. Description - COM object that controls the security translation process.
  8. Reads the settings for the translation and performs the necessary
  9. operations.
  10. Updates -
  11. ===============================================================================
  12. */
  13. // SecTranslator.cpp : Implementation of CSecTranslator
  14. #include "stdafx.h"
  15. #include "WorkObj.h"
  16. #include "SecTrans.h"
  17. #include "Mcs.h"
  18. #include "EaLen.hpp"
  19. #include "BkupRstr.hpp"
  20. #include "exchange.hpp"
  21. #include "ErrDct.hpp"
  22. #include "MapiProf.hpp"
  23. #include "SDStat.hpp"
  24. #include "sd.hpp"
  25. #include "SecObj.hpp"
  26. #include "LGTrans.h"
  27. #include "RightsTr.h"
  28. #include "RegTrans.h"
  29. #include "RebootU.h"
  30. #include "TReg.hpp"
  31. #include "TxtSid.h"
  32. #include "LSAUtils.h"
  33. //#import "\bin\DBManager.tlb" no_namespace, named_guids
  34. #import "DBMgr.tlb" no_namespace, named_guids
  35. #include "varset_i.c"
  36. #ifdef _DEBUG
  37. #define new DEBUG_NEW
  38. #undef THIS_FILE
  39. static char THIS_FILE[] = __FILE__;
  40. #endif
  41. #ifndef IStatusObjPtr
  42. _COM_SMARTPTR_TYPEDEF(IStatusObj, __uuidof(IStatusObj));
  43. #endif
  44. /////////////////////////////////////////////////////////////////////////////
  45. // CSecTranslator
  46. #define BACKUP_FAILED 5
  47. #define BAD_PATH 6
  48. #define BAD_LOG 2
  49. #define LEN_SID 200
  50. extern TErrorDct err;
  51. // Defined in EnumVols.cpp
  52. bool // ret -true if name begins with "\\" has at least 3 total chars, and no other '\'
  53. IsMachineName(
  54. const LPWSTR name // in -possible machine name to check
  55. );
  56. DWORD // ret- OS return code
  57. GetProgramFilesDirectory(
  58. WCHAR * directory, // out- location of program files directory
  59. WCHAR const * computer // in - computer to find PF directory on
  60. )
  61. {
  62. TRegKey hklm;
  63. TRegKey key;
  64. DWORD rc;
  65. rc = hklm.Connect(HKEY_LOCAL_MACHINE,computer);
  66. if ( ! rc )
  67. {
  68. rc = key.Open(L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion",&hklm);
  69. }
  70. if ( !rc )
  71. {
  72. rc = key.ValueGetStr(L"ProgramFilesDir",directory,MAX_PATH * (sizeof WCHAR));
  73. }
  74. return rc;
  75. }
  76. BOOL
  77. IsLocallyInstalled()
  78. {
  79. BOOL bFound;
  80. TRegKey key;
  81. DWORD rc;
  82. rc = key.Open(GET_STRING(IDS_HKLM_DomainAdmin_Key));
  83. if ( ! rc )
  84. {
  85. bFound = TRUE;
  86. }
  87. else
  88. {
  89. bFound = FALSE;
  90. }
  91. return bFound;
  92. }
  93. DWORD // ret- OS return code
  94. GetLocalMachineName(WCHAR * computer)
  95. {
  96. DWORD rc = 0;
  97. WKSTA_INFO_100 * buf = NULL;
  98. rc = NetWkstaGetInfo(NULL,100,(LPBYTE*)&buf);
  99. if ( ! rc )
  100. {
  101. UStrCpy(computer,L"\\\\");
  102. UStrCpy(computer+2,buf->wki100_computername);
  103. NetApiBufferFree(buf);
  104. }
  105. return rc;
  106. }
  107. BOOL
  108. IsThisDispatcherMachine(IVarSet * pVarSet)
  109. {
  110. BOOL bIsIt = FALSE;
  111. _bstr_t dispatcher = pVarSet->get(GET_BSTR(DCTVS_Options_Credentials_Server));
  112. WCHAR localComputer[LEN_Computer] = L"";
  113. GetLocalMachineName(localComputer);
  114. if ( ! UStrICmp(dispatcher,localComputer) )
  115. {
  116. bIsIt = TRUE;
  117. }
  118. return bIsIt;
  119. }
  120. class TSession : public TNode
  121. {
  122. WCHAR server[LEN_Computer];
  123. public:
  124. TSession(WCHAR const * s) { safecopy(server,s); }
  125. WCHAR const * ServerName() { return server;}
  126. };
  127. BOOL
  128. CSecTranslator::EstablishASession(
  129. WCHAR const * serverName // in - computer to establish a session to
  130. )
  131. {
  132. BOOL bSuccess = TRUE;
  133. TSession * pSession = new TSession(serverName);
  134. if ( EstablishSession(serverName,m_domain,m_username,m_password,TRUE) )
  135. {
  136. m_ConnectionList.InsertBottom(pSession);
  137. }
  138. else
  139. {
  140. delete pSession;
  141. bSuccess = FALSE;
  142. err.SysMsgWrite(ErrW,GetLastError(),DCT_MSG_NO_SESSION_SD,serverName,GetLastError());
  143. }
  144. return bSuccess;
  145. }
  146. void
  147. CSecTranslator::CleanupSessions()
  148. {
  149. TNodeListEnum e;
  150. TSession * s;
  151. TSession * snext;
  152. for ( s = (TSession*)e.OpenFirst(&m_ConnectionList) ; s ; s = snext )
  153. {
  154. snext = (TSession*) e.Next();
  155. m_ConnectionList.Remove(s);
  156. // close the session
  157. EstablishSession(s->ServerName(),NULL,NULL,NULL,FALSE);
  158. delete s;
  159. }
  160. e.Close();
  161. }
  162. STDMETHODIMP
  163. CSecTranslator::Process(
  164. IUnknown * pWorkItem // in - varset describing translation options
  165. )
  166. {
  167. HRESULT hr = S_OK;
  168. IVarSetPtr pVarSet = pWorkItem;
  169. IStatusObjPtr pStatus = pVarSet->get(GET_BSTR(DCTVS_StatusObject));
  170. BOOL bReallyDoEverything = FALSE; // this (though not implemented yet) can be used
  171. // to provide a way to override the default behavior
  172. // of only processing file, etc. security when running as
  173. // local system. This would allow selective translation of items
  174. // on the local machine
  175. _bstr_t text = pVarSet->get(GET_BSTR(DCTVS_Options_Logfile));
  176. m_Args.LogFile(text);
  177. // Open the log file
  178. // use append mode since other processes may also be using this file
  179. if ( ! err.LogOpen(m_Args.LogFile(),1 /*append*/,0) )
  180. {
  181. return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  182. }
  183. LoadSettingsFromVarSet(pVarSet);
  184. // Set up the cache
  185. TSDResolveStats stat(m_Args.Cache(),m_Args.PathList(),pVarSet);
  186. if ( pStatus )
  187. {
  188. m_Args.Cache()->SetStatusObject(pStatus);
  189. }
  190. if ( m_Args.Cache()->IsTree() )
  191. {
  192. m_Args.Cache()->ToSorted();
  193. }
  194. m_Args.Cache()->SortedToScrambledTree();
  195. m_Args.Cache()->Sort(&RidComp);
  196. m_Args.Cache()->Balance();
  197. m_Args.Cache()->UnCancel();
  198. // Verify that the Cache got the source and target domain information it needs
  199. if ( ! m_Args.Cache()->IsInitialized() )
  200. {
  201. err.MsgWrite(ErrS,DCT_MSG_NO_CACHE_INFO);
  202. }
  203. else
  204. // if (1)
  205. {
  206. if ( m_Args.IsLocalSystem() || bReallyDoEverything )
  207. {// Do the required translations
  208. if ( m_Args.TranslateFiles() || m_Args.TranslateShares() || m_Args.TranslatePrinters() || m_Args.TranslateRecycler() )
  209. {
  210. // This runs the old FST code
  211. pVarSet->put(GET_BSTR(DCTVS_CurrentOperation),GET_BSTR(IDS_FST_OPERATION_TEXT));
  212. DoResolution(&stat);
  213. }
  214. if ( m_Args.TranslateLocalGroups() )
  215. {
  216. pVarSet->put(GET_BSTR(DCTVS_CurrentOperation),GET_BSTR(IDS_LGST_OPERATION_TEXT));
  217. DoLocalGroupResolution(&stat);
  218. }
  219. if ( m_Args.TranslateUserRights() )
  220. {
  221. pVarSet->put(GET_BSTR(DCTVS_CurrentOperation),GET_BSTR(IDS_URST_OPERATION_TEXT));
  222. DoUserRightsTranslation(&stat);
  223. }
  224. if ( m_Args.TranslateRegistry() )
  225. {
  226. pVarSet->put(GET_BSTR(DCTVS_CurrentOperation),GET_BSTR(IDS_REGST_OPERATION_TEXT));
  227. GetBkupRstrPriv((WCHAR*)NULL);
  228. GetPrivilege((WCHAR*)NULL,SE_SECURITY_NAME);
  229. TranslateRegistry(NULL,&m_Args,m_Args.Cache(),&stat);
  230. }
  231. if ( m_Args.TranslateUserProfiles() )
  232. {
  233. GetBkupRstrPriv((WCHAR*)NULL);
  234. GetPrivilege((WCHAR*)NULL,SE_SECURITY_NAME);
  235. TranslateLocalProfiles(&m_Args,m_Args.Cache(),&stat);
  236. }
  237. }
  238. else
  239. {
  240. // do exchange translation
  241. if ( m_Args.TranslateMailboxes() || m_Args.TranslateContainers() )
  242. {
  243. // This will run the old EST code
  244. pVarSet->put(GET_BSTR(DCTVS_CurrentOperation),GET_BSTR(IDS_EST_OPERATION_TEXT));
  245. DoExchangeResolution(&stat,pVarSet);
  246. }
  247. }
  248. }
  249. pVarSet->put(GET_BSTR(DCTVS_CurrentOperation),"");
  250. ExportStatsToVarSet(pVarSet,&stat);
  251. if ( *m_CacheFile )
  252. {
  253. BuildCacheFile(m_CacheFile);
  254. }
  255. // Record whether errors occurred
  256. long level = pVarSet->get(GET_BSTR(DCTVS_Results_ErrorLevel));
  257. if ( level < err.GetMaxSeverityLevel() )
  258. {
  259. pVarSet->put(GET_BSTR(DCTVS_Results_ErrorLevel),(LONG)err.GetMaxSeverityLevel());
  260. }
  261. err.LogClose();
  262. CleanupSessions();
  263. return hr;
  264. }
  265. void
  266. CSecTranslator::LoadSettingsFromVarSet(
  267. IVarSet * pVarSet // in - varset containing settings
  268. )
  269. {
  270. MCSASSERT(pVarSet);
  271. _bstr_t text;
  272. _bstr_t text2;
  273. DWORD val;
  274. try
  275. {
  276. m_Args.Reset();
  277. text = pVarSet->get(GET_BSTR(DCTVS_Options_LocalProcessingOnly));
  278. if ( !UStrICmp(text,GET_STRING(IDS_YES)) )
  279. {
  280. err.MsgWrite(0,DCT_MSG_LOCAL_MODE);
  281. m_LocalOnly = TRUE;
  282. m_Args.SetLocalMode(TRUE);
  283. text = pVarSet->get(GET_BSTR(DCTVS_Options_SourceDomainSid));
  284. safecopy(m_SourceSid,(WCHAR const *)text);
  285. text = pVarSet->get(GET_BSTR(DCTVS_Options_TargetDomainSid));
  286. safecopy(m_TargetSid,(WCHAR const *)text);
  287. }
  288. text = pVarSet->get(GET_BSTR(DCTVS_Options_SourceDomain));
  289. m_Args.Source(text);
  290. text = pVarSet->get(GET_BSTR(DCTVS_Options_TargetDomain));
  291. m_Args.Target(text);
  292. val = (LONG)pVarSet->get(GET_BSTR(DCTVS_Options_LogLevel));
  293. if ( val )
  294. m_Args.SetLogging(val);
  295. val = (LONG)pVarSet->get(L"Security.DebugLogLevel");
  296. if ( val )
  297. m_Args.SetLogging(val);
  298. text = pVarSet->get(GET_BSTR(DCTVS_Options_NoChange));
  299. if ( ! UStrICmp(text,GET_STRING(IDS_YES)) )
  300. {
  301. m_Args.SetWriteChanges(FALSE);
  302. }
  303. else
  304. {
  305. m_Args.SetWriteChanges(TRUE);
  306. }
  307. text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslationMode));
  308. if ( !UStrICmp(text,GET_STRING(IDS_Add)) )
  309. {
  310. m_Args.SetTranslationMode(ADD_SECURITY);
  311. }
  312. else if (! UStrICmp(text,GET_STRING(IDS_Replace)) )
  313. {
  314. m_Args.SetTranslationMode(REPLACE_SECURITY);
  315. }
  316. else if ( ! UStrICmp(text,GET_STRING(IDS_Remove)) )
  317. {
  318. m_Args.SetTranslationMode(REMOVE_SECURITY);
  319. }
  320. else
  321. {
  322. // Incorrect value - don't need to log this, just use replace
  323. // the log will show replace as the translation mode
  324. // err.MsgWrite(ErrE,DCT_MSG_BAD_TRANSLATION_MODE_S,(WCHAR*)text);
  325. }
  326. text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslateFiles));
  327. if ( !UStrICmp(text,GET_STRING(IDS_YES)) )
  328. {
  329. m_Args.TranslateFiles(TRUE);
  330. }
  331. else
  332. {
  333. m_Args.TranslateFiles(FALSE);
  334. }
  335. text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslateShares));
  336. if ( ! UStrICmp(text,GET_STRING(IDS_YES)) )
  337. {
  338. m_Args.TranslateShares(TRUE);
  339. }
  340. else
  341. {
  342. m_Args.TranslateShares(FALSE);
  343. }
  344. text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslatePrinters));
  345. if ( ! UStrICmp(text,GET_STRING(IDS_YES)) )
  346. {
  347. m_Args.TranslatePrinters(TRUE);
  348. }
  349. else
  350. {
  351. m_Args.TranslatePrinters(FALSE);
  352. }
  353. text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslateUserProfiles));
  354. if ( ! UStrICmp(text,GET_STRING(IDS_YES)) )
  355. {
  356. m_Args.TranslateUserProfiles(TRUE);
  357. m_Args.TranslateRecycler(TRUE);
  358. }
  359. else
  360. {
  361. m_Args.TranslateUserProfiles(FALSE);
  362. m_Args.TranslateRecycler(FALSE);
  363. }
  364. text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslateLocalGroups));
  365. if ( !UStrICmp(text,GET_STRING(IDS_YES)) )
  366. {
  367. m_Args.TranslateLocalGroups(TRUE);
  368. }
  369. else
  370. {
  371. m_Args.TranslateLocalGroups(FALSE);
  372. }
  373. text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslateRegistry));
  374. if (! UStrICmp(text,GET_STRING(IDS_YES)) )
  375. {
  376. m_Args.TranslateRegistry(TRUE);
  377. }
  378. else
  379. {
  380. m_Args.TranslateRegistry(FALSE);
  381. }
  382. val = (LONG)pVarSet->get(GET_BSTR(DCTVS_Servers_NumItems));
  383. for ( int i = 0 ; i < (int)val ; i++ )
  384. {
  385. WCHAR key[MAX_PATH];
  386. DWORD flags = 0;
  387. _bstr_t bStr;
  388. swprintf(key,GET_STRING(DCTVSFmt_Servers_D),i);
  389. bStr = key;
  390. text = pVarSet->get(bStr);
  391. if ( text.length() )
  392. {
  393. m_Args.PathList()->AddPath(text,flags);
  394. }
  395. }
  396. text = pVarSet->get(GET_BSTR(DCTVS_Security_GatherInformation));
  397. if ( !UStrICmp(text,GET_STRING(IDS_YES)) )
  398. {
  399. m_Args.Cache()->AddIfNotFound(TRUE);
  400. m_Args.SetWriteChanges(FALSE);
  401. m_Args.SetLogging(m_Args.LogSettings() & ~FILESTATS);
  402. }
  403. else
  404. {
  405. m_Args.Cache()->AddIfNotFound(FALSE);
  406. }
  407. // Exchange Security Translation settings
  408. text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslateMailboxes));
  409. if ( text.length() )
  410. {
  411. m_Args.TranslateMailboxes(TRUE);
  412. safecopy(m_Container,(WCHAR*)text);
  413. text = pVarSet->get(GET_BSTR(DCTVS_Security_MapiProfile));
  414. safecopy(m_Profile,(WCHAR*)text);
  415. }
  416. else
  417. {
  418. m_Args.TranslateMailboxes(FALSE);
  419. }
  420. text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslateContainers));
  421. if ( text.length() )
  422. {
  423. m_Args.TranslateContainers(TRUE);
  424. if ( ((WCHAR*)text)[0] == L'\\' && ((WCHAR*)text)[1] == L'\\' )
  425. safecopy(m_exchServer,(WCHAR*)text+2);
  426. else
  427. safecopy(m_exchServer,(WCHAR*)text);
  428. }
  429. else
  430. {
  431. m_Args.TranslateContainers(FALSE);
  432. }
  433. text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslateUserRights));
  434. if ( !UStrICmp(text,GET_STRING(IDS_YES)) )
  435. {
  436. m_Args.TranslateUserRights(TRUE);
  437. }
  438. text = pVarSet->get(GET_BSTR(DCTVS_Security_BuildCacheFile));
  439. if ( text.length() )
  440. {
  441. safecopy(m_CacheFile,(WCHAR*)text);
  442. }
  443. // Check for inconsistent arguments
  444. // Load the cache
  445. // There are 4 possible ways to populate the cache
  446. // 1. Use the list from the migrated objects table in our database
  447. // 2. We are given a list of accounts in the VarSet, under "Accounts.". This allows for renaming, but requires the most space
  448. // 3. We are given an input file that was generated by AR, in "Accounts.InputFile". This also allows for renaming, with less overall memory use.
  449. // 4. We are given a sid mapping, comma-seperated, file with source and target sids.
  450. text = pVarSet->get(GET_BSTR(DCTVS_Security_BuildCacheFile));
  451. text2 = pVarSet->get(GET_BSTR(DCTVS_AccountOptions_SecurityInputMOT));
  452. //if list is in the migrated objects table
  453. if ((!m_LocalOnly) && (!UStrICmp(text2,GET_STRING(IDS_YES))))
  454. {
  455. LoadMigratedObjects(pVarSet);
  456. }
  457. //else if a sid mapping file is being used
  458. else if ((!m_LocalOnly) && (UStrICmp(text2,GET_STRING(IDS_YES))))
  459. {
  460. m_Args.SetUsingMapFile(TRUE); //set the arg flag to indicate use of map file
  461. text2 = pVarSet->get(GET_BSTR(DCTVS_AccountOptions_SecurityMapFile));
  462. LoadCacheFromMapFile(text2, pVarSet);
  463. }
  464. // took out the not because gather information sets this to false.
  465. //else if ( !m_Args.Cache()->AddIfNotFound() ) // skip loading the cache if we're gathering information
  466. else if ( m_Args.Cache()->AddIfNotFound() ) // skip loading the cache if we're gathering information
  467. {
  468. if ( m_LocalOnly )
  469. {
  470. m_Args.Cache()->SetSourceAndTargetDomainsWithSids(m_Args.Source(),m_SourceSid,m_Args.Target(),m_TargetSid);
  471. }
  472. else
  473. {
  474. m_Args.Cache()->SetSourceAndTargetDomains(m_Args.Source(),m_Args.Target());
  475. }
  476. }
  477. else
  478. {
  479. text = pVarSet->get(GET_BSTR(DCTVS_Accounts_InputFile));
  480. if ( text.length() )
  481. {
  482. LoadCacheFromFile(text,pVarSet);
  483. }
  484. else
  485. {
  486. LoadCacheFromVarSet(pVarSet);
  487. }
  488. }
  489. }
  490. catch ( ... )
  491. {
  492. err.MsgWrite(ErrS,DCT_MSG_EXCEPTION_READING_VARSET);
  493. throw;
  494. }
  495. }
  496. void
  497. CSecTranslator::ExportStatsToVarSet(
  498. IVarSet * pVarSet, // in - varset to write stats to
  499. TSDResolveStats * stat // in - object containing stats
  500. )
  501. {
  502. _bstr_t filename;
  503. _bstr_t domain = pVarSet->get(GET_BSTR(DCTVS_Options_Credentials_Domain));
  504. _bstr_t username = pVarSet->get(GET_BSTR(DCTVS_Options_Credentials_UserName));
  505. _bstr_t password = pVarSet->get(GET_BSTR(DCTVS_Options_Credentials_Password));
  506. _bstr_t server = pVarSet->get(GET_BSTR(DCTVS_Options_Credentials_Server));
  507. _bstr_t share = pVarSet->get(GET_BSTR(DCTVS_Options_Credentials_Share));
  508. BOOL bSessEstablished;
  509. if ( username.length() && server.length() && share.length() )
  510. {
  511. bSessEstablished = EstablishSession(server, domain, username, password, TRUE);
  512. }
  513. filename = pVarSet->get(GET_BSTR(DCTVS_Security_ReportAccountReferences));
  514. stat->Report(m_Args.LogSummary(),m_Args.LogAccountDetails(),m_Args.LogPathDetails());
  515. if ( m_Args.NoChange() )
  516. {
  517. err.MsgWrite(0,DCT_MSG_NO_CHANGE_MODE);
  518. }
  519. stat->ReportToVarSet(pVarSet,m_Args.LogSettings() & SUMMARYSTATS);
  520. if ( filename.length() )
  521. {
  522. err.MsgWrite(0,DCT_MSG_EXPORTING_ACCOUNT_REFS_S,(WCHAR*)filename);
  523. m_Args.Cache()->ReportAccountReferences((WCHAR*)filename);
  524. }
  525. // if session was established, unestablish
  526. if (bSessEstablished)
  527. {
  528. EstablishSession(server, domain, username, password, FALSE);
  529. }
  530. long level = pVarSet->get(GET_BSTR(DCTVS_Results_ErrorLevel));
  531. if ( level < err.GetMaxSeverityLevel() )
  532. {
  533. pVarSet->put(GET_BSTR(DCTVS_Results_ErrorLevel),(LONG)err.GetMaxSeverityLevel());
  534. }
  535. }
  536. void
  537. CSecTranslator::DoResolution(
  538. TSDResolveStats * stat // in - object to write translation stats to
  539. )
  540. {
  541. // display confirmation message if writing changes
  542. int result;
  543. result = ResolveAll(&m_Args,stat);
  544. }
  545. void
  546. CSecTranslator::DoLocalGroupResolution(
  547. TSDResolveStats * stat // in - object to write translation stats to
  548. )
  549. {
  550. DWORD rc;
  551. TNodeListEnum tenum;
  552. TPathNode * tnode;
  553. if ( m_LocalOnly )
  554. {
  555. err.MsgWrite(0,DCT_MSG_TRANSLATING_LOCAL_GROUPS);
  556. rc = TranslateLocalGroups(NULL,&m_Args,m_Args.Cache(),stat);
  557. }
  558. else
  559. { // Enumerate the machines in the pathlist
  560. for (tnode = (TPathNode *)tenum.OpenFirst((TNodeList *)m_Args.PathList())
  561. ; tnode
  562. ; tnode = (TPathNode *)tenum.Next() )
  563. {
  564. if ( IsMachineName(tnode->GetPathName()) )
  565. {
  566. err.MsgWrite(0,DCT_MSG_TRANSLATING_LOCAL_GROUPS_ON_S,tnode->GetPathName());
  567. rc = TranslateLocalGroups(tnode->GetPathName(),&m_Args,m_Args.Cache(),stat);
  568. }
  569. }
  570. }
  571. tenum.Close();
  572. }
  573. void
  574. CSecTranslator::DoUserRightsTranslation(
  575. TSDResolveStats * stat // in - object to write stats to
  576. )
  577. {
  578. DWORD rc;
  579. TNodeListEnum tenum;
  580. TPathNode * tnode;
  581. if ( m_LocalOnly )
  582. {
  583. err.MsgWrite(0,DCT_MSG_TRANSLATING_USER_RIGHTS);
  584. rc = TranslateUserRights(NULL,&m_Args,m_Args.Cache(),stat);
  585. }
  586. else
  587. { // Enumerate the machines in the pathlist
  588. for (tnode = (TPathNode *)tenum.OpenFirst((TNodeList *)m_Args.PathList())
  589. ; tnode
  590. ; tnode = (TPathNode *)tenum.Next() )
  591. {
  592. if ( IsMachineName(tnode->GetPathName()) )
  593. {
  594. err.MsgWrite(0,DCT_MSG_TRANSLATING_RIGHTS_ON_S,tnode->GetPathName());
  595. rc = TranslateUserRights(tnode->GetPathName(),&m_Args,m_Args.Cache(),stat);
  596. }
  597. }
  598. }
  599. tenum.Close();
  600. }
  601. BOOL
  602. CSecTranslator::LoadCacheFromVarSet(
  603. IVarSet * pVarSet // in - varset containing account mapping
  604. )
  605. {
  606. BOOL bSuccess = TRUE;
  607. _bstr_t text;
  608. if ( m_LocalOnly )
  609. {
  610. m_Args.Cache()->SetSourceAndTargetDomainsWithSids(m_Args.Source(),m_SourceSid,m_Args.Target(),m_TargetSid);
  611. }
  612. else
  613. {
  614. m_Args.Cache()->SetSourceAndTargetDomains(m_Args.Source(),m_Args.Target());
  615. }
  616. m_Args.Cache()->ToSorted();
  617. // no wildcard filter specified. Use the explicit list of accounts
  618. long numAccounts = pVarSet->get(GET_BSTR(DCTVS_Accounts_NumItems));
  619. for ( int i = 0 ; i < numAccounts ; i++ )
  620. {
  621. WCHAR key[LEN_Path];
  622. WCHAR name[LEN_Account];
  623. WCHAR targetName[LEN_Account];
  624. WCHAR type[LEN_Path];
  625. short sType;
  626. swprintf(key,GET_STRING(DCTVSFmt_Accounts_D),i);
  627. text = pVarSet->get(key);
  628. safecopy(name,(WCHAR*)text);
  629. swprintf(key,GET_STRING(DCTVSFmt_Accounts_TargetName_D),i);
  630. text = pVarSet->get(key);
  631. safecopy(targetName,(WCHAR*)text);
  632. swprintf(key,GET_STRING(DCTVSFmt_Accounts_Type_D),i);
  633. text = pVarSet->get(key);
  634. safecopy(type,(WCHAR*)text);
  635. if (! UStrICmp(type,L"user") )
  636. sType = EA_AccountUser;
  637. else if (! UStrICmp(type,L"group") )
  638. sType = EA_AccountGroup;
  639. else
  640. sType = 0;
  641. m_Args.Cache()->InsertLast(name,0,targetName,0,sType);
  642. }
  643. if ( bSuccess && ! m_LocalOnly )
  644. {
  645. bSuccess = GetRIDsFromEA();
  646. }
  647. return bSuccess;
  648. }
  649. HRESULT CSecTranslator::LoadMigratedObjects(IVarSet * pVarSetIn)
  650. {
  651. HRESULT hr = S_OK;
  652. // this reads the migrated objects table from the database, and
  653. // constructs a mapping file to be used for security translation
  654. IIManageDBPtr pDB;
  655. IUnknown * pUnk = NULL;
  656. IVarSetPtr pVarSet(CLSID_VarSet);
  657. WCHAR strKey[MAX_PATH];
  658. long ndx = 0;
  659. _bstr_t srcSam = L"?";
  660. _bstr_t tgtSam = L"?";
  661. _bstr_t type;
  662. _bstr_t srcDom;
  663. _bstr_t tgtDom;
  664. // FILE * pFile = NULL;
  665. // BOOL bSuccess = TRUE;
  666. UCHAR srcEaServer[LEN_Computer];
  667. UCHAR tgtEaServer[LEN_Computer];
  668. _bstr_t text;
  669. safecopy(srcEaServer,m_Args.Source());
  670. safecopy(tgtEaServer,m_Args.Target());
  671. if ( m_LocalOnly )
  672. {
  673. m_Args.Cache()->SetSourceAndTargetDomainsWithSids(m_Args.Source(),m_SourceSid,m_Args.Target(),m_TargetSid);
  674. }
  675. else
  676. {
  677. m_Args.Cache()->SetSourceAndTargetDomains(m_Args.Source(),m_Args.Target());
  678. }
  679. m_Args.Cache()->ToSorted();
  680. hr = pDB.CreateInstance(CLSID_IManageDB);
  681. if ( SUCCEEDED(hr) )
  682. {
  683. hr = pVarSet->QueryInterface(IID_IUnknown,(void**)&pUnk);
  684. if ( SUCCEEDED(hr) )
  685. {
  686. hr = pDB->raw_GetMigratedObjects(-1,&pUnk);
  687. }
  688. if ( SUCCEEDED(hr) )
  689. {
  690. pVarSet = pUnk;
  691. pUnk->Release();
  692. short sType;
  693. long rid = 0;
  694. long rid2 = 0;
  695. // GetMigratedObjects returns the migrated objects in the varset as:
  696. // MigratedObjects.%ld.*
  697. for ( ndx = 0 ;srcSam.length() && tgtSam.length() ; ndx++ )
  698. {
  699. swprintf(strKey,L"MigratedObjects.%ld.%s",ndx,GET_STRING(DB_SourceDomain));
  700. srcDom = pVarSet->get(strKey);
  701. swprintf(strKey,L"MigratedObjects.%ld.%s",ndx,GET_STRING(DB_TargetDomain));
  702. tgtDom = pVarSet->get(strKey);
  703. swprintf(strKey,L"MigratedObjects.%ld.%s",ndx,GET_STRING(DB_SourceSamName));
  704. srcSam = pVarSet->get(strKey);
  705. swprintf(strKey,L"MigratedObjects.%ld.%s",ndx,GET_STRING(DB_TargetSamName));
  706. tgtSam = pVarSet->get(strKey);
  707. swprintf(strKey,L"MigratedObjects.%ld.%s",ndx,GET_STRING(DB_Type));
  708. type = pVarSet->get(strKey);
  709. swprintf(strKey,L"MigratedObjects.%ld.%s",ndx,GET_STRING(DB_SourceRid));
  710. rid = pVarSet->get(strKey);
  711. swprintf(strKey,L"MigratedObjects.%ld.%s",ndx,GET_STRING(DB_TargetRid));
  712. rid2 = pVarSet->get(strKey);
  713. if ( !UStrICmp(srcDom, m_Args.Source()) && !UStrICmp(tgtDom, m_Args.Target()) )
  714. {
  715. if ( !UStrICmp(type,L"user") || !UStrICmp(type,L"group") )
  716. {
  717. if (! UStrICmp(type,L"user") )
  718. sType = EA_AccountUser;
  719. else if (! UStrICmp(type,L"group") )
  720. sType = EA_AccountGroup;
  721. else
  722. sType = 0;
  723. m_Args.Cache()->InsertLast((WCHAR*)srcSam,rid,(WCHAR*)tgtSam,rid2,sType);
  724. }
  725. }
  726. }
  727. }
  728. }
  729. /* if ( SUCCEEDED(hr) )
  730. {
  731. GetRIDsFromEA();
  732. }
  733. */ return hr;
  734. }
  735. BOOL
  736. CSecTranslator::BuildCacheFile(
  737. WCHAR const * filename // in - file to write account mapping to
  738. )
  739. {
  740. BOOL bSuccess = TRUE;
  741. FILE * pFile;
  742. m_Args.Cache()->ToSorted();
  743. TNodeListEnum e;
  744. TRidNode * node;
  745. WCHAR type[LEN_Path];
  746. pFile = _wfopen(filename,L"wb");
  747. if ( pFile )
  748. {
  749. for ( node = (TRidNode*) e.OpenFirst(m_Args.Cache() ); node ; node = (TRidNode*)e.Next() )
  750. {
  751. switch ( node->Type() )
  752. {
  753. case EA_AccountUser:
  754. safecopy(type,L"user");
  755. break;
  756. case EA_AccountGroup:
  757. case EA_AccountGGroup:
  758. case EA_AccountLGroup:
  759. safecopy(type,L"group");
  760. break;
  761. default:
  762. type[0] = 0;
  763. break;
  764. }
  765. // if (!UStrICmp(node->GetAcctName(),node->GetTargetAcctName()))
  766. if ((UStrICmp(node->GetSrcDomSid(),L"")) && (UStrICmp(node->GetTgtDomSid(),L"")))
  767. {
  768. //account and domain names could be empty when using a sid
  769. //mapping file for security translation. A later scanf by
  770. //the agent will fail on a NULL name, so we will store "(UnKnown)"
  771. //instead and deal with that on the scanf-side
  772. WCHAR ssname[MAX_PATH];
  773. wcscpy(ssname, node->GetAcctName());
  774. if (!wcslen(ssname))
  775. wcscpy(ssname, GET_STRING(IDS_UnknownSid));
  776. WCHAR stname[MAX_PATH];
  777. wcscpy(stname, node->GetTargetAcctName());
  778. if (!wcslen(stname))
  779. wcscpy(stname, GET_STRING(IDS_UnknownSid));
  780. WCHAR ssdname[MAX_PATH];
  781. wcscpy(ssdname, node->GetSrcDomName());
  782. if (!wcslen(ssdname))
  783. wcscpy(ssdname, GET_STRING(IDS_UnknownSid));
  784. WCHAR stdname[MAX_PATH];
  785. wcscpy(stdname, node->GetTgtDomName());
  786. if (!wcslen(stdname))
  787. wcscpy(stdname, GET_STRING(IDS_UnknownSid));
  788. fwprintf(pFile,L"%s\t%s\t%s\t%lx\t%lx\t%lx\t%s\t%s\t%s\t%s\r\n",ssname,stname,type,
  789. 0, node->SrcRid(), node->TgtRid(), node->GetSrcDomSid(), node->GetTgtDomSid(),
  790. ssdname, stdname);
  791. }
  792. else
  793. {
  794. fwprintf(pFile,L"%s\t%s\t%s\t%lx\t%lx\t%lx\r\n",node->GetAcctName(),node->GetTargetAcctName(),type,
  795. 0, node->SrcRid(), node->TgtRid());
  796. }
  797. }
  798. e.Close();
  799. fclose(pFile);
  800. }
  801. else
  802. {
  803. bSuccess = FALSE;
  804. // DWORD rc = GetLastError();
  805. }
  806. return bSuccess;
  807. }
  808. BOOL
  809. CSecTranslator::LoadCacheFromFile(
  810. WCHAR const * filename, // in - file to read account mapping from
  811. IVarSet * pVarSet // in - pointer to varset
  812. )
  813. {
  814. BOOL bSuccess = TRUE;
  815. _bstr_t text;
  816. FILE * pFile;
  817. WCHAR sourceName[LEN_Account];
  818. WCHAR targetName[LEN_Account];
  819. WCHAR sourceDomSid[MAX_PATH];
  820. WCHAR targetDomSid[MAX_PATH];
  821. WCHAR sourceDomName[MAX_PATH];
  822. WCHAR targetDomName[MAX_PATH];
  823. WCHAR type[LEN_Account];
  824. DWORD status;
  825. int count = 0;
  826. BOOL bNeedRids = FALSE;
  827. WCHAR path[MAX_PATH];
  828. WCHAR temp[MAX_PATH];
  829. BOOL bUseMapFile = FALSE;
  830. if ( m_LocalOnly )
  831. {
  832. m_Args.Cache()->SetSourceAndTargetDomainsWithSids(m_Args.Source(),m_SourceSid,m_Args.Target(),m_TargetSid);
  833. // find the module path
  834. DWORD rc = GetModuleFileName(NULL,temp,DIM(temp));
  835. if ( rc )
  836. {
  837. // Generally, our DCTCache file will be in the same directory as our EXE.
  838. // This is true 1) when agent is dispatched to clean machine (all will be in OnePointDomainAgent directory)
  839. // and also 2) when agent is dispatched to the local ADMT machine (all will be in Program Files\ADMT directory)
  840. // The exception is when the agent is dispatched to a remote machine where ADMT is also installed.
  841. WCHAR * slash = wcsrchr(temp,L'\\');
  842. UStrCpy(slash+1,filename);
  843. // Check whether ADMT is locally installed here
  844. if ( IsLocallyInstalled() && !IsThisDispatcherMachine(pVarSet) )
  845. {
  846. // ADMT is installed here, so we're running from the binaries
  847. // in the Program files\ADMT directory
  848. // However, our cache file should be in %Program Files%\\OnePOintDomainAgent
  849. GetProgramFilesDirectory(temp,NULL);
  850. UStrCpy(temp+UStrLen(temp),L"\\OnePointDomainAgent\\");
  851. UStrCpy(temp+UStrLen(temp),filename);
  852. }
  853. }
  854. else
  855. {
  856. rc = GetLastError();
  857. err.DbgMsgWrite(0,L"Couldn't get the module filename, rc=%ld",rc);
  858. swprintf(temp,L"..\\OnePointDomainAgent\\%ls",filename);
  859. }
  860. _wfullpath(path,temp,MAX_PATH);
  861. }
  862. else
  863. {
  864. m_Args.Cache()->SetSourceAndTargetDomains(m_Args.Source(),m_Args.Target());
  865. _wfullpath(path,filename,MAX_PATH);
  866. }
  867. m_Args.Cache()->ToSorted();
  868. text = pVarSet->get(GET_BSTR(DCTVS_AccountOptions_SecurityInputMOT));
  869. if (UStrICmp(text,GET_STRING(IDS_YES)))
  870. {
  871. m_Args.SetUsingMapFile(TRUE); //set the arg flag to indicate use of map file
  872. bUseMapFile = TRUE;
  873. }
  874. // The input file should have the format:
  875. // SourceName, TargetName, Type, Status [,rid1, rid2]
  876. pFile = _wfopen(path,L"rb");
  877. if ( pFile )
  878. {
  879. int result;
  880. do
  881. {
  882. DWORD rid1 = 0;
  883. DWORD rid2 = 0;
  884. if (!bUseMapFile)
  885. {
  886. result = fwscanf(pFile,L"%[^\t]\t%[^\t]\t%[^\t]\t%lx\t%lx\t%lx\r\n",
  887. sourceName,targetName,type,&status,&rid1,&rid2);
  888. if ( result < 4 )
  889. break;
  890. }
  891. else
  892. {
  893. result = fwscanf(pFile,L"%[^\t]\t%[^\t]\t%[^\t]\t%lx\t%lx\t%lx\t%[^\t]\t%[^\t]\t%[^\t]\t%[^\r]\r\n",
  894. sourceName,targetName,type,&status,&rid1,&rid2,sourceDomSid,targetDomSid,
  895. sourceDomName, targetDomName);
  896. if ( result < 8 )
  897. break;
  898. }
  899. short lType = 0;
  900. if ( !UStrICmp(type,L"user") )
  901. lType = EA_AccountUser;
  902. else if ( ! UStrICmp(type,L"group") )
  903. lType = EA_AccountGroup;
  904. if (!bUseMapFile)
  905. m_Args.Cache()->InsertLast(sourceName,rid1,targetName,rid2,lType);
  906. else
  907. m_Args.Cache()->InsertLastWithSid(sourceName,sourceDomSid,sourceDomName,rid1,
  908. targetName,targetDomSid,targetDomName,rid2,lType);
  909. count++;
  910. if ( ! rid1 | ! rid2 )
  911. {
  912. bNeedRids = TRUE;
  913. }
  914. } while ( result >= 4 ); // 4 fields read and assigned
  915. if ( result )
  916. {
  917. err.MsgWrite(ErrS,DCT_MSG_ERROR_READING_INPUT_FILE_S,path);
  918. }
  919. err.MsgWrite(0,DCT_MSG_ACCOUNTS_READ_FROM_FILE_DS,count,path);
  920. fclose(pFile);
  921. }
  922. else
  923. {
  924. err.MsgWrite(ErrS,DCT_MSG_ERROR_OPENING_FILE_S,path);
  925. bSuccess = FALSE;
  926. }
  927. if ( bSuccess && bNeedRids && ! m_LocalOnly)
  928. {
  929. bSuccess = GetRIDsFromEA();
  930. }
  931. return bSuccess;
  932. }
  933. // This doesn't get RIDs from EA any more, since we have removed dependencies on MCS products.
  934. // Instead, we use the Net APIs to get this information
  935. BOOL CSecTranslator::GetRIDsFromEA()
  936. {
  937. BOOL bSuccess = TRUE;
  938. // set the cache to a tree sorted by name
  939. m_Args.Cache()->SortedToScrambledTree();
  940. m_Args.Cache()->Sort(&CompN);
  941. // do NQDI to get RIDS for accounts
  942. DWORD rc = 0;
  943. NET_DISPLAY_USER * pUser = NULL;
  944. NET_DISPLAY_GROUP * pGroup = NULL;
  945. DWORD count = 0;
  946. DWORD resume = 0;
  947. TRidNode * pNode = NULL;
  948. // Get source rids for users
  949. do
  950. {
  951. rc = NetQueryDisplayInformation(m_Args.Cache()->GetSourceDCName(),1,resume,5000,100000,&count,(void**)&pUser);
  952. if ( 0 == rc || ERROR_MORE_DATA == rc )
  953. {
  954. for ( DWORD i = 0 ; i < count ; i++ )
  955. {
  956. // see if this account is in the cache
  957. pNode = (TRidNode*)m_Args.Cache()->Find(&vNameComp,pUser[i].usri1_name);
  958. if ( pNode )
  959. {
  960. pNode->SrcRid(pUser[i].usri1_user_id);
  961. }
  962. }
  963. if ( count )
  964. {
  965. resume = pUser[count-1].usri1_next_index;
  966. }
  967. else
  968. {
  969. // no items were returned - get out of here
  970. break;
  971. }
  972. NetApiBufferFree(pUser);
  973. }
  974. } while ( rc == ERROR_MORE_DATA );
  975. count = 0;
  976. resume = 0;
  977. // Get source rids for global groups
  978. do
  979. {
  980. rc = NetQueryDisplayInformation(m_Args.Cache()->GetSourceDCName(),3,resume,5000,100000,&count,(void**)&pGroup);
  981. if ( 0 == rc || ERROR_MORE_DATA == rc )
  982. {
  983. for ( DWORD i = 0 ; i < count ; i++ )
  984. {
  985. // see if this account is in the cache
  986. pNode = (TRidNode*)m_Args.Cache()->Find(&vNameComp,pGroup[i].grpi3_name);
  987. if ( pNode )
  988. {
  989. pNode->SrcRid(pGroup[i].grpi3_group_id);
  990. }
  991. }
  992. if ( count )
  993. {
  994. resume = pGroup[count-1].grpi3_next_index;
  995. }
  996. else
  997. {
  998. // no items were returned - get out of here
  999. break;
  1000. }
  1001. NetApiBufferFree(pGroup);
  1002. }
  1003. } while ( rc == ERROR_MORE_DATA );
  1004. count = 0;
  1005. resume = 0;
  1006. // Get target rids for users
  1007. // set the cache to a tree sorted by target name
  1008. m_Args.Cache()->ToSorted();
  1009. m_Args.Cache()->SortedToScrambledTree();
  1010. m_Args.Cache()->Sort(&CompTargetN);
  1011. do
  1012. {
  1013. rc = NetQueryDisplayInformation(m_Args.Cache()->GetTargetDCName(),1,resume,5000,100000,&count,(void**)&pUser);
  1014. if ( 0 == rc || ERROR_MORE_DATA == rc )
  1015. {
  1016. for ( DWORD i = 0 ; i < count ; i++ )
  1017. {
  1018. // see if this account is in the cache
  1019. pNode = (TRidNode*)m_Args.Cache()->Find(&vTargetNameComp,pUser[i].usri1_name);
  1020. if ( pNode )
  1021. {
  1022. pNode->TgtRid(pUser[i].usri1_user_id);
  1023. }
  1024. }
  1025. if ( count )
  1026. {
  1027. resume = pUser[count-1].usri1_next_index;
  1028. }
  1029. else
  1030. {
  1031. // no items were returned - get out of here
  1032. break;
  1033. }
  1034. NetApiBufferFree(pUser);
  1035. }
  1036. } while ( rc == ERROR_MORE_DATA );
  1037. // TODO: Add error message if rc != 0
  1038. count = 0;
  1039. resume = 0;
  1040. // Get target rids for global groups
  1041. do
  1042. {
  1043. rc = NetQueryDisplayInformation(m_Args.Cache()->GetTargetDCName(),3,resume,5000,100000,&count,(void**)&pGroup);
  1044. if ( 0 == rc || ERROR_MORE_DATA == rc )
  1045. {
  1046. for ( DWORD i = 0 ; i < count ; i++ )
  1047. {
  1048. // see if this account is in the cache
  1049. pNode = (TRidNode*)m_Args.Cache()->Find(&vTargetNameComp,pGroup[i].grpi3_name);
  1050. if ( pNode )
  1051. {
  1052. pNode->TgtRid(pGroup[i].grpi3_group_id);
  1053. }
  1054. }
  1055. if ( count )
  1056. {
  1057. resume = pGroup[count-1].grpi3_next_index;
  1058. }
  1059. else
  1060. {
  1061. // no items were returned - get out of here
  1062. break;
  1063. }
  1064. NetApiBufferFree(pGroup);
  1065. }
  1066. } while ( rc == ERROR_MORE_DATA );
  1067. // sort back to regular source name order
  1068. m_Args.Cache()->ToSorted();
  1069. m_Args.Cache()->SortedToScrambledTree();
  1070. m_Args.Cache()->Sort(&CompN);
  1071. // get source and target rids for local groups
  1072. TNodeTreeEnum tEnum;
  1073. BYTE sid[LEN_SID];
  1074. DWORD lenSid;
  1075. WCHAR domain[LEN_Domain];
  1076. DWORD lenDomain;
  1077. SID_NAME_USE snu;
  1078. for ( pNode = (TRidNode*)tEnum.OpenFirst(m_Args.Cache()) ; pNode ; pNode = (TRidNode*) tEnum.Next() )
  1079. {
  1080. if ( ! pNode->SrcRid() )
  1081. {
  1082. // we don't have a rid for this account, possibly because it is a local group
  1083. lenSid = DIM(sid);
  1084. lenDomain = DIM(domain);
  1085. if ( LookupAccountName(m_Args.Cache()->GetSourceDCName(),pNode->GetAcctName(),sid,&lenSid,domain,&lenDomain,&snu) )
  1086. {
  1087. if (! UStrICmp(m_Args.Source(),domain) )
  1088. {
  1089. // found the source SID
  1090. // get the last sub-id
  1091. PUCHAR pCount = GetSidSubAuthorityCount(&sid);
  1092. if ( pCount )
  1093. {
  1094. LPDWORD pRid = GetSidSubAuthority(&sid,(*pCount) - 1 );
  1095. if ( pRid )
  1096. {
  1097. pNode->SrcRid(*pRid);
  1098. }
  1099. }
  1100. }
  1101. }
  1102. }
  1103. if ( pNode->SrcRid() && !pNode->TgtRid() )
  1104. {
  1105. // we got the source RID, now try to get the target RID
  1106. lenSid = DIM(sid);
  1107. lenDomain = DIM(domain);
  1108. if ( LookupAccountName(m_Args.Cache()->GetTargetDCName(),pNode->GetTargetAcctName(),sid,&lenSid,domain,&lenDomain,&snu) )
  1109. {
  1110. if (! UStrICmp(m_Args.Target(),domain) )
  1111. {
  1112. // found the source SID
  1113. // get the last sub-id
  1114. PUCHAR pCount = GetSidSubAuthorityCount(&sid);
  1115. if ( pCount )
  1116. {
  1117. LPDWORD pRid = GetSidSubAuthority(&sid,(*pCount) - 1 );
  1118. if ( pRid )
  1119. {
  1120. pNode->TgtRid(*pRid);
  1121. }
  1122. }
  1123. }
  1124. }
  1125. }
  1126. }
  1127. tEnum.Close();
  1128. return bSuccess;
  1129. }
  1130. // We remove the Exchange server service accont from the cache before translating,
  1131. // since it is not recommended to change the service account from exchange
  1132. // in any event, the service account for exchange cannot be changed simply by granting
  1133. // exchange permissions to the new account. It also requires configuration changes within
  1134. // exchange that must be performed manually
  1135. BOOL
  1136. CSecTranslator::RemoveExchangeServiceAccountFromCache()
  1137. {
  1138. WCHAR const * exServiceName = L"MSExchangeDS";
  1139. SC_HANDLE hSCM;
  1140. DWORD rc = 0; // return code
  1141. BOOL result = FALSE;
  1142. BOOL bUseMapFile = m_Args.UsingMapFile();
  1143. if ( m_Args.TranslateContainers() )
  1144. {
  1145. // get the service account name for the exchange directory service on exchServer
  1146. // BOOL retval=FALSE; // returned value
  1147. SC_HANDLE hSvc; // Service handle
  1148. DWORD lenQsc; // required qsc info len
  1149. union
  1150. {
  1151. QUERY_SERVICE_CONFIG qsc; // Exchange Directory service information
  1152. BYTE padding[1000];
  1153. } bufQsc;
  1154. hSCM = OpenSCManager( m_exchServer, NULL, GENERIC_READ );
  1155. if ( !hSCM )
  1156. {
  1157. rc = GetLastError();
  1158. err.SysMsgWrite( ErrW, rc,
  1159. DCT_MSG_SCM_OPEN_FAILED_SD, m_exchServer,rc );
  1160. }
  1161. else
  1162. {
  1163. hSvc = OpenService( hSCM, exServiceName, SERVICE_QUERY_CONFIG );
  1164. if ( !hSvc )
  1165. {
  1166. rc = GetLastError();
  1167. switch ( rc )
  1168. {
  1169. case ERROR_SERVICE_DOES_NOT_EXIST: // 1060
  1170. default:
  1171. err.SysMsgWrite( ErrW, rc, DCT_MSG_OPEN_SERVICE_FAILED_SSD,
  1172. m_exchServer , exServiceName, rc );
  1173. break;
  1174. }
  1175. }
  1176. else
  1177. {
  1178. if ( !QueryServiceConfig( hSvc, &bufQsc.qsc, sizeof bufQsc, &lenQsc ) )
  1179. {
  1180. rc = GetLastError();
  1181. err.SysMsgWrite( ErrW, rc, DCT_MSG_QUERY_SERVICE_CONFIG_FAILED_SSD,
  1182. m_exchServer, exServiceName, rc );
  1183. }
  1184. else
  1185. {
  1186. // We've found the account
  1187. result = TRUE;
  1188. // bufQsc.qsc.lpServiceStartName is DOMAIN\Account or .\Account
  1189. WCHAR * domAcct = bufQsc.qsc.lpServiceStartName;
  1190. WCHAR * domName; // domain-name
  1191. WCHAR * acctName; // account-name
  1192. for ( domName = domAcct ; *domName && *domName != _T('\\') ; domName++ )
  1193. ;
  1194. if ( *domName == _T('\\') )
  1195. {
  1196. *domName = 0;
  1197. acctName = domName+1;
  1198. domName = domAcct;
  1199. }
  1200. // Is the account from the source domain?
  1201. WCHAR szSourceDomain[LEN_Domain];
  1202. WCHAR wszAccountName[LEN_Account];
  1203. safecopy(wszAccountName,acctName);
  1204. //use the domain name from the cache if we are not using a sID mapping
  1205. //file
  1206. if (!bUseMapFile)
  1207. {
  1208. safecopy(szSourceDomain,m_Args.Cache()->GetSourceDomainName());
  1209. if ( !UStrICmp(domName,szSourceDomain ) )
  1210. {
  1211. // if so, is it in the cache?
  1212. TAcctNode * tnode;
  1213. TNodeTreeEnum tEnum;
  1214. // the cache is a tree, sorted by RID
  1215. for ( tnode = (TAcctNode *)tEnum.OpenFirst(m_Args.Cache()) ; tnode ; tnode = (TAcctNode *)tEnum.Next() )
  1216. {
  1217. if ( !UStrICmp(tnode->GetAcctName(),wszAccountName) )
  1218. {
  1219. // remove it from the cache, and notify the user
  1220. err.MsgWrite(ErrW,DCT_MSG_SKIPPING_EXCHANGE_ACCOUNT_SS,domName,acctName);
  1221. m_Args.Cache()->Remove(tnode);
  1222. }
  1223. }
  1224. tEnum.Close();
  1225. }
  1226. }//end if not using mapping file
  1227. else //else using sID mapping file, get the source domain name from the
  1228. { //node itself
  1229. //is this account in the cache?
  1230. TAcctNode * tnode;
  1231. TNodeTreeEnum tEnum;
  1232. // the cache is a tree, sorted by RID
  1233. for ( tnode = (TAcctNode *)tEnum.OpenFirst(m_Args.Cache()) ; tnode ; tnode = (TAcctNode *)tEnum.Next() )
  1234. {
  1235. if (( !UStrICmp(tnode->GetAcctName(),wszAccountName) ) &&
  1236. ( !UStrICmp(((TRidNode*)tnode)->GetSrcDomName(),domName) ))
  1237. {
  1238. // remove it from the cache, and notify the user
  1239. err.MsgWrite(ErrW,DCT_MSG_SKIPPING_EXCHANGE_ACCOUNT_SS,domName,acctName);
  1240. m_Args.Cache()->Remove(tnode);
  1241. }
  1242. }
  1243. tEnum.Close();
  1244. }//end if using mapping file
  1245. CloseServiceHandle( hSvc );
  1246. }
  1247. }
  1248. CloseServiceHandle(hSCM);
  1249. }
  1250. }
  1251. if ( !result )
  1252. {
  1253. // couldn't get the service account name
  1254. err.SysMsgWrite(ErrW,rc,DCT_MSG_CANT_FIND_EXCHANGE_ACCOUNT_SD,
  1255. m_exchServer,rc);
  1256. }
  1257. return result;
  1258. }
  1259. void
  1260. CSecTranslator::DoExchangeResolution(
  1261. TSDResolveStats * stat, // in - stats object to record stats
  1262. IVarSet * pVarSet
  1263. )
  1264. {
  1265. {
  1266. TGlobalDirectory m_exDir;
  1267. _bstr_t domain = pVarSet->get(GET_BSTR(DCTVS_AccountOptions_SidHistoryCredentials_Domain));
  1268. _bstr_t username = pVarSet->get(GET_BSTR(DCTVS_AccountOptions_SidHistoryCredentials_UserName));
  1269. _bstr_t password = pVarSet->get(GET_BSTR(DCTVS_AccountOptions_SidHistoryCredentials_Password));
  1270. _bstr_t mode = pVarSet->get(GET_BSTR(DCTVS_Security_TranslationMode));
  1271. _bstr_t mbquery = pVarSet->get(L"ExchangeMigration.LdapQuery");
  1272. WCHAR creds[LEN_Account + LEN_Domain + 6];
  1273. WCHAR query[LEN_Path] = L"(objectClass=*)";
  1274. if ( m_exchServer[0] )
  1275. {
  1276. if (! RemoveExchangeServiceAccountFromCache() )
  1277. goto end;
  1278. }
  1279. if ( mbquery.length() )
  1280. {
  1281. UStrCpy(query,(WCHAR*)mbquery);
  1282. }
  1283. if ( m_Args.TranslateMailboxes() || m_Args.TranslateContainers() )
  1284. {
  1285. // make sure we have some accts in the cache
  1286. m_exDir.SetStats(stat);
  1287. m_Args.Cache()->UnCancel();
  1288. swprintf(creds,L"cn=%ls,cn=%ls",(WCHAR*)username,(WCHAR*)domain);
  1289. err.MsgWrite(0,DCT_MSG_EXCHANGE_TRANSLATION_MODE_S,(WCHAR*)mode);
  1290. m_exDir.DoLdapTranslation(m_exchServer,creds,password,&m_Args,NULL,query);
  1291. stat->DisplayPath(L"");
  1292. }
  1293. }
  1294. end:
  1295. // destructor for m_exDir must be called before we release the MAPI library!
  1296. ReleaseMAPI();
  1297. ReleaseDAPI();
  1298. return;
  1299. }
  1300. /*********************************************************************
  1301. * *
  1302. * Written by: Paul Thompson *
  1303. * Date: 4 OCT 2000 *
  1304. * *
  1305. * This function is responsible for retrieving account sIDs from *
  1306. * the given sID mapping file and adding these sids to the cache. *
  1307. * *
  1308. *********************************************************************/
  1309. //BEGIN LoadCacheFromMapFile
  1310. BOOL
  1311. CSecTranslator::LoadCacheFromMapFile(
  1312. WCHAR const * filename, // in - file to read sid mapping from
  1313. IVarSet * pVarSet // in - pointer to varset
  1314. )
  1315. {
  1316. FILE * pFile = NULL;
  1317. WCHAR path[MAX_PATH];
  1318. WCHAR sourceSid[MAX_PATH];
  1319. WCHAR targetSid[MAX_PATH];
  1320. int count = 0;
  1321. BOOL bSuccess = TRUE;
  1322. // m_Args.Cache()->SetSourceAndTargetDomains(m_Args.Source(),m_Args.Target());
  1323. _wfullpath(path,filename,MAX_PATH);
  1324. m_Args.Cache()->ToSorted();
  1325. // The input file should have the format:
  1326. // srcSid,tgtSid
  1327. pFile = OpenMappingFile(path);
  1328. // pFile = _wfopen(path,L"rb");
  1329. if ( pFile )
  1330. {
  1331. int result;
  1332. //move past the UNICODE Byte Order Mark
  1333. // fgetwc(pFile);
  1334. do
  1335. {
  1336. result = fwscanf(pFile,L"%[^,], %[^\r\n]\n",sourceSid,targetSid);
  1337. if ( result < 2 )
  1338. break;
  1339. short lType = EA_AccountUser;
  1340. //divide the sids into domain sids and rids
  1341. WCHAR srcDomainSid[MAX_PATH] = L"";
  1342. WCHAR tgtDomainSid[MAX_PATH] = L"";
  1343. WCHAR srcDomainName[MAX_PATH] = L"";
  1344. WCHAR tgtDomainName[MAX_PATH] = L"";
  1345. DWORD srcRid = 0;
  1346. DWORD tgtRid = 0;
  1347. WCHAR srcName[MAX_PATH] = L"";
  1348. WCHAR tgtName[MAX_PATH] = L"";
  1349. WCHAR domainName[MAX_PATH] = L"";
  1350. DWORD cb = MAX_PATH;
  1351. DWORD cbDomain = MAX_PATH;
  1352. SID_NAME_USE sid_Use;
  1353. PSID srcSid = NULL;
  1354. PSID tgtSid = NULL;
  1355. WCHAR * slash;
  1356. LPWSTR pdomc;
  1357. WCHAR DCName[MAX_PATH];
  1358. BYTE ssid[200];
  1359. BYTE tsid[200];
  1360. DWORD lenSid = DIM(ssid);
  1361. BOOL bNeedToFreeSrc = FALSE;
  1362. BOOL bNeedToFreeTgt = FALSE;
  1363. //see if the source is given by domain\account format or
  1364. //decimal-style sid format
  1365. if (wcschr(sourceSid,L'\\'))
  1366. {
  1367. //seperate domain and account names
  1368. wcscpy(srcDomainName,sourceSid);
  1369. slash = wcschr(srcDomainName,L'\\');
  1370. if ( slash )
  1371. {
  1372. *slash = 0;
  1373. wcscpy(srcName,slash+1);
  1374. }
  1375. //get a DC for the given domain
  1376. HRESULT res = NetGetDCName(NULL,srcDomainName,(LPBYTE *)&pdomc);
  1377. if (res!=NERR_Success)
  1378. {
  1379. err.MsgWrite(0,DCT_MSG_SRC_ACCOUNT_NOT_READ_FROM_FILE_DS, sourceSid, targetSid, path, sourceSid);
  1380. continue;
  1381. }
  1382. wcscpy(DCName, pdomc);
  1383. NetApiBufferFree(pdomc);
  1384. //get the sid for this account
  1385. if(!LookupAccountName(DCName,srcName,(PSID)ssid,&lenSid,srcDomainName,&cbDomain,&sid_Use))
  1386. {
  1387. err.MsgWrite(0,DCT_MSG_SRC_ACCOUNT_NOT_READ_FROM_FILE_DS, sourceSid, targetSid, path, sourceSid);
  1388. continue;
  1389. }
  1390. srcSid = (PSID)ssid;
  1391. if (sid_Use == SidTypeGroup)
  1392. lType = EA_AccountGroup;
  1393. else
  1394. lType = EA_AccountUser;
  1395. }//end if domain\account format
  1396. else
  1397. {
  1398. srcSid = SidFromString(sourceSid);
  1399. if (!srcSid)
  1400. {
  1401. err.MsgWrite(0,DCT_MSG_SRC_ACCOUNT_NOT_READ_FROM_FILE_DS, sourceSid, targetSid, path, sourceSid);
  1402. continue;
  1403. }
  1404. bNeedToFreeSrc = TRUE;
  1405. if (LookupAccountSid(NULL, srcSid, srcName, &cb, srcDomainName, &cbDomain, &sid_Use))
  1406. {
  1407. if (sid_Use == SidTypeGroup)
  1408. lType = EA_AccountGroup;
  1409. else
  1410. lType = EA_AccountUser;
  1411. }
  1412. }//end else sid format
  1413. //see if the target is given by domain\account format or
  1414. //decimal-style sid format
  1415. lenSid = DIM(tsid);
  1416. cb = cbDomain = MAX_PATH;
  1417. if (wcschr(targetSid,L'\\'))
  1418. {
  1419. //seperate domain and account names
  1420. wcscpy(tgtDomainName,targetSid);
  1421. slash = wcschr(tgtDomainName,L'\\');
  1422. if ( slash )
  1423. {
  1424. *slash = 0;
  1425. wcscpy(tgtName,slash+1);
  1426. }
  1427. //get a DC for the given domain
  1428. HRESULT res = NetGetDCName(NULL,tgtDomainName,(LPBYTE *)&pdomc);
  1429. if (res!=NERR_Success)
  1430. {
  1431. if (bNeedToFreeSrc)
  1432. FreeSid(srcSid);
  1433. err.MsgWrite(0,DCT_MSG_TGT_ACCOUNT_NOT_READ_FROM_FILE_DS, sourceSid, targetSid, path, targetSid);
  1434. continue;
  1435. }
  1436. wcscpy(DCName, pdomc);
  1437. NetApiBufferFree(pdomc);
  1438. //get the sid for this account
  1439. if(!LookupAccountName(DCName,tgtName,(PSID)tsid,&lenSid,tgtDomainName,&cbDomain,&sid_Use))
  1440. {
  1441. if (bNeedToFreeSrc)
  1442. FreeSid(srcSid);
  1443. err.MsgWrite(0,DCT_MSG_TGT_ACCOUNT_NOT_READ_FROM_FILE_DS, sourceSid, targetSid, path, targetSid);
  1444. continue;
  1445. }
  1446. tgtSid = (PSID)tsid;
  1447. if (sid_Use == SidTypeGroup)
  1448. lType = EA_AccountGroup;
  1449. else
  1450. lType = EA_AccountUser;
  1451. }//end if domain\account format
  1452. else
  1453. {
  1454. tgtSid = SidFromString(targetSid);
  1455. if (!tgtSid)
  1456. {
  1457. if (bNeedToFreeSrc)
  1458. FreeSid(srcSid);
  1459. err.MsgWrite(0,DCT_MSG_TGT_ACCOUNT_NOT_READ_FROM_FILE_DS, sourceSid, targetSid, path, targetSid);
  1460. continue;
  1461. }
  1462. bNeedToFreeTgt = TRUE;
  1463. if (LookupAccountSid(NULL, tgtSid, tgtName, &cb, tgtDomainName, &cbDomain, &sid_Use))
  1464. {
  1465. if (sid_Use == SidTypeGroup)
  1466. lType = EA_AccountGroup;
  1467. else
  1468. lType = EA_AccountUser;
  1469. }
  1470. }//end else sid format
  1471. //if the source account is not already in the cache, then add it
  1472. if ((m_Args.Cache()->GetNumAccts() == 0) || (m_Args.Cache()->LookupWODomain(srcSid) == NULL))
  1473. {
  1474. //get the domain sids and account rids from the account sids
  1475. SplitAccountSids(srcSid, srcDomainSid, &srcRid, tgtSid, tgtDomainSid, &tgtRid);
  1476. //insert this node into the cache
  1477. m_Args.Cache()->InsertLastWithSid(srcName,srcDomainSid,srcDomainName,srcRid,tgtName,
  1478. tgtDomainSid,tgtDomainName,tgtRid,lType);
  1479. count++;
  1480. }
  1481. else
  1482. err.MsgWrite(0,DCT_MSG_SRC_ACCOUNT_DUPLICATE_IN_FILE_DS, sourceSid, targetSid, path, sourceSid);
  1483. if (bNeedToFreeSrc)
  1484. FreeSid(srcSid);
  1485. if (bNeedToFreeTgt)
  1486. FreeSid(tgtSid);
  1487. } while ( result >= 2 ); // 2 fields read and assigned
  1488. err.MsgWrite(0,DCT_MSG_ACCOUNTS_READ_FROM_FILE_DS,count,path);
  1489. fclose(pFile);
  1490. }
  1491. else
  1492. {
  1493. err.MsgWrite(ErrS,DCT_MSG_ERROR_OPENING_FILE_S,path);
  1494. bSuccess = FALSE;
  1495. }
  1496. return bSuccess;
  1497. }
  1498. //END LoadCacheFromMapFile
  1499. /*********************************************************************
  1500. * *
  1501. * Written by: Paul Thompson *
  1502. * Date: 11 OCT 2000 *
  1503. * *
  1504. * This function is responsible for opening the sid mapping file *
  1505. * whether it is anm ANSI or UNICODE file and return the file *
  1506. * pointer. *
  1507. * *
  1508. *********************************************************************/
  1509. //BEGIN OpenMappingFile
  1510. FILE* CSecTranslator::OpenMappingFile(LPCTSTR pszFileName)
  1511. {
  1512. // open in binary mode first in order to check for UNICODE byte order
  1513. // mark if the file is UNICODE then it must be read in binary mode
  1514. // with the stream i/o functions
  1515. FILE* fp = _tfopen(pszFileName, _T("rb"));
  1516. if (fp == NULL)
  1517. {
  1518. return NULL;
  1519. // _com_issue_error(E_INVALIDARG);
  1520. }
  1521. // check if file is ANSI or UNICODE or UTF-8
  1522. BYTE byteSignature[3];
  1523. if (fread(byteSignature, sizeof(BYTE), 3, fp) == 3)
  1524. {
  1525. static BYTE byteUtf8[] = { 0xEF, 0xBB, 0xBF };
  1526. static BYTE byteUnicodeLE[] = { 0xFF, 0xFE };
  1527. static BYTE byteUnicodeBE[] = { 0xFE, 0xFF };
  1528. // check for signature or byte order mark
  1529. if (memcmp(byteSignature, byteUtf8, sizeof(byteUtf8)) == 0)
  1530. {
  1531. // UTF-8 signature
  1532. // TODO: not currently supported
  1533. return NULL;
  1534. // _com_issue_error(E_INVALIDARG);
  1535. }
  1536. else if (memcmp(byteSignature, byteUnicodeLE, sizeof(byteUnicodeLE)) == 0)
  1537. {
  1538. // UNICODE Little Endian Byte Order Mark
  1539. // supported
  1540. // must read in binary mode
  1541. // move file pointer back one byte because we read 3 bytes
  1542. fseek(fp, -1, SEEK_CUR);
  1543. }
  1544. else if (memcmp(byteSignature, byteUnicodeBE, sizeof(byteUnicodeBE)) == 0)
  1545. {
  1546. // UNICODE Big Endian Byte Order Mark
  1547. // TODO: not currently supported
  1548. return NULL;
  1549. // _com_issue_error(E_INVALIDARG);
  1550. }
  1551. else
  1552. {
  1553. // assume ANSI
  1554. // re-open file in text mode as the stream i/o functions will
  1555. // treat the file as multi-byte characters and will convert them
  1556. // to UNICODE
  1557. fclose(fp);
  1558. fp = _tfopen(pszFileName, _T("rt"));
  1559. }
  1560. }
  1561. else
  1562. {
  1563. return NULL;
  1564. // _com_issue_error(E_INVALIDARG);
  1565. }
  1566. return fp;
  1567. }
  1568. //END OpenMappingFile