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.

1473 lines
37 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999 - 1999
  6. //
  7. // File: copyobj.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. /////////////////////////////////////////////////////////////////////
  11. // copyobj.cpp
  12. //
  13. /////////////////////////////////////////////////////////////////////
  14. #include "stdafx.h"
  15. #include "resource.h"
  16. #include "util.h"
  17. #include "dsutil.h"
  18. #include "newobj.h"
  19. #include "copyobj.h"
  20. #include "dscmn.h" // CrackName()
  21. #include "querysup.h"
  22. // attributes for "intelligent" copy user
  23. static const PWSTR g_szProfilePath = L"profilePath";
  24. static const PWSTR g_szHomeDir = L"homeDirectory";
  25. /////////////////////////////////////////////////////////////////////
  26. // global functions
  27. //+----------------------------------------------------------------------------
  28. //
  29. // Function: _GetDomainScope
  30. //
  31. // Synopsis: Returns the full LDAP DN of the domain of the given object.
  32. //
  33. //-----------------------------------------------------------------------------
  34. HRESULT _GetDomainScope(IADs* pIADs, CString& szDomainLDAPPath)
  35. {
  36. // get the DN of the current object
  37. // get the SID of the object
  38. CComVariant varObjectDistinguishedName;
  39. HRESULT hr = pIADs->Get(L"distinguishedName", &varObjectDistinguishedName);
  40. if (FAILED(hr))
  41. {
  42. TRACE(L"pIADs->Get(distinguishedName,...) failed with hr = 0x%x\n", hr);
  43. return hr;
  44. }
  45. TRACE(L"Retrieved distinguishedName = <%s>\n", varObjectDistinguishedName.bstrVal);
  46. // obtain the FQDN of the domain the object is in
  47. LPWSTR pwzDomainDN = NULL;
  48. hr = CrackName(varObjectDistinguishedName.bstrVal, &pwzDomainDN, GET_FQDN_DOMAIN_NAME);
  49. if (FAILED(hr))
  50. {
  51. TRACE(L"CrackName(%s) failed with hr = 0x%x\n", varObjectDistinguishedName.bstrVal, hr);
  52. return hr;
  53. }
  54. TRACE(L"CrackName(%s) returned <%s>\n", varObjectDistinguishedName.bstrVal, pwzDomainDN);
  55. // retrieve the server name the object is bound to
  56. CString szServer;
  57. hr = GetADSIServerName(OUT szServer, IN pIADs);
  58. if (FAILED(hr))
  59. {
  60. TRACE(L"GetADSIServerName() failed with hr = 0x%x\n", hr);
  61. return hr;
  62. }
  63. TRACE(L"GetADSIServerName() returned <%s>\n", (LPCWSTR)szServer);
  64. // build the full LDAP path of the domain
  65. CPathCracker pathCracker;
  66. hr = pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
  67. hr = pathCracker.Set((LPWSTR)((LPCWSTR)szServer), ADS_SETTYPE_SERVER);
  68. hr = pathCracker.Set(pwzDomainDN, ADS_SETTYPE_DN);
  69. LocalFreeStringW(&pwzDomainDN);
  70. CComBSTR bstrDomainPath;
  71. hr = pathCracker.Retrieve(ADS_FORMAT_X500, &bstrDomainPath);
  72. if (FAILED(hr))
  73. {
  74. TRACE(L"PathCracker() failed to build LDAP path. hr = 0x%x\n", hr);
  75. return hr;
  76. }
  77. szDomainLDAPPath = bstrDomainPath;
  78. TRACE(L"Object's domain is: <%s>\n", (LPCWSTR)szDomainLDAPPath);
  79. return S_OK;
  80. }
  81. //+----------------------------------------------------------------------------
  82. //
  83. // Method: _ConvertRIDtoName
  84. //
  85. // Synopsis: Convert the RID to the object DN.
  86. //
  87. //-----------------------------------------------------------------------------
  88. HRESULT _ConvertRIDtoName(IN LPCWSTR lpszDomainLDAPPath,
  89. IN PSID pObjSID,
  90. IN DWORD priGroupRID,
  91. OUT CString& szGroupPath)
  92. {
  93. PWSTR g_wzADsPath = L"ADsPath";
  94. if ((pObjSID == NULL) || (priGroupRID == 0))
  95. {
  96. return E_INVALIDARG;
  97. }
  98. HRESULT hr = S_OK;
  99. UCHAR * psaCount, i;
  100. PSID pSID = NULL;
  101. PSID_IDENTIFIER_AUTHORITY psia;
  102. DWORD rgRid[8];
  103. psaCount = GetSidSubAuthorityCount(pObjSID);
  104. if (psaCount == NULL)
  105. {
  106. hr = HRESULT_FROM_WIN32(GetLastError());
  107. TRACE(L"GetSidSubAuthorityCount() failed, hr = 0x%x\n", hr);
  108. return hr;
  109. }
  110. ASSERT(*psaCount <= 8);
  111. if (*psaCount > 8)
  112. {
  113. return E_FAIL;
  114. }
  115. for (i = 0; i < (*psaCount - 1); i++)
  116. {
  117. PDWORD pRid = GetSidSubAuthority(pObjSID, (DWORD)i);
  118. if (pRid == NULL)
  119. {
  120. hr = HRESULT_FROM_WIN32(GetLastError());
  121. TRACE(L"GetSidSubAuthority() failed, hr = 0x%x\n", hr);
  122. return hr;
  123. }
  124. rgRid[i] = *pRid;
  125. }
  126. rgRid[*psaCount - 1] = priGroupRID;
  127. for (i = *psaCount; i < 8; i++)
  128. {
  129. rgRid[i] = 0;
  130. }
  131. psia = GetSidIdentifierAuthority(pObjSID);
  132. if (psia == NULL)
  133. {
  134. hr = HRESULT_FROM_WIN32(GetLastError());
  135. TRACE(L"GetSidIdentifierAuthority() failed, hr = 0x%x\n", hr);
  136. return hr;
  137. }
  138. if (!AllocateAndInitializeSid(psia, *psaCount, rgRid[0], rgRid[1],
  139. rgRid[2], rgRid[3], rgRid[4],
  140. rgRid[5], rgRid[6], rgRid[7], &pSID))
  141. {
  142. hr = HRESULT_FROM_WIN32(GetLastError());
  143. TRACE(L"AllocateAndInitializeSid() failed, hr = 0x%x\n", hr);
  144. return hr;
  145. }
  146. PWSTR rgpwzAttrNames[] = {g_wzADsPath};
  147. const WCHAR wzSearchFormat[] = L"(&(objectCategory=group)(objectSid=%s))";
  148. PWSTR pwzSID;
  149. CString strSearchFilter;
  150. hr = ADsEncodeBinaryData((PBYTE)pSID, GetLengthSid(pSID), &pwzSID);
  151. if (FAILED(hr))
  152. {
  153. TRACE(L"ADsEncodeBinaryData() failed, hr = 0x%x\n", hr);
  154. return hr;
  155. }
  156. strSearchFilter.Format(wzSearchFormat, pwzSID);
  157. FreeADsMem(pwzSID);
  158. CDSSearch Search;
  159. hr = Search.Init(lpszDomainLDAPPath);
  160. if (FAILED(hr))
  161. {
  162. TRACE(L"Search.Init(%s) failed, hr = 0x%x\n", lpszDomainLDAPPath, hr);
  163. return hr;
  164. }
  165. Search.SetFilterString(const_cast<LPWSTR>((LPCTSTR)strSearchFilter));
  166. Search.SetAttributeList(rgpwzAttrNames, 1);
  167. Search.SetSearchScope(ADS_SCOPE_SUBTREE);
  168. hr = Search.DoQuery();
  169. if (FAILED(hr))
  170. {
  171. TRACE(L"Search.DoQuery() failed, hr = 0x%x\n", hr);
  172. return hr;
  173. }
  174. hr = Search.GetNextRow();
  175. if (hr == S_ADS_NOMORE_ROWS)
  176. {
  177. hr = S_OK;
  178. szGroupPath = L"";
  179. TRACE(L"Search. returned S_ADS_NOMORE_ROWS, we failed to find the primary group object, hr = 0x%x\n", hr);
  180. return hr;
  181. }
  182. if (FAILED(hr))
  183. {
  184. TRACE(L"Search.GetNextRow() failed, hr = 0x%x\n", hr);
  185. return hr;
  186. }
  187. ADS_SEARCH_COLUMN Column;
  188. hr = Search.GetColumn(g_wzADsPath, &Column);
  189. if (FAILED(hr))
  190. {
  191. TRACE(L"Search.GetColumn(%s) failed, hr = 0x%x\n", g_wzADsPath, hr);
  192. return hr;
  193. }
  194. szGroupPath = Column.pADsValues->CaseIgnoreString;
  195. Search.FreeColumn(&Column);
  196. return hr;
  197. }
  198. /////////////////////////////////////////////////////////////////////
  199. // CCopyableAttributesHolder
  200. HRESULT CCopyableAttributesHolder::LoadFromSchema(MyBasePathsInfo* pBasePathsInfo)
  201. {
  202. TRACE(L"CCopyableAttributesHolder::LoadFromSchema()\n");
  203. // build the LDAP path for the schema class
  204. LPCWSTR lpszPhysicalSchemaNamingContext = pBasePathsInfo->GetSchemaNamingContext();
  205. CString szPhysicalSchemaPath;
  206. pBasePathsInfo->ComposeADsIPath(szPhysicalSchemaPath,lpszPhysicalSchemaNamingContext);
  207. CDSSearch search;
  208. HRESULT hr = search.Init(szPhysicalSchemaPath);
  209. if (FAILED(hr))
  210. {
  211. TRACE(L"search.Init(%s) failed with hr = 0x%x\n", (LPCWSTR)szPhysicalSchemaPath, hr);
  212. return hr;
  213. }
  214. // the query string filters out the attribute classes that have the
  215. // "searchFlags" attribute with the 5th bit set (16 == 2^4)
  216. static LPCWSTR lpszFilterFormat =
  217. L"(&(objectCategory=CN=Attribute-Schema,%s)(searchFlags:1.2.840.113556.1.4.803:=16))";
  218. int nFmtLen = lstrlen(lpszFilterFormat);
  219. int nSchemaContextLen = lstrlen(lpszPhysicalSchemaNamingContext);
  220. WCHAR* pszFilter = new WCHAR[nFmtLen+nSchemaContextLen+1];
  221. if (!pszFilter)
  222. {
  223. TRACE(L"Could not allocate enough space for filter string\n");
  224. return E_OUTOFMEMORY;
  225. }
  226. wsprintf(pszFilter, lpszFilterFormat, lpszPhysicalSchemaNamingContext);
  227. static const int cAttrs = 1;
  228. static LPCWSTR pszAttribsArr[cAttrs] =
  229. {
  230. L"lDAPDisplayName", // e.g. "accountExpires"
  231. };
  232. search.SetFilterString(pszFilter);
  233. search.SetSearchScope(ADS_SCOPE_ONELEVEL);
  234. search.SetAttributeList((LPWSTR*)pszAttribsArr, cAttrs);
  235. hr = search.DoQuery();
  236. if (FAILED(hr))
  237. {
  238. TRACE(L"search.DoQuery() failed with hr = 0x%x\n", hr);
  239. return hr;
  240. }
  241. TRACE(L"\n*** Query Results BEGIN ***\n\n");
  242. ADS_SEARCH_COLUMN Column;
  243. hr = search.GetNextRow();
  244. while (hr != S_ADS_NOMORE_ROWS)
  245. {
  246. if (FAILED(hr))
  247. {
  248. continue;
  249. }
  250. HRESULT hr0 = search.GetColumn((LPWSTR)pszAttribsArr[0], &Column);
  251. if (FAILED(hr0))
  252. {
  253. continue;
  254. }
  255. LPCWSTR lpszAttr = Column.pADsValues->CaseIgnoreString;
  256. TRACE(L"Attribute = %s", lpszAttr);
  257. // screen against attributes we want to skip anyway
  258. if (!_FindInNotCopyableHardwiredList(lpszAttr))
  259. {
  260. TRACE(L" can be copied");
  261. m_attributeNameList.AddTail(lpszAttr);
  262. }
  263. TRACE(L"\n");
  264. search.FreeColumn(&Column);
  265. hr = search.GetNextRow();
  266. } // while
  267. TRACE(L"\n*** Query Results END ***\n\n");
  268. if (pszFilter)
  269. {
  270. delete[] pszFilter;
  271. pszFilter = 0;
  272. }
  273. return hr;
  274. }
  275. BOOL CCopyableAttributesHolder::CanCopy(LPCWSTR lpszAttributeName)
  276. {
  277. for (POSITION pos = m_attributeNameList.GetHeadPosition(); pos != NULL; )
  278. {
  279. CString& strRef = m_attributeNameList.GetNext(pos);
  280. if (_wcsicmp(lpszAttributeName, strRef) == 0)
  281. return TRUE;
  282. }
  283. return FALSE;
  284. }
  285. // function to screen out attributes that will not
  286. // be copied (or not copied in bulk) no matter what the
  287. // schema setting are
  288. BOOL CCopyableAttributesHolder::_FindInNotCopyableHardwiredList(LPCWSTR lpszAttributeName)
  289. {
  290. static LPCWSTR _lpszNoCopyArr[] =
  291. {
  292. // we skip the toxic waste dump, no matter what
  293. L"userParameters",
  294. // userAccountControl handled separately after commit
  295. L"userAccountControl",
  296. // group membership (to be handled after commit)
  297. L"primaryGroupID",
  298. L"memberOf",
  299. NULL // end of table marker
  300. };
  301. for (int k = 0; _lpszNoCopyArr[k] != NULL; k++)
  302. {
  303. if (_wcsicmp(lpszAttributeName, _lpszNoCopyArr[k]) == 0)
  304. return TRUE;
  305. }
  306. return FALSE;
  307. }
  308. /////////////////////////////////////////////////////////////////////
  309. // CCopyObjectHandlerBase
  310. /////////////////////////////////////////////////////////////////////
  311. // CSid
  312. HRESULT CSid::Init(IADs* pIADs)
  313. {
  314. static LPWSTR g_wzObjectSID = L"objectSID";
  315. CComPtr<IDirectoryObject> spDirObj;
  316. HRESULT hr = pIADs->QueryInterface(IID_IDirectoryObject, (void**)&spDirObj);
  317. if (FAILED(hr))
  318. {
  319. return hr;
  320. }
  321. PWSTR rgpwzAttrNames[] = {g_wzObjectSID};
  322. DWORD cAttrs = 1;
  323. Smart_PADS_ATTR_INFO spAttrs;
  324. hr = spDirObj->GetObjectAttributes(rgpwzAttrNames, cAttrs, &spAttrs, &cAttrs);
  325. if (FAILED(hr))
  326. {
  327. return hr;
  328. }
  329. if (_wcsicmp(spAttrs[0].pszAttrName, g_wzObjectSID) != 0)
  330. {
  331. return E_FAIL;
  332. }
  333. if (!Init(spAttrs[0].pADsValues->OctetString.dwLength,
  334. spAttrs[0].pADsValues->OctetString.lpValue))
  335. {
  336. return E_OUTOFMEMORY;
  337. }
  338. return S_OK;
  339. }
  340. /////////////////////////////////////////////////////////////////////
  341. // CGroupMembershipHolder
  342. HRESULT CGroupMembershipHolder::Read(IADs* pIADs)
  343. {
  344. if (pIADs == NULL)
  345. return E_INVALIDARG;
  346. // hang on to the ADSI pointer
  347. m_spIADs = pIADs;
  348. // get the SID of the object
  349. HRESULT hr = m_objectSid.Init(m_spIADs);
  350. if (FAILED(hr))
  351. {
  352. TRACE(L"Failed to retrieve object SID, hr = 0x%x\n", hr);
  353. return hr;
  354. }
  355. // get the info about the domain we are in
  356. hr = _GetDomainScope(m_spIADs, m_szDomainLDAPPath);
  357. if (FAILED(hr))
  358. {
  359. TRACE(L"_GetDomainScope() failed, hr = 0x%x\n", hr);
  360. return hr;
  361. }
  362. hr = _ReadPrimaryGroupInfo();
  363. if (FAILED(hr))
  364. {
  365. TRACE(L"_ReadPrimaryGroupInfo() failed, hr = 0x%x\n", hr);
  366. return hr;
  367. }
  368. hr = _ReadNonPrimaryGroupInfo();
  369. if (FAILED(hr))
  370. {
  371. TRACE(L"_ReadNonPrimaryGroupInfo() failed, hr = 0x%x\n", hr);
  372. return hr;
  373. }
  374. #ifdef DBG
  375. m_entryList.Trace(L"Group Membership List:");
  376. #endif // DBG
  377. return hr;
  378. }
  379. HRESULT CGroupMembershipHolder::CopyFrom(CGroupMembershipHolder* pSource)
  380. {
  381. // Add all the elements that are in the source
  382. // but not yet in the destination
  383. CGroupMembershipEntryList* pSourceList = &(pSource->m_entryList);
  384. //
  385. // Copy the state of the primary group
  386. //
  387. m_bPrimaryGroupFound = pSource->m_bPrimaryGroupFound;
  388. CGroupMembershipEntryList additionsEntryList;
  389. for (POSITION pos = pSourceList->GetHeadPosition(); pos != NULL; )
  390. {
  391. CGroupMembershipEntry* pCurrSourceEntry = pSourceList->GetNext(pos);
  392. // look if the the source item is already in the current list
  393. CGroupMembershipEntry* pEntry = m_entryList.FindByDN(pCurrSourceEntry->GetDN());
  394. if (pEntry == NULL)
  395. {
  396. if (_wcsicmp(pCurrSourceEntry->GetDN(), L"") != 0)
  397. {
  398. // not found in the entry list, need to add
  399. pEntry = new CGroupMembershipEntry(pCurrSourceEntry->GetRID(), pCurrSourceEntry->GetDN());
  400. pEntry->MarkAdd();
  401. additionsEntryList.AddTail(pEntry);
  402. TRACE(L"add: RID %d, DN = <%s>\n", pEntry->GetRID(), pEntry->GetDN());
  403. }
  404. }
  405. } // for
  406. // find all the elements that are in the destination
  407. // but not in the source (slated for deletion)
  408. for (pos = m_entryList.GetHeadPosition(); pos != NULL; )
  409. {
  410. CGroupMembershipEntry* pCurrDestEntry = m_entryList.GetNext(pos);
  411. // look if the the source item is in the source list
  412. CGroupMembershipEntry* pEntry = pSourceList->FindByDN(pCurrDestEntry->GetDN());
  413. if (pEntry == NULL)
  414. {
  415. // not found in the entry list, need to mark for deletion
  416. pCurrDestEntry->MarkRemove();
  417. TRACE(L"remove: RID %d, DN = <%s>\n", pCurrDestEntry->GetRID(), pCurrDestEntry->GetDN());
  418. }
  419. } // for
  420. // catenate the list of additions to the entry list
  421. m_entryList.Merge(&additionsEntryList);
  422. return S_OK;
  423. }
  424. HRESULT _EditGroupMembership(LPCWSTR lpszServer, LPCWSTR lpszUserPath, LPCWSTR lpszGroupDN, BOOL bAdd)
  425. {
  426. // build the full LDAP path of the domain
  427. CPathCracker pathCracker;
  428. HRESULT hr = pathCracker.Set((LPWSTR)lpszServer, ADS_SETTYPE_SERVER);
  429. hr = pathCracker.Set((LPWSTR)lpszGroupDN, ADS_SETTYPE_DN);
  430. CComBSTR bstrGroupPath;
  431. hr = pathCracker.Retrieve(ADS_FORMAT_X500, &bstrGroupPath);
  432. if (FAILED(hr))
  433. {
  434. TRACE(L"PathCracker() failed to build LDAP path. hr = 0x%x\n", hr);
  435. return hr;
  436. }
  437. CComPtr<IADs> spIADs;
  438. hr = DSAdminOpenObject(bstrGroupPath,
  439. IID_IADs,
  440. (void **)&spIADs,
  441. TRUE /*bServer*/);
  442. if (FAILED(hr))
  443. {
  444. TRACE(L"DSAdminOpenObject(%s) on group failed, hr = 0x%x\n", bstrGroupPath, hr);
  445. return hr;
  446. }
  447. hr = spIADs->GetInfo();
  448. CComPtr<IADsGroup> spIADsGroup;
  449. hr = spIADs->QueryInterface(IID_IADsGroup, (void**)&spIADsGroup);
  450. if (bAdd)
  451. {
  452. hr = spIADsGroup->Add((LPWSTR)lpszUserPath);
  453. if (FAILED(hr))
  454. {
  455. TRACE(L"spIADsGroup->Add(%s) on group failed, hr = 0x%x\n", lpszUserPath, hr);
  456. return hr;
  457. }
  458. }
  459. else
  460. {
  461. hr = spIADsGroup->Remove((LPWSTR)lpszUserPath);
  462. if (FAILED(hr))
  463. {
  464. TRACE(L"spIADsGroup->Remove(%s) on group failed, hr = 0x%x\n", lpszUserPath, hr);
  465. return hr;
  466. }
  467. }
  468. hr = spIADsGroup->SetInfo();
  469. if (FAILED(hr))
  470. {
  471. TRACE(L"spIADsGroup->SetInfo() on group failed, hr = 0x%x\n", hr);
  472. return hr;
  473. }
  474. return hr;
  475. }
  476. HRESULT CGroupMembershipHolder::Write()
  477. {
  478. TRACE(L"CGroupMembershipHolder::Write()\n");
  479. #ifdef DBG
  480. m_entryList.Trace(L"Group Membership List:");
  481. #endif // DBG
  482. // get the path of the user object
  483. CComBSTR bstrObjPath;
  484. HRESULT hr = m_spIADs->get_ADsPath(&bstrObjPath);
  485. if (FAILED(hr))
  486. {
  487. TRACE(L"m_spIADs->get_ADsPath() failed with hr = 0x%x\n", hr);
  488. return hr;
  489. }
  490. TRACE(L"bstrPath = %s\n", (LPCWSTR)bstrObjPath);
  491. // retrieve the server name the object is bound to
  492. CString szServer;
  493. hr = GetADSIServerName(OUT szServer, IN m_spIADs);
  494. if (FAILED(hr))
  495. {
  496. TRACE(L"GetADSIServerName() failed with hr = 0x%x\n", hr);
  497. return hr;
  498. }
  499. // first do all the additions
  500. // also remember if we added a primary group
  501. CGroupMembershipEntry* pNewPrimaryGroupEntry = NULL;
  502. TRACE(L"\nfirst do all the additions\n\n");
  503. for (POSITION pos = m_entryList.GetHeadPosition(); pos != NULL; )
  504. {
  505. CGroupMembershipEntry* pCurrEntry = m_entryList.GetNext(pos);
  506. if (pCurrEntry->GetActionType() == CGroupMembershipEntry::add)
  507. {
  508. TRACE(L"add: RID %d, DN = <%s>\n", pCurrEntry->GetRID(), pCurrEntry->GetDN());
  509. pCurrEntry->m_hr = _EditGroupMembership(szServer, bstrObjPath, pCurrEntry->GetDN(), TRUE /*bAdd*/);
  510. if (SUCCEEDED(pCurrEntry->m_hr) && (pCurrEntry->IsPrimaryGroup()))
  511. {
  512. ASSERT(pNewPrimaryGroupEntry == NULL);
  513. pNewPrimaryGroupEntry = pCurrEntry;
  514. }
  515. }
  516. } // for
  517. if (m_bPrimaryGroupFound)
  518. {
  519. // second, do the primary group change
  520. TRACE(L"\ndo the primary group change\n\n");
  521. if (pNewPrimaryGroupEntry != NULL)
  522. {
  523. TRACE(L"new primary: RID %d, DN = <%s>\n",
  524. pNewPrimaryGroupEntry->GetRID(), pNewPrimaryGroupEntry->GetDN());
  525. CComVariant varPrimaryGroupID;
  526. varPrimaryGroupID.vt = VT_I4;
  527. varPrimaryGroupID.lVal = pNewPrimaryGroupEntry->GetRID();
  528. hr = m_spIADs->Put(L"primaryGroupID", varPrimaryGroupID);
  529. if (FAILED(hr))
  530. {
  531. TRACE(L"m_spIADs->Put(primaryGroupID) failed with hr = 0x%x\n", hr);
  532. return hr;
  533. }
  534. hr = m_spIADs->SetInfo();
  535. if (FAILED(hr))
  536. {
  537. TRACE(L"m_spIADs->SetInfo() failed with hr = 0x%x\n", hr);
  538. return hr;
  539. }
  540. }
  541. }
  542. // finally do the deletes
  543. TRACE(L"\ndo the deletes\n\n");
  544. for (pos = m_entryList.GetHeadPosition(); pos != NULL; )
  545. {
  546. CGroupMembershipEntry* pCurrEntry = m_entryList.GetNext(pos);
  547. if (pCurrEntry->GetActionType() == CGroupMembershipEntry::remove)
  548. {
  549. TRACE(L"remove: RID %d, DN = <%s>\n", pCurrEntry->GetRID(), pCurrEntry->GetDN());
  550. pCurrEntry->m_hr = _EditGroupMembership(szServer, bstrObjPath, pCurrEntry->GetDN(), FALSE /*bAdd*/);
  551. }
  552. } // for
  553. return S_OK;
  554. }
  555. void CGroupMembershipHolder::ProcessFailures(HRESULT& hr, CString& szFailureString, BOOL* pPrimaryGroupFound)
  556. {
  557. // reset variables
  558. hr = S_OK;
  559. szFailureString.Empty();
  560. BOOL bFirstOne = TRUE;
  561. BOOL bGotAccessDenied = FALSE;
  562. *pPrimaryGroupFound = m_bPrimaryGroupFound;
  563. // compose the best error code. If one code is access denied,
  564. // return it. If none is access denied, use the first error code
  565. for (POSITION pos = m_entryList.GetHeadPosition(); pos != NULL; )
  566. {
  567. CGroupMembershipEntry* pCurrEntry = m_entryList.GetNext(pos);
  568. if (FAILED(pCurrEntry->m_hr))
  569. {
  570. if (pCurrEntry->m_hr == E_ACCESSDENIED)
  571. {
  572. bGotAccessDenied = TRUE;
  573. }
  574. if (bFirstOne)
  575. {
  576. bFirstOne = FALSE;
  577. hr = pCurrEntry->m_hr;
  578. }
  579. else
  580. {
  581. szFailureString += L"\n";
  582. }
  583. LPWSTR pszCanonical = NULL;
  584. HRESULT hrCanonical =
  585. CrackName((LPWSTR)pCurrEntry->GetDN(), &pszCanonical, GET_OBJ_CAN_NAME, NULL);
  586. if ((S_OK == hrCanonical) && (pszCanonical != NULL))
  587. {
  588. szFailureString += pszCanonical;
  589. LocalFreeStringW(&pszCanonical);
  590. }
  591. else
  592. {
  593. szFailureString += pCurrEntry->GetDN();
  594. }
  595. }
  596. } // for
  597. if (bGotAccessDenied)
  598. {
  599. // override any error we have
  600. hr = E_ACCESSDENIED;
  601. }
  602. }
  603. HRESULT CGroupMembershipHolder::_ReadPrimaryGroupInfo()
  604. {
  605. // from the object SID and the primary group RID, get the full
  606. // primary group info
  607. // read the RID for the primary group
  608. CComVariant varPrimaryGroupID;
  609. HRESULT hr = m_spIADs->Get(L"primaryGroupID", &varPrimaryGroupID);
  610. if (FAILED(hr))
  611. {
  612. TRACE(L"m_spIADs->Get(primaryGroupID, ...) failed, hr = 0x%x\n", hr);
  613. return hr;
  614. }
  615. ASSERT(varPrimaryGroupID.vt == VT_I4);
  616. TRACE(L"primaryGroupID = %d\n", varPrimaryGroupID.lVal);
  617. // now need to map it into actual group information
  618. CString szGroupPath;
  619. PSID pObjSID = m_objectSid.GetSid();
  620. DWORD priGroupRID = varPrimaryGroupID.lVal;
  621. hr = _ConvertRIDtoName(IN m_szDomainLDAPPath,
  622. IN pObjSID,
  623. IN priGroupRID,
  624. OUT szGroupPath);
  625. if (FAILED(hr))
  626. {
  627. TRACE(L"_ConvertRIDtoName() failed, hr = 0x%x\n", hr);
  628. return hr;
  629. }
  630. CComBSTR bstrGroupDN;
  631. if (szGroupPath != L"")
  632. {
  633. m_bPrimaryGroupFound = TRUE;
  634. // from the LDAP path, retrieve the DN
  635. CPathCracker pathCracker;
  636. hr = pathCracker.Set((LPWSTR)(LPCWSTR)szGroupPath, ADS_SETTYPE_FULL);
  637. hr = pathCracker.Retrieve(ADS_FORMAT_X500_DN, &bstrGroupDN);
  638. if (FAILED(hr))
  639. {
  640. TRACE(L"PathCracker() failed to build primary group DN path. hr = 0x%x\n", hr);
  641. return hr;
  642. }
  643. }
  644. else
  645. {
  646. bstrGroupDN = szGroupPath;
  647. }
  648. // create a new entry
  649. CGroupMembershipEntry* pEntry = new CGroupMembershipEntry(priGroupRID, bstrGroupDN);
  650. m_entryList.AddTail(pEntry);
  651. TRACE(L"CGroupMembershipEntry(%d,%s) added to list\n", priGroupRID, bstrGroupDN);
  652. return hr;
  653. }
  654. HRESULT CGroupMembershipHolder::_ReadNonPrimaryGroupInfo()
  655. {
  656. // copy group membership
  657. CComVariant varMemberOf;
  658. HRESULT hr = m_spIADs->Get(L"memberOf", &varMemberOf);
  659. if (hr == E_ADS_PROPERTY_NOT_FOUND)
  660. {
  661. TRACE(L"_ReadNonPrimaryGroupInfo(): memberOf not set\n");
  662. return S_OK;
  663. }
  664. if (FAILED(hr))
  665. {
  666. return hr;
  667. }
  668. CStringList groupList;
  669. hr = HrVariantToStringList(IN varMemberOf, groupList);
  670. if (FAILED(hr))
  671. {
  672. TRACE(L"HrVariantToStringList() failed with hr = 0x%x\n", hr);
  673. return hr;
  674. }
  675. CComBSTR bstrPath;
  676. hr = m_spIADs->get_ADsPath(&bstrPath);
  677. if (FAILED(hr))
  678. {
  679. TRACE(L"m_spIADs->get_ADsPath() failed with hr = 0x%x\n", hr);
  680. return hr;
  681. }
  682. TRACE(L"bstrPath = %s\n", (LPCWSTR)bstrPath);
  683. for (POSITION pos = groupList.GetHeadPosition(); pos != NULL; )
  684. {
  685. CString szGroupDN = groupList.GetNext(pos);
  686. TRACE(_T("szGroupDN: %s\n"), (LPCWSTR)szGroupDN);
  687. CGroupMembershipEntry* pEntry = new CGroupMembershipEntry(0x0, szGroupDN);
  688. m_entryList.AddTail(pEntry);
  689. }
  690. return hr;
  691. }
  692. /////////////////////////////////////////////////////////////////////
  693. // CCopyUserHandler
  694. HRESULT CCopyUserHandler::Init(MyBasePathsInfo* pBasePathsInfo, IADs* pIADsCopyFrom)
  695. {
  696. HRESULT hr = CCopyObjectHandlerBase::Init(pBasePathsInfo, pIADsCopyFrom);
  697. if (FAILED(hr))
  698. {
  699. return hr;
  700. }
  701. // read list of copyable attributes form the schema
  702. hr = m_copyableAttributesHolder.LoadFromSchema(pBasePathsInfo);
  703. if (FAILED(hr))
  704. {
  705. return hr;
  706. }
  707. // read group membership information
  708. hr = m_sourceMembershipHolder.Read(m_spIADsCopyFrom);
  709. if (FAILED(hr))
  710. {
  711. return hr;
  712. }
  713. hr = _ReadPasswordCannotChange();
  714. if (FAILED(hr))
  715. {
  716. return hr;
  717. }
  718. hr = _ReadPasswordMustChange();
  719. return hr;
  720. }
  721. HRESULT CCopyUserHandler::Copy(IADs* pIADsCopyTo, BOOL bPostCommit,
  722. HWND hWnd, LPCWSTR lpszObjectName)
  723. {
  724. HRESULT hr = S_OK;
  725. if (bPostCommit)
  726. {
  727. hr = _CopyGroupMembership(pIADsCopyTo);
  728. if (SUCCEEDED(hr))
  729. {
  730. // might have failed to add to some group(s)
  731. _ShowGroupMembershipWarnings(hWnd, lpszObjectName);
  732. }
  733. if (FAILED(hr))
  734. {
  735. // something went really wrong, need to bail out
  736. return hr;
  737. }
  738. if (m_bNeedToCreateHomeDir)
  739. {
  740. // it might fail under unforeseen circumstances
  741. hr = _CreateHomeDirectory(pIADsCopyTo, lpszObjectName, hWnd);
  742. }
  743. }
  744. else
  745. {
  746. hr = _UpdatePaths(pIADsCopyTo);
  747. }
  748. return hr;
  749. }
  750. HRESULT CCopyUserHandler::_ReadPasswordCannotChange()
  751. {
  752. CChangePasswordPrivilegeAction ChangePasswordPrivilegeAction;
  753. HRESULT hr = ChangePasswordPrivilegeAction.Load(GetCopyFrom());
  754. if (FAILED(hr))
  755. {
  756. TRACE(L"ChangePasswordPrivilegeAction.Load() failed with hr = 0x%x\n", hr);
  757. return hr;
  758. }
  759. hr = ChangePasswordPrivilegeAction.Read(&m_bPasswordCannotChange);
  760. if (FAILED(hr))
  761. {
  762. TRACE(L"ChangePasswordPrivilegeAction.Read() failed with hr = 0x%x\n", hr);
  763. return hr;
  764. }
  765. return S_OK;
  766. }
  767. HRESULT CCopyUserHandler::_ReadPasswordMustChange()
  768. {
  769. CComPtr<IDirectoryObject> spDirObj;
  770. HRESULT hr = GetCopyFrom()->QueryInterface(IID_IDirectoryObject, (void**)&spDirObj);
  771. if (FAILED(hr))
  772. {
  773. return hr;
  774. }
  775. PWSTR rgpwzAttrNames[] = {L"pwdLastSet"};
  776. DWORD cAttrs = 1;
  777. Smart_PADS_ATTR_INFO spAttrs;
  778. hr = spDirObj->GetObjectAttributes(rgpwzAttrNames, cAttrs, &spAttrs, &cAttrs);
  779. if (FAILED(hr))
  780. {
  781. return hr;
  782. }
  783. if ( (_wcsicmp(spAttrs[0].pszAttrName, L"pwdLastSet") != 0) ||
  784. (spAttrs[0].dwADsType != ADSTYPE_LARGE_INTEGER) )
  785. {
  786. return E_FAIL;
  787. }
  788. m_bPasswordMustChange = (spAttrs[0].pADsValues->LargeInteger.QuadPart == 0);
  789. return S_OK;
  790. }
  791. HRESULT CCopyUserHandler::_CopyAttributes(IADs* pIADsCopyTo)
  792. {
  793. ASSERT(pIADsCopyTo != NULL);
  794. ASSERT(m_spIADsCopyFrom != NULL);
  795. HRESULT hr = S_OK;
  796. CComPtr<IADsPropertyList> spIADsPropertyList;
  797. // get a property list interface from the object we want to copy from
  798. hr = m_spIADsCopyFrom->QueryInterface(IID_IADsPropertyList, (void**)&spIADsPropertyList);
  799. if (FAILED(hr))
  800. {
  801. return hr;
  802. }
  803. // ignore the return value and try to continue even if it didn't reset
  804. hr = spIADsPropertyList->Reset();
  805. // loop thru the list of set attributes
  806. CComVariant varProperty;
  807. do
  808. {
  809. hr = spIADsPropertyList->Next(&varProperty);
  810. if (SUCCEEDED(hr))
  811. {
  812. ASSERT(varProperty.vt == VT_DISPATCH);
  813. if (varProperty.pdispVal != NULL)
  814. {
  815. CComPtr<IADsPropertyEntry> spIADsPropertyEntry;
  816. hr = (varProperty.pdispVal)->QueryInterface(IID_IADsPropertyEntry, (void**)&spIADsPropertyEntry);
  817. if (SUCCEEDED(hr))
  818. {
  819. CComBSTR bstrName;
  820. hr = spIADsPropertyEntry->get_Name(&bstrName);
  821. if (SUCCEEDED(hr))
  822. {
  823. TRACE(L" Property Name = <%s>", bstrName);
  824. if (m_copyableAttributesHolder.CanCopy(bstrName))
  825. {
  826. TRACE(L" Can copy: ");
  827. CComVariant varData;
  828. hr = m_spIADsCopyFrom->Get(bstrName, &varData);
  829. if (SUCCEEDED(hr))
  830. {
  831. HRESULT hr1 = pIADsCopyTo->Put(bstrName, varData);
  832. if (SUCCEEDED(hr1))
  833. {
  834. TRACE(L"Added");
  835. }
  836. else
  837. {
  838. TRACE(L"Failed: 0x%x", hr1);
  839. }
  840. }
  841. }
  842. TRACE(L"\n");
  843. }
  844. }
  845. }
  846. }
  847. varProperty.Clear();
  848. }
  849. while (hr == S_OK);
  850. return S_OK;
  851. }
  852. // Given an IADs* of an object, retrieves a string attrubute
  853. // in a variant
  854. HRESULT _GetStringAttribute(IN IADs* pIADs, IN LPCWSTR lpszAttribute, OUT CComVariant& var)
  855. {
  856. TRACE(L"_GetStringAttribute(_, %s, _)\n", lpszAttribute);
  857. HRESULT hr = pIADs->Get((LPWSTR)lpszAttribute, &var);
  858. if (FAILED(hr))
  859. {
  860. TRACE(L"_GetStringAttribute(): pIADs->Get() failed with hr = 0x%x\n", hr);
  861. return hr;
  862. }
  863. if (var.vt != VT_BSTR)
  864. {
  865. TRACE(L"_GetStringAttribute(): failed because var.vt != VT_BSTR\n");
  866. return E_INVALIDARG;
  867. }
  868. return S_OK;
  869. }
  870. BOOL _ChangePathUsingSAMAccountName(IN LPCWSTR lpszSAMAccountNameSource,
  871. IN LPCWSTR lpszSAMAccountDestination,
  872. INOUT CComVariant& varValPath)
  873. {
  874. // NOTICE: we do the substitution only if we find
  875. // something like:
  876. // \\myhost\myshare\JoeB
  877. // i.e. the last token in the path is the source SAM account name
  878. // we change into \\myhost\myshare\FrankM
  879. TRACE(L"_ChangePathUsingSAMAccountName(%s, %s, _)\n",
  880. lpszSAMAccountNameSource, lpszSAMAccountDestination);
  881. ASSERT(lpszSAMAccountNameSource != NULL);
  882. ASSERT(lpszSAMAccountDestination != NULL);
  883. // invalid string
  884. if ( (varValPath.vt != VT_BSTR) || (varValPath.bstrVal == NULL))
  885. {
  886. TRACE(L"returning FALSE, varValPath of wrong type or NULL\n");
  887. return FALSE;
  888. }
  889. CString szSourcePath = varValPath.bstrVal;
  890. TRACE(L"Input value for varValPath.bstrVal = %s\n", varValPath.bstrVal);
  891. // look for a \ as a separator
  892. int iLastSlash = szSourcePath.ReverseFind(L'\\');
  893. if (iLastSlash == -1)
  894. {
  895. //
  896. // No slashes were found
  897. //
  898. TRACE(L"returning FALSE, could not find the \\ at the end of the string\n");
  899. return FALSE;
  900. }
  901. CString szSAMName = szSourcePath.Right(szSourcePath.GetLength() - iLastSlash - 1);
  902. ASSERT(!szSAMName.IsEmpty());
  903. // compare what is after the \ with the source SAM account name
  904. if (szSAMName.CompareNoCase(lpszSAMAccountNameSource) != 0)
  905. {
  906. TRACE(L"returning FALSE, lpszLeaf = %s does not match source SAM account name\n", szSAMName);
  907. return FALSE;
  908. }
  909. CString szBasePath = szSourcePath.Left(iLastSlash + 1);
  910. CString szNewPath = szBasePath + lpszSAMAccountDestination;
  911. // replace old value in variant
  912. ::SysFreeString(varValPath.bstrVal);
  913. varValPath.bstrVal = ::SysAllocString(szNewPath);
  914. TRACE(L"returning TRUE, new varValPath.bstrVal = %s\n", varValPath.bstrVal);
  915. return TRUE; // we did a replacement
  916. }
  917. HRESULT _UpdatePathAttribute(IN LPCWSTR lpszAttributeName,
  918. IN LPCWSTR lpszSAMAccountNameSource,
  919. IN LPCWSTR lpszSAMAccountDestination,
  920. IN IADs* pIADsCopySource,
  921. IN IADs* pIADsCopyTo,
  922. OUT BOOL* pbDirChanged)
  923. {
  924. TRACE(L"_UpdatePathAttribute(%s, %s, %s, _, _, _)\n",
  925. lpszAttributeName, lpszSAMAccountNameSource, lpszSAMAccountDestination);
  926. *pbDirChanged = FALSE;
  927. // get the value of the source attribute
  928. CComVariant varVal;
  929. HRESULT hr = pIADsCopySource->Get((LPWSTR)lpszAttributeName, &varVal);
  930. // if attribute not set, nothing to do
  931. if (hr == E_ADS_PROPERTY_NOT_FOUND)
  932. {
  933. TRACE(L"attribute not set, just returning\n");
  934. return E_ADS_PROPERTY_NOT_FOUND;
  935. }
  936. // handle other unexpected failures
  937. if (FAILED(hr))
  938. {
  939. TRACE(L"pIADsCopySource->Get(%s,_) failed with hr = 0x%x\n", lpszAttributeName, hr);
  940. return hr;
  941. }
  942. if (varVal.vt == VT_EMPTY)
  943. {
  944. TRACE(L"just returning because varVal.vt == VT_EMPTY\n");
  945. return E_ADS_PROPERTY_NOT_FOUND;
  946. }
  947. if (varVal.vt != VT_BSTR)
  948. {
  949. TRACE(L"failed because var.vt != VT_BSTR\n");
  950. return E_INVALIDARG;
  951. }
  952. // synthesize the new value of the path, if appropriate
  953. if (_ChangePathUsingSAMAccountName(lpszSAMAccountNameSource, lpszSAMAccountDestination, varVal))
  954. {
  955. // the path got updated, need to update the destination object
  956. hr = pIADsCopyTo->Put((LPWSTR)lpszAttributeName, varVal);
  957. TRACE(L"pIADsCopyTo->Put(%s,_) returned hr = 0x%x\n", lpszAttributeName, hr);
  958. if (SUCCEEDED(hr))
  959. {
  960. *pbDirChanged = TRUE;
  961. }
  962. }
  963. TRACE(L"*pbDirChanged = %d\n", *pbDirChanged);
  964. // we should fail only in really exceptional circumstances
  965. ASSERT(SUCCEEDED(hr));
  966. return hr;
  967. }
  968. HRESULT CCopyUserHandler::_UpdatePaths(IADs* pIADsCopyTo)
  969. {
  970. // NOTICE: we assume that, if the paths are copyable, they have been
  971. // bulk copied when the temporary object was created.
  972. // If the paths have to be adjusted, we overwrite the copy.
  973. TRACE(L"CCopyUserHandler::_UpdatePaths()\n");
  974. // reset the flag for post commit
  975. m_bNeedToCreateHomeDir = FALSE;
  976. BOOL bCopyHomeDir = m_copyableAttributesHolder.CanCopy(g_szHomeDir);
  977. BOOL bCopyProfilePath = m_copyableAttributesHolder.CanCopy(g_szProfilePath);
  978. TRACE(L"bCopyHomeDir = %d, bCopyProfilePath = %d\n", bCopyHomeDir, bCopyProfilePath);
  979. if (!bCopyHomeDir && !bCopyProfilePath)
  980. {
  981. TRACE(L"no need to update anything, bail out\n");
  982. return S_OK;
  983. }
  984. // retrieve the SAM account names of source and destination
  985. // to synthesize the new paths
  986. IADs* pIADsCopySource = GetCopyFrom();
  987. CComVariant varSAMNameSource;
  988. HRESULT hr = _GetStringAttribute(pIADsCopySource, gsz_samAccountName, varSAMNameSource);
  989. if (FAILED(hr))
  990. {
  991. TRACE(L"_GetStringAttribute() failed on source SAM account name\n");
  992. return hr;
  993. }
  994. CComVariant varSAMNameDestination;
  995. hr = _GetStringAttribute(pIADsCopyTo, gsz_samAccountName, varSAMNameDestination);
  996. if (FAILED(hr))
  997. {
  998. TRACE(L"_GetStringAttribute() failed on destination SAM account name\n");
  999. return hr;
  1000. }
  1001. if (bCopyHomeDir)
  1002. {
  1003. BOOL bDummy;
  1004. hr = _UpdatePathAttribute(g_szHomeDir, varSAMNameSource.bstrVal,
  1005. varSAMNameDestination.bstrVal,
  1006. pIADsCopySource,
  1007. pIADsCopyTo,
  1008. &bDummy);
  1009. if (hr == E_ADS_PROPERTY_NOT_FOUND)
  1010. {
  1011. // not set, just clear the HRESULT
  1012. hr = S_OK;
  1013. }
  1014. else
  1015. {
  1016. // the home directory was set, verify it is a UNC path
  1017. CComVariant varDestinationHomeDir;
  1018. hr = _GetStringAttribute(pIADsCopyTo, g_szHomeDir, varDestinationHomeDir);
  1019. if (FAILED(hr))
  1020. {
  1021. TRACE(L"_GetStringAttribute() failed on homeDir hr = 0x%x\n", hr);
  1022. return hr;
  1023. }
  1024. m_bNeedToCreateHomeDir = DSPROP_IsValidUNCPath(varDestinationHomeDir.bstrVal);
  1025. TRACE(L"DSPROP_IsValidUNCPath(%s) returned = %d\n",
  1026. varDestinationHomeDir.bstrVal, m_bNeedToCreateHomeDir);
  1027. }
  1028. if (FAILED(hr))
  1029. {
  1030. TRACE(L"_UpdatePathAttribute() failed on homeDir hr = 0x%x\n", hr);
  1031. return hr;
  1032. }
  1033. }
  1034. if (bCopyProfilePath)
  1035. {
  1036. BOOL bDummy;
  1037. hr = _UpdatePathAttribute(g_szProfilePath, varSAMNameSource.bstrVal,
  1038. varSAMNameDestination.bstrVal,
  1039. pIADsCopySource,
  1040. pIADsCopyTo,
  1041. &bDummy);
  1042. if (hr == E_ADS_PROPERTY_NOT_FOUND)
  1043. {
  1044. // not set, just clear the HRESULT
  1045. hr = S_OK;
  1046. }
  1047. if (FAILED(hr))
  1048. {
  1049. TRACE(L"_UpdatePathAttribute() failed on profilePath hr = 0x%x\n", hr);
  1050. return hr;
  1051. }
  1052. }
  1053. // failure expected only under exceptional circumstances
  1054. return S_OK;
  1055. }
  1056. HRESULT CCopyUserHandler::_CreateHomeDirectory(IADs* pIADsCopyTo,
  1057. LPCWSTR lpszObjectName, HWND hWnd)
  1058. {
  1059. TRACE(L"CCopyUserHandler::_CreateHomeDirectory()\n");
  1060. ASSERT(m_bNeedToCreateHomeDir);
  1061. // retrieve the home directory attribute
  1062. CComVariant VarHomeDir;
  1063. HRESULT hr = pIADsCopyTo->Get(g_szHomeDir, &VarHomeDir);
  1064. if (FAILED(hr))
  1065. {
  1066. TRACE(L"pIADsCopyTo->Get(%s,_) failed, hr = 0x%x\n", g_szHomeDir, hr);
  1067. return hr;
  1068. }
  1069. if (VarHomeDir.vt != VT_BSTR)
  1070. {
  1071. TRACE(L"failing because varVal.vt != VT_BSTR\n");
  1072. return E_INVALIDARG;
  1073. }
  1074. // retrieve the SID of the newly created object
  1075. CSid destinationObjectSid;
  1076. hr = destinationObjectSid.Init(pIADsCopyTo);
  1077. if (FAILED(hr))
  1078. {
  1079. TRACE(L"destinationObjectSid.Init() failed, , hr = 0x%x\n", hr);
  1080. // unforeseen error
  1081. PVOID apv[1] = {(LPWSTR)(lpszObjectName) };
  1082. ReportErrorEx(hWnd, IDS_CANT_READ_HOME_DIR_SID, hr,
  1083. MB_OK | MB_ICONWARNING, apv, 1);
  1084. // we cannot proceed further, but we return success because
  1085. // we already displayed the error message and we want to treat the
  1086. // failure as a warning
  1087. return S_OK;
  1088. }
  1089. // make call to helper function to create directory and set ACL's on it
  1090. DWORD dwErr = ::DSPROP_CreateHomeDirectory(destinationObjectSid.GetSid(), VarHomeDir.bstrVal);
  1091. TRACE(L"DSPROP_CreateHomeDirectory(%s, pSid) returned dwErr = 0x%x\n", VarHomeDir.bstrVal, dwErr);
  1092. if (dwErr != 0)
  1093. {
  1094. // treat as a warning, display a message and continue
  1095. PVOID apv[1] = {VarHomeDir.bstrVal};
  1096. UINT nMsgID = 0;
  1097. switch (dwErr)
  1098. {
  1099. case ERROR_ALREADY_EXISTS:
  1100. nMsgID = IDS_HOME_DIR_EXISTS;
  1101. break;
  1102. case ERROR_PATH_NOT_FOUND:
  1103. nMsgID = IDS_HOME_DIR_CREATE_FAILED;
  1104. break;
  1105. case ERROR_LOGON_FAILURE:
  1106. case ERROR_NOT_AUTHENTICATED:
  1107. case ERROR_INVALID_PASSWORD:
  1108. case ERROR_PASSWORD_EXPIRED:
  1109. case ERROR_ACCOUNT_DISABLED:
  1110. case ERROR_ACCOUNT_LOCKED_OUT:
  1111. nMsgID = IDS_HOME_DIR_CREATE_NO_ACCESS;
  1112. break;
  1113. default:
  1114. nMsgID = IDS_HOME_DIR_CREATE_FAIL;
  1115. } // switch
  1116. HRESULT hrTemp = HRESULT_FROM_WIN32(dwErr);
  1117. ReportErrorEx(hWnd, nMsgID, hrTemp,
  1118. MB_OK|MB_ICONWARNING , apv, 1);
  1119. }
  1120. return S_OK;
  1121. }
  1122. HRESULT CCopyUserHandler::_CopyGroupMembership(IADs* pIADsCopyTo)
  1123. {
  1124. if (pIADsCopyTo == NULL)
  1125. return E_INVALIDARG;
  1126. HRESULT hr = pIADsCopyTo->GetInfo();
  1127. if (FAILED(hr))
  1128. {
  1129. TRACE(L"pIADsCopyTo->GetInfo() failed with hr = 0x%x\n", hr);
  1130. return hr;
  1131. }
  1132. CGroupMembershipHolder destinationMembership;
  1133. hr = destinationMembership.Read(pIADsCopyTo);
  1134. if (FAILED(hr))
  1135. {
  1136. TRACE(L"destinationMembership.Read(pIADsCopyTo) failed with hr = 0x%x\n", hr);
  1137. return hr;
  1138. }
  1139. hr = destinationMembership.CopyFrom(&m_sourceMembershipHolder);
  1140. if (FAILED(hr))
  1141. {
  1142. TRACE(L"destinationMembership.CopyFrom() failed with hr = 0x%x\n", hr);
  1143. return hr;
  1144. }
  1145. hr = destinationMembership.Write();
  1146. if (FAILED(hr))
  1147. {
  1148. // something unexpected failed and we are going to percolate
  1149. // it to the wizards for a generic warning message
  1150. TRACE(L"destinationMembership.Write() failed with hr = 0x%x\n", hr);
  1151. return hr;
  1152. }
  1153. // there can be failures related to acccess denied on some groups
  1154. // we handle them with a cumulative warning
  1155. destinationMembership.ProcessFailures(m_hrFailure, m_szFailureString, &m_bPrimaryGroupFound);
  1156. return S_OK;
  1157. }
  1158. void CCopyUserHandler::_ShowGroupMembershipWarnings(HWND hWnd, LPCWSTR lpszObjectName)
  1159. {
  1160. if (!m_bPrimaryGroupFound)
  1161. {
  1162. // Some message box
  1163. ReportMessageEx(hWnd, IDS_123_CANT_COPY_PRIMARY_GROUP_NOT_FOUND,
  1164. MB_OK | MB_ICONWARNING);
  1165. }
  1166. if (m_szFailureString.IsEmpty())
  1167. {
  1168. // we have nothing
  1169. return;
  1170. }
  1171. // we have an HRESULT we can use
  1172. ASSERT(FAILED(m_hrFailure));
  1173. UINT nMsgID = (m_hrFailure == E_ACCESSDENIED) ?
  1174. IDS_123_CANT_COPY_SOME_GROUP_MEMBERSHIP_ACCESS_DENIED :
  1175. IDS_123_CANT_COPY_SOME_GROUP_MEMBERSHIP;
  1176. PVOID apv[2] = {(LPWSTR)(lpszObjectName), (LPWSTR)(LPCWSTR)m_szFailureString };
  1177. ReportErrorEx(hWnd,nMsgID, m_hrFailure,
  1178. MB_OK | MB_ICONERROR, apv, 2);
  1179. }