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.

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