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.

3229 lines
99 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1999
  5. //
  6. // File: dsctx.cpp
  7. //
  8. // Contents: object to implement context menu extensions
  9. //
  10. // History: 08-dec-97 jimharr Created
  11. //
  12. //
  13. //--------------------------------------------------------------------------
  14. #include "stdafx.h"
  15. #include "resource.h"
  16. #include "util.h"
  17. #include "dsutil.h"
  18. #include "dsctx.h"
  19. #include "dataobj.h"
  20. #include "dscookie.h"
  21. #include "dsdlgs.h"
  22. #include "gsz.h"
  23. #include "querysup.h"
  24. #include "simdata.h"
  25. #include <lm.h>
  26. #include <cmnquery.h> // IPersistQuery
  27. #include <cmnquryp.h> // to get IQueryFrame to notify DS Find
  28. #include <dsquery.h>
  29. #include <dsqueryp.h>
  30. #include <ntlsa.h> // LsaQueryInformationPolicy
  31. const CLSID CLSID_DSContextMenu = { /* 08eb4fa6-6ffd-11d1-b0e0-00c04fd8dca6 */
  32. 0x08eb4fa6, 0x6ffd, 0x11d1,
  33. {0xb0, 0xe0, 0x00, 0xc0, 0x4f, 0xd8, 0xdc, 0xa6}
  34. };
  35. ////////////////////////////////////////////////////////////////////
  36. // Language independent context menu IDs
  37. // WARNING : these should NEVER be changed
  38. // the whole point of having these is so that other
  39. // developers can rely on them being the same no matter
  40. // what language or version they use. The context menus
  41. // can change but their IDs should not
  42. //
  43. #define CMID_ENABLE_ACCOUNT L"_DSADMIN_ENABLE_ACCOUNT"
  44. #define CMID_DISABLE_ACCOUNT L"_DSADMIN_DISABLE_ACCOUNT"
  45. #define CMID_MAP_CERTIFICATES L"_DSADMIN_MAP_CERTIFICATES"
  46. #define CMID_CHANGE_PASSWORD L"_DSADMIN_CHANGE_PASSWORD"
  47. #define CMID_MOVE_OBJECT L"_DSADMIN_MOVE"
  48. #define CMID_DELETE_OBJECT L"_DSADMIN_DELETE"
  49. #define CMID_REPLICATE_NOW L"_DSADMIN_REPLICATE_NOW"
  50. #define CMID_ADD_OBJECTS_TO_GROUP L"_DSADMIN_ADD_TO_GROUP"
  51. #define CMID_COPY_OBJECT L"_DSADMIN_COPY"
  52. #define CMID_RENAME_OBJECT L"_DSADMIN_RENAME"
  53. static CLIPFORMAT g_cfDsObjectNames;
  54. static CLIPFORMAT g_cfDsInternal;
  55. static CLIPFORMAT g_cfCoClass;
  56. static CLIPFORMAT g_cfPropSheetCfg;
  57. static CLIPFORMAT g_cfParentHwnd;
  58. static CLIPFORMAT g_cfComponentData;
  59. ///////////////////////////////////////////////////////////////////////////
  60. // CContextMenuSingleDeleteHandler
  61. class CContextMenuSingleDeleteHandler : public CSingleDeleteHandlerBase
  62. {
  63. public:
  64. CContextMenuSingleDeleteHandler(CDSComponentData* pComponentData, HWND hwnd,
  65. LPCWSTR lpszPath, LPCWSTR lpszClass,
  66. BOOL bContainer, CDSContextMenu* pCtxMenu)
  67. : CSingleDeleteHandlerBase(pComponentData, hwnd)
  68. {
  69. m_pCtxMenu = pCtxMenu;
  70. m_lpszPath = lpszPath;
  71. m_lpszClass= lpszClass;
  72. m_bContainer = bContainer;
  73. }
  74. protected:
  75. CDSContextMenu* m_pCtxMenu;
  76. LPCWSTR m_lpszPath;
  77. LPCWSTR m_lpszClass;
  78. BOOL m_bContainer;
  79. virtual HRESULT BeginTransaction()
  80. {
  81. return GetTransaction()->Begin(m_lpszPath, m_lpszClass, m_bContainer, NULL, NULL, FALSE);
  82. }
  83. virtual HRESULT DeleteObject()
  84. {
  85. CString szName;
  86. return m_pCtxMenu->_Delete(m_lpszPath, m_lpszClass, &szName);
  87. }
  88. virtual HRESULT DeleteSubtree()
  89. {
  90. CString szName;
  91. return m_pCtxMenu->_DeleteSubtree(m_lpszPath, &szName);
  92. }
  93. virtual void GetItemName(OUT CString& szName)
  94. {
  95. //
  96. // Clear out any existing value
  97. //
  98. szName.Empty();
  99. CPathCracker pathCracker;
  100. HRESULT hr = pathCracker.Set((BSTR)(LPWSTR)GetItemPath(), ADS_SETTYPE_FULL);
  101. if (SUCCEEDED(hr))
  102. {
  103. hr = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  104. if (SUCCEEDED(hr))
  105. {
  106. hr = pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_OFF_EX);
  107. if (SUCCEEDED(hr))
  108. {
  109. CComBSTR bstrName;
  110. hr = pathCracker.Retrieve(ADS_FORMAT_LEAF, &bstrName);
  111. if (SUCCEEDED(hr))
  112. {
  113. szName = bstrName;
  114. }
  115. }
  116. }
  117. }
  118. if (szName.IsEmpty())
  119. {
  120. szName = GetItemPath();
  121. }
  122. }
  123. virtual LPCWSTR GetItemClass(){ return m_lpszClass; }
  124. virtual LPCWSTR GetItemPath(){ return m_lpszPath; }
  125. };
  126. ///////////////////////////////////////////////////////////////////////////
  127. // CContextMenuMultipleDeleteHandler
  128. class CContextMenuMultipleDeleteHandler : public CMultipleDeleteHandlerBase
  129. {
  130. public:
  131. CContextMenuMultipleDeleteHandler(CDSComponentData* pComponentData, HWND hwnd,
  132. IDataObject* pDataObject,
  133. CObjectNamesFormatCracker* pObjCracker,
  134. CDSContextMenu* pCtxMenu)
  135. : CMultipleDeleteHandlerBase(pComponentData, hwnd)
  136. {
  137. m_pDataObject = pDataObject;
  138. m_pObjCracker = pObjCracker;
  139. m_pCtxMenu = pCtxMenu;
  140. ASSERT(m_pObjCracker->GetCount() > 1);
  141. // allocate an array of BOOL's to keep track of what actually got deleted
  142. // and initialize ot to zero (FALSE)
  143. m_pDeletedArr = new BOOL[GetItemCount()];
  144. ::ZeroMemory(m_pDeletedArr, sizeof(BOOL)*GetItemCount());
  145. }
  146. virtual ~CContextMenuMultipleDeleteHandler()
  147. {
  148. delete[] m_pDeletedArr;
  149. }
  150. BOOL WasItemDeleted(UINT i)
  151. {
  152. ASSERT(i < GetItemCount());
  153. return m_pDeletedArr[i];
  154. }
  155. protected:
  156. virtual UINT GetItemCount() { return m_pObjCracker->GetCount();}
  157. virtual HRESULT BeginTransaction()
  158. {
  159. return GetTransaction()->Begin(m_pDataObject, NULL, NULL, FALSE);
  160. }
  161. virtual HRESULT DeleteObject(UINT i)
  162. {
  163. bool fAlternateDeleteMethod = false;
  164. LPCWSTR lpszObjectPath = m_pObjCracker->GetName(i);
  165. LPCWSTR lpszObjectClass = m_pObjCracker->GetClass(i);
  166. HRESULT hr = ObjectDeletionCheck(
  167. lpszObjectPath,
  168. NULL,
  169. lpszObjectClass,
  170. fAlternateDeleteMethod );
  171. if (FAILED(hr) || HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr)
  172. return hr;
  173. if (!fAlternateDeleteMethod)
  174. {
  175. CString szName;
  176. hr = m_pCtxMenu->_Delete(lpszObjectPath, lpszObjectClass, &szName);
  177. }
  178. if (SUCCEEDED(hr) && (hr != S_FALSE))
  179. {
  180. m_pDeletedArr[i] = TRUE;
  181. }
  182. return hr;
  183. }
  184. virtual HRESULT DeleteSubtree(UINT i)
  185. {
  186. CString szName;
  187. HRESULT hr = m_pCtxMenu->_DeleteSubtree(m_pObjCracker->GetName(i), &szName);
  188. if (SUCCEEDED(hr) && (hr != S_FALSE))
  189. {
  190. m_pDeletedArr[i] = TRUE;
  191. }
  192. return hr;
  193. }
  194. virtual void GetItemName(IN UINT i, OUT CString& szName)
  195. {
  196. //
  197. // Clear out any existing value
  198. //
  199. szName.Empty();
  200. CPathCracker pathCracker;
  201. HRESULT hr = pathCracker.Set((BSTR)(LPWSTR)m_pObjCracker->GetName(i), ADS_SETTYPE_FULL);
  202. if (SUCCEEDED(hr))
  203. {
  204. hr = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  205. if (SUCCEEDED(hr))
  206. {
  207. hr = pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_OFF_EX);
  208. if (SUCCEEDED(hr))
  209. {
  210. CComBSTR bstrName;
  211. hr = pathCracker.Retrieve(ADS_FORMAT_LEAF, &bstrName);
  212. if (SUCCEEDED(hr))
  213. {
  214. szName = bstrName;
  215. }
  216. }
  217. }
  218. }
  219. if (szName.IsEmpty())
  220. {
  221. szName = m_pObjCracker->GetName(i);
  222. }
  223. }
  224. virtual void GetItemPath(UINT i, CString& szPath)
  225. {
  226. szPath = m_pObjCracker->GetName(i);
  227. }
  228. virtual PCWSTR GetItemClass(UINT i)
  229. {
  230. return m_pObjCracker->GetClass(i);
  231. }
  232. private:
  233. IDataObject* m_pDataObject;
  234. CObjectNamesFormatCracker* m_pObjCracker;
  235. CDSContextMenu* m_pCtxMenu;
  236. BOOL* m_pDeletedArr;
  237. };
  238. ///////////////////////////////////////////////////////////////////////////
  239. // ContextMenu
  240. class CContextMenuMoveHandler : public CMoveHandlerBase
  241. {
  242. public:
  243. CContextMenuMoveHandler(CDSComponentData* pComponentData, HWND hwnd,
  244. LPCWSTR lpszBrowseRootPath,
  245. IDataObject* pDataObject,
  246. CInternalFormatCracker* pInternalFormatCracker,
  247. CObjectNamesFormatCracker* pObjectNamesFormatCracker)
  248. : CMoveHandlerBase(pComponentData, hwnd, lpszBrowseRootPath)
  249. {
  250. m_pDataObject = pDataObject;
  251. m_pInternalFormatCracker = pInternalFormatCracker;
  252. m_pObjectNamesFormatCracker = pObjectNamesFormatCracker;
  253. }
  254. protected:
  255. virtual UINT GetItemCount() { return m_pObjectNamesFormatCracker->GetCount();}
  256. virtual HRESULT BeginTransaction()
  257. {
  258. return GetTransaction()->Begin(m_pDataObject,
  259. GetDestPath(), GetDestClass(), IsDestContainer());
  260. }
  261. virtual void GetNewPath(UINT i, CString& szNewPath)
  262. {
  263. szNewPath = m_pObjectNamesFormatCracker->GetName(i);
  264. }
  265. virtual void GetItemPath(UINT i, CString& szPath)
  266. {
  267. szPath = m_pObjectNamesFormatCracker->GetName(i);
  268. }
  269. virtual PCWSTR GetItemClass(UINT i)
  270. {
  271. return m_pObjectNamesFormatCracker->GetClass(i);
  272. }
  273. virtual void GetName(UINT i, CString& strref)
  274. {
  275. HRESULT hr = S_OK;
  276. if (m_pInternalFormatCracker->HasData())
  277. {
  278. CUINode* pUINode = m_pInternalFormatCracker->GetCookie(i);
  279. CDSCookie* pCookie = GetDSCookieFromUINode(pUINode);
  280. if (pCookie != NULL)
  281. {
  282. strref = pCookie->GetName();
  283. }
  284. else
  285. {
  286. strref = L"";
  287. }
  288. return;
  289. }
  290. else
  291. {
  292. // REVIEW_MARCOC_PORT: this might be inefficent, need to make a member variable
  293. CPathCracker pathCracker;
  294. hr = pathCracker.Set((LPWSTR)m_pObjectNamesFormatCracker->GetName(i),
  295. ADS_SETTYPE_FULL);
  296. hr = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  297. CComBSTR DestName;
  298. hr = pathCracker.GetElement( 0, &DestName );
  299. strref = DestName;
  300. return;
  301. }
  302. }
  303. virtual HRESULT OnItemMoved(UINT i, IADs* /*pIADs*/)
  304. {
  305. HRESULT hr = S_OK;
  306. if (m_pInternalFormatCracker != NULL && m_pInternalFormatCracker->HasData())
  307. {
  308. CUINode* pUINode = m_pInternalFormatCracker->GetCookie(i);
  309. pUINode->SetExtOp(OPCODE_MOVE);
  310. /* REVIEW_JEFFJON : removed due to bug 190532 After changing view from list to detail
  311. and back to list the drag and drop does not work from query window
  312. We decided that saved queries will be snapshots of the time
  313. they are run and we should not try to keep them updated.
  314. CDSCookie* pCookie = GetDSCookieFromUINode(pUINode);
  315. if (pCookie != NULL)
  316. {
  317. CUINode* pParentNode = pUINode->GetParent();
  318. if (pParentNode != NULL && !IS_CLASS(*pParentNode, CDSUINode))
  319. {
  320. CComBSTR bsPath;
  321. hr = pIADs->get_ADsPath(&bsPath);
  322. if (SUCCEEDED(hr))
  323. {
  324. CString szPath;
  325. StripADsIPath(bsPath, szPath);
  326. pCookie->SetPath(szPath);
  327. }
  328. }
  329. }
  330. */
  331. }
  332. return hr;
  333. }
  334. virtual void GetClassOfMovedItem(CString& szClass)
  335. {
  336. szClass.Empty();
  337. if (NULL == m_pObjectNamesFormatCracker)
  338. return;
  339. UINT nCount = GetItemCount();
  340. if (0 == nCount)
  341. return;
  342. szClass = m_pObjectNamesFormatCracker->GetClass(0);
  343. for (UINT i = 1; i < nCount; i++)
  344. {
  345. if (0 != szClass.CompareNoCase( m_pObjectNamesFormatCracker->GetClass(i) ))
  346. {
  347. szClass.Empty();
  348. return;
  349. }
  350. }
  351. }
  352. private:
  353. IDataObject* m_pDataObject;
  354. CInternalFormatCracker* m_pInternalFormatCracker;
  355. CObjectNamesFormatCracker* m_pObjectNamesFormatCracker;
  356. };
  357. ///////////////////////////////////////////////////////////////////////////
  358. // CDSContextMenu
  359. CDSContextMenu::CDSContextMenu()
  360. {
  361. m_pDsObject = NULL;
  362. m_fClasses = 0;
  363. m_hwnd = NULL;
  364. m_pCD = NULL;
  365. }
  366. CDSContextMenu::~CDSContextMenu()
  367. {
  368. if (m_pDsObject) {
  369. m_pDsObject->Release();
  370. }
  371. }
  372. const UINT Type_User = 0x0001;
  373. const UINT Type_Group = 0x0002;
  374. const UINT Type_Computer = 0x0004;
  375. const UINT Type_NTDSConnection = 0x0008;
  376. const UINT Type_TrueNTDSConnection = 0x0010;
  377. const UINT Type_FRSConnection = 0x0020;
  378. const UINT Type_Domain = 0x0040;
  379. const UINT Type_Contact = 0x0080;
  380. const UINT Type_OU = 0x0100;
  381. const UINT Type_Others = 0x8000;
  382. extern CDSComponentData* g_pCD;
  383. ////////////////////////////////////////////////////////////
  384. // IShellExtInit methods
  385. STDMETHODIMP
  386. CDSContextMenu::Initialize(LPCITEMIDLIST,
  387. LPDATAOBJECT pDataObj,
  388. HKEY)
  389. {
  390. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  391. HRESULT hr = 0;
  392. USES_CONVERSION;
  393. TRACE(_T("CDsContextMenu::Initialize.\n"));
  394. TIMER(_T("Entering DSContext Init().\n"));
  395. if (pDataObj == NULL)
  396. {
  397. return E_INVALIDARG; // no point in going on
  398. }
  399. // hold on to the data object
  400. m_spDataObject = pDataObj;
  401. // get path and class info: this format is always needed
  402. hr = m_objectNamesFormat.Extract(pDataObj);
  403. if (FAILED(hr))
  404. return hr;
  405. // we need at least one object in the selection
  406. ASSERT(m_objectNamesFormat.HasData());
  407. if (m_objectNamesFormat.GetCount() == 0)
  408. {
  409. TRACE (_T("DSContextMenu::Init: can't find path\n"));
  410. return S_OK;
  411. }
  412. // get DSADMIN internal format (it can be there or not)
  413. // if present, we are called from DS Admin
  414. m_internalFormat.Extract(pDataObj);
  415. // get extra info
  416. _GetExtraInfo(pDataObj);
  417. // check whether an NTDSConnection is actually an FRS connection
  418. if (m_fClasses & Type_NTDSConnection)
  419. {
  420. //
  421. // check whether this is an NTDS instance or an FRS instance
  422. // CODEWORK this will not work outside of DSADMIN (e.g. in DSFIND)
  423. //
  424. if ( m_internalFormat.HasData()
  425. && NULL != m_internalFormat.GetCookie(0)
  426. && NULL != m_internalFormat.GetCookie(0)->GetParent() )
  427. {
  428. CUINode* pUIParentNode = m_internalFormat.GetCookie(0)->GetParent();
  429. CDSCookie* pParentCookie = GetDSCookieFromUINode(pUIParentNode);
  430. CString strClass = pParentCookie->GetClass();
  431. bool fParentIsFrs = false;
  432. HRESULT hr2 = DSPROP_IsFrsObject(
  433. const_cast<LPWSTR>((LPCTSTR)strClass), &fParentIsFrs );
  434. ASSERT( SUCCEEDED(hr2) );
  435. if ( SUCCEEDED(hr2) )
  436. m_fClasses |= ( (fParentIsFrs) ? Type_FRSConnection : Type_TrueNTDSConnection );
  437. }
  438. }
  439. TIMER(_T("Exiting DSContext Init().\n"));
  440. return hr;
  441. }
  442. ///////////////////////////////////////////////////////////
  443. // IContextMenu methods
  444. STDMETHODIMP
  445. CDSContextMenu::QueryContextMenu(HMENU hMenu,
  446. UINT indexMenu,
  447. UINT idCmdFirst,
  448. UINT,
  449. UINT)
  450. {
  451. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  452. HRESULT hr = S_OK;
  453. TCHAR szBuffer[MAX_PATH];
  454. const INT cItems = 10; //max num of items added
  455. UINT nLargestCmd = 0;
  456. CComVariant CurrentState;
  457. BOOL bEnableMove = TRUE;
  458. BOOL bEnableDelete = TRUE;
  459. BOOL bEnableRename = TRUE;
  460. TRACE(_T("CDsContextMenu::QueryContextMenu.\n"));
  461. TIMER(_T("Entering DSContext QCM().\n"));
  462. if (m_internalFormat.HasData())
  463. {
  464. int iSystemFlags = 0;
  465. DWORD i = 0;
  466. //
  467. // Loop through all the selected nodes adding the appropriate menu items
  468. //
  469. for (i=0; i < m_internalFormat.GetCookieCount(); i++)
  470. {
  471. CUINode* pUINode = m_internalFormat.GetCookie(i);
  472. iSystemFlags = GetDSCookieFromUINode(pUINode)->GetSystemFlags();
  473. switch (m_internalFormat.GetSnapinType()) // assume multi-selected items all have the same snapin type
  474. {
  475. case SNAPINTYPE_DS:
  476. case SNAPINTYPE_DSEX:
  477. bEnableMove = bEnableMove &&
  478. !(iSystemFlags & FLAG_DOMAIN_DISALLOW_MOVE);
  479. bEnableDelete = bEnableDelete &&
  480. !(iSystemFlags & FLAG_DISALLOW_DELETE);
  481. bEnableRename = bEnableRename &&
  482. !(iSystemFlags & FLAG_DOMAIN_DISALLOW_RENAME);
  483. break;
  484. case SNAPINTYPE_SITE:
  485. bEnableMove = bEnableMove &&
  486. ( iSystemFlags & (FLAG_CONFIG_ALLOW_MOVE | FLAG_CONFIG_ALLOW_LIMITED_MOVE) );
  487. bEnableDelete = bEnableDelete &&
  488. !(iSystemFlags & FLAG_DISALLOW_DELETE);
  489. bEnableRename = bEnableRename &&
  490. (iSystemFlags & FLAG_CONFIG_ALLOW_RENAME);
  491. break;
  492. default:
  493. break;
  494. } // switch
  495. } // end of for loop
  496. } // if
  497. //
  498. // add them items to your menu, inserting them at indexMenu + the offset for your
  499. // item. idCmdFirst / idCmdList is the range you should use, they should
  500. // not exceed this range. On exit return the number of items and IDs you claimed,
  501. //
  502. //
  503. // Add the Move menu item if this is the Sites snapin
  504. //
  505. if ((m_CallerSnapin != CLSID_SiteSnapin) &&
  506. !(m_fClasses & Type_Domain) &&
  507. bEnableMove &&
  508. (m_pCD != NULL))
  509. {
  510. if ( !LoadString(AfxGetInstanceHandle(), IDS_MOVE_OBJECT,
  511. szBuffer, ARRAYLEN(szBuffer)) )
  512. {
  513. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  514. goto exit_gracefully;
  515. }
  516. InsertMenu(hMenu,
  517. indexMenu,
  518. MF_BYPOSITION|MF_STRING,
  519. idCmdFirst+IDC_MOVE_OBJECT,
  520. szBuffer);
  521. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_MOVE_OBJECT);
  522. }
  523. //
  524. // If this is a User or Computer object add the Reset Account menu item
  525. // It is done this way so that if m_fClasses contains more than computer
  526. // and object types in conjuction with user and/or object types we fail
  527. //
  528. if ( m_fClasses && !(m_fClasses & ~(Type_User | Type_Computer)))
  529. {
  530. if (m_objectNamesFormat.GetCount() == 1)
  531. {
  532. //
  533. // Load the string for the menu item
  534. //
  535. if (m_fClasses == Type_Computer) // Computer
  536. {
  537. if ( !LoadString(AfxGetInstanceHandle(), IDS_RESET_ACCOUNT,
  538. szBuffer, ARRAYLEN(szBuffer)) )
  539. {
  540. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  541. goto exit_gracefully;
  542. }
  543. }
  544. else // User
  545. {
  546. if ( !LoadString(AfxGetInstanceHandle(), IDS_CHANGE_PASSWORD,
  547. szBuffer, ARRAYLEN(szBuffer)) )
  548. {
  549. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  550. goto exit_gracefully;
  551. }
  552. }
  553. //
  554. // Insert the menu item
  555. //
  556. InsertMenu(hMenu,
  557. indexMenu,
  558. MF_BYPOSITION|MF_STRING,
  559. idCmdFirst+IDC_CHANGE_PASSWORD,
  560. szBuffer);
  561. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_CHANGE_PASSWORD);
  562. //
  563. // Bind and figure out if the account is disabled
  564. // then add a menu item to enable or disable the account accordingly
  565. //
  566. hr = DSAdminOpenObject(m_objectNamesFormat.GetName(0),
  567. IID_IADsUser,
  568. (void **)&m_pDsObject,
  569. TRUE /*bServer*/);
  570. if (SUCCEEDED(hr))
  571. {
  572. hr = m_pDsObject->Get(L"userAccountControl", &CurrentState);
  573. if (SUCCEEDED(hr))
  574. {
  575. m_UserAccountState = CurrentState.lVal;
  576. if (!(m_UserAccountState & UF_SERVER_TRUST_ACCOUNT))
  577. {
  578. if ((m_UserAccountState & UF_ACCOUNTDISABLE))
  579. {
  580. //
  581. // Account is disabled... Load the enable string and insert
  582. // the menu item
  583. //
  584. if ( !LoadString(AfxGetInstanceHandle(), IDS_ENABLE_ACCOUNT,
  585. szBuffer, ARRAYLEN(szBuffer)) )
  586. {
  587. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  588. goto exit_gracefully;
  589. }
  590. InsertMenu(hMenu,
  591. indexMenu,
  592. MF_BYPOSITION|MF_STRING,
  593. idCmdFirst+IDC_ENABLE_ACCOUNT,
  594. szBuffer);
  595. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_ENABLE_ACCOUNT);
  596. }
  597. else
  598. {
  599. //
  600. // Account is enabled... Load the disable string and insert
  601. // the menu item.
  602. //
  603. if ( !LoadString(AfxGetInstanceHandle(), IDS_DISABLE_ACCOUNT,
  604. szBuffer, ARRAYLEN(szBuffer)) )
  605. {
  606. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  607. goto exit_gracefully;
  608. }
  609. InsertMenu(hMenu,
  610. indexMenu,
  611. MF_BYPOSITION|MF_STRING,
  612. idCmdFirst+IDC_ENABLE_ACCOUNT,
  613. szBuffer);
  614. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_ENABLE_ACCOUNT);
  615. }
  616. }
  617. } // if get userAccountControl succeeded
  618. } // if bind succeeded
  619. if (m_Advanced)
  620. {
  621. if ( !LoadString(AfxGetInstanceHandle(), IDS_MAP_CERTIFICATES,
  622. szBuffer, ARRAYLEN(szBuffer)) ) {
  623. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  624. goto exit_gracefully;
  625. }
  626. InsertMenu(hMenu,
  627. indexMenu,
  628. MF_BYPOSITION|MF_STRING,
  629. idCmdFirst+IDC_MAP_CERTIFICATES,
  630. szBuffer);
  631. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_MAP_CERTIFICATES);
  632. }
  633. }
  634. else // m_objectNamesFormat.GetCount() != 1
  635. {
  636. if (m_fClasses && !(m_fClasses & ~(Type_User | Type_Computer)))
  637. {
  638. //
  639. // Load the enable account menu item
  640. //
  641. if ( !LoadString(AfxGetInstanceHandle(), IDS_ENABLE_ACCOUNT,
  642. szBuffer, ARRAYLEN(szBuffer)) )
  643. {
  644. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  645. goto exit_gracefully;
  646. }
  647. InsertMenu(hMenu,
  648. indexMenu,
  649. MF_BYPOSITION|MF_STRING,
  650. idCmdFirst+IDC_ENABLE_ACCOUNT,
  651. szBuffer);
  652. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_ENABLE_ACCOUNT);
  653. //
  654. // Load the disable account menu item
  655. //
  656. if ( !LoadString(AfxGetInstanceHandle(), IDS_DISABLE_ACCOUNT,
  657. szBuffer, ARRAYLEN(szBuffer)) )
  658. {
  659. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  660. goto exit_gracefully;
  661. }
  662. InsertMenu(hMenu,
  663. indexMenu,
  664. MF_BYPOSITION|MF_STRING,
  665. idCmdFirst+IDC_DISABLE_ACCOUNT,
  666. szBuffer);
  667. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_DISABLE_ACCOUNT);
  668. } // if (m_objectNamesFormat.GetCount() == 1)
  669. }
  670. } // if User or Computer
  671. //
  672. // If the node is a user, or contact insert Add objects to group menu item
  673. // Note: OU removed 08/02/2000 by JeffJon
  674. //
  675. if (m_fClasses && !(m_fClasses & ~(Type_User | Type_Contact)))
  676. {
  677. if ( !LoadString(AfxGetInstanceHandle(), IDS_ADD_TO_GROUP,
  678. szBuffer, ARRAYLEN(szBuffer)) )
  679. {
  680. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  681. goto exit_gracefully;
  682. }
  683. BOOL bInsertSuccess = InsertMenu(hMenu,
  684. indexMenu,
  685. MF_BYPOSITION|MF_STRING,
  686. idCmdFirst+IDC_ADD_OBJECTS_TO_GROUP,
  687. szBuffer);
  688. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_ADD_OBJECTS_TO_GROUP);
  689. if (!bInsertSuccess)
  690. {
  691. TRACE(_T("Failed to insert Add to group context menu item. 0x%x\n"), GetLastError());
  692. }
  693. }
  694. //
  695. // If we weren't called from MMC
  696. //
  697. if (!m_internalFormat.HasData())
  698. {
  699. //
  700. // Insert the delete menu item if appropriate
  701. //
  702. if ( !LoadString(AfxGetInstanceHandle(), IDS_DELETE,
  703. szBuffer, ARRAYLEN(szBuffer)) )
  704. {
  705. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  706. goto exit_gracefully;
  707. }
  708. if (bEnableDelete)
  709. {
  710. InsertMenu(hMenu,
  711. indexMenu,
  712. MF_BYPOSITION|MF_STRING,
  713. idCmdFirst+IDC_DELETE_OBJECT,
  714. szBuffer);
  715. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_DELETE_OBJECT);
  716. }
  717. //
  718. // If single selection and node is a computer insert the rename menu item
  719. // NOTE : the rename handler is heavily dependent on DSAdmin being the caller
  720. // hence the check for m_pCD.
  721. //
  722. if (m_pCD != NULL &&
  723. (m_objectNamesFormat.GetCount() == 1) &&
  724. !(m_fClasses & Type_Computer))
  725. {
  726. if ( !LoadString(AfxGetInstanceHandle(), IDS_RENAME,
  727. szBuffer, ARRAYLEN(szBuffer)) )
  728. {
  729. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  730. goto exit_gracefully;
  731. }
  732. if (bEnableRename)
  733. {
  734. InsertMenu(hMenu,
  735. indexMenu,
  736. MF_BYPOSITION|MF_STRING,
  737. idCmdFirst+IDC_RENAME_OBJECT,
  738. szBuffer);
  739. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_RENAME_OBJECT);
  740. }
  741. }
  742. } // if not called from mmc
  743. //
  744. // If node type is NTDSConnection insert the replicate now menu item
  745. //
  746. if (m_fClasses & Type_TrueNTDSConnection)
  747. {
  748. if ( !LoadString(AfxGetInstanceHandle(), IDS_REPLICATE_NOW,
  749. szBuffer, ARRAYLEN(szBuffer)) )
  750. {
  751. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  752. goto exit_gracefully;
  753. }
  754. InsertMenu(hMenu,
  755. indexMenu,
  756. MF_BYPOSITION|MF_STRING,
  757. idCmdFirst+IDC_REPLICATE_NOW,
  758. szBuffer);
  759. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_REPLICATE_NOW);
  760. } // node type NTDSConnection
  761. //
  762. // If node type is user and we can copy it the add the copy object menu item
  763. //
  764. if ( (m_pCD != NULL) && (m_objectNamesFormat.GetCount() == 1) && (m_fClasses == Type_User) )
  765. {
  766. if (S_OK == m_pCD->_CanCopyDSObject(m_spDataObject))
  767. {
  768. if ( !LoadString(AfxGetInstanceHandle(), IDS_COPY_OBJECT,
  769. szBuffer, ARRAYLEN(szBuffer)) )
  770. {
  771. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  772. goto exit_gracefully;
  773. }
  774. InsertMenu(hMenu,
  775. indexMenu,
  776. MF_BYPOSITION|MF_STRING,
  777. idCmdFirst+IDC_COPY_OBJECT,
  778. szBuffer);
  779. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_COPY_OBJECT);
  780. } // if
  781. } // if
  782. hr = S_OK;
  783. exit_gracefully:
  784. if (SUCCEEDED(hr))
  785. hr = MAKE_HRESULT(SEVERITY_SUCCESS, 0, cItems);
  786. TIMER(_T("Exiting DSContext QCM().\n"));
  787. return hr;
  788. }
  789. STDMETHODIMP
  790. CDSContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
  791. {
  792. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  793. HRESULT hr = S_OK;
  794. TRACE (_T("CDSContextMenu::InvokeCommand\n"));
  795. if (lpcmi->hwnd != m_hwnd)
  796. {
  797. m_hwnd = lpcmi->hwnd;
  798. }
  799. TRACE (_T("\tlpcmi->lpVerb is %d.\n"), lpcmi->lpVerb);
  800. switch ((INT_PTR)(lpcmi->lpVerb)) {
  801. case IDC_ENABLE_ACCOUNT:
  802. if (m_objectNamesFormat.GetCount() == 1) {
  803. if (m_UserAccountState & UF_ACCOUNTDISABLE) {
  804. DisableAccount(FALSE);
  805. } else {
  806. DisableAccount(TRUE);
  807. }
  808. } else {
  809. DisableAccount(FALSE);
  810. }
  811. break;
  812. case IDC_DISABLE_ACCOUNT:
  813. DisableAccount(TRUE);
  814. break;
  815. case IDC_MAP_CERTIFICATES:
  816. {
  817. ASSERT (m_objectNamesFormat.GetCount() == 1);
  818. LPWSTR pszCanonical = NULL;
  819. CString szName = m_objectNamesFormat.GetName(0);
  820. CString szPath;
  821. StripADsIPath(szName, szPath, false); // don't use escaped mode
  822. // we don't care about the return code here
  823. CrackName((LPWSTR) (LPCWSTR)szPath,
  824. &pszCanonical,
  825. GET_OBJ_CAN_NAME,
  826. NULL);
  827. CSimData simData;
  828. if ( simData.FInit(pszCanonical, szName, m_hwnd))
  829. simData.DoModal();
  830. else
  831. hr = E_FAIL;
  832. if ( pszCanonical )
  833. LocalFreeStringW(&pszCanonical);
  834. return hr;
  835. }
  836. break;
  837. case IDC_CHANGE_PASSWORD:
  838. ASSERT (m_objectNamesFormat.GetCount() == 1);
  839. ModifyPassword();
  840. break;
  841. case IDC_MOVE_OBJECT:
  842. MoveObject();
  843. break;
  844. case IDC_DELETE_OBJECT:
  845. TRACE(_T("called Delete in context menu extension\n"));
  846. DeleteObject();
  847. break;
  848. case IDC_REPLICATE_NOW:
  849. ReplicateNow();
  850. break;
  851. case IDC_ADD_OBJECTS_TO_GROUP:
  852. AddToGroup();
  853. break;
  854. case IDC_COPY_OBJECT:
  855. CopyObject();
  856. break;
  857. case IDC_RENAME_OBJECT:
  858. Rename();
  859. break;
  860. }
  861. return hr;
  862. }
  863. STDMETHODIMP
  864. CDSContextMenu::GetCommandString(UINT_PTR idCmd,
  865. UINT uFlags,
  866. UINT FAR*,
  867. LPSTR pszName,
  868. UINT ccMax)
  869. {
  870. HRESULT hr = S_OK;
  871. TRACE (_T("CDSContextMenu::GetCommandString\n"));
  872. TRACE (_T("\tidCmd is %d.\n"), idCmd);
  873. if (uFlags == GCS_HELPTEXT)
  874. {
  875. CString csHelp;
  876. switch ((idCmd))
  877. {
  878. case IDC_ENABLE_ACCOUNT:
  879. csHelp.LoadString (IDS_ENABLE_ACCOUNT_HELPSTRING);
  880. break;
  881. case IDC_DISABLE_ACCOUNT:
  882. csHelp.LoadString (IDS_DISABLE_ACCOUNT_HELPSTRING);
  883. break;
  884. case IDC_MAP_CERTIFICATES:
  885. csHelp.LoadString (IDS_MAP_CERTS_HELPSTRING);
  886. break;
  887. case IDC_CHANGE_PASSWORD:
  888. csHelp.LoadString (IDS_CHANGE_PWD_HELPSTRING);
  889. break;
  890. case IDC_MOVE_OBJECT:
  891. csHelp.LoadString (IDS_MOVE_OBJECT_HELPSTRING);
  892. break;
  893. case IDC_DELETE_OBJECT:
  894. csHelp.LoadString (IDS_DELETE_OBJECT_HELPSTRING);
  895. break;
  896. case IDC_REPLICATE_NOW:
  897. csHelp.LoadString (IDS_REPLICATE_HELPSTRING);
  898. break;
  899. case IDC_ADD_OBJECTS_TO_GROUP:
  900. csHelp.LoadString (IDS_ADD_OBJECTS_HELPSTRING);
  901. break;
  902. case IDC_COPY_OBJECT:
  903. csHelp.LoadString (IDS_COPY_HELPSTRING);
  904. break;
  905. case IDC_RENAME_OBJECT:
  906. csHelp.LoadString (IDS_RENAME_HELPSTRING);
  907. break;
  908. }
  909. ASSERT ((UINT)csHelp.GetLength() < ccMax);
  910. wcscpy ((LPWSTR)pszName, (LPWSTR)(LPCWSTR)csHelp);
  911. }
  912. else if (uFlags == GCS_VERB)
  913. {
  914. //
  915. // Return the language independent ID of the context menu item
  916. //
  917. CString szMenuID;
  918. switch ((idCmd))
  919. {
  920. case IDC_ENABLE_ACCOUNT:
  921. szMenuID = CMID_ENABLE_ACCOUNT;
  922. break;
  923. case IDC_DISABLE_ACCOUNT:
  924. szMenuID = CMID_DISABLE_ACCOUNT;
  925. break;
  926. case IDC_MAP_CERTIFICATES:
  927. szMenuID = CMID_MAP_CERTIFICATES;
  928. break;
  929. case IDC_CHANGE_PASSWORD:
  930. szMenuID = CMID_CHANGE_PASSWORD;
  931. break;
  932. case IDC_MOVE_OBJECT:
  933. szMenuID = CMID_MOVE_OBJECT;
  934. break;
  935. case IDC_DELETE_OBJECT:
  936. szMenuID = CMID_DELETE_OBJECT;
  937. break;
  938. case IDC_REPLICATE_NOW:
  939. szMenuID = CMID_REPLICATE_NOW;
  940. break;
  941. case IDC_ADD_OBJECTS_TO_GROUP:
  942. szMenuID = CMID_ADD_OBJECTS_TO_GROUP;
  943. break;
  944. case IDC_COPY_OBJECT:
  945. szMenuID = CMID_COPY_OBJECT;
  946. break;
  947. case IDC_RENAME_OBJECT:
  948. szMenuID = CMID_RENAME_OBJECT;
  949. break;
  950. }
  951. ASSERT ((UINT)szMenuID.GetLength() < ccMax);
  952. wcscpy ((LPWSTR)pszName, (LPWSTR)(LPCWSTR)szMenuID);
  953. }
  954. else
  955. {
  956. TRACE(_T("We are not supporting any other GetCommandString() flags besides GCS_VERB and GCS_HELPTEXT"));
  957. return E_INVALIDARG;
  958. }
  959. return hr;
  960. }
  961. void CDSContextMenu::_ToggleDisabledIcon(UINT index, BOOL bDisable)
  962. {
  963. if ( (m_pCD != NULL) && m_internalFormat.HasData())
  964. {
  965. CDSUINode* pDSUINode = dynamic_cast<CDSUINode*>(m_internalFormat.GetCookie(index));
  966. ASSERT(pDSUINode != NULL);
  967. if (pDSUINode == NULL)
  968. return;
  969. m_pCD->ToggleDisabled(pDSUINode, bDisable);
  970. }
  971. }
  972. void CDSContextMenu::DisableAccount(BOOL bDisable)
  973. {
  974. HRESULT hr = S_OK;
  975. HRESULT hr2 = S_OK;
  976. CComVariant Disabled;
  977. DWORD Response = IDYES;
  978. if (m_objectNamesFormat.GetCount() == 1) { // single selection
  979. if (m_pDsObject) {
  980. if (((bDisable) && (!(m_UserAccountState & UF_ACCOUNTDISABLE))) ||
  981. ((!bDisable) && (m_UserAccountState & UF_ACCOUNTDISABLE))) {
  982. Disabled.vt = VT_I4;
  983. Disabled.lVal = m_UserAccountState;
  984. if (bDisable == TRUE) {
  985. Disabled.lVal |= UF_ACCOUNTDISABLE;
  986. } else {
  987. Disabled.lVal &= ~UF_ACCOUNTDISABLE;
  988. }
  989. // prep for display by getting obj name
  990. CPathCracker pathCracker;
  991. hr2 = pathCracker.Set((LPWSTR)m_objectNamesFormat.GetName(0), ADS_SETTYPE_FULL);
  992. ASSERT(SUCCEEDED(hr2));
  993. hr2 = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  994. ASSERT(SUCCEEDED(hr2));
  995. CComBSTR DestName;
  996. LONG iEMode = 0;
  997. hr2 = pathCracker.get_EscapedMode(&iEMode);
  998. ASSERT(SUCCEEDED(hr2));
  999. hr2 = pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_OFF_EX);
  1000. ASSERT(SUCCEEDED(hr2));
  1001. hr2 = pathCracker.GetElement( 0, &DestName );
  1002. ASSERT(SUCCEEDED(hr2));
  1003. hr2 = pathCracker.put_EscapedMode(iEMode);
  1004. ASSERT(SUCCEEDED(hr2));
  1005. PVOID apv[1] = {(LPWSTR)DestName};
  1006. CString strClass = m_objectNamesFormat.GetClass(0);
  1007. if ((strClass == "computer") && (bDisable)) {
  1008. Response = ReportErrorEx (m_hwnd,IDS_12_DISABLE_COMPUTER_P,hr,
  1009. MB_YESNO | MB_ICONWARNING, apv, 1);
  1010. }
  1011. if (Response == IDYES) {
  1012. hr = m_pDsObject->Put(L"userAccountControl", Disabled);
  1013. hr = m_pDsObject->SetInfo();
  1014. if (SUCCEEDED(hr)) {
  1015. _ToggleDisabledIcon(0, bDisable);
  1016. if (bDisable) {
  1017. ReportErrorEx (m_hwnd,IDS_12_USER_DISABLED_SUCCESSFULLY,hr,
  1018. MB_OK | MB_ICONINFORMATION, apv, 1);
  1019. }
  1020. else {
  1021. ReportErrorEx (m_hwnd,IDS_12_USER_ENABLED_SUCCESSFULLY,hr,
  1022. MB_OK | MB_ICONINFORMATION, apv, 1);
  1023. }
  1024. } else {
  1025. if (bDisable) {
  1026. ReportErrorEx (m_hwnd,IDS_12_USER_DISABLE_FAILED,hr,
  1027. MB_OK | MB_ICONERROR, apv, 1);
  1028. } else
  1029. ReportErrorEx (m_hwnd,IDS_12_USER_ENABLE_FAILED,hr,
  1030. MB_OK | MB_ICONERROR, apv, 1);
  1031. }
  1032. }
  1033. }
  1034. } else {
  1035. PVOID apv[1] = {(LPWSTR)m_objectNamesFormat.GetName(0)};
  1036. ReportErrorEx (m_hwnd,IDS_12_USER_OBJECT_NOT_ACCESSABLE,hr,
  1037. MB_OK | MB_ICONERROR, apv, 1);
  1038. }
  1039. }
  1040. else //multiple selection
  1041. {
  1042. UINT index;
  1043. IADsUser * pObj = NULL;
  1044. CComVariant CurrentState;
  1045. DWORD UserAccountState;
  1046. BOOL error = FALSE;
  1047. DWORD ResponseToo = IDYES;
  1048. if ((m_fClasses & Type_Computer) && (bDisable))
  1049. {
  1050. ResponseToo = ReportMessageEx (m_hwnd, IDS_MULTI_DISABLE_COMPUTER,
  1051. MB_YESNO | MB_ICONWARNING);
  1052. }
  1053. if (ResponseToo == IDYES)
  1054. {
  1055. for (index = 0; index < m_objectNamesFormat.GetCount(); index++)
  1056. {
  1057. hr = DSAdminOpenObject(m_objectNamesFormat.GetName(index),
  1058. IID_IADsUser,
  1059. (void **)&pObj,
  1060. TRUE /*bServer*/);
  1061. if (SUCCEEDED(hr))
  1062. {
  1063. hr = pObj->Get(L"userAccountControl", &CurrentState);
  1064. if (SUCCEEDED(hr))
  1065. {
  1066. UserAccountState = CurrentState.lVal;
  1067. if (((bDisable) && (!(UserAccountState & UF_ACCOUNTDISABLE))) ||
  1068. ((!bDisable) && (UserAccountState & UF_ACCOUNTDISABLE)))
  1069. {
  1070. Disabled.vt = VT_I4;
  1071. Disabled.lVal = UserAccountState;
  1072. if (bDisable == TRUE)
  1073. {
  1074. Disabled.lVal |= UF_ACCOUNTDISABLE;
  1075. }
  1076. else
  1077. {
  1078. Disabled.lVal &= ~UF_ACCOUNTDISABLE;
  1079. }
  1080. hr = pObj->Put(L"userAccountControl", Disabled);
  1081. hr = pObj->SetInfo();
  1082. if (FAILED(hr))
  1083. {
  1084. error = TRUE;
  1085. break;
  1086. }
  1087. else
  1088. {
  1089. _ToggleDisabledIcon(index, bDisable);
  1090. }
  1091. }
  1092. }
  1093. pObj->Release();
  1094. }
  1095. else
  1096. {
  1097. // prep for display by getting obj name
  1098. CPathCracker pathCracker;
  1099. hr2 = pathCracker.Set((LPWSTR)m_objectNamesFormat.GetName(index), ADS_SETTYPE_FULL);
  1100. ASSERT(SUCCEEDED(hr2));
  1101. hr2 = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  1102. ASSERT(SUCCEEDED(hr2));
  1103. CComBSTR ObjName;
  1104. hr2 = pathCracker.GetElement( 0, &ObjName );
  1105. ASSERT(SUCCEEDED(hr2));
  1106. PVOID apv[1] = {(LPWSTR)ObjName};
  1107. ReportErrorEx (m_hwnd,IDS_12_USER_OBJECT_NOT_ACCESSABLE,hr,
  1108. MB_OK | MB_ICONERROR, apv, 1);
  1109. }
  1110. }
  1111. }
  1112. if (error)
  1113. {
  1114. if (bDisable)
  1115. ReportErrorEx (m_hwnd,IDS_DISABLES_FAILED,hr,
  1116. MB_OK | MB_ICONERROR, NULL, 0);
  1117. else
  1118. ReportErrorEx (m_hwnd,IDS_ENABLES_FAILED,hr,
  1119. MB_OK | MB_ICONERROR, NULL, 0);
  1120. }
  1121. else
  1122. {
  1123. if (bDisable)
  1124. {
  1125. ReportErrorEx (m_hwnd, IDS_DISABLED_SUCCESSFULLY, S_OK,
  1126. MB_OK | MB_ICONINFORMATION, NULL, 0);
  1127. }
  1128. else
  1129. {
  1130. ReportErrorEx (m_hwnd, IDS_ENABLED_SUCCESSFULLY, S_OK,
  1131. MB_OK | MB_ICONINFORMATION, NULL, 0);
  1132. }
  1133. }
  1134. }
  1135. }
  1136. void CDSContextMenu::ModifyPassword()
  1137. {
  1138. HRESULT hr = S_OK;
  1139. CString NewPwd, CfmPwd;
  1140. CComVariant Var;
  1141. BOOL error;
  1142. LPCWSTR lpszClass, lpszPath;
  1143. CChangePassword ChgDlg;
  1144. CWaitCursor CWait;
  1145. lpszPath = m_objectNamesFormat.GetName(0);
  1146. // prep for display by getting obj name
  1147. CPathCracker pathCracker;
  1148. hr = pathCracker.Set((LPWSTR)lpszPath, ADS_SETTYPE_FULL);
  1149. hr = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  1150. hr = pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_OFF_EX);
  1151. CComBSTR ObjName;
  1152. hr = pathCracker.Retrieve(ADS_FORMAT_LEAF, &ObjName );
  1153. PVOID apv[1] = {(LPWSTR)ObjName};
  1154. if (!m_pDsObject) {
  1155. hr = DSAdminOpenObject(lpszPath,
  1156. IID_IADsUser,
  1157. (void **)&m_pDsObject,
  1158. TRUE /*bServer*/);
  1159. if (FAILED(hr)) {
  1160. ReportErrorEx (m_hwnd,IDS_12_USER_OBJECT_NOT_ACCESSABLE,hr,
  1161. MB_OK | MB_ICONERROR, apv, 1);
  1162. goto exit_gracefully;
  1163. }
  1164. }
  1165. lpszClass = m_objectNamesFormat.GetClass(0);
  1166. //
  1167. // Get the userAccountControl
  1168. //
  1169. ASSERT(SUCCEEDED(hr));
  1170. hr = m_pDsObject->Get(L"userAccountControl", &Var);
  1171. if (wcscmp(lpszClass, L"computer") == 0)
  1172. {
  1173. if (FAILED(hr) || ((Var.lVal & UF_SERVER_TRUST_ACCOUNT) != 0))
  1174. {
  1175. ReportErrorEx (m_hwnd, IDS_1_CANT_RESET_DOMAIN_CONTROLLER, S_OK,
  1176. MB_OK | MB_ICONERROR, apv, 1);
  1177. }
  1178. else
  1179. {
  1180. DWORD Response = IDYES;
  1181. Response = ReportMessageEx (m_hwnd, IDS_CONFIRM_PASSWORD,
  1182. MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2);
  1183. if (Response == IDYES)
  1184. {
  1185. hr = m_pDsObject->Get(L"sAMAccountName", &Var);
  1186. ASSERT(SUCCEEDED(hr));
  1187. NewPwd = Var.bstrVal;
  1188. NewPwd = NewPwd.Left(14);
  1189. INT loc = NewPwd.Find(L"$");
  1190. if (loc > 0)
  1191. {
  1192. NewPwd = NewPwd.Left(loc);
  1193. }
  1194. NewPwd.MakeLower();
  1195. if (SUCCEEDED(hr))
  1196. {
  1197. hr = m_pDsObject->SetPassword((LPWSTR)(LPCWSTR)NewPwd);
  1198. if (SUCCEEDED(hr))
  1199. {
  1200. ReportErrorEx (m_hwnd,IDS_1_RESET_ACCOUNT_SUCCESSFULL,hr,
  1201. MB_OK | MB_ICONINFORMATION, apv, 1);
  1202. }
  1203. else
  1204. {
  1205. ReportErrorEx (m_hwnd,IDS_12_RESET_ACCOUNT_FAILED,hr,
  1206. MB_OK | MB_ICONERROR, apv, 1);
  1207. }
  1208. }
  1209. }
  1210. }
  1211. }
  1212. else // Not computer object
  1213. {
  1214. //
  1215. // If password doesn't expire don't allow the checkbox for
  1216. // requiring the user to change the password at next logon
  1217. //
  1218. if (Var.lVal & UF_DONT_EXPIRE_PASSWD)
  1219. {
  1220. ChgDlg.AllowMustChangePasswordCheck(FALSE);
  1221. }
  1222. //
  1223. // NTRAID#Windows Bugs-278296-2001/01/12-jeffjon
  1224. // Checking "user must change password" on the Reset Pwd dialog
  1225. // is silently ignored when Write PwdLastSet not granted
  1226. //
  1227. // Disable the checkbox if the admin doesn't have the right
  1228. // to write the pwdLastSet attribute
  1229. //
  1230. BOOL bAllowMustChangePassword = FALSE;
  1231. CComPtr<IDirectoryObject> spDirObject;
  1232. hr = m_pDsObject->QueryInterface(IID_IDirectoryObject, (void**)&spDirObject);
  1233. if (SUCCEEDED(hr))
  1234. {
  1235. PWSTR ppAttrs[] = { (PWSTR)g_pszAllowedAttributesEffective };
  1236. DWORD dwAttrsReturned = 0;
  1237. PADS_ATTR_INFO pAttrInfo = 0;
  1238. hr = spDirObject->GetObjectAttributes(ppAttrs, 1, &pAttrInfo, &dwAttrsReturned);
  1239. if (SUCCEEDED(hr) && dwAttrsReturned == 1 && pAttrInfo)
  1240. {
  1241. if (pAttrInfo->pszAttrName &&
  1242. 0 == _wcsicmp(pAttrInfo->pszAttrName, g_pszAllowedAttributesEffective) &&
  1243. pAttrInfo->pADsValues)
  1244. {
  1245. for (DWORD dwIdx = 0; dwIdx < pAttrInfo->dwNumValues; ++dwIdx)
  1246. {
  1247. if (pAttrInfo->pADsValues[dwIdx].CaseIgnoreString &&
  1248. _wcsicmp(pAttrInfo->pADsValues[dwIdx].CaseIgnoreString, g_pszPwdLastSet))
  1249. {
  1250. bAllowMustChangePassword = TRUE;
  1251. break;
  1252. }
  1253. }
  1254. }
  1255. }
  1256. //
  1257. // Disable the checkbox if the user object doesn't have rights
  1258. // to change their password
  1259. //
  1260. if (!CanUserChangePassword(spDirObject))
  1261. {
  1262. bAllowMustChangePassword = FALSE;
  1263. }
  1264. }
  1265. if (!bAllowMustChangePassword)
  1266. {
  1267. ChgDlg.AllowMustChangePasswordCheck(FALSE);
  1268. }
  1269. do
  1270. {
  1271. error = FALSE;
  1272. if (ChgDlg.DoModal() == IDOK)
  1273. {
  1274. CWaitCursor CWait2;
  1275. NewPwd = ChgDlg.GetNew();
  1276. CfmPwd = ChgDlg.GetConfirm();
  1277. if (NewPwd==CfmPwd)
  1278. {
  1279. if (SUCCEEDED(hr))
  1280. {
  1281. hr = m_pDsObject->SetPassword((LPWSTR)(LPCWSTR)NewPwd);
  1282. if (SUCCEEDED(hr))
  1283. {
  1284. hr = ModifyNetWareUserPassword(m_pDsObject, lpszPath, NewPwd);
  1285. }
  1286. if (SUCCEEDED(hr))
  1287. {
  1288. BOOL ForceChange = ChgDlg.GetChangePwd();
  1289. if (ForceChange)
  1290. {
  1291. //Check to see if the user password does not expire
  1292. BOOL bContinueToForceChange = TRUE;
  1293. IADs* pIADs = NULL;
  1294. HRESULT hr3 = m_pDsObject->QueryInterface(IID_IADs, OUT (void **)&pIADs);
  1295. if (SUCCEEDED(hr3))
  1296. {
  1297. ASSERT(pIADs != NULL);
  1298. CComVariant var;
  1299. hr3 = pIADs->Get(IN (LPWSTR)gsz_userAccountControl, OUT &var);
  1300. if (SUCCEEDED(hr3))
  1301. {
  1302. ASSERT(var.vt == VT_I4);
  1303. if (var.lVal & UF_DONT_EXPIRE_PASSWD)
  1304. {
  1305. ReportErrorEx (m_hwnd,IDS_12_PASSWORD_DOES_NOT_EXPIRE,hr,
  1306. MB_OK | MB_ICONWARNING, apv, 1);
  1307. bContinueToForceChange = FALSE;
  1308. }
  1309. pIADs->Release();
  1310. }
  1311. }
  1312. // If password can expire then force the change at next logon
  1313. if (bContinueToForceChange)
  1314. {
  1315. IDirectoryObject * pIDSObject = NULL;
  1316. LPWSTR szPwdLastSet = L"pwdLastSet";
  1317. ADSVALUE ADsValuePwdLastSet = {ADSTYPE_LARGE_INTEGER, NULL};
  1318. ADS_ATTR_INFO AttrInfoPwdLastSet = {szPwdLastSet, ADS_ATTR_UPDATE,
  1319. ADSTYPE_LARGE_INTEGER,
  1320. &ADsValuePwdLastSet, 1};
  1321. ADsValuePwdLastSet.LargeInteger.QuadPart = 0;
  1322. HRESULT hr2 = m_pDsObject->QueryInterface(IID_IDirectoryObject,
  1323. OUT (void **)&pIDSObject);
  1324. if (SUCCEEDED(hr2))
  1325. {
  1326. ASSERT(pIDSObject != NULL);
  1327. DWORD cAttrModified = 0;
  1328. hr2 = pIDSObject->SetObjectAttributes(&AttrInfoPwdLastSet,
  1329. 1, &cAttrModified);
  1330. pIDSObject->Release();
  1331. }
  1332. }
  1333. }
  1334. ReportErrorEx (m_hwnd,IDS_12_PASSWORD_CHANGE_SUCCESSFUL,hr,
  1335. MB_OK | MB_ICONINFORMATION, apv, 1);
  1336. }
  1337. else
  1338. {
  1339. ReportErrorEx (m_hwnd,IDS_12_PASSWORD_CHANGE_FAILED,hr,
  1340. MB_OK | MB_ICONERROR, apv, 1);
  1341. }
  1342. }
  1343. }
  1344. else
  1345. {
  1346. ReportErrorEx (m_hwnd,IDS_NEW_AND_CONFIRM_NOT_SAME,hr,
  1347. MB_OK | MB_ICONERROR, NULL, 0);
  1348. ChgDlg.Clear();
  1349. error = TRUE;
  1350. }
  1351. }
  1352. } while (error);
  1353. }
  1354. exit_gracefully:
  1355. return;
  1356. }
  1357. #define BREAK_ON_FAIL if (FAILED(hr)) { break; }
  1358. #define BREAK_AND_ASSERT_ON_FAIL if (FAILED(hr)) { ASSERT(FALSE); break; }
  1359. #define RETURN_AND_ASSERT_ON_FAIL if (FAILED(hr)) { ASSERT(FALSE); return; }
  1360. void CDSContextMenu::MoveObject()
  1361. {
  1362. // REVIEW_MARCOC: need to make sure the LDAP path has the SERVER or DOMAIN in it
  1363. // if called in the context of DS Admin, guard against property sheet open on this cookie
  1364. if (_WarningOnSheetsUp())
  1365. return;
  1366. // get the first path in the data object
  1367. ASSERT(m_objectNamesFormat.HasData());
  1368. // now do crack name to get root path for the browse dialog
  1369. CString szRootPath;
  1370. if (m_pCD != NULL)
  1371. {
  1372. szRootPath = m_pCD->GetBasePathsInfo()->GetProviderAndServerName();
  1373. szRootPath += m_pCD->GetRootPath();
  1374. }
  1375. else
  1376. {
  1377. LPCWSTR lpszObjPath = m_objectNamesFormat.GetName(0);
  1378. // make sure there's no strange escaping in the path
  1379. CComBSTR bstrPath;
  1380. CComBSTR bstrProvider;
  1381. CComBSTR bstrServer;
  1382. CPathCracker pathCracker;
  1383. pathCracker.Set((LPTSTR)lpszObjPath, ADS_SETTYPE_FULL);
  1384. pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
  1385. pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_OFF);
  1386. pathCracker.Retrieve( ADS_FORMAT_X500_DN, &bstrPath);
  1387. pathCracker.Retrieve( ADS_FORMAT_SERVER, &bstrServer);
  1388. pathCracker.Retrieve( ADS_FORMAT_PROVIDER, &bstrProvider);
  1389. LPWSTR pwszDomainPath;
  1390. HRESULT hr = CrackName(const_cast<LPWSTR>((LPCWSTR)bstrPath),
  1391. &pwszDomainPath,
  1392. GET_FQDN_DOMAIN_NAME,
  1393. m_hwnd);
  1394. if ((FAILED(hr)) || (HRESULT_CODE(hr) == DS_NAME_ERROR_NO_MAPPING))
  1395. {
  1396. TRACE(_T("CrackNames failed to get domain for %s.\n"),
  1397. lpszObjPath);
  1398. szRootPath = L"";
  1399. }
  1400. else
  1401. {
  1402. CPathCracker pathCrackerOther;
  1403. hr = pathCrackerOther.Set( pwszDomainPath, ADS_SETTYPE_DN );
  1404. RETURN_AND_ASSERT_ON_FAIL;
  1405. hr = pathCrackerOther.Set( bstrProvider, ADS_SETTYPE_PROVIDER );
  1406. RETURN_AND_ASSERT_ON_FAIL;
  1407. hr = pathCrackerOther.Set( bstrServer, ADS_SETTYPE_SERVER );
  1408. RETURN_AND_ASSERT_ON_FAIL;
  1409. CComBSTR sbstrRootPath;
  1410. hr = pathCrackerOther.Retrieve( ADS_FORMAT_X500, &sbstrRootPath );
  1411. RETURN_AND_ASSERT_ON_FAIL;
  1412. szRootPath = sbstrRootPath;
  1413. }
  1414. if (pwszDomainPath != NULL)
  1415. ::LocalFreeStringW(&pwszDomainPath);
  1416. }
  1417. CMultiselectMoveHandler moveHandler(m_pCD, m_hwnd, szRootPath);
  1418. HRESULT hr = moveHandler.Initialize(m_spDataObject, &m_objectNamesFormat,
  1419. &m_internalFormat);
  1420. ASSERT(SUCCEEDED(hr));
  1421. moveHandler.Move();
  1422. }
  1423. void CDSContextMenu::DeleteObject()
  1424. {
  1425. _ASSERTE(m_objectNamesFormat.HasData());
  1426. // if called in the context of DS Admin, guard against property sheet open on this cookie
  1427. if (_WarningOnSheetsUp())
  1428. return;
  1429. UINT nObjectCount = m_objectNamesFormat.GetCount();
  1430. if (nObjectCount == 0)
  1431. {
  1432. ASSERT(nObjectCount != 0);
  1433. return;
  1434. }
  1435. UINT nDeletedCount = 0;
  1436. PCWSTR* pszNameDelArr = 0;
  1437. PCWSTR* pszClassDelArr = 0;
  1438. DWORD* dwFlagsDelArr = 0;
  1439. DWORD* dwProviderFlagsDelArr = 0;
  1440. do // false loop
  1441. {
  1442. pszNameDelArr = new PCWSTR[nObjectCount];
  1443. pszClassDelArr = new PCWSTR[nObjectCount];
  1444. dwFlagsDelArr = new DWORD[nObjectCount];
  1445. dwProviderFlagsDelArr = new DWORD[nObjectCount];
  1446. if (!pszNameDelArr ||
  1447. !pszClassDelArr ||
  1448. !dwFlagsDelArr ||
  1449. !dwProviderFlagsDelArr)
  1450. {
  1451. break;
  1452. }
  1453. switch(nObjectCount)
  1454. {
  1455. case 1:
  1456. {
  1457. // single selection delete
  1458. CContextMenuSingleDeleteHandler deleteHandler(m_pCD, m_hwnd,
  1459. m_objectNamesFormat.GetName(0),
  1460. m_objectNamesFormat.GetClass(0),
  1461. m_objectNamesFormat.IsContainer(0),
  1462. this);
  1463. HRESULT hr = deleteHandler.Delete();
  1464. if (SUCCEEDED(hr) && (hr != S_FALSE))
  1465. {
  1466. nDeletedCount = 1;
  1467. pszNameDelArr[0] = m_objectNamesFormat.GetName(0);
  1468. pszClassDelArr[0] = m_objectNamesFormat.GetClass(0);
  1469. dwFlagsDelArr[0] = m_objectNamesFormat.GetFlags(0);
  1470. dwProviderFlagsDelArr[0] = m_objectNamesFormat.GetProviderFlags(0);
  1471. }
  1472. }
  1473. break;
  1474. default:
  1475. {
  1476. // multiple selection
  1477. CContextMenuMultipleDeleteHandler deleteHandler(m_pCD, m_hwnd, m_spDataObject,
  1478. &m_objectNamesFormat, this);
  1479. deleteHandler.Delete();
  1480. for (UINT k=0; k< nObjectCount; k++)
  1481. {
  1482. if (deleteHandler.WasItemDeleted(k))
  1483. {
  1484. pszNameDelArr[nDeletedCount] = m_objectNamesFormat.GetName(k);
  1485. pszClassDelArr[nDeletedCount] = m_objectNamesFormat.GetClass(k);
  1486. dwFlagsDelArr[nDeletedCount] = m_objectNamesFormat.GetFlags(k);
  1487. dwProviderFlagsDelArr[nDeletedCount] = m_objectNamesFormat.GetProviderFlags(k);
  1488. nDeletedCount++;
  1489. } // if
  1490. } // for
  1491. }
  1492. }; // switch
  1493. _NotifyDsFind((PCWSTR*)pszNameDelArr,
  1494. (PCWSTR*)pszClassDelArr,
  1495. dwFlagsDelArr,
  1496. dwProviderFlagsDelArr,
  1497. nDeletedCount);
  1498. } while (false);
  1499. if (pszNameDelArr)
  1500. {
  1501. delete[] pszNameDelArr;
  1502. pszNameDelArr = 0;
  1503. }
  1504. if (pszClassDelArr)
  1505. {
  1506. delete[] pszClassDelArr;
  1507. pszClassDelArr = 0;
  1508. }
  1509. if (dwFlagsDelArr)
  1510. {
  1511. delete[] dwFlagsDelArr;
  1512. dwFlagsDelArr = 0;
  1513. }
  1514. if (dwProviderFlagsDelArr)
  1515. {
  1516. delete[] dwProviderFlagsDelArr;
  1517. dwProviderFlagsDelArr = 0;
  1518. }
  1519. }
  1520. void CDSContextMenu::_NotifyDsFind(LPCWSTR* lpszNameDelArr,
  1521. LPCWSTR* lpszClassDelArr,
  1522. DWORD* dwFlagsDelArr,
  1523. DWORD* dwProviderFlagsDelArr,
  1524. UINT nDeletedCount)
  1525. {
  1526. if (nDeletedCount == 0)
  1527. {
  1528. // nothing to delete
  1529. return;
  1530. }
  1531. if (m_internalFormat.HasData())
  1532. {
  1533. // called from DS Admin directly, not from DS Find
  1534. return;
  1535. }
  1536. // ask DS Find about the notification interface
  1537. CComPtr<IQueryFrame> spIQueryFrame;
  1538. if ( !::SendMessage(m_hwnd, CQFWM_GETFRAME, 0, (LPARAM)&spIQueryFrame) )
  1539. {
  1540. // interface not found
  1541. return;
  1542. }
  1543. CComPtr<IDsQueryHandler> spDsQueryHandler;
  1544. HRESULT hr = spIQueryFrame->GetHandler(IID_IDsQueryHandler, (void **)&spDsQueryHandler);
  1545. if (FAILED(hr))
  1546. {
  1547. // interface not found
  1548. return;
  1549. }
  1550. // we finally have the interface, build the data structures
  1551. // figure out how much storage we need
  1552. DWORD cbStruct = sizeof(DSOBJECTNAMES) +
  1553. ((nDeletedCount - 1) * sizeof(DSOBJECT));
  1554. size_t cbStorage = 0;
  1555. for (UINT index = 0; index < nDeletedCount; index++)
  1556. {
  1557. cbStorage += sizeof(WCHAR)*(wcslen(lpszNameDelArr[index])+1);
  1558. cbStorage += sizeof(WCHAR)*(wcslen(lpszClassDelArr[index])+1);
  1559. }
  1560. // allocate memory
  1561. LPDSOBJECTNAMES pDSObj = (LPDSOBJECTNAMES)::malloc(cbStruct + cbStorage);
  1562. if (pDSObj == NULL)
  1563. {
  1564. ASSERT(FALSE);
  1565. return;
  1566. }
  1567. // fill in the structs
  1568. pDSObj->clsidNamespace = m_CallerSnapin;
  1569. pDSObj->cItems = nDeletedCount;
  1570. DWORD NextOffset = cbStruct;
  1571. for (index = 0; index < nDeletedCount; index++)
  1572. {
  1573. pDSObj->aObjects[index].dwFlags = dwFlagsDelArr[index];
  1574. pDSObj->aObjects[index].dwProviderFlags = dwProviderFlagsDelArr[index];
  1575. pDSObj->aObjects[index].offsetName = NextOffset;
  1576. pDSObj->aObjects[index].offsetClass = static_cast<ULONG>(NextOffset +
  1577. (wcslen(lpszNameDelArr[index])+1) * sizeof(WCHAR));
  1578. _tcscpy((LPTSTR)((BYTE *)pDSObj + NextOffset), lpszNameDelArr[index]);
  1579. NextOffset += static_cast<ULONG>((wcslen(lpszNameDelArr[index]) + 1) * sizeof(WCHAR));
  1580. _tcscpy((LPTSTR)((BYTE *)pDSObj + NextOffset), lpszClassDelArr[index]);
  1581. NextOffset += static_cast<ULONG>((wcslen(lpszClassDelArr[index]) + 1) * sizeof(WCHAR));
  1582. }
  1583. // make the call
  1584. hr = spDsQueryHandler->UpdateView(DSQRVF_ITEMSDELETED, pDSObj);
  1585. ::free(pDSObj);
  1586. }
  1587. HRESULT
  1588. CDSContextMenu::_Delete(LPCWSTR lpszPath, LPCWSTR lpszClass,
  1589. CString * csName)
  1590. {
  1591. CComBSTR strParent;
  1592. CComBSTR strThisRDN;
  1593. IADsContainer * pDSContainer = NULL;
  1594. IADs * pDSObject = NULL;
  1595. HRESULT hr = S_OK;
  1596. hr = DSAdminOpenObject(lpszPath,
  1597. IID_IADs,
  1598. (void **) &pDSObject,
  1599. TRUE /*bServer*/);
  1600. if (!SUCCEEDED(hr)) {
  1601. goto error;
  1602. }
  1603. hr = pDSObject->get_Parent(&strParent);
  1604. if (!SUCCEEDED(hr)) {
  1605. goto error;
  1606. }
  1607. hr = pDSObject->get_Name (&strThisRDN);
  1608. if (!SUCCEEDED(hr)) {
  1609. goto error;
  1610. }
  1611. pDSObject->Release();
  1612. pDSObject = NULL;
  1613. hr = DSAdminOpenObject(strParent,
  1614. IID_IADsContainer,
  1615. (void **) &pDSContainer,
  1616. TRUE /*bServer*/);
  1617. if (!SUCCEEDED(hr)) {
  1618. goto error;
  1619. }
  1620. hr = pDSContainer->Delete ((LPWSTR)lpszClass,
  1621. (LPWSTR)(LPCWSTR)strThisRDN);
  1622. error:
  1623. if (pDSContainer)
  1624. pDSContainer->Release();
  1625. if (pDSObject)
  1626. pDSObject->Release();
  1627. if (FAILED(hr)) {
  1628. *csName = strThisRDN;
  1629. }
  1630. return hr;
  1631. }
  1632. HRESULT
  1633. CDSContextMenu::_DeleteSubtree(LPCWSTR lpszPath,
  1634. CString * csName)
  1635. {
  1636. HRESULT hr = S_OK;
  1637. IADsDeleteOps * pObj = NULL;
  1638. IADs * pObj2 = NULL;
  1639. hr = DSAdminOpenObject(lpszPath,
  1640. IID_IADsDeleteOps,
  1641. (void **)&pObj,
  1642. TRUE /*bServer*/);
  1643. if (SUCCEEDED(hr)) {
  1644. TIMER(_T("Call to Deleteobject (to do subtree delete).\n"));
  1645. hr = pObj->DeleteObject(NULL); //flag is reserved by ADSI
  1646. TIMER(_T("Call to Deleteobject completed.\n"));
  1647. }
  1648. if (FAILED(hr)) {
  1649. CComBSTR strName;
  1650. HRESULT hr2 = pObj->QueryInterface (IID_IADs, (void **)&pObj2);
  1651. if (SUCCEEDED(hr2)) {
  1652. hr2 = pObj2->get_Name(&strName);
  1653. if (SUCCEEDED(hr2)) {
  1654. *csName = strName;
  1655. } else {
  1656. csName->LoadString (IDS_UNKNOWN);
  1657. }
  1658. }
  1659. }
  1660. if (pObj2) {
  1661. pObj2->Release();
  1662. }
  1663. if (pObj) {
  1664. pObj->Release();
  1665. }
  1666. return hr;
  1667. }
  1668. // code from JeffParh
  1669. NTSTATUS RetrieveRootDomainName( LPCWSTR lpcwszTargetDC, BSTR* pbstrRootDomainName )
  1670. {
  1671. if (NULL == pbstrRootDomainName)
  1672. {
  1673. ASSERT(FALSE);
  1674. return STATUS_INVALID_PARAMETER;
  1675. }
  1676. ASSERT( NULL == *pbstrRootDomainName );
  1677. NTSTATUS ntStatus = STATUS_SUCCESS;
  1678. LSA_HANDLE hPolicy = NULL;
  1679. POLICY_DNS_DOMAIN_INFO* pDnsDomainInfo = NULL;
  1680. do { // false loop
  1681. UNICODE_STRING unistrTargetDC;
  1682. if (NULL != lpcwszTargetDC)
  1683. {
  1684. unistrTargetDC.Length = (USHORT)(::lstrlen(lpcwszTargetDC)*sizeof(WCHAR));
  1685. unistrTargetDC.MaximumLength = unistrTargetDC.Length;
  1686. unistrTargetDC.Buffer = (LPWSTR)lpcwszTargetDC;
  1687. }
  1688. LSA_OBJECT_ATTRIBUTES oa;
  1689. ZeroMemory( &oa, sizeof(oa) );
  1690. ntStatus = LsaOpenPolicy(
  1691. (NULL != lpcwszTargetDC) ? &unistrTargetDC : NULL,
  1692. &oa,
  1693. POLICY_VIEW_LOCAL_INFORMATION,
  1694. &hPolicy
  1695. );
  1696. if ( !LSA_SUCCESS( ntStatus ) )
  1697. {
  1698. ASSERT(FALSE);
  1699. break;
  1700. }
  1701. ntStatus = LsaQueryInformationPolicy(
  1702. hPolicy,
  1703. PolicyDnsDomainInformation,
  1704. (PVOID*)&pDnsDomainInfo
  1705. );
  1706. if ( !LSA_SUCCESS( ntStatus ) )
  1707. {
  1708. ASSERT(FALSE);
  1709. break;
  1710. }
  1711. *pbstrRootDomainName = ::SysAllocStringLen(
  1712. pDnsDomainInfo->DnsForestName.Buffer,
  1713. pDnsDomainInfo->DnsForestName.Length / sizeof(WCHAR) );
  1714. if (NULL == *pbstrRootDomainName)
  1715. {
  1716. ntStatus = STATUS_NO_MEMORY;
  1717. break;
  1718. }
  1719. } while (false); // false loop
  1720. if (NULL != pDnsDomainInfo)
  1721. {
  1722. NTSTATUS ntstatus2 = LsaFreeMemory( pDnsDomainInfo );
  1723. ASSERT( LSA_SUCCESS(ntstatus2) );
  1724. }
  1725. if (NULL != hPolicy)
  1726. {
  1727. NTSTATUS ntstatus2 = LsaClose( hPolicy );
  1728. ASSERT( LSA_SUCCESS(ntstatus2) );
  1729. }
  1730. return ntStatus;
  1731. }
  1732. void AddMatchingNCs(
  1733. IN OUT CStringList& refstrlist,
  1734. IN const PADS_ATTR_INFO padsattrinfo1,
  1735. IN const PADS_ATTR_INFO padsattrinfo2 )
  1736. {
  1737. if ( !padsattrinfo1 || !padsattrinfo2 )
  1738. return;
  1739. for (DWORD iTarget = 0; iTarget < padsattrinfo1[0].dwNumValues; iTarget++)
  1740. {
  1741. LPWSTR lpszTargetNC = padsattrinfo1[0].pADsValues[iTarget].DNString;
  1742. ASSERT( NULL != lpszTargetNC );
  1743. bool fFound = false;
  1744. for (DWORD iSource = 0; iSource < padsattrinfo2[0].dwNumValues; iSource++)
  1745. {
  1746. LPWSTR lpszSourceNC = padsattrinfo2[0].pADsValues[iSource].DNString;
  1747. ASSERT( NULL != lpszSourceNC );
  1748. if ( !lstrcmpiW( lpszTargetNC, lpszSourceNC ) )
  1749. {
  1750. fFound = true;
  1751. break;
  1752. }
  1753. }
  1754. if (fFound)
  1755. refstrlist.AddHead( lpszTargetNC ); // CODEWORK can throw
  1756. }
  1757. }
  1758. HRESULT PrepareReplicaSyncParameters(
  1759. IN LPCWSTR strNTDSConnection,
  1760. IN BSTR bstrRootDomainName,
  1761. OUT BSTR* pbstrDsBindName,
  1762. OUT UUID* puuidSourceObjectGUID,
  1763. OUT CStringList& refstrlistCommonNCs,
  1764. OUT ULONG* pulDsSyncOptions,
  1765. OUT BSTR* pbstrFromServer
  1766. )
  1767. {
  1768. ASSERT( NULL != strNTDSConnection
  1769. && NULL != bstrRootDomainName
  1770. && NULL != pbstrDsBindName
  1771. && NULL == *pbstrDsBindName
  1772. && NULL != puuidSourceObjectGUID
  1773. && refstrlistCommonNCs.IsEmpty()
  1774. && NULL != pulDsSyncOptions
  1775. );
  1776. HRESULT hr = S_OK;
  1777. do { // false loop
  1778. CComPtr<IADs> spIADs;
  1779. // read attributes of nTDSConnection object
  1780. hr = DSAdminOpenObject(strNTDSConnection,
  1781. IID_IADs,
  1782. (void **) &spIADs,
  1783. TRUE /*bServer*/);
  1784. BREAK_ON_FAIL;
  1785. hr = GetStringAttr( spIADs, L"fromServer", pbstrFromServer);
  1786. BREAK_AND_ASSERT_ON_FAIL; // required attribute
  1787. spIADs.Release(); // method of CComPtr<>, also sets pointer to NULL
  1788. // get the path to the target nTDSDSA object
  1789. CPathCracker pathCracker;
  1790. hr = pathCracker.Set( const_cast<BSTR>(strNTDSConnection), ADS_SETTYPE_FULL );
  1791. BREAK_AND_ASSERT_ON_FAIL;
  1792. hr = pathCracker.RemoveLeafElement();
  1793. BREAK_AND_ASSERT_ON_FAIL;
  1794. CComBSTR sbstrTargetNTDSDSAPath;
  1795. hr = pathCracker.Retrieve( ADS_FORMAT_X500, &sbstrTargetNTDSDSAPath );
  1796. BREAK_AND_ASSERT_ON_FAIL;
  1797. // get the sitename for the target NTDSA object
  1798. hr = pathCracker.SetDisplayType( ADS_DISPLAY_VALUE_ONLY );
  1799. BREAK_AND_ASSERT_ON_FAIL;
  1800. CComBSTR sbstrTargetSite;
  1801. hr = pathCracker.GetElement( 3L, &sbstrTargetSite );
  1802. BREAK_AND_ASSERT_ON_FAIL;
  1803. hr = pathCracker.SetDisplayType( ADS_DISPLAY_FULL );
  1804. BREAK_AND_ASSERT_ON_FAIL;
  1805. // read objectGUID of the target nTDSDSA object
  1806. hr = DSAdminOpenObject(sbstrTargetNTDSDSAPath,
  1807. IID_IADs,
  1808. (void **) &spIADs,
  1809. TRUE /*bServer*/);
  1810. BREAK_ON_FAIL;
  1811. CComBSTR sbstrTargetObjectGUID;
  1812. hr = GetObjectGUID( spIADs, &sbstrTargetObjectGUID );
  1813. // The objectGUID attribute should be set for nTDSDSA objects
  1814. BREAK_AND_ASSERT_ON_FAIL;
  1815. // read hasMasterNCs of the target nTDSDSA object
  1816. Smart_PADS_ATTR_INFO spTargetMasterNCAttrs;
  1817. hr = GetAttr( spIADs, L"hasMasterNCs", &spTargetMasterNCAttrs );
  1818. // The hasMasterNCs attribute should be set for nTDSDSA objects
  1819. BREAK_AND_ASSERT_ON_FAIL;
  1820. // read hasPartialReplicaNCs of the target nTDSDSA object
  1821. Smart_PADS_ATTR_INFO spTargetPartialNCAttrs;
  1822. (void) GetAttr( spIADs, L"hasPartialReplicaNCs", &spTargetPartialNCAttrs );
  1823. // The hasPartialReplicaNCs attribute may or may not be set for nTDSDSA objects
  1824. spIADs.Release(); // method of CComPtr<>, also sets pointer to NULL
  1825. /*
  1826. hr = spIADsPathname->RemoveLeafElement();
  1827. BREAK_AND_ASSERT_ON_FAIL;
  1828. CComBSTR sbstrTargetServerPath;
  1829. hr = spIADsPathname->Retrieve( ADS_FORMAT_X500, &sbstrTargetServerPath );
  1830. BREAK_AND_ASSERT_ON_FAIL;
  1831. hr = DSAdminOpenObject(sbstrTargetServerPath,
  1832. IID_IADs,
  1833. (void **) &spIADs,
  1834. TRUE);
  1835. BREAK_ON_FAIL;
  1836. CComVariant var;
  1837. hr = spIADs->Get(L"dNSHostName", &var);
  1838. BREAK_ON_FAIL; // can be missing for brand-new DCs
  1839. spIADs.Release(); // method of CComPtr<>, also sets pointer to NULL
  1840. ASSERT((var.vt == VT_BSTR) && var.bstrVal && *(var.bstrVal));
  1841. LPWSTR lpszDNSHostName = var.bstrVal;
  1842. */
  1843. // get the path to the source nTDSDSA object
  1844. hr = pathCracker.Set(
  1845. (pbstrFromServer) ? *pbstrFromServer : NULL,
  1846. ADS_SETTYPE_DN );
  1847. BREAK_AND_ASSERT_ON_FAIL;
  1848. CComBSTR sbstrSourceNTDSDSAPath;
  1849. hr = pathCracker.Retrieve( ADS_FORMAT_X500, &sbstrSourceNTDSDSAPath );
  1850. BREAK_AND_ASSERT_ON_FAIL;
  1851. // get the sitename for the source NTDSA object
  1852. hr = pathCracker.SetDisplayType( ADS_DISPLAY_VALUE_ONLY );
  1853. BREAK_AND_ASSERT_ON_FAIL;
  1854. CComBSTR sbstrSourceSite;
  1855. hr = pathCracker.GetElement( 3L, &sbstrSourceSite );
  1856. BREAK_AND_ASSERT_ON_FAIL;
  1857. hr = pathCracker.SetDisplayType( ADS_DISPLAY_FULL );
  1858. BREAK_AND_ASSERT_ON_FAIL;
  1859. // determine whether the two DCs are in the same site
  1860. *pulDsSyncOptions = (lstrcmpi(sbstrSourceSite, sbstrTargetSite))
  1861. ? DS_REPSYNC_ASYNCHRONOUS_OPERATION
  1862. : 0;
  1863. // read objectGUID of the source NTDSDSA object
  1864. hr = DSAdminOpenObject(sbstrSourceNTDSDSAPath,
  1865. IID_IADs,
  1866. (void **) &spIADs,
  1867. TRUE /*bServer*/);
  1868. BREAK_ON_FAIL;
  1869. hr = GetObjectGUID( spIADs, puuidSourceObjectGUID );
  1870. // The objectGUID attribute should be set for nTDSDSA objects
  1871. BREAK_AND_ASSERT_ON_FAIL;
  1872. // read hasMasterNCs of the source nTDSDSA object
  1873. Smart_PADS_ATTR_INFO spSourceMasterNCAttrs;
  1874. hr = GetAttr( spIADs, L"hasMasterNCs", &spSourceMasterNCAttrs );
  1875. // The hasMasterNCs attribute should be set for nTDSDSA objects
  1876. BREAK_AND_ASSERT_ON_FAIL;
  1877. // read hasMasterNCs of the source nTDSDSA object
  1878. Smart_PADS_ATTR_INFO spSourcePartialNCAttrs;
  1879. (void) GetAttr( spIADs, L"hasPartialReplicaNCs", &spSourcePartialNCAttrs );
  1880. // The hasPartialReplicaNCs attribute may or may not be set for nTDSDSA objects
  1881. spIADs.Release(); // method of CComPtr<>, also sets pointer to NULL
  1882. // Determine which NCs the two NTDSDSAs have in common
  1883. AddMatchingNCs( refstrlistCommonNCs, spTargetMasterNCAttrs, spSourceMasterNCAttrs );
  1884. AddMatchingNCs( refstrlistCommonNCs, spTargetPartialNCAttrs, spSourceMasterNCAttrs );
  1885. AddMatchingNCs( refstrlistCommonNCs, spTargetPartialNCAttrs, spSourcePartialNCAttrs );
  1886. // Build the name of the inbound domain controller for this connection
  1887. CString csGUID( sbstrTargetObjectGUID );
  1888. ASSERT( L'{' == csGUID[0] && L'}' == csGUID[csGUID.GetLength()-1] );
  1889. CString csDC = csGUID.Mid( 1, csGUID.GetLength()-2 );
  1890. csDC += L"._msdcs.";
  1891. csDC += bstrRootDomainName;
  1892. *pbstrDsBindName = ::SysAllocString( csDC );
  1893. /*
  1894. *pbstrDsBindName = ::SysAllocString( lpszDNSHostName );
  1895. */
  1896. if (NULL == *pbstrDsBindName)
  1897. {
  1898. hr = E_OUTOFMEMORY;
  1899. BREAK_AND_ASSERT_ON_FAIL;
  1900. }
  1901. } while (false); // false loop
  1902. return hr;
  1903. }
  1904. void CDSContextMenu::AddToGroup()
  1905. {
  1906. CWaitCursor waitcursor;
  1907. HRESULT hr = S_OK;
  1908. TRACE (_T("CDSContextMenu::AddToGroup\n"));
  1909. hr = AddDataObjListToGroup (&m_objectNamesFormat, m_hwnd, m_pCD);
  1910. return;
  1911. }
  1912. // This level takes care of displaying the error messages
  1913. // CODEWORK should this try to replicate other domains to GCs?
  1914. void CDSContextMenu::ReplicateNow()
  1915. {
  1916. CWaitCursor waitcursor;
  1917. CComBSTR sbstrRootDomainName;
  1918. LPCWSTR lpcwszTargetDC = NULL;
  1919. if ( NULL != m_pCD && NULL != m_pCD->GetBasePathsInfo() )
  1920. lpcwszTargetDC = m_pCD->GetBasePathsInfo()->GetServerName();
  1921. NTSTATUS ntstatus = RetrieveRootDomainName( lpcwszTargetDC, &sbstrRootDomainName );
  1922. if ( !LSA_SUCCESS(ntstatus) )
  1923. {
  1924. // error in RetrieveRootDomainName against DSADMIN target DC
  1925. PVOID apv[1] = {(LPWSTR)(lpcwszTargetDC) };
  1926. (void) ReportErrorEx( m_hwnd,
  1927. IDS_REPLNOW_1_PARAMLOAD_ERROR,
  1928. ntstatus, // CODEWORK
  1929. MB_OK | MB_ICONEXCLAMATION,
  1930. apv,
  1931. 1,
  1932. IDS_REPLNOW_TITLE );
  1933. return;
  1934. }
  1935. CComBSTR sbstrFailingConnection;
  1936. CComBSTR sbstrFromServer;
  1937. CComBSTR sbstrFailingNC;
  1938. HRESULT hr = S_OK;
  1939. bool fSyncError = false;
  1940. ULONG ulOptionsUsed = 0;
  1941. // loop through the array of objects
  1942. UINT cCount;
  1943. for (cCount=0; cCount < m_objectNamesFormat.GetCount(); cCount++) {
  1944. if (wcscmp(m_objectNamesFormat.GetClass(cCount), L"nTDSConnection") !=0)
  1945. continue;
  1946. // get the replication parameters for this connection object
  1947. CComBSTR sbstrDsBindName;
  1948. UUID uuidSourceObjectGUID;
  1949. CStringList strlistCommonNCs;
  1950. ULONG ulDsSyncOptions = 0L;
  1951. sbstrFromServer.Empty();
  1952. sbstrFailingConnection = m_objectNamesFormat.GetName(cCount);
  1953. hr = PrepareReplicaSyncParameters(
  1954. sbstrFailingConnection,
  1955. sbstrRootDomainName,
  1956. &sbstrDsBindName,
  1957. &uuidSourceObjectGUID,
  1958. strlistCommonNCs,
  1959. &ulDsSyncOptions,
  1960. &sbstrFromServer
  1961. );
  1962. BREAK_ON_FAIL;
  1963. // now bind to the target DC
  1964. Smart_DsHandle shDS;
  1965. DWORD dwWinError = DsBind( sbstrDsBindName, // DomainControllerAddress
  1966. NULL, // DnsDomainName
  1967. &shDS );
  1968. if (ERROR_SUCCESS != dwWinError)
  1969. {
  1970. hr = HRESULT_FROM_WIN32(dwWinError);
  1971. ASSERT( FAILED(hr) );
  1972. break;
  1973. }
  1974. // sync all common naming contexts for this connection
  1975. CString strCommonNC;
  1976. POSITION pos = strlistCommonNCs.GetHeadPosition();
  1977. while (NULL != pos)
  1978. {
  1979. strCommonNC = strlistCommonNCs.GetNext( pos ) ;
  1980. ASSERT( 0 != strCommonNC.GetLength() );
  1981. dwWinError = DsReplicaSync( shDS,
  1982. const_cast<LPWSTR>((LPCTSTR)strCommonNC),
  1983. &uuidSourceObjectGUID,
  1984. ulDsSyncOptions );
  1985. if (ERROR_SUCCESS != dwWinError)
  1986. {
  1987. sbstrFailingNC = strCommonNC;
  1988. hr = HRESULT_FROM_WIN32(dwWinError);
  1989. ASSERT( FAILED(hr) );
  1990. break;
  1991. }
  1992. }
  1993. if ( FAILED(hr) )
  1994. {
  1995. fSyncError = true;
  1996. break;
  1997. }
  1998. ulOptionsUsed |= ulDsSyncOptions;
  1999. } // for
  2000. if ( SUCCEEDED(hr) )
  2001. {
  2002. (void) ReportMessageEx( m_hwnd,
  2003. (ulOptionsUsed & DS_REPSYNC_ASYNCHRONOUS_OPERATION)
  2004. ? IDS_REPLNOW_SUCCEEDED_DELAYED
  2005. : IDS_REPLNOW_SUCCEEDED_IMMEDIATE,
  2006. MB_OK | MB_ICONINFORMATION,
  2007. NULL,
  2008. 0,
  2009. IDS_REPLNOW_TITLE );
  2010. }
  2011. else
  2012. {
  2013. // JonN 3/30/00
  2014. // 6793: SITEREPL: ReplicateNow should provide more error information
  2015. // retrieve name of target DC
  2016. CComBSTR sbstrToServerRDN;
  2017. CPathCracker pathCracker;
  2018. HRESULT hr2 = pathCracker.Set(sbstrFailingConnection, ADS_SETTYPE_FULL);
  2019. ASSERT( SUCCEEDED(hr2) );
  2020. hr2 = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  2021. ASSERT( SUCCEEDED(hr2) );
  2022. hr2 = pathCracker.GetElement(2, &sbstrToServerRDN);
  2023. ASSERT( SUCCEEDED(hr2) );
  2024. if (fSyncError)
  2025. {
  2026. // error in DsReplicaSync against connection target DC
  2027. // retrieve name of source DC
  2028. CComBSTR sbstrFromServerRDN;
  2029. hr2 = pathCracker.Set(sbstrFromServer, ADS_SETTYPE_DN);
  2030. ASSERT( SUCCEEDED(hr2) );
  2031. hr2 = pathCracker.GetElement(1, &sbstrFromServerRDN);
  2032. ASSERT( SUCCEEDED(hr2) );
  2033. // retrieve name of naming context
  2034. if (sbstrFailingNC && !wcsncmp(L"CN=",sbstrFailingNC,3))
  2035. {
  2036. hr2 = pathCracker.Set(sbstrFailingNC, ADS_SETTYPE_DN);
  2037. ASSERT( SUCCEEDED(hr2) );
  2038. hr2 = pathCracker.GetElement( 0, &sbstrFailingNC );
  2039. ASSERT( SUCCEEDED(hr2) );
  2040. } else {
  2041. LPWSTR pwzDomainNC = NULL;
  2042. hr2 = CrackName(sbstrFailingNC, &pwzDomainNC, GET_DNS_DOMAIN_NAME, NULL);
  2043. ASSERT( SUCCEEDED(hr2) && NULL != pwzDomainNC );
  2044. sbstrFailingNC = pwzDomainNC;
  2045. LocalFreeStringW(&pwzDomainNC);
  2046. }
  2047. PVOID apv[3] = { sbstrToServerRDN, sbstrFromServerRDN, sbstrFailingNC };
  2048. (void) ReportErrorEx( m_hwnd,
  2049. IDS_REPLNOW_3_FORCESYNC_ERROR,
  2050. hr,
  2051. MB_OK | MB_ICONEXCLAMATION,
  2052. apv,
  2053. 3,
  2054. IDS_REPLNOW_TITLE );
  2055. }
  2056. else
  2057. {
  2058. // error in PrepareReplicaSyncParameters against connection target DC
  2059. PVOID apv[1] = { sbstrToServerRDN };
  2060. (void) ReportErrorEx( m_hwnd,
  2061. IDS_REPLNOW_1_PARAMLOAD_ERROR,
  2062. hr,
  2063. MB_OK | MB_ICONEXCLAMATION,
  2064. apv,
  2065. 1,
  2066. IDS_REPLNOW_TITLE );
  2067. }
  2068. }
  2069. }
  2070. void CDSContextMenu::CopyObject()
  2071. {
  2072. if (m_pCD != NULL)
  2073. {
  2074. m_pCD->_CopyDSObject(m_spDataObject);
  2075. }
  2076. }
  2077. void CDSContextMenu::_GetExtraInfo(LPDATAOBJECT pDataObj)
  2078. {
  2079. FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  2080. ASSERT(m_objectNamesFormat.HasData());
  2081. //we assume these are all the same
  2082. m_Advanced = (m_objectNamesFormat.GetProviderFlags(0) & DSPROVIDER_ADVANCED) != 0;
  2083. // set classes flag
  2084. for (UINT index = 0; index < m_objectNamesFormat.GetCount(); index++)
  2085. {
  2086. if (wcscmp(m_objectNamesFormat.GetClass(index), L"user") == 0
  2087. #ifdef INETORGPERSON
  2088. || wcscmp(m_objectNamesFormat.GetClass(index), L"inetOrgPerson") == 0
  2089. #endif
  2090. )
  2091. m_fClasses |= Type_User;
  2092. else if (wcscmp(m_objectNamesFormat.GetClass(index), L"group") == 0)
  2093. m_fClasses |= Type_Group;
  2094. else if (wcscmp(m_objectNamesFormat.GetClass(index), L"computer") == 0)
  2095. m_fClasses |= Type_Computer;
  2096. else if (wcscmp(m_objectNamesFormat.GetClass(index), L"nTDSConnection") == 0)
  2097. m_fClasses |= Type_NTDSConnection;
  2098. else if (wcscmp(m_objectNamesFormat.GetClass(index), L"domainDNS") == 0)
  2099. m_fClasses |= Type_Domain;
  2100. else if (wcscmp(m_objectNamesFormat.GetClass(index), L"contact") == 0)
  2101. m_fClasses |= Type_Contact;
  2102. else if (wcscmp(m_objectNamesFormat.GetClass(index), L"group") == 0)
  2103. m_fClasses |= Type_Group;
  2104. else if (wcscmp(m_objectNamesFormat.GetClass(index), L"organizationalUnit") == 0)
  2105. m_fClasses |= Type_OU;
  2106. else
  2107. m_fClasses |= Type_Others;
  2108. } // for
  2109. // set classid
  2110. g_cfCoClass = (CLIPFORMAT)RegisterClipboardFormat(CCF_SNAPIN_CLASSID);
  2111. fmte.cfFormat = g_cfCoClass;
  2112. STGMEDIUM Stg;
  2113. Stg.tymed = TYMED_HGLOBAL;
  2114. Stg.hGlobal = GlobalAlloc (GPTR, sizeof(CLSID));
  2115. HRESULT hr = pDataObj->GetDataHere(&fmte, &Stg);
  2116. if ( SUCCEEDED(hr) )
  2117. {
  2118. memcpy (&m_CallerSnapin, Stg.hGlobal, sizeof(GUID));
  2119. ::GlobalFree(Stg.hGlobal);
  2120. }
  2121. else
  2122. {
  2123. m_CallerSnapin = GUID_NULL;
  2124. }
  2125. // get HWND (MMC mainframe window)
  2126. g_cfParentHwnd = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_DS_PARENTHWND);
  2127. fmte.cfFormat = g_cfParentHwnd;
  2128. Stg.tymed = TYMED_NULL;
  2129. if ( SUCCEEDED(pDataObj->GetData(&fmte, &Stg)) )
  2130. {
  2131. memcpy (&m_hwnd, Stg.hGlobal, sizeof(HWND));
  2132. ::GlobalFree(Stg.hGlobal);
  2133. }
  2134. else
  2135. {
  2136. // need an HWND anyway
  2137. m_hwnd = ::GetActiveWindow();
  2138. }
  2139. TRACE(L"HWND = 0x%x\n", m_hwnd);
  2140. ASSERT((m_hwnd != NULL) && ::IsWindow(m_hwnd));
  2141. // get component data (if in the context of DS Admin)
  2142. g_cfComponentData = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_DS_COMPDATA);
  2143. fmte.cfFormat = g_cfComponentData;
  2144. Stg.tymed = TYMED_NULL;
  2145. if ( SUCCEEDED(pDataObj->GetData(&fmte, &Stg)) )
  2146. {
  2147. memcpy (&m_pCD, Stg.hGlobal, sizeof(CDSComponentData*));
  2148. ::GlobalFree(Stg.hGlobal);
  2149. } else
  2150. {
  2151. m_pCD = NULL;
  2152. }
  2153. // get component data (if in the context of DS Find)
  2154. if (m_pCD == NULL)
  2155. {
  2156. m_pCD = g_pCD;
  2157. }
  2158. }
  2159. BOOL
  2160. CDSContextMenu::_WarningOnSheetsUp()
  2161. {
  2162. // if called in the context of DS Admin, guard against property sheet open on this cookie
  2163. if ( (m_pCD != NULL) && m_internalFormat.HasData() )
  2164. {
  2165. return m_pCD->_WarningOnSheetsUp(&m_internalFormat);
  2166. }
  2167. return FALSE;
  2168. }
  2169. void
  2170. CDSContextMenu::Rename()
  2171. {
  2172. HRESULT hr = S_OK;
  2173. INT_PTR answer = IDOK;
  2174. LPWSTR pszDomain = NULL;
  2175. LPWSTR pwzLocalDomain = NULL;
  2176. IDirectoryObject * pObj = NULL;
  2177. IADs * pObj2 = NULL;
  2178. IADs * pPartitions = NULL;
  2179. CString csLogin;
  2180. CString csTemp;
  2181. CString csSam;
  2182. CWaitCursor cwait;
  2183. BOOL error = FALSE;
  2184. BOOL fAccessDenied = FALSE;
  2185. LPWSTR pszNewName = NULL;
  2186. LPWSTR pszFirstName = NULL;
  2187. LPWSTR pszDispName = NULL;
  2188. LPWSTR pszSurName = NULL;
  2189. LPWSTR pszSAMName = NULL;
  2190. LPWSTR pszUPN = NULL;
  2191. BOOL NoRename = FALSE;
  2192. CComVariant Var;
  2193. // guard against property sheet open on this cookie
  2194. if (_WarningOnSheetsUp())
  2195. return;
  2196. CString strClass = m_objectNamesFormat.GetClass(0);
  2197. if (strClass == L"user"
  2198. #ifdef INETORGPERSON
  2199. || strClass == L"inetOrgPerson"
  2200. #endif
  2201. )
  2202. {
  2203. // rename user
  2204. CRenameUserDlg dlgRename(m_pCD);
  2205. LPWSTR pAttrNames[] = {L"distinguishedName",
  2206. L"userPrincipalName",
  2207. L"sAMAccountName",
  2208. L"givenName",
  2209. L"displayName",
  2210. L"sn",
  2211. L"cn"};
  2212. PADS_ATTR_INFO pAttrs = NULL;
  2213. ULONG cAttrs = 0;
  2214. CString szPath = m_objectNamesFormat.GetName(0);
  2215. hr = DSAdminOpenObject(szPath,
  2216. IID_IDirectoryObject,
  2217. (void **)&pObj,
  2218. TRUE /*bServer*/);
  2219. if (SUCCEEDED(hr)) {
  2220. hr = pObj->GetObjectAttributes (pAttrNames, 7, &pAttrs, &cAttrs);
  2221. if (SUCCEEDED(hr)) {
  2222. for (UINT i = 0; i < cAttrs; i++) {
  2223. if (_wcsicmp (L"distinguishedName", pAttrs[i].pszAttrName) == 0) {
  2224. hr = CrackName (pAttrs[i].pADsValues->CaseIgnoreString,
  2225. &pszDomain, GET_NT4_DOMAIN_NAME, NULL);
  2226. if (SUCCEEDED(hr)) {
  2227. dlgRename.m_dldomain = pszDomain;
  2228. dlgRename.m_dldomain += L'\\';
  2229. }
  2230. // get the Domain of this object, need it later.
  2231. CComBSTR bsDN;
  2232. CPathCracker pathCracker;
  2233. pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
  2234. pathCracker.Set((LPTSTR)(LPCTSTR)szPath, ADS_SETTYPE_FULL);
  2235. pathCracker.Retrieve(ADS_FORMAT_X500_DN, &bsDN);
  2236. // get the NT 5 (dns) domain name
  2237. TRACE(L"CrackName(%s, &pwzLocalDomain, GET_DNS_DOMAIN_NAME, NULL);\n", bsDN);
  2238. hr = CrackName(bsDN, &pwzLocalDomain, GET_DNS_DOMAIN_NAME, NULL);
  2239. TRACE(L"CrackName returned hr = 0x%x, pwzLocalDomain = <%s>\n", hr, pwzLocalDomain);
  2240. }
  2241. if (_wcsicmp (L"userPrincipalName", pAttrs[i].pszAttrName) == 0) {
  2242. csTemp = pAttrs[i].pADsValues->CaseIgnoreString;
  2243. INT loc = csTemp.Find (L'@');
  2244. if (loc > 0) {
  2245. dlgRename.m_login = csTemp.Left(loc);
  2246. dlgRename.m_domain = csTemp.Right (csTemp.GetLength() - loc);
  2247. } else {
  2248. dlgRename.m_login = csTemp;
  2249. ASSERT (0 && L"can't find @ in upn");
  2250. }
  2251. }
  2252. if (_wcsicmp (L"sAMAccountName", pAttrs[i].pszAttrName) == 0) {
  2253. dlgRename.m_samaccountname = pAttrs[i].pADsValues->CaseIgnoreString;
  2254. }
  2255. if (_wcsicmp (L"givenName", pAttrs[i].pszAttrName) == 0) {
  2256. dlgRename.m_first = pAttrs[i].pADsValues->CaseIgnoreString;
  2257. }
  2258. if (_wcsicmp (L"displayName", pAttrs[i].pszAttrName) == 0) {
  2259. dlgRename.m_displayname = pAttrs[i].pADsValues->CaseIgnoreString;
  2260. }
  2261. if (_wcsicmp (L"sn", pAttrs[i].pszAttrName) == 0) {
  2262. dlgRename.m_last = pAttrs[i].pADsValues->CaseIgnoreString;
  2263. }
  2264. if (_wcsicmp (L"cn", pAttrs[i].pszAttrName) == 0) {
  2265. dlgRename.m_cn = pAttrs[i].pADsValues->CaseIgnoreString;
  2266. dlgRename.m_oldcn = dlgRename.m_cn;
  2267. }
  2268. }
  2269. }
  2270. // get UPN suffixes from this OU, if present
  2271. IADs * pObjADs = NULL;
  2272. IADs * pCont = NULL;
  2273. BSTR bsParentPath;
  2274. CStringList UPNs;
  2275. hr = pObj->QueryInterface (IID_IADs, (void **)&pObjADs);
  2276. ASSERT (SUCCEEDED(hr));
  2277. hr = pObjADs->get_Parent(&bsParentPath);
  2278. ASSERT (SUCCEEDED(hr));
  2279. hr = DSAdminOpenObject(bsParentPath,
  2280. IID_IADs,
  2281. (void **)&pCont,
  2282. TRUE /*bServer*/);
  2283. CComVariant sVar;
  2284. hr = pCont->Get ( L"uPNSuffixes", &sVar);
  2285. if (SUCCEEDED(hr)) {
  2286. hr = HrVariantToStringList (IN sVar, UPNs);
  2287. if (SUCCEEDED(hr)) {
  2288. POSITION pos = UPNs.GetHeadPosition();
  2289. CString csSuffix;
  2290. while (pos != NULL) {
  2291. csSuffix = L"@";
  2292. csSuffix += UPNs.GetNext(INOUT pos);
  2293. TRACE(_T("UPN suffix: %s\n"), csSuffix);
  2294. if (wcscmp (csSuffix, dlgRename.m_domain)) {
  2295. dlgRename.m_domains.AddTail (csSuffix);
  2296. }
  2297. }
  2298. }
  2299. } else {// now get the domain options
  2300. IDsBrowseDomainTree* pDsDomains = NULL;
  2301. hr = ::CoCreateInstance(CLSID_DsDomainTreeBrowser,
  2302. NULL,
  2303. CLSCTX_INPROC_SERVER,
  2304. IID_IDsBrowseDomainTree,
  2305. (LPVOID*)&pDsDomains);
  2306. ASSERT(SUCCEEDED(hr));
  2307. PDOMAIN_TREE pNewDomains = NULL;
  2308. hr = pDsDomains->GetDomains(&pNewDomains, 0);
  2309. if (SUCCEEDED(hr))
  2310. {
  2311. ASSERT(pNewDomains);
  2312. for (UINT index = 0; index < pNewDomains->dwCount; index++) {
  2313. if (pNewDomains->aDomains[index].pszTrustParent == NULL) {
  2314. CString strAtDomain = "@";
  2315. strAtDomain += pNewDomains->aDomains[index].pszName;
  2316. if (wcscmp (strAtDomain, dlgRename.m_domain)) {
  2317. dlgRename.m_domains.AddTail (strAtDomain);
  2318. }
  2319. }
  2320. }
  2321. pDsDomains->FreeDomains(&pNewDomains);
  2322. }
  2323. if (pDsDomains) {
  2324. pDsDomains->Release();
  2325. }
  2326. LocalFreeStringW(&pszDomain);
  2327. // get UPN suffixes
  2328. CString csPartitions;
  2329. CStringList UPNsToo;
  2330. // get config path from main object
  2331. csPartitions = m_pCD->GetBasePathsInfo()->GetProviderAndServerName();
  2332. csPartitions += L"CN=Partitions,";
  2333. csPartitions += m_pCD->GetBasePathsInfo()->GetConfigNamingContext();
  2334. hr = DSAdminOpenObject(csPartitions,
  2335. IID_IADs,
  2336. (void **)&pPartitions,
  2337. TRUE /*bServer*/);
  2338. if (SUCCEEDED(hr)) {
  2339. CComVariant sVarToo;
  2340. hr = pPartitions->Get ( L"uPNSuffixes", &sVarToo);
  2341. if (SUCCEEDED(hr)) {
  2342. hr = HrVariantToStringList (IN sVarToo, UPNsToo);
  2343. if (SUCCEEDED(hr)) {
  2344. POSITION pos = UPNs.GetHeadPosition();
  2345. CString csSuffix;
  2346. while (pos != NULL) {
  2347. csSuffix = L"@";
  2348. csSuffix += UPNsToo.GetNext(INOUT pos);
  2349. TRACE(_T("UPN suffix: %s\n"), csSuffix);
  2350. if (wcscmp (csSuffix, dlgRename.m_domain)) {
  2351. dlgRename.m_domains.AddTail (csSuffix);
  2352. }
  2353. }
  2354. }
  2355. }
  2356. pPartitions->Release();
  2357. }
  2358. }
  2359. error = TRUE;
  2360. while ((error) && (!fAccessDenied)){
  2361. answer = dlgRename.DoModal();
  2362. if (answer == IDOK) {
  2363. ADSVALUE avUPN = {ADSTYPE_CASE_IGNORE_STRING, NULL};
  2364. ADS_ATTR_INFO aiUPN = {L"userPrincipalName", ADS_ATTR_UPDATE,
  2365. ADSTYPE_CASE_IGNORE_STRING, &avUPN, 1};
  2366. ADSVALUE avSAMName = {ADSTYPE_CASE_IGNORE_STRING, NULL};
  2367. ADS_ATTR_INFO aiSAMName = {L"sAMAccountName", ADS_ATTR_UPDATE,
  2368. ADSTYPE_CASE_IGNORE_STRING, &avSAMName, 1};
  2369. ADSVALUE avGiven = {ADSTYPE_CASE_IGNORE_STRING, NULL};
  2370. ADS_ATTR_INFO aiGiven = {L"givenName", ADS_ATTR_UPDATE,
  2371. ADSTYPE_CASE_IGNORE_STRING, &avGiven, 1};
  2372. ADSVALUE avSurName = {ADSTYPE_CASE_IGNORE_STRING, NULL};
  2373. ADS_ATTR_INFO aiSurName = {L"sn", ADS_ATTR_UPDATE,
  2374. ADSTYPE_CASE_IGNORE_STRING, &avSurName, 1};
  2375. ADSVALUE avDispName = {ADSTYPE_CASE_IGNORE_STRING, NULL};
  2376. ADS_ATTR_INFO aiDispName = {L"displayName", ADS_ATTR_UPDATE,
  2377. ADSTYPE_CASE_IGNORE_STRING, &avDispName, 1};
  2378. ADS_ATTR_INFO rgAttrs[5];
  2379. ULONG cModified = 0;
  2380. cAttrs = 0;
  2381. if (!dlgRename.m_login.IsEmpty() &&
  2382. !dlgRename.m_domain.IsEmpty()) {
  2383. dlgRename.m_login.TrimRight();
  2384. dlgRename.m_login.TrimLeft();
  2385. dlgRename.m_domain.TrimRight();
  2386. dlgRename.m_domain.TrimLeft();
  2387. csTemp = (dlgRename.m_login + dlgRename.m_domain);
  2388. pszUPN = new WCHAR[wcslen(csTemp) + sizeof(WCHAR)];
  2389. wcscpy (pszUPN, csTemp);
  2390. avUPN.CaseIgnoreString = pszUPN;
  2391. } else {
  2392. aiUPN.dwControlCode = ADS_ATTR_CLEAR;
  2393. }
  2394. rgAttrs[cAttrs++] = aiUPN;
  2395. // test UPN for duplication
  2396. // test UPN for duplication
  2397. // validate UPN with GC before doing the put.
  2398. BOOL fDomainSearchFailed = FALSE;
  2399. BOOL fGCSearchFailed = FALSE;
  2400. BOOL dup = FALSE;
  2401. CString strFilter;
  2402. LPWSTR pAttributes[1] = {L"cn"};
  2403. IDirectorySearch * pGCObj = NULL;
  2404. CDSSearch DSS (m_pCD->m_pClassCache, m_pCD);
  2405. hr = DSPROP_GetGCSearchOnDomain(pwzLocalDomain,
  2406. IID_IDirectorySearch,
  2407. (void **)&pGCObj);
  2408. if (FAILED(hr)) {
  2409. fGCSearchFailed = TRUE;
  2410. } else {
  2411. DSS.Init (pGCObj);
  2412. LPWSTR pUserAttributes[1] = {L"cn"};
  2413. strFilter = L"(userPrincipalName=";
  2414. strFilter += pszUPN;
  2415. strFilter += L")";
  2416. DSS.SetAttributeList (pUserAttributes, 1);
  2417. DSS.SetFilterString ((LPWSTR)(LPCWSTR)strFilter);
  2418. DSS.SetSearchScope (ADS_SCOPE_SUBTREE);
  2419. DSS.DoQuery();
  2420. hr = DSS.GetNextRow();
  2421. dup = FALSE;
  2422. while ((hr == S_OK) && (dup == FALSE)) { // this means a row was returned, so we're dup
  2423. ADS_SEARCH_COLUMN Col;
  2424. hr = DSS.GetColumn(pUserAttributes[0], &Col);
  2425. if (_wcsicmp(Col.pADsValues->CaseIgnoreString, dlgRename.m_oldcn)) {
  2426. dup = TRUE;
  2427. ReportErrorEx (m_hwnd, IDS_UPN_DUP, hr,
  2428. MB_OK, NULL, 0);
  2429. }
  2430. hr = DSS.GetNextRow();
  2431. }
  2432. if (hr != S_ADS_NOMORE_ROWS) {
  2433. fGCSearchFailed = TRUE;
  2434. }
  2435. }
  2436. HRESULT hr2 = S_OK;
  2437. if (dup)
  2438. continue;
  2439. else {
  2440. CString strInitPath = L"LDAP://";
  2441. strInitPath += pwzLocalDomain;
  2442. TRACE(_T("Initialize Domain search object with: %s...\n"), strInitPath);
  2443. hr2 = DSS.Init (strInitPath);
  2444. if (SUCCEEDED(hr2)) {
  2445. LPWSTR pAttributes2[1] = {L"cn"};
  2446. strFilter = L"(userPrincipalName=";
  2447. strFilter += pszUPN;
  2448. strFilter += L")";
  2449. TRACE(_T("searching current domain for %s...\n"), pszUPN);
  2450. DSS.SetAttributeList (pAttributes2, 1);
  2451. DSS.SetFilterString ((LPWSTR)(LPCWSTR)strFilter);
  2452. DSS.SetSearchScope (ADS_SCOPE_SUBTREE);
  2453. DSS.DoQuery();
  2454. hr2 = DSS.GetNextRow();
  2455. TRACE(_T("done searching current domain for %s...\n"), pszUPN);
  2456. }
  2457. while ((hr2 == S_OK) && (dup == FALSE)) { // this means a row was returned, so we're dup
  2458. ADS_SEARCH_COLUMN Col;
  2459. HRESULT hr3 = DSS.GetColumn(pAttributes[0], &Col);
  2460. ASSERT(hr3 == S_OK);
  2461. if (_wcsicmp(Col.pADsValues->CaseIgnoreString, dlgRename.m_oldcn)) {
  2462. dup = TRUE;
  2463. ReportErrorEx (m_hwnd, IDS_UPN_DUP, hr,
  2464. MB_OK, NULL, 0);
  2465. }
  2466. hr2 = DSS.GetNextRow();
  2467. }
  2468. if (hr2 != S_ADS_NOMORE_ROWS) { // oops, had another problem
  2469. fDomainSearchFailed = TRUE;
  2470. }
  2471. }
  2472. if (dup)
  2473. continue;
  2474. else {
  2475. if (fDomainSearchFailed || fGCSearchFailed) {
  2476. HRESULT hrSearch = S_OK;
  2477. if (fDomainSearchFailed) {
  2478. hrSearch = hr2;
  2479. } else {
  2480. hrSearch = hr;
  2481. }
  2482. ReportErrorEx (m_hwnd,IDS_UPN_SEARCH_FAILED2,hrSearch,
  2483. MB_OK | MB_ICONWARNING, NULL, 0);
  2484. }
  2485. }
  2486. if (pGCObj) {
  2487. pGCObj->Release();
  2488. pGCObj = NULL;
  2489. }
  2490. pszNewName = new WCHAR[wcslen(dlgRename.m_cn) + sizeof(WCHAR)];
  2491. dlgRename.m_cn.TrimRight();
  2492. dlgRename.m_cn.TrimLeft();
  2493. wcscpy (pszNewName, dlgRename.m_cn);
  2494. if (dlgRename.m_cn == dlgRename.m_oldcn)
  2495. NoRename = TRUE;
  2496. if (!dlgRename.m_displayname.IsEmpty()) {
  2497. dlgRename.m_displayname.TrimLeft();
  2498. dlgRename.m_displayname.TrimRight();
  2499. pszDispName = new WCHAR[wcslen(dlgRename.m_displayname) + sizeof(WCHAR)];
  2500. wcscpy (pszDispName, dlgRename.m_displayname);
  2501. avDispName.CaseIgnoreString = pszDispName;
  2502. } else {
  2503. aiDispName.dwControlCode = ADS_ATTR_CLEAR;
  2504. }
  2505. rgAttrs[cAttrs++] = aiDispName;
  2506. if (!dlgRename.m_first.IsEmpty()) {
  2507. dlgRename.m_first.TrimLeft();
  2508. dlgRename.m_first.TrimRight();
  2509. pszFirstName = new WCHAR[wcslen(dlgRename.m_first) + sizeof(WCHAR)];
  2510. wcscpy (pszFirstName, dlgRename.m_first);
  2511. avGiven.CaseIgnoreString = pszFirstName;
  2512. } else {
  2513. aiGiven.dwControlCode = ADS_ATTR_CLEAR;
  2514. }
  2515. rgAttrs[cAttrs++] = aiGiven;
  2516. if (!dlgRename.m_last.IsEmpty()) {
  2517. dlgRename.m_last.TrimLeft();
  2518. dlgRename.m_last.TrimRight();
  2519. pszSurName = new WCHAR[wcslen(dlgRename.m_last) + sizeof(WCHAR)];
  2520. wcscpy (pszSurName, dlgRename.m_last);
  2521. avSurName.CaseIgnoreString = pszSurName;
  2522. } else {
  2523. aiSurName.dwControlCode = ADS_ATTR_CLEAR;
  2524. }
  2525. rgAttrs[cAttrs++] = aiSurName;
  2526. if (!dlgRename.m_samaccountname.IsEmpty()) {
  2527. dlgRename.m_samaccountname.TrimLeft();
  2528. dlgRename.m_samaccountname.TrimRight();
  2529. pszSAMName = new WCHAR[wcslen(dlgRename.m_samaccountname) + sizeof(WCHAR)];
  2530. wcscpy (pszSAMName, dlgRename.m_samaccountname);
  2531. avSAMName.CaseIgnoreString = pszSAMName;
  2532. } else {
  2533. aiSAMName.dwControlCode = ADS_ATTR_CLEAR;
  2534. }
  2535. rgAttrs[cAttrs++] = aiSAMName;
  2536. hr = pObj->SetObjectAttributes (rgAttrs, cAttrs, &cModified);
  2537. if (FAILED(hr)) {
  2538. if (hr == E_ACCESSDENIED) {
  2539. fAccessDenied = TRUE;
  2540. NoRename = TRUE;
  2541. } else {
  2542. ReportErrorEx (m_hwnd, IDS_NAME_CHANGE_FAILED, hr,
  2543. MB_OK|MB_ICONERROR, NULL, 0, TRUE);
  2544. }
  2545. } else {
  2546. error = FALSE;
  2547. }
  2548. } else {
  2549. error = FALSE;
  2550. }
  2551. }
  2552. } else {
  2553. answer = IDCANCEL;
  2554. PVOID apv[1] = {(BSTR)(LPWSTR)(LPCWSTR)m_objectNamesFormat.GetName(0)};
  2555. ReportErrorEx (m_hwnd,IDS_12_USER_OBJECT_NOT_ACCESSABLE,hr,
  2556. MB_OK | MB_ICONERROR, apv, 1);
  2557. }
  2558. } else if (strClass == L"group") {
  2559. CRenameGroupDlg * pdlgRename = new CRenameGroupDlg;
  2560. CString szPath;
  2561. szPath = m_objectNamesFormat.GetName(0);
  2562. hr = DSAdminOpenObject(szPath,
  2563. IID_IADs,
  2564. (void **)&pObj2,
  2565. TRUE /*bServer*/);
  2566. if (SUCCEEDED(hr)) {
  2567. hr = pObj2->Get (L"sAMAccountName", &Var);
  2568. ASSERT (SUCCEEDED(hr));
  2569. csSam = Var.bstrVal;
  2570. if (strClass == L"computer") {
  2571. INT loc = csSam.Find(L"$");
  2572. if (loc > 0) {
  2573. csSam = csSam.Left(loc);
  2574. }
  2575. }
  2576. hr = pObj2->Get (L"cn", &Var);
  2577. ASSERT (SUCCEEDED(hr));
  2578. pdlgRename->m_cn = Var.bstrVal;
  2579. // figure out group type
  2580. if (strClass == L"group") {
  2581. CComVariant varType;
  2582. hr = pObj2->Get(L"groupType", &varType);
  2583. ASSERT(SUCCEEDED(hr));
  2584. INT GroupType = (varType.lVal & ~GROUP_TYPE_SECURITY_ENABLED);
  2585. if (GroupType == GROUP_TYPE_RESOURCE_GROUP) {
  2586. pdlgRename->m_samtextlimit = 64;
  2587. }
  2588. }
  2589. pdlgRename->m_samaccountname = csSam;
  2590. error = TRUE;
  2591. while ((error) && (!fAccessDenied)){
  2592. answer = pdlgRename->DoModal();
  2593. if (answer == IDOK) {
  2594. pdlgRename->m_cn.TrimRight();
  2595. pdlgRename->m_cn.TrimLeft();
  2596. pszNewName = new WCHAR[wcslen(pdlgRename->m_cn) + (1 * sizeof(WCHAR))];
  2597. wcscpy (pszNewName, pdlgRename->m_cn);
  2598. Var.vt = VT_BSTR;
  2599. pdlgRename->m_samaccountname.TrimLeft();
  2600. pdlgRename->m_samaccountname.TrimRight();
  2601. csSam = pdlgRename->m_samaccountname;
  2602. if (strClass == L"computer") {
  2603. csSam += L"$";
  2604. }
  2605. Var.bstrVal = SysAllocString(csSam);
  2606. hr = pObj2->Put (L"sAMAccountName", Var);
  2607. ASSERT (SUCCEEDED(hr));
  2608. if (FAILED(hr)) {
  2609. continue;
  2610. }
  2611. hr = pObj2->SetInfo();
  2612. if (FAILED(hr)) {
  2613. if (hr == E_ACCESSDENIED) {
  2614. fAccessDenied = TRUE;
  2615. NoRename = TRUE;
  2616. } else {
  2617. ReportErrorEx (m_hwnd, IDS_NAME_CHANGE_FAILED, hr,
  2618. MB_OK|MB_ICONERROR, NULL, 0, TRUE);
  2619. }
  2620. } else {
  2621. error = FALSE;
  2622. }
  2623. } else {
  2624. error = FALSE;
  2625. }
  2626. }
  2627. } else {
  2628. answer = IDCANCEL;
  2629. }
  2630. if (pdlgRename) {
  2631. delete pdlgRename;
  2632. }
  2633. } else if (strClass == L"contact") {
  2634. // rename contact
  2635. CRenameContactDlg dlgRename;
  2636. CString szPath;
  2637. szPath = m_objectNamesFormat.GetName(0);
  2638. hr = DSAdminOpenObject(szPath,
  2639. IID_IADs,
  2640. (void **)&pObj2,
  2641. TRUE /*bServer*/);
  2642. if (SUCCEEDED(hr)) {
  2643. hr = pObj2->Get (L"givenName", &Var);
  2644. ASSERT (SUCCEEDED(hr) || (hr == E_ADS_PROPERTY_NOT_FOUND));
  2645. if (SUCCEEDED(hr)) {
  2646. dlgRename.m_first = Var.bstrVal;
  2647. }
  2648. hr = pObj2->Get (L"sn", &Var);
  2649. ASSERT (SUCCEEDED(hr) || (hr == E_ADS_PROPERTY_NOT_FOUND));
  2650. if (SUCCEEDED(hr)) {
  2651. dlgRename.m_last = Var.bstrVal;
  2652. }
  2653. hr = pObj2->Get (L"displayName", &Var);
  2654. ASSERT (SUCCEEDED(hr) || (hr == E_ADS_PROPERTY_NOT_FOUND));
  2655. if (SUCCEEDED(hr)) {
  2656. dlgRename.m_disp = Var.bstrVal;
  2657. }
  2658. hr = pObj2->Get (L"cn", &Var);
  2659. ASSERT (SUCCEEDED(hr) || (hr == E_ADS_PROPERTY_NOT_FOUND));
  2660. if (SUCCEEDED(hr)) {
  2661. dlgRename.m_cn = Var.bstrVal;
  2662. }
  2663. error = TRUE;
  2664. while ((error) && (!fAccessDenied)){
  2665. answer = dlgRename.DoModal();
  2666. if (answer == IDOK) {
  2667. dlgRename.m_cn.TrimRight();
  2668. dlgRename.m_cn.TrimLeft();
  2669. pszNewName = new WCHAR[wcslen(dlgRename.m_cn) + (1 * sizeof(WCHAR))];
  2670. wcscpy (pszNewName, dlgRename.m_cn);
  2671. Var.vt = VT_BSTR;
  2672. if (!dlgRename.m_first.IsEmpty()) {
  2673. dlgRename.m_first.TrimLeft();
  2674. dlgRename.m_first.TrimRight();
  2675. Var.bstrVal = SysAllocString (dlgRename.m_first);
  2676. hr = pObj2->Put (L"givenName", Var);
  2677. ASSERT (SUCCEEDED(hr));
  2678. }
  2679. if (!dlgRename.m_last.IsEmpty()) {
  2680. dlgRename.m_last.TrimLeft();
  2681. dlgRename.m_last.TrimRight();
  2682. Var.bstrVal = SysAllocString(dlgRename.m_last);
  2683. hr = pObj2->Put (L"sn", Var);
  2684. ASSERT (SUCCEEDED(hr));
  2685. }
  2686. if (!dlgRename.m_disp.IsEmpty()) {
  2687. dlgRename.m_disp.TrimLeft();
  2688. dlgRename.m_disp.TrimRight();
  2689. Var.bstrVal = SysAllocString(dlgRename.m_disp);
  2690. hr = pObj2->Put (L"displayName", Var);
  2691. ASSERT (SUCCEEDED(hr));
  2692. }
  2693. hr = pObj2->SetInfo();
  2694. if (FAILED(hr)) {
  2695. if (hr == E_ACCESSDENIED) {
  2696. fAccessDenied = TRUE;
  2697. NoRename = TRUE;
  2698. } else {
  2699. ReportErrorEx (m_hwnd, IDS_NAME_CHANGE_FAILED, hr,
  2700. MB_OK|MB_ICONERROR, NULL, 0, TRUE);
  2701. }
  2702. } else {
  2703. error = FALSE;
  2704. }
  2705. } else {
  2706. error = FALSE;
  2707. }
  2708. }
  2709. } else {
  2710. answer = IDCANCEL;
  2711. }
  2712. } else {
  2713. // need generic dialog here.
  2714. CRenameGenericDlg dlgRename (CWnd::FromHandle(m_hwnd));
  2715. CString szPath;
  2716. szPath = m_objectNamesFormat.GetName(0);
  2717. hr = DSAdminOpenObject(szPath,
  2718. IID_IADs,
  2719. (void **)&pObj2,
  2720. TRUE /*bServer*/);
  2721. if (SUCCEEDED(hr)) {
  2722. CDSClassCacheItemBase* pItem = NULL;
  2723. pItem = m_pCD->m_pClassCache->FindClassCacheItem(m_pCD, (LPCWSTR)strClass, szPath);
  2724. ASSERT (pItem != NULL);
  2725. //get the naming attribute
  2726. CString csNewAttrName;
  2727. csNewAttrName = pItem->GetNamingAttribute();
  2728. hr = pObj2->Get (CComBSTR(csNewAttrName), &Var);
  2729. ASSERT (SUCCEEDED(hr) || (hr == E_ADS_PROPERTY_NOT_FOUND));
  2730. if (SUCCEEDED(hr)) {
  2731. dlgRename.m_cn = Var.bstrVal;
  2732. }
  2733. error = TRUE;
  2734. while (error) {
  2735. answer = dlgRename.DoModal();
  2736. if (answer == IDOK) {
  2737. dlgRename.m_cn.TrimRight();
  2738. dlgRename.m_cn.TrimLeft();
  2739. pszNewName = new WCHAR[wcslen(dlgRename.m_cn) + (1 * sizeof(WCHAR))];
  2740. wcscpy (pszNewName, dlgRename.m_cn);
  2741. error = FALSE;
  2742. } else {
  2743. error = FALSE;
  2744. }
  2745. }
  2746. }
  2747. }
  2748. if ((answer == IDOK) && (error == FALSE) && (NoRename == FALSE)) {
  2749. CString csObjectPath = m_objectNamesFormat.GetName(0);
  2750. CDSClassCacheItemBase* pItem = NULL;
  2751. pItem = m_pCD->m_pClassCache->FindClassCacheItem(m_pCD, (LPCWSTR)strClass, csObjectPath);
  2752. ASSERT (pItem != NULL);
  2753. // get the new name in the form "cn=foo" or "ou=foo"
  2754. CString csNewAttrName;
  2755. csNewAttrName = pItem->GetNamingAttribute();
  2756. csNewAttrName += L"=";
  2757. csNewAttrName += pszNewName;
  2758. TRACE(_T("_RenameObject: Attributed name is %s.\n"), csNewAttrName);
  2759. // bind to object
  2760. IADs *pDSObject = NULL;
  2761. hr = DSAdminOpenObject(csObjectPath,
  2762. IID_IADs,
  2763. (void **)&pDSObject,
  2764. TRUE /*bServer*/);
  2765. if (!SUCCEEDED(hr)) {
  2766. goto error;
  2767. }
  2768. BSTR bsParentPath;
  2769. // get the path of the object container
  2770. hr = pDSObject->get_Parent (&bsParentPath);
  2771. if (!SUCCEEDED(hr)) {
  2772. goto error;
  2773. }
  2774. pDSObject->Release();
  2775. pDSObject = NULL;
  2776. IADsContainer * pContainer = NULL;
  2777. // bind to the object container
  2778. hr = DSAdminOpenObject(bsParentPath,
  2779. IID_IADsContainer,
  2780. (void **)&pContainer,
  2781. TRUE /*bServer*/);
  2782. if (!SUCCEEDED(hr)) {
  2783. goto error;
  2784. }
  2785. // build the new LDAP path
  2786. CString csNewNamingContext, csNewPath, szPath;
  2787. BSTR bsEscapedName;
  2788. csNewNamingContext = csNewAttrName;
  2789. csNewNamingContext += L",";
  2790. StripADsIPath(bsParentPath, szPath);
  2791. csNewNamingContext += szPath;
  2792. m_pCD->GetBasePathsInfo()->ComposeADsIPath(csNewPath, csNewNamingContext);
  2793. // create a transaction object, the destructor will call End() on it
  2794. CDSNotifyHandlerTransaction transaction(m_pCD);
  2795. transaction.SetEventType(DSA_NOTIFY_REN);
  2796. // start the transaction
  2797. hr = transaction.Begin(m_objectNamesFormat.GetName(0),
  2798. m_objectNamesFormat.GetClass(0),
  2799. m_objectNamesFormat.IsContainer(0),
  2800. csNewPath,
  2801. m_objectNamesFormat.GetClass(0),
  2802. m_objectNamesFormat.IsContainer(0));
  2803. // ask for confirmation
  2804. if (transaction.NeedNotifyCount() > 0)
  2805. {
  2806. CString szMessage, szAssocData;
  2807. szMessage.LoadString(IDS_CONFIRM_RENAME);
  2808. szAssocData.LoadString(IDS_EXTENS_RENAME);
  2809. CConfirmOperationDialog dlg(::GetParent(m_hwnd), &transaction);
  2810. dlg.SetStrings(szMessage, szAssocData);
  2811. if (IDNO == dlg.DoModal())
  2812. {
  2813. transaction.End();
  2814. hr = S_OK;
  2815. goto error;
  2816. }
  2817. }
  2818. CPathCracker pathCracker;
  2819. hr = pathCracker.GetEscapedElement(0, //reserved
  2820. (BSTR)(LPCWSTR)csNewAttrName,
  2821. &bsEscapedName);
  2822. if (FAILED(hr))
  2823. goto error;
  2824. IDispatch * pDispObj = NULL;
  2825. // do the actual rename
  2826. hr = pContainer->MoveHere((LPWSTR)(LPCWSTR)csObjectPath,
  2827. (LPWSTR)(LPCWSTR)bsEscapedName,
  2828. &pDispObj);
  2829. if (SUCCEEDED(hr) && (hr != S_FALSE)) {
  2830. // let extensions know
  2831. transaction.Notify(0);
  2832. // send notify to diz
  2833. }
  2834. if (pDispObj) {
  2835. pDispObj->Release();
  2836. }
  2837. }
  2838. if (fAccessDenied) {
  2839. PVOID apv[1] = {(LPWSTR)m_objectNamesFormat.GetName(0)};
  2840. ReportErrorEx(::GetParent(m_hwnd),IDS_12_RENAME_NOT_ALLOWED,hr,
  2841. MB_OK | MB_ICONERROR, apv, 1);
  2842. }
  2843. error:
  2844. // transaction.End() will be called by the transaction's destructor
  2845. if (pwzLocalDomain) {
  2846. LocalFreeStringW(&pwzLocalDomain);
  2847. }
  2848. if (pszNewName) {
  2849. delete pszNewName;
  2850. }
  2851. if (pszFirstName) {
  2852. delete pszFirstName;
  2853. }
  2854. if (pszDispName) {
  2855. delete pszDispName;
  2856. }
  2857. if (pszSurName) {
  2858. delete pszSurName;
  2859. }
  2860. if (pszSAMName){
  2861. delete pszSAMName;
  2862. }
  2863. if (pszUPN) {
  2864. delete pszUPN;
  2865. }
  2866. if (pObj) {
  2867. pObj->Release();
  2868. }
  2869. if (pObj2) {
  2870. pObj2->Release();
  2871. }
  2872. }