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.

858 lines
30 KiB

  1. //---------------------------------------------------------------------------
  2. // UPDTUPN.cpp
  3. //
  4. // Comment: This is a COM object extension for the MCS DCTAccountReplicator.
  5. // This object implements the IExtendAccountMigration interface.
  6. // The process method on this object updates the userPrincipalName
  7. // property on the user object.
  8. //
  9. // (c) Copyright 1995-1998, Mission Critical Software, Inc., All Rights Reserved
  10. //
  11. // Proprietary and confidential to Mission Critical Software, Inc.
  12. //---------------------------------------------------------------------------
  13. #include "stdafx.h"
  14. #include "ARExt.h"
  15. #include "ARExt_i.c"
  16. #include "UPNUpdt.h"
  17. #include "ErrDCT.hpp"
  18. #include "Names.hpp"
  19. #include <iads.h>
  20. #include <AdsHlp.h>
  21. #include "resstr.h"
  22. //#import "\bin\NetEnum.tlb" no_namespace
  23. #import "NetEnum.tlb" no_namespace
  24. #include "UpdtUPN.h"
  25. TErrorDct err;
  26. /////////////////////////////////////////////////////////////////////////////
  27. // CUpdtUPN
  28. StringLoader gString;
  29. //---------------------------------------------------------------------------
  30. // Get and set methods for the properties.
  31. //---------------------------------------------------------------------------
  32. STDMETHODIMP CUpdtUPN::get_sName(BSTR *pVal)
  33. {
  34. *pVal = m_sName;
  35. return S_OK;
  36. }
  37. STDMETHODIMP CUpdtUPN::put_sName(BSTR newVal)
  38. {
  39. m_sName = newVal;
  40. return S_OK;
  41. }
  42. STDMETHODIMP CUpdtUPN::get_sDesc(BSTR *pVal)
  43. {
  44. *pVal = m_sDesc;
  45. return S_OK;
  46. }
  47. STDMETHODIMP CUpdtUPN::put_sDesc(BSTR newVal)
  48. {
  49. m_sDesc = newVal;
  50. return S_OK;
  51. }
  52. //---------------------------------------------------------------------------
  53. // ProcessObject : This method doesn't do anything.
  54. //---------------------------------------------------------------------------
  55. STDMETHODIMP CUpdtUPN::PreProcessObject(
  56. IUnknown *pSource, //in- Pointer to the source AD object
  57. IUnknown *pTarget, //in- Pointer to the target AD object
  58. IUnknown *pMainSettings, //in- Varset filled with the settings supplied by user
  59. IUnknown **ppPropsToSet //in,out - Varset filled with Prop-Value pairs that will be set
  60. // once all extension objects are executed.
  61. )
  62. {
  63. IVarSetPtr pVs = pMainSettings;
  64. _variant_t var;
  65. _bstr_t sTemp;
  66. _bstr_t sUPN;
  67. _bstr_t sPref;
  68. _bstr_t sSuff;
  69. IADs * pAds = NULL;
  70. IADs * pAdsSource = NULL;
  71. HRESULT hr;
  72. WCHAR sTempUPN[7000];
  73. long ub, lb;
  74. _bstr_t sFull;
  75. _variant_t HUGEP * pDt;
  76. _bstr_t sAdsPath;
  77. _variant_t varDN;
  78. _bstr_t sIntraforest;
  79. _bstr_t sDomainDNS;
  80. _bstr_t sTargetOU;
  81. WCHAR fileName[MAX_PATH];
  82. bool bReplace = false;
  83. tstring sSAMName;
  84. tstring sUPNName;
  85. _bstr_t sOldUPN;
  86. bool bConflicted = false;
  87. SUPNStruc UPNStruc;
  88. // We need to process the user accounts only
  89. sTemp = pVs->get(GET_BSTR(DCTVS_CopiedAccount_Type));
  90. if (!sTemp.length())
  91. return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  92. if (_wcsicmp((WCHAR*)sTemp,L"user"))
  93. return S_OK;
  94. //store the name of this user in the UPN list
  95. sSAMName = _bstr_t(pVs->get(GET_BSTR(DCTVS_CopiedAccount_SourceSam)));
  96. //get the target domain DNS name
  97. sDomainDNS = pVs->get(GET_BSTR(DCTVS_Options_TargetDomainDns));
  98. //get the target OU path
  99. sTargetOU = pVs->get(GET_BSTR(DCTVS_Options_OuPath));
  100. //if not retrieved yet, get the default UPN suffix for this domain
  101. if (m_sUPNSuffix.length() == 0)
  102. {
  103. //if failed, use the domain's DNS name
  104. if (!GetDefaultUPNSuffix(sDomainDNS, sTargetOU))
  105. m_sUPNSuffix = sDomainDNS;
  106. }
  107. // Get the Error log filename from the Varset
  108. wcscpy(fileName, (WCHAR*)(pVs->get(GET_BSTR(DCTVS_Options_Logfile)).bstrVal));
  109. // Open the error log
  110. err.LogOpen(fileName, 1);
  111. sPref = pVs->get(GET_BSTR(DCTVS_Options_Prefix));
  112. sSuff = pVs->get(GET_BSTR(DCTVS_Options_Suffix));
  113. sIntraforest = pVs->get(GET_BSTR(DCTVS_Options_IsIntraforest));
  114. sTemp = pVs->get(GET_BSTR(DCTVS_AccountOptions_ReplaceExistingAccounts));
  115. if (!UStrICmp(sTemp,GET_STRING(IDS_YES)))
  116. bReplace = true;
  117. sAdsPath = L"";
  118. if ( pSource )
  119. {
  120. // Get the UPN from the source domain
  121. hr = pSource->QueryInterface(IID_IADs, (void**) &pAdsSource);
  122. }
  123. if ( pAdsSource )
  124. {
  125. if ( SUCCEEDED(hr) )
  126. {
  127. hr = pAdsSource->GetEx(L"userPrincipalName", &var);
  128. if (SUCCEEDED(hr) )
  129. {
  130. SAFEARRAY * pArray = V_ARRAY(&var);
  131. hr = SafeArrayGetLBound(pArray, 1, &lb);
  132. hr = SafeArrayGetUBound(pArray, 1, &ub);
  133. hr = SafeArrayAccessData(pArray, (void HUGEP **) &pDt);
  134. if ( SUCCEEDED(hr) )
  135. {
  136. // translate all the UPNs to the target domain.
  137. for ( long x = lb; x <= ub; x++)
  138. {
  139. wcsncpy(sTempUPN, (WCHAR*) pDt[x].bstrVal, 5000);
  140. sTempUPN[4999] = 0;
  141. //Get the stuff before the LAST @ sign.
  142. WCHAR * ndx = NULL;
  143. WCHAR * tempNdx = sTempUPN;
  144. do
  145. {
  146. tempNdx = wcschr(tempNdx + 1, L'@');
  147. if ( tempNdx )
  148. ndx = tempNdx;
  149. } while (tempNdx);
  150. if (ndx) *ndx = L'\0';
  151. if ( sPref.length() )
  152. sFull = sPref + _bstr_t(sTempUPN);
  153. else if ( sSuff.length() )
  154. sFull = _bstr_t(sTempUPN) + sSuff;
  155. else
  156. sFull = sTempUPN;
  157. sTemp = sFull;
  158. sUPN = sTemp + _bstr_t(L"@");
  159. sUPN = sUPN + m_sUPNSuffix;
  160. //store UPN name as it enters
  161. sOldUPN = sUPN;
  162. sUPNName = sUPN;
  163. //get unigue UPN on target
  164. GetUniqueUPN(sUPN, pVs, false, sAdsPath);
  165. //see if the two UPN's differ. If they do, then we had a conflict
  166. // if ((_wcsicmp(sOldUPN, sUPN) != 0) && (!bReplace))
  167. if (_wcsicmp((WCHAR*)sOldUPN, sUPN) != 0)
  168. {
  169. sUPNName = sUPN;
  170. hr = ERROR_OBJECT_ALREADY_EXISTS;
  171. bConflicted = true;
  172. }
  173. pDt[x] = _variant_t(sUPN);
  174. }
  175. SafeArrayUnaccessData(pArray);
  176. }
  177. }
  178. else
  179. {
  180. sTemp = pVs->get(GET_BSTR(DCTVS_CopiedAccount_TargetSam));
  181. sUPN = sTemp + _bstr_t(L"@");
  182. sUPN = sUPN + m_sUPNSuffix;
  183. //store UPN name as it enters
  184. sOldUPN = sUPN;
  185. sUPNName = sUPN;
  186. //get unigue UPN on target
  187. GetUniqueUPN(sUPN, pVs, true, sAdsPath);
  188. //see if the two UPN's differ. If they do, then we had a conflict
  189. // if ((_wcsicmp(sOldUPN, sUPN) != 0) && (!bReplace))
  190. if (_wcsicmp((WCHAR*)sOldUPN, sUPN) != 0)
  191. {
  192. sUPNName = sUPN;
  193. hr = ERROR_OBJECT_ALREADY_EXISTS;
  194. bConflicted = true;
  195. }
  196. }
  197. }
  198. }
  199. else
  200. {
  201. sTemp = pVs->get(GET_BSTR(DCTVS_CopiedAccount_TargetSam));
  202. sUPN = sTemp + _bstr_t(L"@");
  203. sUPN = sUPN + m_sUPNSuffix;
  204. //store UPN name as it enters
  205. sOldUPN = sUPN;
  206. sUPNName = sUPN;
  207. //get unigue UPN on target
  208. GetUniqueUPN(sUPN, pVs, true, sAdsPath);
  209. //see if the two UPN's differ. If they do, then we had a conflict
  210. // if ((_wcsicmp(sOldUPN, sUPN) != 0) && (!bReplace))
  211. if (_wcsicmp((WCHAR*)sOldUPN, sUPN) != 0)
  212. {
  213. sUPNName = sUPN;
  214. hr = ERROR_OBJECT_ALREADY_EXISTS;
  215. bConflicted = true;
  216. }
  217. }
  218. if ( pAds ) pAds->Release();
  219. if (pAdsSource) pAdsSource->Release();
  220. UPNStruc.sName = sUPNName;
  221. UPNStruc.sOldName = sOldUPN;
  222. UPNStruc.bConflicted = bConflicted;
  223. //insert UPN into Map
  224. mUPNMap.insert(CUPNMap::value_type(sSAMName, UPNStruc));
  225. return hr;
  226. }
  227. //---------------------------------------------------------------------------
  228. // ProcessObject : This method updates the UPN property of the object. It
  229. // first sees if a E-Mail is specified then it will set UPN
  230. // to that otherwise it builds it from SAMAccountName and the
  231. // Domain name
  232. //---------------------------------------------------------------------------
  233. STDMETHODIMP CUpdtUPN::ProcessObject(
  234. IUnknown *pSource, //in- Pointer to the source AD object
  235. IUnknown *pTarget, //in- Pointer to the target AD object
  236. IUnknown *pMainSettings, //in- Varset filled with the settings supplied by user
  237. IUnknown **ppPropsToSet //in,out - Varset filled with Prop-Value pairs that will be set
  238. // once all extension objects are executed.
  239. )
  240. {
  241. IVarSetPtr pVs = pMainSettings;
  242. _bstr_t sTemp;
  243. IADs * pAds = NULL;
  244. _variant_t var;
  245. HRESULT hr;
  246. WCHAR fileName[MAX_PATH];
  247. CUPNMap::iterator itUPNMap;
  248. tstring sSam;
  249. SUPNStruc UPNStruc;
  250. bool bReplace = false;
  251. _bstr_t sOldUPNSuffix;
  252. // We need to process the user accounts only
  253. sTemp = pVs->get(GET_BSTR(DCTVS_CopiedAccount_Type));
  254. if ( _wcsicmp((WCHAR*)sTemp,L"user") ) return S_OK;
  255. sTemp = pVs->get(GET_BSTR(DCTVS_AccountOptions_ReplaceExistingAccounts));
  256. if (!UStrICmp(sTemp,GET_STRING(IDS_YES)))
  257. bReplace = true;
  258. //get the target SAM name
  259. sSam = _bstr_t(pVs->get(GET_BSTR(DCTVS_CopiedAccount_SourceSam)));
  260. // Get the Error log filename from the Varset
  261. wcscpy(fileName, (WCHAR*)(pVs->get(GET_BSTR(DCTVS_Options_Logfile)).bstrVal));
  262. // Open the error log
  263. err.LogOpen(fileName, 1);
  264. // And only need to process the accounts copied to Win2k domain.
  265. if ( pTarget )
  266. {
  267. //Get the IADs pointer to manipulate properties
  268. hr = pTarget->QueryInterface(IID_IADs, (void**) &pAds);
  269. if (SUCCEEDED(hr))
  270. {
  271. //get the UPN name for this user from the list
  272. itUPNMap = mUPNMap.find(sSam);
  273. if (itUPNMap != mUPNMap.end())
  274. UPNStruc = itUPNMap->second;
  275. if (!UPNStruc.sName.empty())
  276. {
  277. bool bSame = false;
  278. //if replace mode, don't set UPN if same object we are replacing and
  279. //if not the same object, get it's current UPN Suffix
  280. if (bReplace)
  281. {
  282. hr = pAds->Get(L"userPrincipalName", &var);
  283. if (SUCCEEDED(hr))
  284. {
  285. //if replacing the object whose UPN conflicted, don't change it
  286. if (!UPNStruc.sOldName.compare(var.bstrVal))
  287. bSame = true;
  288. else //else, get the object's current UPN suffix for re-use
  289. sOldUPNSuffix = GetUPNSuffix(var.bstrVal);
  290. }
  291. }
  292. if (!bSame)
  293. {
  294. var = UPNStruc.sName.c_str();
  295. //if replacing an existing object, use it's old UPN suffix
  296. if ((bReplace) && (sOldUPNSuffix.length() != 0))
  297. {
  298. //change the suffix on the old name, since it may longer conflict
  299. _bstr_t sUPN = ChangeUPNSuffix(UPNStruc.sOldName.c_str(), sOldUPNSuffix);
  300. //if changed, make sure we don't still have a UPN conflict and save the
  301. //new UPN for setting
  302. if (sUPN.length() != 0)
  303. {
  304. _bstr_t sTempUPN = sUPN;
  305. //get unigue UPN on target, now that we could conflict
  306. GetUniqueUPN(sUPN, pVs, true, _bstr_t(L""));
  307. //if changed, set conflicted flag and names for error message
  308. if (sUPN != sTempUPN)
  309. {
  310. UPNStruc.sName = sUPN;
  311. UPNStruc.sOldName = sTempUPN;
  312. UPNStruc.bConflicted = true;
  313. }
  314. else
  315. UPNStruc.bConflicted = false;
  316. var = sUPN;
  317. }
  318. }
  319. hr = pAds->Put(L"userPrincipalName", var);
  320. if (SUCCEEDED(hr))
  321. {
  322. hr = pAds->SetInfo();
  323. if (SUCCEEDED(hr))
  324. {
  325. // If we changed the UPN Name due to conflict, we need to log a
  326. //message indicating the fact that we changed it.
  327. if (UPNStruc.bConflicted)
  328. err.MsgWrite(1, DCT_MSG_CREATE_FAILED_UPN_CONF_SS,
  329. UPNStruc.sOldName.c_str(), UPNStruc.sName.c_str());
  330. }
  331. }
  332. }
  333. }
  334. }
  335. }
  336. if ( pAds ) pAds->Release();
  337. return hr;
  338. }
  339. //---------------------------------------------------------------------------
  340. // ProcessUndo : We are not going to undo this.
  341. //---------------------------------------------------------------------------
  342. STDMETHODIMP CUpdtUPN::ProcessUndo(
  343. IUnknown *pSource, //in- Pointer to the source AD object
  344. IUnknown *pTarget, //in- Pointer to the target AD object
  345. IUnknown *pMainSettings, //in- Varset filled with the settings supplied by user
  346. IUnknown **ppPropsToSet //in,out - Varset filled with Prop-Value pairs that will be set
  347. // once all extension objects are executed.
  348. )
  349. {
  350. IVarSetPtr pVs = pMainSettings;
  351. _bstr_t sTemp, sSUPN;
  352. IADs * pAds = NULL;
  353. _variant_t var;
  354. HRESULT hr = S_OK;
  355. _bstr_t sAdsPath = L"";
  356. _bstr_t sTempUPN;
  357. // We need to process the user accounts only
  358. sTemp = pVs->get(GET_BSTR(DCTVS_CopiedAccount_Type));
  359. if ( _wcsicmp((WCHAR*)sTemp,L"user") ) return S_OK;
  360. // get the original source account's UPN
  361. sSUPN = pVs->get(GET_BSTR(DCTVS_CopiedAccount_SourceUPN));
  362. if (sSUPN.length())
  363. {
  364. sTempUPN = sSUPN;
  365. GetUniqueUPN(sTempUPN, pVs, true, sAdsPath);
  366. int len;
  367. WCHAR * ndx, * tempNdx = (WCHAR*)sTempUPN;
  368. do
  369. {
  370. tempNdx = wcschr(tempNdx + 1, L'@');
  371. if ( tempNdx )
  372. ndx = tempNdx;
  373. } while (tempNdx);
  374. if (ndx) len = ndx - sTempUPN;
  375. if (_wcsnicmp(sTempUPN, sSUPN, len) != 0)
  376. return S_OK;
  377. // And only need to process the accounts copied to Win2k domain.
  378. if ( pTarget )
  379. {
  380. //Get the IADs pointer to manipulate properties
  381. hr = pTarget->QueryInterface(IID_IADs, (void**) &pAds);
  382. if ( SUCCEEDED(hr) )
  383. {
  384. var = sSUPN;
  385. hr = pAds->Put(L"userPrincipalName", var);
  386. hr = pAds->SetInfo();
  387. }
  388. }
  389. if ( pAds ) pAds->Release();
  390. }
  391. return S_OK;
  392. }
  393. //---------------------------------------------------------------------------
  394. // GetUniqueUPN : This function checks if the UPN is unique if not then
  395. // appends a number starting with 0 and retries till a unique
  396. // UPN is found.
  397. //---------------------------------------------------------------------------
  398. void CUpdtUPN::GetUniqueUPN(_bstr_t &sUPN, IVarSetPtr pVs, bool bUsingSamName, _bstr_t sAdsPath)
  399. {
  400. // Here are the steps that we follow to get the unique UPN name
  401. // 1. Check if the current name is unique. If it is then return that.
  402. // 2. Append collision prefix and suffix if the sam account name has changed due to pref/suffix.
  403. // 3. Add a numeric suffix to the UPN and repeat till a unique UPN is found.
  404. // If the user tells us not to do this then we simply return the current UPN name.
  405. _bstr_t sProcess = pVs->get(GET_BSTR(DCTVS_Options_AllowDuplicateUPNs));
  406. if ( sProcess == GET_BSTR(IDS_YES) ) return;
  407. WCHAR sTempUPN[5000];
  408. // long x = 0;
  409. WCHAR sQuery[5000], sPath[5000];
  410. HRESULT hr = E_FAIL;
  411. // LPWSTR pCols[] = { L"distinguishedName" };
  412. LPWSTR pCols[] = { L"sAMAccountName" };
  413. BSTR * pData = NULL;
  414. SAFEARRAY * pSaCols = NULL;
  415. SAFEARRAYBOUND bd = { 1, 0 };
  416. _bstr_t sTgtDomain = pVs->get(GET_BSTR(DCTVS_Options_TargetDomainDns));
  417. INetObjEnumeratorPtr pQuery(__uuidof(NetObjEnumerator));
  418. IEnumVARIANT * pEnum = NULL;
  419. DWORD fetched = 0;
  420. _variant_t var;
  421. bool bCollPrefSufProcessed = false;
  422. _bstr_t sSourceSam = pVs->get(GET_BSTR(DCTVS_CopiedAccount_SourceSam));
  423. _bstr_t sTargetSam = pVs->get(GET_BSTR(DCTVS_CopiedAccount_TargetSam));
  424. _bstr_t sPrefix = pVs->get(GET_BSTR(DCTVS_AccountOptions_Prefix));
  425. _bstr_t sSuffix = pVs->get(GET_BSTR(DCTVS_AccountOptions_Suffix));
  426. _bstr_t sPref = pVs->get(GET_BSTR(DCTVS_Options_Prefix));
  427. _bstr_t sSuff = pVs->get(GET_BSTR(DCTVS_Options_Suffix));
  428. int offset = 0;
  429. WCHAR sTemp[5000];
  430. SAFEARRAY * psaPath = NULL;
  431. _variant_t varPath;
  432. _variant_t * pVar;
  433. bool bReplace = false;
  434. WCHAR sTempSAM[MAX_PATH];
  435. _bstr_t sNewSAM;
  436. _bstr_t sUPNSuffix;
  437. _bstr_t sUPNPrefix;
  438. _bstr_t sReplace = pVs->get(GET_BSTR(DCTVS_AccountOptions_ReplaceExistingAccounts));
  439. if (!UStrICmp(sReplace,GET_STRING(IDS_YES)))
  440. bReplace = true;
  441. wcscpy(sTempSAM, (WCHAR*)sSourceSam);
  442. StripSamName(sTempSAM);
  443. if ( sPref.length() )
  444. sNewSAM = sPref + _bstr_t(sTempSAM);
  445. else if ( sSuff.length() )
  446. sNewSAM = _bstr_t(sTempSAM) + sSuff;
  447. else
  448. sNewSAM = sTempSAM;
  449. wcscpy(sTempUPN, (WCHAR*) sUPN);
  450. //Get the stuff before the LAST @ sign.
  451. WCHAR * ndx = NULL;
  452. WCHAR * tempNdx = sTempUPN;
  453. do
  454. {
  455. tempNdx = wcschr(tempNdx + 1, L'@');
  456. if ( tempNdx )
  457. ndx = tempNdx;
  458. } while (tempNdx);
  459. if (ndx) *ndx = L'\0';
  460. sUPNSuffix = ndx+1;
  461. sUPNPrefix = sTempUPN;
  462. // Setup the path name to the domain.
  463. wsprintf(sPath, L"LDAP://%s", (WCHAR*)sTgtDomain);
  464. // setup the columns that we want the query to return to us.
  465. pSaCols = SafeArrayCreate(VT_BSTR, 1, &bd);
  466. if (pSaCols)
  467. {
  468. hr = SafeArrayAccessData(pSaCols, (void HUGEP **) &pData);
  469. if ( SUCCEEDED(hr) )
  470. {
  471. pData[0] = SysAllocString(pCols[0]);
  472. }
  473. hr = SafeArrayUnaccessData(pSaCols);
  474. }
  475. if ( SUCCEEDED(hr) )
  476. {
  477. // First we need to set up a query to find the UPN
  478. wcscpy(sTempUPN, (WCHAR*)sUPN);
  479. do
  480. {
  481. wsprintf(sQuery, L"(userPrincipalName=%s)", sTempUPN);
  482. hr = pQuery->raw_SetQuery(sPath, sTgtDomain, sQuery, ADS_SCOPE_SUBTREE, FALSE);
  483. if ( SUCCEEDED(hr) )
  484. hr = pQuery->raw_SetColumns(pSaCols);
  485. if ( SUCCEEDED(hr) )
  486. hr = pQuery->raw_Execute(&pEnum);
  487. if ( SUCCEEDED(hr) )
  488. {
  489. hr = pEnum->Next(1, &var, &fetched);
  490. while ( hr == S_OK )
  491. {
  492. if ( var.vt & VT_ARRAY )
  493. {
  494. psaPath = var.parray;
  495. hr = SafeArrayAccessData(psaPath, (void HUGEP**) &pVar);
  496. if ( SUCCEEDED(hr) )
  497. {
  498. varPath = pVar[0];
  499. }
  500. SafeArrayUnaccessData(psaPath);
  501. //SafeArrayGetElement(psaPath, &x, (void*)&varPath);
  502. if ( !wcslen((WCHAR*) varPath.bstrVal) )
  503. {
  504. hr = S_FALSE;
  505. }
  506. if ((!_wcsicmp((WCHAR*)varPath.bstrVal, (WCHAR*)sNewSAM)) && (bReplace))
  507. {
  508. // If the account found is the same as the account being processed then we
  509. // need to see if any other accounts have this UPN. if they do then we need
  510. // to change it other wise we do not need to process this any further.
  511. hr = pEnum->Next(1, &var, &fetched);
  512. continue;
  513. }
  514. else
  515. break;
  516. }
  517. }
  518. if ( hr == S_OK )
  519. {
  520. // If we are here that means we have a collision So we need to update the UPN and try again
  521. // See if we have processed the Prefix/Suffix
  522. if ( !bCollPrefSufProcessed )
  523. {
  524. // See if we renamed the samAccountName with the prefix/suffix. If we are already using
  525. // sam name then there is no need to add the prefix/suffix.
  526. if ( !bUsingSamName && RenamedWithPrefixSuffix(sSourceSam, sTargetSam, sPrefix, sSuffix))
  527. {
  528. // Since we renamed the sam names we can rename the UPN
  529. if ( sPrefix.length() )
  530. wsprintf(sTempUPN, L"%s%s", (WCHAR*)sPrefix, (WCHAR*)sUPNPrefix);
  531. if ( sSuffix.length() )
  532. wsprintf(sTempUPN, L"%s%s",(WCHAR*)sUPNPrefix, (WCHAR*)sSuffix);
  533. sUPNPrefix = sTempUPN; // we want to apply the prefix/suffix in any case.
  534. }
  535. else
  536. {
  537. // just add a number to the end of the name.
  538. wsprintf(sTempUPN, L"%s%d", (WCHAR*)sUPNPrefix, offset);
  539. offset++;
  540. }
  541. bCollPrefSufProcessed = true;
  542. }
  543. else
  544. {
  545. // we went through prefix/suffix and still found a collision so we need to go by the count now.
  546. wsprintf(sTempUPN, L"%s%d", (WCHAR*)sUPNPrefix, offset);
  547. offset++;
  548. }
  549. wcscpy(sTemp, sTempUPN);
  550. wsprintf(sTempUPN, L"%s@%s", sTemp, (WCHAR*)sUPNSuffix);
  551. }
  552. VariantInit(&var);
  553. if ( pEnum ) pEnum->Release();
  554. }
  555. } while ( hr == S_OK );
  556. SafeArrayDestroy(pSaCols);
  557. }
  558. sUPN = sTempUPN;
  559. }
  560. //---------------------------------------------------------------------------
  561. // RenamedWithPrefixSuffix : Checks to see if the Target sam name
  562. // was renamed with a prefix/suffix.
  563. //---------------------------------------------------------------------------
  564. bool CUpdtUPN::RenamedWithPrefixSuffix(_bstr_t sSourceSam, _bstr_t sTargetSam, _bstr_t sPrefix, _bstr_t sSuffix)
  565. {
  566. bool retVal = false;
  567. if ( sSourceSam != sTargetSam )
  568. {
  569. if ( sPrefix.length() )
  570. {
  571. if ( !wcsncmp((WCHAR*) sTargetSam, (WCHAR*) sPrefix, sPrefix.length()) )
  572. retVal = true;
  573. }
  574. if ( sSuffix.length() )
  575. {
  576. if ( !wcscmp((WCHAR*) sTargetSam + (sTargetSam.length() - sSuffix.length()), (WCHAR*) sSuffix ) )
  577. retVal = true;
  578. }
  579. }
  580. return retVal;
  581. }
  582. /*********************************************************************
  583. * *
  584. * Written by: Paul Thompson *
  585. * Date: 24 MAR 2001 *
  586. * *
  587. * This function is responsible for retrieving the default UPN *
  588. * suffix to be used in making UPN names. The suffix will be stored *
  589. * in a class member variable. *
  590. * First, using the given target OU path, see if the target OU *
  591. * has any UPN suffixes defined for it. If so, return store the *
  592. * last one enumerated. Otherwise, see if any UPN suffixes have *
  593. * been defined on the configuration's partition. If so, store the *
  594. * last one enumerated. If no success yet, use the forest root's *
  595. * domain DNS name. *
  596. * *
  597. *********************************************************************/
  598. //BEGIN GetDefaultUPNSuffix
  599. bool CUpdtUPN::GetDefaultUPNSuffix(_bstr_t sDomainDNS, _bstr_t sTargetOU)
  600. {
  601. /* local variables */
  602. IADs * pDSE = NULL;
  603. IADs * pCont = NULL;
  604. WCHAR sRoot[1000];
  605. HRESULT hr = S_OK;
  606. _variant_t var;
  607. _variant_t HUGEP * pVar;
  608. int nLast;
  609. /* function body */
  610. //check incoming parameters
  611. if ((sDomainDNS.length() == 0) || (sTargetOU.length() == 0))
  612. return false;
  613. /* first see if the target OU has UPN suffixes defined */
  614. //get a pointer to the target OU
  615. hr = ADsGetObject(sTargetOU,IID_IADs,(void**)&pCont);
  616. if ( SUCCEEDED(hr) )
  617. {
  618. //get any UPN suffixes defined
  619. hr = pCont->Get( L"uPNSuffixes", &var);
  620. if ( SUCCEEDED(hr) )
  621. {
  622. //if one, store it and return
  623. if ( var.vt == VT_BSTR )
  624. {
  625. m_sUPNSuffix = var.bstrVal; //store the suffix
  626. pCont->Release();
  627. return true;
  628. }
  629. //else if nore than one, get the first one, store it, and return
  630. else if ( var.vt & VT_ARRAY )
  631. {
  632. SAFEARRAY * multiVals = var.parray;
  633. SafeArrayAccessData(multiVals, (void HUGEP **) &pVar);
  634. nLast = multiVals->rgsabound->cElements - 1;
  635. m_sUPNSuffix = _bstr_t(V_BSTR(&pVar[nLast]));
  636. SafeArrayUnaccessData(multiVals);
  637. pCont->Release();
  638. return true;
  639. }
  640. }//end if suffixes defined on the partition
  641. pCont->Release();
  642. pCont = NULL;
  643. }//if got partition
  644. /* next try the UPN suffixes on the partition container or the root
  645. domain's DNS name */
  646. //get the root DSE container
  647. wcscpy(sRoot,L"LDAP://RootDSE");
  648. hr = ADsGetObject(sRoot,IID_IADs,(void**)&pDSE);
  649. if ( SUCCEEDED(hr) )
  650. {
  651. //get the suffixes listed on the configuration partition
  652. hr = pDSE->Get(L"configurationNamingContext",&var);
  653. if ( SUCCEEDED(hr) )
  654. {
  655. swprintf(sRoot,L"LDAP://%ls/CN=Partitions,%ls", (WCHAR*)sDomainDNS, var.bstrVal);
  656. hr = ADsGetObject(sRoot,IID_IADs,(void**)&pCont);
  657. if ( SUCCEEDED(hr) )
  658. {
  659. //get any UPN suffixes defined
  660. hr = pCont->Get( L"uPNSuffixes", &var);
  661. if ( SUCCEEDED(hr) )
  662. {
  663. //if one, store it and return
  664. if ( var.vt == VT_BSTR )
  665. {
  666. m_sUPNSuffix = var.bstrVal; //store the suffix
  667. pDSE->Release();
  668. pCont->Release();
  669. return true;
  670. }
  671. //else if nore than one, get the first one, store it, and return
  672. else if ( var.vt & VT_ARRAY )
  673. {
  674. SAFEARRAY * multiVals = var.parray;
  675. SafeArrayAccessData(multiVals, (void HUGEP **) &pVar);
  676. nLast = multiVals->rgsabound->cElements - 1;
  677. m_sUPNSuffix = _bstr_t(V_BSTR(&pVar[nLast]));
  678. SafeArrayUnaccessData(multiVals);
  679. pDSE->Release();
  680. pCont->Release();
  681. return true;
  682. }
  683. }//end if suffixes defined on the partition
  684. pCont->Release();
  685. pCont = NULL;
  686. }//if got partition
  687. }//if got config naming context
  688. //since no UPN suffixes defined on the partition, try the root domain's
  689. //DNS name
  690. hr = pDSE->Get(L"RootDomainNamingContext",&var);
  691. if ( SUCCEEDED(hr) )
  692. {
  693. //convert the DN of the root domain to a DNS name, store it, and return
  694. m_sUPNSuffix = GetDomainDNSFromPath(_bstr_t(var.bstrVal));
  695. pDSE->Release();
  696. return true;
  697. }
  698. pDSE->Release();
  699. pDSE = NULL;
  700. }//if got rootDSE
  701. return false;
  702. }
  703. //END GetDefaultUPNSuffix
  704. /*********************************************************************
  705. * *
  706. * Written by: Paul Thompson *
  707. * Date: 26 MAR 2001 *
  708. * *
  709. * This function is responsible for extracting the UPN Suffix *
  710. * from a given UPN name and returning that suffix. *
  711. * *
  712. *********************************************************************/
  713. //BEGIN GetUPNSuffix
  714. _bstr_t CUpdtUPN::GetUPNSuffix(_bstr_t sUPNName)
  715. {
  716. /* local variables */
  717. _bstr_t sUPNSuffix = L"";
  718. WCHAR * pTemp;
  719. /* function body */
  720. //check incoming parameters
  721. if (sUPNName.length() == 0)
  722. return sUPNSuffix;
  723. //find the last '@'
  724. pTemp = wcsrchr((WCHAR*)sUPNName, L'@');
  725. //if found, copy the suffix to the return variable
  726. if (pTemp)
  727. sUPNSuffix = pTemp+1;
  728. return sUPNSuffix;
  729. }
  730. //END GetUPNSuffix
  731. /*********************************************************************
  732. * *
  733. * Written by: Paul Thompson *
  734. * Date: 26 MAR 2001 *
  735. * *
  736. * This function is responsible for replacing the UPN Suffix *
  737. * on a given UPN name with the given suffix and returning the new *
  738. * UPN name. *
  739. * *
  740. *********************************************************************/
  741. //BEGIN ChangeUPNSuffix
  742. _bstr_t CUpdtUPN::ChangeUPNSuffix(_bstr_t sUPNName, _bstr_t sNewSuffix)
  743. {
  744. /* local variables */
  745. _bstr_t sNewUPN = L"";
  746. WCHAR * pTemp;
  747. /* function body */
  748. //check incoming parameters
  749. if (sUPNName.length() == 0)
  750. return sNewUPN;
  751. //create a temporary buffer to hold the UPN Name
  752. WCHAR* sUPN = new WCHAR[sUPNName.length() + 1];
  753. if (!sUPN)
  754. return sNewUPN;
  755. //copy the UPN to this buffer
  756. wcscpy(sUPN, sUPNName);
  757. //find the last '@'
  758. pTemp = wcsrchr(sUPN, L'@');
  759. //if found, make the new UPN with the old Prefix and given suffix
  760. if (pTemp)
  761. {
  762. //end the string after the '@'
  763. *(pTemp+1) = L'\0';
  764. //copy the Prefix plus the new Suffix to the new UPN name
  765. sNewUPN = sUPN + sNewSuffix;
  766. }
  767. //delete the prefix string
  768. delete [] sUPN;
  769. return sNewUPN;
  770. }
  771. //END ChangeUPNSuffix