Leaked source code of windows server 2003
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.

1517 lines
46 KiB

  1. // ServMigr.cpp : Implementation of CServMigr
  2. #include "stdafx.h"
  3. #include "ScmMigr.h"
  4. #include "ServMigr.h"
  5. #include "ErrDct.hpp"
  6. #include "ResStr.h"
  7. #include "Common.hpp"
  8. #include "PWGen.hpp"
  9. #include "EaLen.hpp"
  10. #include "TReg.hpp"
  11. #include "TxtSid.h"
  12. #include "ARExt_i.c"
  13. #include "LsaUtils.h"
  14. #include "crypt.hxx"
  15. #include "GetDcName.h"
  16. #include <lm.h>
  17. #include <dsgetdc.h>
  18. #include <ntdsapi.h>
  19. #include <Sddl.h>
  20. #include "folders.h"
  21. using namespace nsFolders;
  22. //#import "\bin\McsVarSetMin.tlb" no_namespace, named_guids
  23. //#import "\bin\DBManager.tlb" no_namespace, named_guids
  24. //#import "\bin\McsDctWorkerObjects.tlb" no_namespace, named_guids
  25. #import "VarSet.tlb" no_namespace, named_guids rename("property", "aproperty")
  26. //#import "DBMgr.tlb" no_namespace, named_guids //already #imported in ServMigr.h
  27. #import "WorkObj.tlb" no_namespace, named_guids
  28. TErrorDct err;
  29. StringLoader gString;
  30. #define BLOCK_SIZE 160
  31. #define BUFFER_SIZE 400
  32. #define SvcAcctStatus_NotMigratedYet 0
  33. #define SvcAcctStatus_DoNotUpdate 1
  34. #define SvcAcctStatus_Updated 2
  35. #define SvcAcctStatus_UpdateFailed 4
  36. #define SvcAcctStatus_NeverAllowUpdate 8
  37. // these defines are for GetWellKnownSid
  38. #define ADMINISTRATORS 1
  39. #define SYSTEM 7
  40. /////////////////////////////////////////////////////////////////////////////
  41. // CServMigr
  42. STDMETHODIMP CServMigr::ProcessUndo(/*[in]*/ IUnknown * pSource, /*[in]*/ IUnknown * pTarget, /*[in]*/ IUnknown * pMainSettings, /*[in, out]*/ IUnknown ** pPropToSet, /*[in,out]*/ EAMAccountStats* pStats)
  43. {
  44. return E_NOTIMPL;
  45. }
  46. STDMETHODIMP CServMigr::PreProcessObject(/*[in]*/ IUnknown * pSource, /*[in]*/ IUnknown * pTarget, /*[in]*/ IUnknown * pMainSettings, /*[in, out]*/ IUnknown ** pPropToSet, /*[in,out]*/ EAMAccountStats* pStats)
  47. {
  48. return S_OK;
  49. }
  50. STDMETHODIMP
  51. CServMigr::ProcessObject(
  52. /*[in]*/ IUnknown * pSource,
  53. /*[in]*/ IUnknown * pTarget,
  54. /*[in]*/ IUnknown * pMainSettings,
  55. /*[in,out]*/IUnknown ** ppPropsToSet,
  56. /*[in,out]*/ EAMAccountStats* pStats
  57. )
  58. {
  59. HRESULT hr = S_OK;
  60. WCHAR domAccount[500];
  61. WCHAR domTgtAccount[500];
  62. IVarSetPtr pVarSet(pMainSettings);
  63. IIManageDBPtr pDB;
  64. _bstr_t logfile;
  65. _bstr_t srcComputer;
  66. _bstr_t tgtComputer;
  67. IVarSetPtr pData(CLSID_VarSet);
  68. IUnknown * pUnk = NULL;
  69. DWORD rc = 0;
  70. _bstr_t sIntraForest;
  71. BOOL bIntraForest = FALSE;
  72. USER_INFO_2 * uInfo = NULL;
  73. try {
  74. logfile = pVarSet->get(GET_BSTR(DCTVS_Options_Logfile));
  75. if ( logfile.length() )
  76. {
  77. err.LogOpen(logfile,1);
  78. }
  79. pDB = pVarSet->get(GET_BSTR(DCTVS_DBManager));
  80. if ( pDB != NULL )
  81. {
  82. // Check to see if this account is referenced in the service accounts table
  83. m_strSourceDomain = pVarSet->get(GET_BSTR(DCTVS_Options_SourceDomain));
  84. m_strSourceDomainFlat = pVarSet->get(GET_BSTR(DCTVS_Options_SourceDomainFlat));
  85. m_strTargetDomain = pVarSet->get(GET_BSTR(DCTVS_Options_TargetDomain));
  86. m_strTargetDomainFlat = pVarSet->get(GET_BSTR(DCTVS_Options_TargetDomainFlat));
  87. m_strSourceSam = pVarSet->get(GET_BSTR(DCTVS_CopiedAccount_SourceSam));
  88. m_strTargetSam = pVarSet->get(GET_BSTR(DCTVS_CopiedAccount_TargetSam));
  89. srcComputer = pVarSet->get(GET_BSTR(DCTVS_Options_SourceServer));
  90. tgtComputer = pVarSet->get(GET_BSTR(DCTVS_Options_TargetServer));
  91. sIntraForest = pVarSet->get(GET_BSTR(DCTVS_Options_IsIntraforest));
  92. if ( ! UStrICmp((WCHAR*)sIntraForest,GET_STRING(IDS_YES)) )
  93. {
  94. // for intra-forest migration we are moving, not copying, so we don't need to update the password
  95. // Actually, it turns out that ChangeServiceConfig will not let us update just the service account
  96. // and not the passord, so we'll have to go ahead and change the password for the service ac
  97. //bIntraForest = TRUE;
  98. }
  99. //if the SAM account name has a " character in it, it cannot be a service
  100. //account, and therefore we leave
  101. if (wcschr((WCHAR*)m_strSourceSam, L'\"')) {
  102. return S_OK;
  103. }
  104. swprintf(domAccount,L"%s\\%s",(WCHAR*)m_strSourceDomainFlat,(WCHAR*)m_strSourceSam);
  105. swprintf(domTgtAccount,L"%s\\%s",(WCHAR*)m_strTargetDomainFlat,(WCHAR*)m_strTargetSam);
  106. }
  107. }
  108. catch (_com_error& ce) {
  109. hr = ce.Error();
  110. return hr;
  111. }
  112. catch (... )
  113. {
  114. return E_FAIL;
  115. }
  116. try {
  117. hr = pData->QueryInterface(IID_IUnknown,(void**)&pUnk);
  118. if ( SUCCEEDED(hr) )
  119. {
  120. hr = pDB->raw_GetServiceAccount(_bstr_t(domAccount),&pUnk);
  121. }
  122. }
  123. catch (_com_error& ce) {
  124. if (pUnk)
  125. pUnk->Release();
  126. hr = ce.Error();
  127. return hr;
  128. }
  129. catch ( ... )
  130. {
  131. if (pUnk)
  132. pUnk->Release();
  133. return E_FAIL;
  134. }
  135. try {
  136. if ( SUCCEEDED(hr) )
  137. {
  138. pData = pUnk;
  139. pUnk->Release();
  140. pUnk=NULL;
  141. // remove the password must change flag, if set
  142. DWORD parmErr = 0;
  143. WCHAR password[LEN_Password];
  144. long entries = pData->get("ServiceAccountEntries");
  145. if ( (entries != 0) && !bIntraForest ) // if we're moving the account, don't mess with its properties
  146. {
  147. //
  148. // Open password log file if it has not been already opened.
  149. //
  150. if (!m_bTriedToOpenFile)
  151. {
  152. m_bTriedToOpenFile = true;
  153. _bstr_t strPasswordFile = pVarSet->get(GET_BSTR(DCTVS_AccountOptions_PasswordFile));
  154. if (m_passwordLog.LogOpen(strPasswordFile) == FALSE)
  155. {
  156. err.MsgWrite(ErrI, DCT_MSG_SERVICES_WILL_NOT_BE_UPDATED);
  157. if (pStats != NULL)
  158. {
  159. pStats->errors.users++;
  160. }
  161. }
  162. }
  163. rc = NetUserGetInfo(tgtComputer,m_strTargetSam,2,(LPBYTE*)&uInfo);
  164. if ( ! rc )
  165. {
  166. // generate a new, strong, 14 character password for this account,
  167. // and set the password to not expire
  168. rc = EaPasswordGenerate(3,3,3,3,6,14,password,DIM(password));
  169. if (!rc)
  170. {
  171. //
  172. // Only set password to not expire if able
  173. // to write password to password file.
  174. //
  175. if (m_passwordLog.IsOpen())
  176. {
  177. uInfo->usri2_flags |= (UF_DONT_EXPIRE_PASSWD);
  178. }
  179. uInfo->usri2_password = password;
  180. rc = NetUserSetInfo(tgtComputer,m_strTargetSam,2,(LPBYTE)uInfo,&parmErr);
  181. if ( ! rc )
  182. {
  183. if (m_passwordLog.IsOpen())
  184. {
  185. err.MsgWrite(0,DCT_MSG_REMOVED_PWDCHANGE_FLAG_S,(WCHAR*)m_strTargetSam);
  186. }
  187. err.MsgWrite(0,DCT_MSG_PWGENERATED_S,(WCHAR*)m_strTargetSam);
  188. // write the password to the password log file and mark this account, so that the
  189. // SetPassword extension will not reset the password again.
  190. pVarSet->put(GET_BSTR(DCTVS_CopiedAccount_DoNotUpdatePassword),m_strSourceSam);
  191. //
  192. // If password log is open then write password to file
  193. // otherwise set error code so that services are not updated.
  194. //
  195. if (m_passwordLog.IsOpen())
  196. {
  197. m_passwordLog.MsgWrite(L"%ls,%ls",(WCHAR*)m_strTargetSam,password);
  198. }
  199. else
  200. {
  201. rc = ERROR_OPEN_FAILED;
  202. }
  203. }
  204. else
  205. {
  206. if (pStats != NULL)
  207. pStats->errors.users++;
  208. err.SysMsgWrite(ErrE,rc,DCT_MSG_REMOVED_PWDCHANGE_FLAG_FAILED_SD,(WCHAR*)m_strTargetSam,rc);
  209. }
  210. uInfo->usri2_password = NULL;
  211. }
  212. NetApiBufferFree(uInfo);
  213. uInfo = NULL;
  214. }
  215. }
  216. if (entries != 0 )
  217. {
  218. try {
  219. if ( ! rc )
  220. {
  221. WCHAR strSID[200] = L"";
  222. BYTE sid[200];
  223. WCHAR sdomain[LEN_Domain];
  224. SID_NAME_USE snu;
  225. DWORD lenSid = DIM(sid);
  226. DWORD lenDomain = DIM(sdomain);
  227. DWORD lenStrSid = DIM(strSID);
  228. if ( LookupAccountName(tgtComputer,m_strTargetSam,sid,&lenSid,sdomain,&lenDomain,&snu) )
  229. {
  230. if ( GetTextualSid(sid,strSID,&lenStrSid) )
  231. {
  232. // for each reference to the service account, update the SCM
  233. // for intra-forest migration, don't update the password
  234. if ( bIntraForest )
  235. UpdateSCMs(pData,domTgtAccount,NULL,strSID,pDB, pStats);
  236. else
  237. UpdateSCMs(pData,domTgtAccount,password,strSID,pDB, pStats);
  238. }
  239. else
  240. {
  241. if (pStats != NULL)
  242. pStats->errors.users++;
  243. err.SysMsgWrite(ErrE,GetLastError(),DCT_MSG_CANNOT_FIND_ACCOUNT_SSD,m_strTargetSam,tgtComputer,GetLastError());
  244. }
  245. }
  246. else
  247. {
  248. if (pStats != NULL)
  249. pStats->errors.users++;
  250. err.SysMsgWrite(ErrE,GetLastError(),DCT_MSG_CANNOT_FIND_ACCOUNT_SSD,m_strTargetSam,tgtComputer,GetLastError());
  251. }
  252. }
  253. }
  254. catch (_com_error& ce) {
  255. hr = ce.Error();
  256. return hr;
  257. }
  258. catch(...)
  259. {
  260. return E_FAIL;
  261. }
  262. }
  263. }
  264. else
  265. {
  266. if (pStats != NULL)
  267. pStats->errors.users++;
  268. err.SysMsgWrite(ErrE,E_FAIL,DCT_MSG_DB_OBJECT_CREATE_FAILED_D,E_FAIL);
  269. }
  270. err.LogClose();
  271. }
  272. catch (_com_error& ce) {
  273. if (pUnk)
  274. pUnk->Release();
  275. if (uInfo)
  276. NetApiBufferFree(uInfo);
  277. hr = ce.Error();
  278. return hr;
  279. }
  280. catch (... )
  281. {
  282. if (pUnk)
  283. pUnk->Release();
  284. if (uInfo)
  285. NetApiBufferFree(uInfo);
  286. return E_FAIL;
  287. }
  288. return S_OK;
  289. }
  290. STDMETHODIMP CServMigr::get_sDesc(/*[out, retval]*/ BSTR *pVal)
  291. {
  292. (*pVal) = SysAllocString(L"Updates SCM entries for services using migrated accounts.");
  293. return S_OK;
  294. }
  295. STDMETHODIMP CServMigr::put_sDesc(/*[in]*/ BSTR newVal)
  296. {
  297. return E_NOTIMPL;
  298. }
  299. STDMETHODIMP CServMigr::get_sName(/*[out, retval]*/ BSTR *pVal)
  300. {
  301. (*pVal) = SysAllocString(L"Generic Service Account Migration");
  302. return S_OK;
  303. }
  304. STDMETHODIMP CServMigr::put_sName(/*[in]*/ BSTR newVal)
  305. {
  306. return E_NOTIMPL;
  307. }
  308. DWORD
  309. CServMigr::DoUpdate(
  310. WCHAR const * account,
  311. WCHAR const * password,
  312. WCHAR const * strSid,
  313. WCHAR const * computer,
  314. WCHAR const * service,
  315. BOOL bNeedToGrantLOS,
  316. EAMAccountStats *pStats
  317. )
  318. {
  319. DWORD rc = 0;
  320. WCHAR const * ppassword = password;
  321. // if password is empty, set it to NULL
  322. if ( ppassword && ppassword[0] == 0 )
  323. {
  324. ppassword = NULL;
  325. }
  326. else if ( !UStrCmp(password,L"NULL") )
  327. {
  328. ppassword = NULL;
  329. }
  330. // only try to update entries that we need to be updating
  331. // try to connect to the SCM on this machine
  332. SC_HANDLE pScm = OpenSCManager(computer, NULL, SC_MANAGER_ALL_ACCESS );
  333. if ( pScm )
  334. {
  335. // grant the logon as a service right to the target account
  336. if ( bNeedToGrantLOS )
  337. {
  338. LSA_HANDLE hPolicy;
  339. NTSTATUS ntsStatus = OpenPolicy(
  340. const_cast<LPWSTR>(computer),
  341. POLICY_CREATE_ACCOUNT|POLICY_LOOKUP_NAMES,
  342. &hPolicy
  343. );
  344. rc = LsaNtStatusToWinError(ntsStatus);
  345. if (rc == ERROR_SUCCESS)
  346. {
  347. LSA_UNICODE_STRING lsausUserRights;
  348. InitLsaString(&lsausUserRights, _T("SeServiceLogonRight"));
  349. PSID pSid = SidFromString(strSid);
  350. if (pSid)
  351. {
  352. ntsStatus = LsaAddAccountRights(hPolicy, pSid, &lsausUserRights, 1L);
  353. rc = LsaNtStatusToWinError(ntsStatus);
  354. FreeSid(pSid);
  355. }
  356. else
  357. {
  358. rc = ERROR_OUTOFMEMORY;
  359. }
  360. LsaClose(hPolicy);
  361. }
  362. if ( rc )
  363. {
  364. if (pStats != NULL)
  365. pStats->errors.users++;
  366. err.SysMsgWrite(ErrE,rc,DCT_MSG_LOS_GRANT_FAILED_SSD,
  367. account,(WCHAR*)computer,rc);
  368. }
  369. else
  370. {
  371. err.MsgWrite(0,DCT_MSG_LOS_GRANTED_SS,
  372. account,(WCHAR*)computer);
  373. }
  374. }
  375. SC_HANDLE pService = OpenService(pScm,service,SERVICE_ALL_ACCESS);
  376. if ( pService )
  377. {
  378. int nCnt = 0;
  379. /* make sure the same user still starts this service */
  380. //get the source account names
  381. BOOL bSameAccount = TRUE;
  382. _bstr_t sSrcDom, sSrcSAM, sSrcUPN;
  383. _bstr_t sSrcAccount = L"";
  384. _bstr_t sSrcAccountUPN = L"";
  385. //if not given src names (not migrating right now), get them
  386. if ((!m_strSourceDomainFlat) && (!m_strSourceSam))
  387. {
  388. //if got names, get UPN name also
  389. if (RetrieveOriginalAccount(sSrcDom, sSrcSAM))
  390. {
  391. sSrcUPN = GetUPNName(sSrcSAM);
  392. sSrcAccount = sSrcDom + _bstr_t(L"\\") + sSrcSAM;
  393. }
  394. }
  395. else //els if given src names (migrate this object now), use those names
  396. {
  397. sSrcDom = m_strSourceDomainFlat;
  398. sSrcSAM = m_strSourceSam;
  399. sSrcUPN = GetUPNName(sSrcSAM);
  400. sSrcAccount = sSrcDom + _bstr_t(L"\\") + sSrcSAM;
  401. }
  402. //if got names to check, check them
  403. if ((sSrcAccount.length()) || (sSrcUPN.length()))
  404. {
  405. BYTE buf[3000];
  406. QUERY_SERVICE_CONFIG * pConfig = (QUERY_SERVICE_CONFIG *)buf;
  407. DWORD lenNeeded = 0;
  408. // get the information about this service
  409. if (QueryServiceConfig(pService, pConfig, sizeof buf, &lenNeeded))
  410. {
  411. //if not the same account, check UPN name or set to FALSE
  412. if ((sSrcAccount.length()) && (UStrICmp(pConfig->lpServiceStartName,sSrcAccount)))
  413. {
  414. //if UPN name, try it
  415. if (sSrcUPN.length())
  416. {
  417. //if not match either, set flag to FALSE;
  418. if (UStrICmp(pConfig->lpServiceStartName,sSrcUPN))
  419. bSameAccount = FALSE;
  420. }
  421. else //else, not a match
  422. bSameAccount = FALSE;
  423. }
  424. }
  425. }//if got names
  426. //if same account, update the SCM
  427. if (bSameAccount)
  428. {
  429. // update the account and password for the service
  430. while ( !ChangeServiceConfig(pService,
  431. SERVICE_NO_CHANGE, // dwServiceType
  432. SERVICE_NO_CHANGE, // dwStartType
  433. SERVICE_NO_CHANGE, // dwErrorControl
  434. NULL, // lpBinaryPathName
  435. NULL, // lpLoadOrderGroup
  436. NULL, // lpdwTagId
  437. NULL, // lpDependencies
  438. account, // lpServiceStartName
  439. ppassword, // lpPassword
  440. NULL) && nCnt < 5) // lpDisplayName
  441. {
  442. nCnt++;
  443. Sleep(500);
  444. }
  445. if ( nCnt < 5 )
  446. {
  447. err.MsgWrite(0,DCT_MSG_UPDATED_SCM_ENTRY_SS,(WCHAR*)computer,(WCHAR*)service);
  448. }
  449. else
  450. {
  451. rc = GetLastError();
  452. }
  453. }//end if still same account
  454. else //else if not same user, put message in log and return error
  455. {
  456. err.MsgWrite(0,DCT_MSG_UPDATE_SCM_ENTRY_UNMATCHED_SSD,(WCHAR*)computer,(WCHAR*)service,(WCHAR*)sSrcAccount);
  457. rc = DCT_MSG_UPDATE_SCM_ENTRY_UNMATCHED_SSD;
  458. }
  459. CloseServiceHandle(pService);
  460. }
  461. CloseServiceHandle(pScm);
  462. }
  463. else
  464. {
  465. rc = GetLastError();
  466. }
  467. return rc;
  468. }
  469. BOOL
  470. CServMigr::UpdateSCMs(
  471. IUnknown * pVS,
  472. WCHAR const * account,
  473. WCHAR const * password,
  474. WCHAR const * strSid,
  475. IIManageDB * pDB,
  476. EAMAccountStats * pStats
  477. )
  478. {
  479. BOOL bGotThemAll = TRUE;
  480. IVarSetPtr pVarSet = pVS;
  481. LONG nCount = 0;
  482. WCHAR key[LEN_Path];
  483. _bstr_t computer;
  484. _bstr_t service;
  485. long status;
  486. DWORD rc = 0;
  487. BOOL bFirst = TRUE;
  488. WCHAR prevComputer[LEN_Path] = L"";
  489. try {
  490. nCount = pVarSet->get("ServiceAccountEntries");
  491. for ( long i = 0 ; i < nCount ; i++ )
  492. {
  493. swprintf(key,L"Computer.%ld",i);
  494. computer = pVarSet->get(key);
  495. swprintf(key,L"Service.%ld",i);
  496. service = pVarSet->get(key);
  497. swprintf(key,L"ServiceAccountStatus.%ld",i);
  498. status = pVarSet->get(key);
  499. if ( status == SvcAcctStatus_NotMigratedYet || status == SvcAcctStatus_UpdateFailed )
  500. {
  501. if ( UStrICmp(prevComputer,(WCHAR*)computer) )
  502. {
  503. bFirst = TRUE; // reset the 'first' flag when the computer changes
  504. }
  505. try {
  506. rc = DoUpdate(account,password,strSid,computer,service,bFirst/*only grant SeServiceLogonRight once per account*/,
  507. pStats);
  508. bFirst = FALSE;
  509. safecopy(prevComputer,(WCHAR*)computer);
  510. }
  511. catch (...)
  512. {
  513. // Do we need to trigger the counter increment here?
  514. // if (pStats != NULL)
  515. // pStats->errors.users++;
  516. err.DbgMsgWrite(ErrE,L"Exception!");
  517. err.DbgMsgWrite(0,L"Updating %ls on %ls",(WCHAR*)service,(WCHAR*)computer);
  518. err.DbgMsgWrite(0,L"Account=%ls, SID=%ls",(WCHAR*)account,(WCHAR*)strSid);
  519. rc = E_FAIL;
  520. }
  521. if (! rc )
  522. {
  523. // the update was successful
  524. pDB->raw_SetServiceAcctEntryStatus(computer,service,_bstr_t(account),SvcAcctStatus_Updated);
  525. }
  526. else
  527. {
  528. // couldn't connect to this one -- we will need to save this account's password
  529. // in our encrypted storage
  530. pDB->raw_SetServiceAcctEntryStatus(computer,service,NULL,SvcAcctStatus_UpdateFailed);
  531. bGotThemAll = FALSE;
  532. SaveEncryptedPassword(computer,service,account,password);
  533. //if the current service account didn't match, we need not log an error
  534. if (rc != DCT_MSG_UPDATE_SCM_ENTRY_UNMATCHED_SSD)
  535. {
  536. err.SysMsgWrite(ErrE,rc,DCT_MSG_UPDATE_SCM_ENTRY_FAILED_SSD,(WCHAR*)computer,(WCHAR*)service,rc);
  537. pStats->errors.users++;
  538. }
  539. }
  540. }
  541. //else if skipping, still log in file so we can update later
  542. else if (status == SvcAcctStatus_DoNotUpdate)
  543. SaveEncryptedPassword(computer,service,account,password);
  544. }
  545. }
  546. catch ( ... )
  547. {
  548. // Do we need to trigger the counter increment here?
  549. // if (pStats != NULL)
  550. // pStats->errors.users++;
  551. err.DbgMsgWrite(ErrE,L"Exception!");
  552. }
  553. return bGotThemAll;
  554. }
  555. HRESULT
  556. CServMigr::SaveEncryptedPassword(
  557. WCHAR const * server,
  558. WCHAR const * service,
  559. WCHAR const * account,
  560. WCHAR const * password
  561. )
  562. {
  563. HRESULT hr = S_OK;
  564. TNodeListEnum e;
  565. TEntryNode* pNode;
  566. // if entry exists...
  567. for (pNode = (TEntryNode*)e.OpenFirst(&m_List); pNode; pNode = (TEntryNode*)e.Next())
  568. {
  569. if (_wcsicmp(pNode->GetComputer(), server) == 0)
  570. {
  571. if (_wcsicmp(pNode->GetService(), service) == 0)
  572. {
  573. if (_wcsicmp(pNode->GetAccount(), account) == 0)
  574. {
  575. // update password
  576. try {
  577. pNode->SetPassword(password);
  578. }
  579. catch (_com_error& ce) {
  580. hr = ce.Error();
  581. return hr;
  582. }
  583. break;
  584. }
  585. }
  586. }
  587. }
  588. // else...
  589. if (pNode == NULL)
  590. {
  591. // insert new entry
  592. try {
  593. pNode = new TEntryNode(server, service, account, password);
  594. }
  595. catch (_com_error& ce) {
  596. hr = ce.Error();
  597. return hr;
  598. }
  599. if (pNode)
  600. {
  601. m_List.InsertBottom(pNode);
  602. }
  603. else
  604. {
  605. hr = E_OUTOFMEMORY;
  606. }
  607. }
  608. return hr;
  609. }
  610. //////////////////////////////////////////////////////////////////////////////////////
  611. ///
  612. /// TEntryList implementation of secure storage for service account passwords
  613. ///
  614. ///
  615. //////////////////////////////////////////////////////////////////////////////////////
  616. DWORD
  617. TEntryList::LoadFromFile(WCHAR const * filename)
  618. {
  619. DWORD rc = 0;
  620. FILE * hSource = NULL;
  621. HCRYPTPROV hProv = 0;
  622. HCRYPTKEY hKey = 0;
  623. BYTE pbBuffer[BLOCK_SIZE];
  624. WCHAR strData[BLOCK_SIZE * 5] = { 0 };
  625. DWORD dwCount;
  626. int eof = 0;
  627. WCHAR fullpath[LEN_Path];
  628. BYTE *pbKeyBlob = NULL;
  629. DWORD dwBlobLen;
  630. // Get our install directory from the registry, and then append the filename
  631. HKEY hRegKey;
  632. DWORD type;
  633. DWORD lenValue = (sizeof fullpath);
  634. rc = RegOpenKey(HKEY_LOCAL_MACHINE,REGKEY_ADMT,&hRegKey);
  635. if ( ! rc )
  636. {
  637. rc = RegQueryValueEx(hRegKey,L"Directory",0,&type,(LPBYTE)fullpath,&lenValue);
  638. if (! rc )
  639. {
  640. UStrCpy(fullpath+UStrLen(fullpath),filename);
  641. }
  642. RegCloseKey(hRegKey);
  643. }
  644. if (rc != ERROR_SUCCESS)
  645. {
  646. goto done;
  647. }
  648. // Open the source file.
  649. if((hSource = _wfopen(fullpath,L"rb"))==NULL)
  650. {
  651. rc = GetLastError();
  652. goto done;
  653. }
  654. // acquire handle to key container which must exist
  655. if ((hProv = AcquireContext(true)) == 0)
  656. {
  657. rc = GetLastError();
  658. goto done;
  659. }
  660. // Read the key blob length from the source file and allocate it to memory.
  661. fread(&dwBlobLen, sizeof(DWORD), 1, hSource);
  662. if(ferror(hSource) || feof(hSource))
  663. {
  664. rc = GetLastError();
  665. goto done;
  666. }
  667. if((pbKeyBlob = (BYTE*)malloc(dwBlobLen)) == NULL)
  668. {
  669. rc = GetLastError();
  670. goto done;
  671. }
  672. // Read the key blob from the source file.
  673. fread(pbKeyBlob, 1, dwBlobLen, hSource);
  674. if(ferror(hSource) || feof(hSource))
  675. {
  676. rc = GetLastError();
  677. goto done;
  678. }
  679. // Import the key blob into the CSP.
  680. if(!CryptImportKey(hProv, pbKeyBlob, dwBlobLen, 0, 0, &hKey))
  681. {
  682. rc = GetLastError();
  683. goto done;
  684. }
  685. // Decrypt the source file and load the list
  686. do {
  687. // Read up to BLOCK_SIZE bytes from source file.
  688. dwCount = fread(pbBuffer, 1, BLOCK_SIZE, hSource);
  689. if(ferror(hSource))
  690. {
  691. rc = GetLastError();
  692. goto done;
  693. }
  694. eof=feof(hSource);
  695. // Decrypt the data.
  696. if(!CryptDecrypt(hKey, 0, eof, 0, pbBuffer, &dwCount))
  697. {
  698. rc = GetLastError();
  699. goto done;
  700. }
  701. // Read any complete entries from the buffer
  702. // first, add the buffer contents to any leftover information we had read from before
  703. WCHAR * curr = strData;
  704. long len = UStrLen(strData);
  705. WCHAR * nl = NULL;
  706. WCHAR computer[LEN_Computer];
  707. WCHAR service[LEN_Service];
  708. WCHAR account[LEN_Account];
  709. WCHAR password[LEN_Password];
  710. wcsncpy(strData + len,(WCHAR*)pbBuffer, dwCount / sizeof(WCHAR));
  711. strData[len + (dwCount / sizeof(WCHAR))] = 0;
  712. do {
  713. nl = wcschr(curr,L'\n');
  714. if ( nl )
  715. {
  716. *nl = 0;
  717. if ( swscanf(curr,L" %[^\t]\t%[^\t]\t%[^\t]\t%[^\t]\n",computer,service,account,password) )
  718. {
  719. TEntryNode * pNode = NULL;
  720. try {
  721. pNode = new TEntryNode(computer,service,account,password);
  722. }
  723. catch (_com_error& ce) {
  724. rc = ERROR_NOT_ENOUGH_MEMORY;
  725. goto done;
  726. }
  727. InsertBottom(pNode);
  728. }
  729. else
  730. {
  731. rc = E_FAIL;
  732. break;
  733. }
  734. // go on to the next entry
  735. curr = nl + 1;
  736. }
  737. } while ( nl );
  738. // there may be a partial record left in the buffer
  739. // if so, save it for the next read
  740. if ( (*curr) != 0 )
  741. {
  742. memmove(strData,curr,( 1 + UStrLen(curr) ) * (sizeof WCHAR));
  743. }
  744. else
  745. {
  746. strData[0] = L'\0';
  747. }
  748. } while(!feof(hSource));
  749. done:
  750. // Clean up
  751. if(pbKeyBlob)
  752. free(pbKeyBlob);
  753. if(hKey != 0)
  754. CryptDestroyKey(hKey);
  755. if(hProv != 0)
  756. CryptReleaseContext(hProv, 0);
  757. if(hSource != NULL)
  758. fclose(hSource);
  759. return rc;
  760. }
  761. DWORD
  762. TEntryList::SaveToFile(WCHAR const * filename)
  763. {
  764. DWORD rc = 0;
  765. BYTE pbBuffer[BUFFER_SIZE];
  766. DWORD dwCount;
  767. HANDLE hDest = INVALID_HANDLE_VALUE;
  768. BYTE * pbKeyBlob = NULL;
  769. DWORD dwBlobLen;
  770. HCRYPTPROV hProv = 0;
  771. HCRYPTKEY hKey = 0;
  772. HCRYPTKEY hXchgKey = 0;
  773. TEntryNode * pNode;
  774. TNodeListEnum e;
  775. WCHAR fullpath[LEN_Path];
  776. DWORD dwBlockSize;
  777. DWORD cbBlockSize = sizeof(dwBlockSize);
  778. DWORD dwPaddedCount;
  779. DWORD cbWritten;
  780. // Open the destination file.
  781. HKEY hRegKey;
  782. DWORD type;
  783. DWORD lenValue = (sizeof fullpath);
  784. rc = RegOpenKey(HKEY_LOCAL_MACHINE,REGKEY_ADMT,&hRegKey);
  785. if ( ! rc )
  786. {
  787. rc = RegQueryValueEx(hRegKey,L"Directory",0,&type,(LPBYTE)fullpath,&lenValue);
  788. if (! rc )
  789. {
  790. UStrCpy(fullpath+UStrLen(fullpath),filename);
  791. }
  792. RegCloseKey(hRegKey);
  793. }
  794. if (rc != ERROR_SUCCESS)
  795. {
  796. goto done;
  797. }
  798. //
  799. // Delete previous data file if it exists. This obviates the need to change the
  800. // security descriptor on the file as CreateFile does not apply the security
  801. // descriptor if the file is opened but only when created.
  802. //
  803. if (!DeleteFile(fullpath))
  804. {
  805. rc = GetLastError();
  806. if (rc == ERROR_FILE_NOT_FOUND)
  807. {
  808. rc = ERROR_SUCCESS;
  809. }
  810. else
  811. {
  812. goto done;
  813. }
  814. }
  815. //
  816. // Create security descriptor with administrators as owner and permissions on file
  817. // so that only administrators and system have full access to the file.
  818. //
  819. PSECURITY_DESCRIPTOR psd = NULL;
  820. BOOL bConvert = ConvertStringSecurityDescriptorToSecurityDescriptor(
  821. _T("O:BAD:P(A;NP;FA;;;BA)(A;NP;FA;;;SY)"),
  822. SDDL_REVISION_1,
  823. &psd,
  824. NULL
  825. );
  826. if (!bConvert)
  827. {
  828. rc = GetLastError();
  829. goto done;
  830. }
  831. //
  832. // Create file.
  833. //
  834. SECURITY_ATTRIBUTES sa;
  835. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  836. sa.lpSecurityDescriptor = psd;
  837. sa.bInheritHandle = FALSE;
  838. hDest = CreateFile(
  839. fullpath,
  840. GENERIC_WRITE,
  841. 0,
  842. &sa,
  843. CREATE_NEW,
  844. FILE_ATTRIBUTE_NORMAL,
  845. NULL
  846. );
  847. rc = GetLastError();
  848. if (psd)
  849. {
  850. LocalFree(psd);
  851. }
  852. if (hDest == INVALID_HANDLE_VALUE)
  853. {
  854. goto done;
  855. }
  856. // acquire handle to key container
  857. if ((hProv = AcquireContext(false)) == 0)
  858. {
  859. rc = GetLastError();
  860. goto done;
  861. }
  862. // Attempt to get handle to exchange key.
  863. if(!CryptGetUserKey(hProv,AT_KEYEXCHANGE,&hKey))
  864. {
  865. if(GetLastError()==NTE_NO_KEY)
  866. {
  867. // Create key exchange key pair.
  868. if(!CryptGenKey(hProv,AT_KEYEXCHANGE,0,&hKey))
  869. {
  870. rc = GetLastError();
  871. goto done;
  872. }
  873. }
  874. else
  875. {
  876. rc = GetLastError();
  877. goto done;
  878. }
  879. }
  880. CryptDestroyKey(hKey);
  881. CryptReleaseContext(hProv,0);
  882. // acquire handle to key container
  883. if ((hProv = AcquireContext(false)) == 0)
  884. {
  885. rc = GetLastError();
  886. goto done;
  887. }
  888. // Get a handle to key exchange key.
  889. if(!CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hXchgKey))
  890. {
  891. rc = GetLastError();
  892. goto done;
  893. }
  894. // Create a random block cipher session key.
  895. if(!CryptGenKey(hProv, CALG_RC2, CRYPT_EXPORTABLE, &hKey))
  896. {
  897. rc = GetLastError();
  898. goto done;
  899. }
  900. // Determine the size of the key blob and allocate memory.
  901. if(!CryptExportKey(hKey, hXchgKey, SIMPLEBLOB, 0, NULL, &dwBlobLen))
  902. {
  903. rc = GetLastError();
  904. goto done;
  905. }
  906. if((pbKeyBlob = (BYTE*)malloc(dwBlobLen)) == NULL)
  907. {
  908. rc = ERROR_NOT_ENOUGH_MEMORY;
  909. goto done;
  910. }
  911. // Export the key into a simple key blob.
  912. if(!CryptExportKey(hKey, hXchgKey, SIMPLEBLOB, 0, pbKeyBlob,
  913. &dwBlobLen))
  914. {
  915. rc = GetLastError();
  916. free(pbKeyBlob);
  917. goto done;
  918. }
  919. // Write the size of the key blob to the destination file.
  920. if (!WriteFile(hDest, &dwBlobLen, sizeof(DWORD), &cbWritten, NULL))
  921. {
  922. rc = GetLastError();
  923. free(pbKeyBlob);
  924. goto done;
  925. }
  926. // Write the key blob to the destination file.
  927. if(!WriteFile(hDest, pbKeyBlob, dwBlobLen, &cbWritten, NULL))
  928. {
  929. rc = GetLastError();
  930. free(pbKeyBlob);
  931. goto done;
  932. }
  933. // Free memory.
  934. free(pbKeyBlob);
  935. // get key cipher's block length in bytes
  936. if (CryptGetKeyParam(hKey, KP_BLOCKLEN, (BYTE*)&dwBlockSize, &cbBlockSize, 0))
  937. {
  938. dwBlockSize /= 8;
  939. }
  940. else
  941. {
  942. rc = GetLastError();
  943. goto done;
  944. }
  945. // Encrypt the item list and write it to the destination file.
  946. for ( pNode = (TEntryNode*)e.OpenFirst(this); pNode ; pNode = (TEntryNode *)e.Next() )
  947. {
  948. // copy an item into the buffer in the following format:
  949. // Computer\tService\tAccount\tPassword
  950. int cchWritten;
  951. const size_t BUFFER_SIZE_IN_WCHARS = sizeof(pbBuffer) / sizeof(wchar_t);
  952. wchar_t* pchLast = &(((wchar_t*)pbBuffer)[BUFFER_SIZE_IN_WCHARS - 1]);
  953. *pchLast = L'\0';
  954. const WCHAR * pszPwd = NULL;
  955. try {
  956. pszPwd = pNode->GetPassword();
  957. }
  958. catch (_com_error& ce) {
  959. rc = ERROR_DECRYPTION_FAILED;
  960. goto done;
  961. }
  962. if ( pszPwd && *pszPwd )
  963. {
  964. cchWritten = _snwprintf(
  965. (wchar_t*)pbBuffer,
  966. BUFFER_SIZE_IN_WCHARS,
  967. L"%s\t%s\t%s\t%s\n",
  968. pNode->GetComputer(),
  969. pNode->GetService(),
  970. pNode->GetAccount(),
  971. pszPwd
  972. );
  973. }
  974. else
  975. {
  976. cchWritten = _snwprintf(
  977. (wchar_t*)pbBuffer,
  978. BUFFER_SIZE_IN_WCHARS,
  979. L"%s\t%s\t%s\t%s\n",
  980. pNode->GetComputer(),
  981. pNode->GetService(),
  982. pNode->GetAccount(),
  983. L"NULL"
  984. );
  985. }
  986. pNode->ReleasePassword();
  987. pszPwd = NULL;
  988. if ((cchWritten < 0) || (*pchLast != L'\0'))
  989. {
  990. rc = ERROR_INSUFFICIENT_BUFFER;
  991. goto done;
  992. }
  993. dwCount = UStrLen((WCHAR*)pbBuffer) * (sizeof WCHAR) ;
  994. // the buffer must be a multiple of the key cipher's block length
  995. // NOTE: this algorithm assumes block length is multiple of sizeof(WCHAR)
  996. if (dwBlockSize > 0)
  997. {
  998. // calculate next multiple greater than count
  999. dwPaddedCount = ((dwCount + dwBlockSize - 1) / dwBlockSize) * dwBlockSize;
  1000. // pad buffer with space characters
  1001. WCHAR* pch = (WCHAR*)(pbBuffer + dwCount);
  1002. for (; dwCount < dwPaddedCount; dwCount += sizeof(WCHAR))
  1003. {
  1004. *pch++ = L' ';
  1005. }
  1006. }
  1007. // Encrypt the data.
  1008. if(!CryptEncrypt(hKey, 0, (pNode->Next() == NULL) , 0, pbBuffer, &dwCount,
  1009. BUFFER_SIZE))
  1010. {
  1011. rc = GetLastError();
  1012. goto done;
  1013. }
  1014. // Write the data to the destination file.
  1015. if(!WriteFile(hDest, pbBuffer, dwCount, &cbWritten, NULL))
  1016. {
  1017. rc = GetLastError();
  1018. goto done;
  1019. }
  1020. }
  1021. done:
  1022. // Destroy the session key.
  1023. if(hKey != 0) CryptDestroyKey(hKey);
  1024. // Destroy the key exchange key.
  1025. if(hXchgKey != 0) CryptDestroyKey(hXchgKey);
  1026. // Release the provider handle.
  1027. if(hProv != 0) CryptReleaseContext(hProv, 0);
  1028. // Close destination file.
  1029. if(hDest != INVALID_HANDLE_VALUE) CloseHandle(hDest);
  1030. return rc;
  1031. }
  1032. // AcquireContext Method
  1033. //
  1034. // acquire handle to key container within cryptographic service provider (CSP)
  1035. //
  1036. HCRYPTPROV TEntryList::AcquireContext(bool bContainerMustExist)
  1037. {
  1038. HCRYPTPROV hProv = 0;
  1039. #define KEY_CONTAINER_NAME _T("A69904BC349C4CFEAAEAB038BAB8C3B1")
  1040. if (bContainerMustExist)
  1041. {
  1042. // first try Microsoft Enhanced Cryptographic Provider
  1043. if (!CryptAcquireContext(&hProv, KEY_CONTAINER_NAME, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
  1044. {
  1045. if (GetLastError() == NTE_KEYSET_NOT_DEF)
  1046. {
  1047. // then try Microsoft Base Cryptographic Provider
  1048. CryptAcquireContext(&hProv, KEY_CONTAINER_NAME, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET);
  1049. }
  1050. }
  1051. }
  1052. else
  1053. {
  1054. // first try Microsoft Enhanced Cryptographic Provider
  1055. if (!CryptAcquireContext(&hProv, KEY_CONTAINER_NAME, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
  1056. {
  1057. DWORD dwError = GetLastError();
  1058. if ((dwError == NTE_BAD_KEYSET) || (dwError == NTE_KEYSET_NOT_DEF))
  1059. {
  1060. // then try creating key container in enhanced provider
  1061. if (!CryptAcquireContext(&hProv, KEY_CONTAINER_NAME, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET|CRYPT_NEWKEYSET))
  1062. {
  1063. dwError = GetLastError();
  1064. if (dwError == NTE_KEYSET_NOT_DEF)
  1065. {
  1066. // then try Microsoft Base Cryptographic Provider
  1067. if (!CryptAcquireContext(&hProv, KEY_CONTAINER_NAME, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
  1068. {
  1069. dwError = GetLastError();
  1070. if ((dwError == NTE_BAD_KEYSET) || (dwError == NTE_KEYSET_NOT_DEF))
  1071. {
  1072. // finally try creating key container in base provider
  1073. CryptAcquireContext(&hProv, KEY_CONTAINER_NAME, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET|CRYPT_NEWKEYSET);
  1074. }
  1075. }
  1076. }
  1077. }
  1078. }
  1079. }
  1080. }
  1081. return hProv;
  1082. }
  1083. STDMETHODIMP CServMigr::TryUpdateSam(BSTR computer,BSTR service,BSTR account)
  1084. {
  1085. HRESULT hr = S_OK;
  1086. // Find the entry in the list, and perform the update
  1087. TNodeListEnum e;
  1088. TEntryNode * pNode;
  1089. BOOL bFound = FALSE;
  1090. for ( pNode = (TEntryNode*)e.OpenFirst(&m_List) ; pNode ; pNode = (TEntryNode*)e.Next() )
  1091. {
  1092. if ( !UStrICmp(computer,pNode->GetComputer())
  1093. && !UStrICmp(service,pNode->GetService())
  1094. && !UStrICmp(account,pNode->GetAccount())
  1095. )
  1096. {
  1097. // found it!
  1098. bFound = TRUE;
  1099. const WCHAR * pszPwd = NULL;
  1100. try {
  1101. pszPwd = pNode->GetPassword();
  1102. }
  1103. catch (_com_error& ce) {
  1104. hr = ce.Error();
  1105. break;
  1106. }
  1107. BSTR bstrPwd = SysAllocString(pszPwd);
  1108. if ((bstrPwd == NULL) && pszPwd && pszPwd[0])
  1109. {
  1110. hr = E_OUTOFMEMORY;
  1111. pNode->ReleasePassword();
  1112. break;
  1113. }
  1114. hr = TryUpdateSamWithPassword(computer,service,account,bstrPwd );
  1115. pNode->ReleasePassword();
  1116. SecureZeroMemory(bstrPwd, wcslen(bstrPwd)*sizeof(WCHAR));
  1117. SysFreeString(bstrPwd);
  1118. break;
  1119. }
  1120. }
  1121. if ( ! bFound )
  1122. {
  1123. hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  1124. }
  1125. return hr;
  1126. }
  1127. STDMETHODIMP CServMigr::TryUpdateSamWithPassword(BSTR computer,BSTR service,BSTR domAccount,BSTR password)
  1128. {
  1129. DWORD rc = 0;
  1130. WCHAR domain[LEN_Domain];
  1131. _bstr_t dc;
  1132. WCHAR account[LEN_Account];
  1133. WCHAR domStr[LEN_Domain];
  1134. BYTE sid[100];
  1135. WCHAR strSid[200];
  1136. WCHAR * pSlash = wcschr(domAccount,L'\\');
  1137. SID_NAME_USE snu;
  1138. DWORD lenSid = DIM(sid);
  1139. DWORD lenDomStr = DIM(domStr);
  1140. DWORD lenStrSid = DIM(strSid);
  1141. // split out the domain and account names
  1142. if ( pSlash )
  1143. {
  1144. // UStrCpy(domain,domAccount,pSlash - domAccount + 1);
  1145. UStrCpy(domain,domAccount,(int)(pSlash - domAccount + 1));
  1146. UStrCpy(account,pSlash+1);
  1147. GetAnyDcName5(domain, dc);
  1148. // get the SID for the target account
  1149. if ( LookupAccountName(dc,account,sid,&lenSid,domStr,&lenDomStr,&snu) )
  1150. {
  1151. GetTextualSid(sid,strSid,&lenStrSid);
  1152. rc = DoUpdate(domAccount,password,strSid,computer,service,TRUE, NULL);
  1153. }
  1154. else
  1155. {
  1156. rc = GetLastError();
  1157. }
  1158. }
  1159. else
  1160. {
  1161. rc = ERROR_NOT_FOUND;
  1162. }
  1163. return HRESULT_FROM_WIN32(rc);
  1164. }
  1165. BOOL // ret - TRUE if directory found
  1166. CServMigr::GetDirectory(
  1167. WCHAR * filename // out - string buffer to store directory name
  1168. )
  1169. {
  1170. DWORD rc = 0;
  1171. BOOL bFound = FALSE;
  1172. TRegKey key;
  1173. rc = key.OpenRead(GET_STRING(IDS_HKLM_DomainAdmin_Key),HKEY_LOCAL_MACHINE);
  1174. if ( ! rc )
  1175. {
  1176. rc = key.ValueGetStr(L"Directory",filename,MAX_PATH);
  1177. if ( ! rc )
  1178. {
  1179. if ( *filename )
  1180. bFound = TRUE;
  1181. }
  1182. }
  1183. key.Close();
  1184. return bFound;
  1185. }
  1186. /*********************************************************************
  1187. * *
  1188. * Written by: Paul Thompson *
  1189. * Date: 28 MAY 2001 *
  1190. * *
  1191. * This function is responsible for retrieving the original *
  1192. * service account of the given migrated service account. We use the*
  1193. * target service account name and domain to lookup its source *
  1194. * account name and domain from the Migrated Objects table. *
  1195. * This function returns TRUE or FALSE and if TRUE, fills in the *
  1196. * given BSTRs for soure domain and source SAM name. *
  1197. * *
  1198. *********************************************************************/
  1199. //BEGIN RetrieveOriginalAccount
  1200. BOOL CServMigr::RetrieveOriginalAccount(_bstr_t &sSrcDom, _bstr_t &sSrcSAM)
  1201. {
  1202. /* local constants */
  1203. const long ONLY_ONE_MATCHED = 1;
  1204. /* local variables */
  1205. WCHAR sTemp[MAX_PATH];
  1206. BOOL bSuccess = FALSE;
  1207. IUnknown * pUnk = NULL;
  1208. /* function body */
  1209. try
  1210. {
  1211. IVarSetPtr pVSMig(__uuidof(VarSet));
  1212. IIManageDBPtr pDb(__uuidof(IManageDB));
  1213. //see if any target account fitting this SAM name and domain have been migrated
  1214. pVSMig->QueryInterface(IID_IUnknown, (void**) &pUnk);
  1215. HRESULT hrFind = pDb->raw_GetMigratedObjectsByTarget(m_strTargetDomain, m_strTargetSam, &pUnk);
  1216. pUnk->Release();
  1217. pUnk = NULL;
  1218. //if migrated only one account to this name, then fill the return strings
  1219. if (hrFind == S_OK)
  1220. {
  1221. //get objects number matching this description
  1222. long nMatched = pVSMig->get(L"MigratedObjects");
  1223. //if only one found, fill output strings
  1224. if (nMatched == ONLY_ONE_MATCHED)
  1225. {
  1226. swprintf(sTemp,L"MigratedObjects.0.%s",GET_STRING(DB_SourceDomain));
  1227. sSrcDom = pVSMig->get(sTemp);
  1228. swprintf(sTemp,L"MigratedObjects.0.%s",GET_STRING(DB_SourceSamName));
  1229. sSrcSAM = pVSMig->get(sTemp);
  1230. bSuccess = TRUE; //set success flag
  1231. }//end if found only one
  1232. }//end if found at least one
  1233. }
  1234. catch ( ... )
  1235. {
  1236. if (pUnk)
  1237. pUnk->Release();
  1238. bSuccess = false;
  1239. }
  1240. return bSuccess;
  1241. }
  1242. //END RetrieveOriginalAccount
  1243. /*********************************************************************
  1244. * *
  1245. * Written by: Paul Thompson *
  1246. * Date: 28 MAY 2001 *
  1247. * *
  1248. * This function is responsible for retrieving the UPN name of *
  1249. * the given account. The given account should be in NT4 format *
  1250. * (Domain\Username). The return will be the UPN or empty if not *
  1251. * retrieved. *
  1252. * *
  1253. *********************************************************************/
  1254. //BEGIN GetUPNName
  1255. _bstr_t CServMigr::GetUPNName(_bstr_t sSrcSAM)
  1256. {
  1257. /* local variables */
  1258. HRESULT hr;
  1259. _bstr_t sUPN = L"";
  1260. HANDLE hDs = NULL;
  1261. /* function body */
  1262. //bind to the source domain
  1263. DWORD dwError = DsBind(NULL,m_strSourceDomain,&hDs);
  1264. //now try to call DSCrackNames to get the UPN name
  1265. if ((dwError == ERROR_SUCCESS) && hDs)
  1266. {
  1267. PDS_NAME_RESULT pNamesOut = NULL;
  1268. WCHAR * pNamesIn[1];
  1269. _bstr_t sSrcAccount = m_strSourceDomainFlat + _bstr_t(L"\\") + m_strSourceSam;
  1270. pNamesIn[0] = (WCHAR*)sSrcAccount;
  1271. hr = DsCrackNames(hDs,DS_NAME_NO_FLAGS,DS_NT4_ACCOUNT_NAME,DS_USER_PRINCIPAL_NAME,1,pNamesIn,&pNamesOut);
  1272. DsUnBind(&hDs);
  1273. hDs = NULL;
  1274. //if got UPN name, store it
  1275. if ( !hr )
  1276. {
  1277. if ( pNamesOut->rItems[0].status == DS_NAME_NO_ERROR )
  1278. sUPN = pNamesOut->rItems[0].pName;
  1279. DsFreeNameResult(pNamesOut); //free the results
  1280. }//end if cracked name
  1281. }//end if bound
  1282. return sUPN;
  1283. }
  1284. //END GetUPNName