Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3446 lines
110 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(CComBSTR(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(CComBSTR(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(CComBSTR(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, DS_UI_NODE))
  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. // CODEWORK JonN 8/21/01 "if this is NOT the Sites snapin"
  505. //
  506. if ((m_CallerSnapin != CLSID_SiteSnapin) &&
  507. !(m_fClasses & Type_Domain) &&
  508. bEnableMove &&
  509. (m_pCD != NULL))
  510. {
  511. if ( !LoadString(AfxGetInstanceHandle(), IDS_MOVE_OBJECT,
  512. szBuffer, ARRAYLEN(szBuffer)) )
  513. {
  514. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  515. goto exit_gracefully;
  516. }
  517. InsertMenu(hMenu,
  518. indexMenu,
  519. MF_BYPOSITION|MF_STRING,
  520. idCmdFirst+IDC_MOVE_OBJECT,
  521. szBuffer);
  522. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_MOVE_OBJECT);
  523. }
  524. //
  525. // If this is a User or Computer object add the Reset Account menu item
  526. // It is done this way so that if m_fClasses contains more than computer
  527. // and object types in conjuction with user and/or object types we fail
  528. //
  529. if ( m_fClasses && !(m_fClasses & ~(Type_User | Type_Computer)))
  530. {
  531. if (m_objectNamesFormat.GetCount() == 1)
  532. {
  533. //
  534. // Load the string for the menu item
  535. //
  536. if (m_fClasses == Type_Computer) // Computer
  537. {
  538. if ( !LoadString(AfxGetInstanceHandle(), IDS_RESET_ACCOUNT,
  539. szBuffer, ARRAYLEN(szBuffer)) )
  540. {
  541. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  542. goto exit_gracefully;
  543. }
  544. }
  545. else // User
  546. {
  547. if ( !LoadString(AfxGetInstanceHandle(), IDS_CHANGE_PASSWORD,
  548. szBuffer, ARRAYLEN(szBuffer)) )
  549. {
  550. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  551. goto exit_gracefully;
  552. }
  553. }
  554. //
  555. // Insert the menu item
  556. //
  557. InsertMenu(hMenu,
  558. indexMenu,
  559. MF_BYPOSITION|MF_STRING,
  560. idCmdFirst+IDC_CHANGE_PASSWORD,
  561. szBuffer);
  562. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_CHANGE_PASSWORD);
  563. //
  564. // Bind and figure out if the account is disabled
  565. // then add a menu item to enable or disable the account accordingly
  566. //
  567. hr = DSAdminOpenObject(m_objectNamesFormat.GetName(0),
  568. IID_IADsUser,
  569. (void **)&m_pDsObject,
  570. TRUE /*bServer*/);
  571. if (SUCCEEDED(hr))
  572. {
  573. hr = m_pDsObject->Get(CComBSTR(L"userAccountControl"), &CurrentState);
  574. if (SUCCEEDED(hr))
  575. {
  576. m_UserAccountState = CurrentState.lVal;
  577. if (!(m_UserAccountState & UF_SERVER_TRUST_ACCOUNT))
  578. {
  579. if ((m_UserAccountState & UF_ACCOUNTDISABLE))
  580. {
  581. //
  582. // Account is disabled... Load the enable string and insert
  583. // the menu item
  584. //
  585. if ( !LoadString(AfxGetInstanceHandle(), IDS_ENABLE_ACCOUNT,
  586. szBuffer, ARRAYLEN(szBuffer)) )
  587. {
  588. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  589. goto exit_gracefully;
  590. }
  591. InsertMenu(hMenu,
  592. indexMenu,
  593. MF_BYPOSITION|MF_STRING,
  594. idCmdFirst+IDC_ENABLE_ACCOUNT,
  595. szBuffer);
  596. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_ENABLE_ACCOUNT);
  597. }
  598. else
  599. {
  600. //
  601. // Account is enabled... Load the disable string and insert
  602. // the menu item.
  603. //
  604. if ( !LoadString(AfxGetInstanceHandle(), IDS_DISABLE_ACCOUNT,
  605. szBuffer, ARRAYLEN(szBuffer)) )
  606. {
  607. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  608. goto exit_gracefully;
  609. }
  610. InsertMenu(hMenu,
  611. indexMenu,
  612. MF_BYPOSITION|MF_STRING,
  613. idCmdFirst+IDC_DISABLE_ACCOUNT,
  614. szBuffer);
  615. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_DISABLE_ACCOUNT);
  616. }
  617. }
  618. } // if get userAccountControl succeeded
  619. } // if bind succeeded
  620. if (m_Advanced)
  621. {
  622. if ( !LoadString(AfxGetInstanceHandle(), IDS_MAP_CERTIFICATES,
  623. szBuffer, ARRAYLEN(szBuffer)) ) {
  624. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  625. goto exit_gracefully;
  626. }
  627. InsertMenu(hMenu,
  628. indexMenu,
  629. MF_BYPOSITION|MF_STRING,
  630. idCmdFirst+IDC_MAP_CERTIFICATES,
  631. szBuffer);
  632. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_MAP_CERTIFICATES);
  633. }
  634. }
  635. else // m_objectNamesFormat.GetCount() != 1
  636. {
  637. if (m_fClasses && !(m_fClasses & ~(Type_User | Type_Computer)))
  638. {
  639. //
  640. // Load the enable account menu item
  641. //
  642. if ( !LoadString(AfxGetInstanceHandle(), IDS_ENABLE_ACCOUNT,
  643. szBuffer, ARRAYLEN(szBuffer)) )
  644. {
  645. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  646. goto exit_gracefully;
  647. }
  648. InsertMenu(hMenu,
  649. indexMenu,
  650. MF_BYPOSITION|MF_STRING,
  651. idCmdFirst+IDC_ENABLE_ACCOUNT,
  652. szBuffer);
  653. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_ENABLE_ACCOUNT);
  654. //
  655. // Load the disable account menu item
  656. //
  657. if ( !LoadString(AfxGetInstanceHandle(), IDS_DISABLE_ACCOUNT,
  658. szBuffer, ARRAYLEN(szBuffer)) )
  659. {
  660. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  661. goto exit_gracefully;
  662. }
  663. InsertMenu(hMenu,
  664. indexMenu,
  665. MF_BYPOSITION|MF_STRING,
  666. idCmdFirst+IDC_DISABLE_ACCOUNT,
  667. szBuffer);
  668. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_DISABLE_ACCOUNT);
  669. } // if (m_objectNamesFormat.GetCount() == 1)
  670. }
  671. } // if User or Computer
  672. //
  673. // If the node is a user, or contact insert Add objects to group menu item
  674. // Note: OU removed 08/02/2000 by JeffJon
  675. //
  676. if (m_fClasses && !(m_fClasses & ~(Type_User | Type_Contact)))
  677. {
  678. if ( !LoadString(AfxGetInstanceHandle(), IDS_ADD_TO_GROUP,
  679. szBuffer, ARRAYLEN(szBuffer)) )
  680. {
  681. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  682. goto exit_gracefully;
  683. }
  684. BOOL bInsertSuccess = InsertMenu(hMenu,
  685. indexMenu,
  686. MF_BYPOSITION|MF_STRING,
  687. idCmdFirst+IDC_ADD_OBJECTS_TO_GROUP,
  688. szBuffer);
  689. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_ADD_OBJECTS_TO_GROUP);
  690. if (!bInsertSuccess)
  691. {
  692. TRACE(_T("Failed to insert Add to group context menu item. 0x%x\n"), GetLastError());
  693. }
  694. }
  695. //
  696. // If we weren't called from MMC
  697. //
  698. if (!m_internalFormat.HasData())
  699. {
  700. //
  701. // Insert the delete menu item if appropriate
  702. //
  703. if ( !LoadString(AfxGetInstanceHandle(), IDS_DELETE,
  704. szBuffer, ARRAYLEN(szBuffer)) )
  705. {
  706. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  707. goto exit_gracefully;
  708. }
  709. if (bEnableDelete)
  710. {
  711. InsertMenu(hMenu,
  712. indexMenu,
  713. MF_BYPOSITION|MF_STRING,
  714. idCmdFirst+IDC_DELETE_OBJECT,
  715. szBuffer);
  716. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_DELETE_OBJECT);
  717. }
  718. //
  719. // If single selection and node is a computer insert the rename menu item
  720. // NOTE : the rename handler is heavily dependent on DSAdmin being the caller
  721. // hence the check for m_pCD.
  722. //
  723. if (m_pCD != NULL &&
  724. (m_objectNamesFormat.GetCount() == 1) &&
  725. !(m_fClasses & Type_Computer))
  726. {
  727. if ( !LoadString(AfxGetInstanceHandle(), IDS_RENAME,
  728. szBuffer, ARRAYLEN(szBuffer)) )
  729. {
  730. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  731. goto exit_gracefully;
  732. }
  733. if (bEnableRename)
  734. {
  735. InsertMenu(hMenu,
  736. indexMenu,
  737. MF_BYPOSITION|MF_STRING,
  738. idCmdFirst+IDC_RENAME_OBJECT,
  739. szBuffer);
  740. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_RENAME_OBJECT);
  741. }
  742. }
  743. } // if not called from mmc
  744. //
  745. // If node type is NTDSConnection insert the replicate now menu item
  746. //
  747. if (m_fClasses & Type_TrueNTDSConnection)
  748. {
  749. if ( !LoadString(AfxGetInstanceHandle(), IDS_REPLICATE_NOW,
  750. szBuffer, ARRAYLEN(szBuffer)) )
  751. {
  752. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  753. goto exit_gracefully;
  754. }
  755. InsertMenu(hMenu,
  756. indexMenu,
  757. MF_BYPOSITION|MF_STRING,
  758. idCmdFirst+IDC_REPLICATE_NOW,
  759. szBuffer);
  760. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_REPLICATE_NOW);
  761. } // node type NTDSConnection
  762. //
  763. // If node type is user and we can copy it the add the copy object menu item
  764. //
  765. if ( (m_pCD != NULL) && (m_objectNamesFormat.GetCount() == 1) && (m_fClasses == Type_User) )
  766. {
  767. if (S_OK == m_pCD->_CanCopyDSObject(m_spDataObject))
  768. {
  769. if ( !LoadString(AfxGetInstanceHandle(), IDS_COPY_OBJECT,
  770. szBuffer, ARRAYLEN(szBuffer)) )
  771. {
  772. TRACE(_T("Failed to load resource for menu item. hr is %lx\n"), hr);
  773. goto exit_gracefully;
  774. }
  775. InsertMenu(hMenu,
  776. indexMenu,
  777. MF_BYPOSITION|MF_STRING,
  778. idCmdFirst+IDC_COPY_OBJECT,
  779. szBuffer);
  780. nLargestCmd = __max(nLargestCmd, idCmdFirst+IDC_COPY_OBJECT);
  781. } // if
  782. } // if
  783. hr = S_OK;
  784. exit_gracefully:
  785. if (SUCCEEDED(hr))
  786. hr = MAKE_HRESULT(SEVERITY_SUCCESS, 0, cItems);
  787. TIMER(_T("Exiting DSContext QCM().\n"));
  788. return hr;
  789. }
  790. STDMETHODIMP
  791. CDSContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
  792. {
  793. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  794. HRESULT hr = S_OK;
  795. TRACE (_T("CDSContextMenu::InvokeCommand\n"));
  796. if (lpcmi->hwnd != m_hwnd)
  797. {
  798. m_hwnd = lpcmi->hwnd;
  799. }
  800. TRACE (_T("\tlpcmi->lpVerb is %d.\n"), lpcmi->lpVerb);
  801. switch ((INT_PTR)(lpcmi->lpVerb)) {
  802. case IDC_ENABLE_ACCOUNT:
  803. if (m_objectNamesFormat.GetCount() == 1) {
  804. if (m_UserAccountState & UF_ACCOUNTDISABLE) {
  805. DisableAccount(FALSE);
  806. } else {
  807. DisableAccount(TRUE);
  808. }
  809. } else {
  810. DisableAccount(FALSE);
  811. }
  812. break;
  813. case IDC_DISABLE_ACCOUNT:
  814. DisableAccount(TRUE);
  815. break;
  816. case IDC_MAP_CERTIFICATES:
  817. {
  818. ASSERT (m_objectNamesFormat.GetCount() == 1);
  819. LPWSTR pszCanonical = NULL;
  820. CString szName = m_objectNamesFormat.GetName(0);
  821. CString szPath;
  822. StripADsIPath(szName, szPath, false); // don't use escaped mode
  823. // we don't care about the return code here
  824. CrackName((LPWSTR) (LPCWSTR)szPath,
  825. &pszCanonical,
  826. GET_OBJ_CAN_NAME,
  827. NULL);
  828. CSimData simData;
  829. if ( simData.FInit(pszCanonical, szName, m_hwnd))
  830. {
  831. CThemeContextActivator activator;
  832. simData.DoModal();
  833. }
  834. else
  835. hr = E_FAIL;
  836. if ( pszCanonical )
  837. LocalFreeStringW(&pszCanonical);
  838. return hr;
  839. }
  840. break;
  841. case IDC_CHANGE_PASSWORD:
  842. ASSERT (m_objectNamesFormat.GetCount() == 1);
  843. ModifyPassword();
  844. break;
  845. case IDC_MOVE_OBJECT:
  846. MoveObject();
  847. break;
  848. case IDC_DELETE_OBJECT:
  849. TRACE(_T("called Delete in context menu extension\n"));
  850. DeleteObject();
  851. break;
  852. case IDC_REPLICATE_NOW:
  853. ReplicateNow();
  854. break;
  855. case IDC_ADD_OBJECTS_TO_GROUP:
  856. AddToGroup();
  857. break;
  858. case IDC_COPY_OBJECT:
  859. CopyObject();
  860. break;
  861. case IDC_RENAME_OBJECT:
  862. Rename();
  863. break;
  864. }
  865. return hr;
  866. }
  867. STDMETHODIMP
  868. CDSContextMenu::GetCommandString(UINT_PTR idCmd,
  869. UINT uFlags,
  870. UINT FAR*,
  871. LPSTR pszName,
  872. UINT ccMax)
  873. {
  874. HRESULT hr = S_OK;
  875. TRACE (_T("CDSContextMenu::GetCommandString\n"));
  876. TRACE (_T("\tidCmd is %d.\n"), idCmd);
  877. if (uFlags == GCS_HELPTEXT)
  878. {
  879. CString csHelp;
  880. switch ((idCmd))
  881. {
  882. case IDC_ENABLE_ACCOUNT:
  883. csHelp.LoadString (IDS_ENABLE_ACCOUNT_HELPSTRING);
  884. break;
  885. case IDC_DISABLE_ACCOUNT:
  886. csHelp.LoadString (IDS_DISABLE_ACCOUNT_HELPSTRING);
  887. break;
  888. case IDC_MAP_CERTIFICATES:
  889. csHelp.LoadString (IDS_MAP_CERTS_HELPSTRING);
  890. break;
  891. case IDC_CHANGE_PASSWORD:
  892. csHelp.LoadString (IDS_CHANGE_PWD_HELPSTRING);
  893. break;
  894. case IDC_MOVE_OBJECT:
  895. csHelp.LoadString (IDS_MOVE_OBJECT_HELPSTRING);
  896. break;
  897. case IDC_DELETE_OBJECT:
  898. csHelp.LoadString (IDS_DELETE_OBJECT_HELPSTRING);
  899. break;
  900. case IDC_REPLICATE_NOW:
  901. csHelp.LoadString (IDS_REPLICATE_HELPSTRING);
  902. break;
  903. case IDC_ADD_OBJECTS_TO_GROUP:
  904. csHelp.LoadString (IDS_ADD_OBJECTS_HELPSTRING);
  905. break;
  906. case IDC_COPY_OBJECT:
  907. csHelp.LoadString (IDS_COPY_HELPSTRING);
  908. break;
  909. case IDC_RENAME_OBJECT:
  910. csHelp.LoadString (IDS_RENAME_HELPSTRING);
  911. break;
  912. }
  913. //NTRAID#NTBUG9-567482-2002/03/10-jmessec There is no release-mode code to validate length < ccMax; could
  914. //cause a buffer overflow of pszName; especially since buffer length is defined by caller
  915. ASSERT ((UINT)csHelp.GetLength() < ccMax);
  916. wcscpy ((LPWSTR)pszName, (LPWSTR)(LPCWSTR)csHelp);
  917. }
  918. else if (uFlags == GCS_VERB)
  919. {
  920. //
  921. // Return the language independent ID of the context menu item
  922. //
  923. CString szMenuID;
  924. switch ((idCmd))
  925. {
  926. case IDC_ENABLE_ACCOUNT:
  927. szMenuID = CMID_ENABLE_ACCOUNT;
  928. break;
  929. case IDC_DISABLE_ACCOUNT:
  930. szMenuID = CMID_DISABLE_ACCOUNT;
  931. break;
  932. case IDC_MAP_CERTIFICATES:
  933. szMenuID = CMID_MAP_CERTIFICATES;
  934. break;
  935. case IDC_CHANGE_PASSWORD:
  936. szMenuID = CMID_CHANGE_PASSWORD;
  937. break;
  938. case IDC_MOVE_OBJECT:
  939. szMenuID = CMID_MOVE_OBJECT;
  940. break;
  941. case IDC_DELETE_OBJECT:
  942. szMenuID = CMID_DELETE_OBJECT;
  943. break;
  944. case IDC_REPLICATE_NOW:
  945. szMenuID = CMID_REPLICATE_NOW;
  946. break;
  947. case IDC_ADD_OBJECTS_TO_GROUP:
  948. szMenuID = CMID_ADD_OBJECTS_TO_GROUP;
  949. break;
  950. case IDC_COPY_OBJECT:
  951. szMenuID = CMID_COPY_OBJECT;
  952. break;
  953. case IDC_RENAME_OBJECT:
  954. szMenuID = CMID_RENAME_OBJECT;
  955. break;
  956. }
  957. //NTRAID#NTBUG9-567482-2002/03/10-jmessec There is no release-mode code to validate length < ccMax; could
  958. //cause a buffer overflow of pszName; especially since buffer length is defined by caller
  959. ASSERT ((UINT)szMenuID.GetLength() < ccMax);
  960. wcscpy ((LPWSTR)pszName, (LPWSTR)(LPCWSTR)szMenuID);
  961. }
  962. else
  963. {
  964. TRACE(_T("We are not supporting any other GetCommandString() flags besides GCS_VERB and GCS_HELPTEXT"));
  965. return E_INVALIDARG;
  966. }
  967. return hr;
  968. }
  969. void CDSContextMenu::_ToggleDisabledIcon(UINT index, BOOL bDisable)
  970. {
  971. if ( (m_pCD != NULL) && m_internalFormat.HasData())
  972. {
  973. CDSUINode* pDSUINode = dynamic_cast<CDSUINode*>(m_internalFormat.GetCookie(index));
  974. ASSERT(pDSUINode != NULL);
  975. if (pDSUINode == NULL)
  976. return;
  977. m_pCD->ToggleDisabled(pDSUINode, bDisable);
  978. }
  979. }
  980. void CDSContextMenu::DisableAccount(BOOL bDisable)
  981. {
  982. HRESULT hr = S_OK;
  983. HRESULT hr2 = S_OK;
  984. CComVariant Disabled;
  985. DWORD Response = IDYES;
  986. if (m_objectNamesFormat.GetCount() == 1) { // single selection
  987. if (m_pDsObject) {
  988. if (((bDisable) && (!(m_UserAccountState & UF_ACCOUNTDISABLE))) ||
  989. ((!bDisable) && (m_UserAccountState & UF_ACCOUNTDISABLE))) {
  990. Disabled.vt = VT_I4;
  991. Disabled.lVal = m_UserAccountState;
  992. if (bDisable == TRUE) {
  993. Disabled.lVal |= UF_ACCOUNTDISABLE;
  994. } else {
  995. Disabled.lVal &= ~UF_ACCOUNTDISABLE;
  996. }
  997. // prep for display by getting obj name
  998. CPathCracker pathCracker;
  999. hr2 = pathCracker.Set(CComBSTR(m_objectNamesFormat.GetName(0)), ADS_SETTYPE_FULL);
  1000. ASSERT(SUCCEEDED(hr2));
  1001. hr2 = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  1002. ASSERT(SUCCEEDED(hr2));
  1003. CComBSTR DestName;
  1004. LONG iEMode = 0;
  1005. hr2 = pathCracker.get_EscapedMode(&iEMode);
  1006. ASSERT(SUCCEEDED(hr2));
  1007. hr2 = pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_OFF_EX);
  1008. ASSERT(SUCCEEDED(hr2));
  1009. hr2 = pathCracker.GetElement( 0, &DestName );
  1010. ASSERT(SUCCEEDED(hr2));
  1011. hr2 = pathCracker.put_EscapedMode(iEMode);
  1012. ASSERT(SUCCEEDED(hr2));
  1013. PVOID apv[1] = {(LPWSTR)DestName};
  1014. CString strClass = m_objectNamesFormat.GetClass(0);
  1015. if ((strClass == "computer") && (bDisable)) {
  1016. Response = ReportErrorEx (m_hwnd,IDS_12_DISABLE_COMPUTER_P,hr,
  1017. MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING, apv, 1);
  1018. }
  1019. if (Response == IDYES) {
  1020. hr = m_pDsObject->Put(CComBSTR(L"userAccountControl"), Disabled);
  1021. hr = m_pDsObject->SetInfo();
  1022. if (SUCCEEDED(hr)) {
  1023. _ToggleDisabledIcon(0, bDisable);
  1024. if (bDisable) {
  1025. ReportErrorEx (m_hwnd,IDS_12_USER_DISABLED_SUCCESSFULLY,hr,
  1026. MB_OK | MB_ICONINFORMATION, apv, 1);
  1027. }
  1028. else {
  1029. ReportErrorEx (m_hwnd,IDS_12_USER_ENABLED_SUCCESSFULLY,hr,
  1030. MB_OK | MB_ICONINFORMATION, apv, 1);
  1031. }
  1032. } else {
  1033. if (bDisable) {
  1034. ReportErrorEx (m_hwnd,IDS_12_USER_DISABLE_FAILED,hr,
  1035. MB_OK | MB_ICONERROR, apv, 1);
  1036. } else
  1037. ReportErrorEx (m_hwnd,IDS_12_USER_ENABLE_FAILED,hr,
  1038. MB_OK | MB_ICONERROR, apv, 1);
  1039. }
  1040. }
  1041. }
  1042. } else {
  1043. PVOID apv[1] = {(LPWSTR)m_objectNamesFormat.GetName(0)};
  1044. ReportErrorEx (m_hwnd,IDS_12_USER_OBJECT_NOT_ACCESSABLE,hr,
  1045. MB_OK | MB_ICONERROR, apv, 1);
  1046. }
  1047. }
  1048. else //multiple selection
  1049. {
  1050. UINT index;
  1051. IADsUser * pObj = NULL;
  1052. CComVariant CurrentState;
  1053. DWORD UserAccountState;
  1054. BOOL error = FALSE;
  1055. DWORD ResponseToo = IDYES;
  1056. if ((m_fClasses & Type_Computer) && (bDisable))
  1057. {
  1058. ResponseToo = ReportMessageEx (m_hwnd, IDS_MULTI_DISABLE_COMPUTER,
  1059. MB_YESNO | MB_ICONWARNING);
  1060. }
  1061. if (ResponseToo == IDYES)
  1062. {
  1063. for (index = 0; index < m_objectNamesFormat.GetCount(); index++)
  1064. {
  1065. hr = DSAdminOpenObject(m_objectNamesFormat.GetName(index),
  1066. IID_IADsUser,
  1067. (void **)&pObj,
  1068. TRUE /*bServer*/);
  1069. if (SUCCEEDED(hr))
  1070. {
  1071. hr = pObj->Get(CComBSTR(L"userAccountControl"), &CurrentState);
  1072. if (SUCCEEDED(hr))
  1073. {
  1074. UserAccountState = CurrentState.lVal;
  1075. if (((bDisable) && (!(UserAccountState & UF_ACCOUNTDISABLE))) ||
  1076. ((!bDisable) && (UserAccountState & UF_ACCOUNTDISABLE)))
  1077. {
  1078. Disabled.vt = VT_I4;
  1079. Disabled.lVal = UserAccountState;
  1080. if (bDisable == TRUE)
  1081. {
  1082. Disabled.lVal |= UF_ACCOUNTDISABLE;
  1083. }
  1084. else
  1085. {
  1086. Disabled.lVal &= ~UF_ACCOUNTDISABLE;
  1087. }
  1088. hr = pObj->Put(CComBSTR(L"userAccountControl"), Disabled);
  1089. hr = pObj->SetInfo();
  1090. if (FAILED(hr))
  1091. {
  1092. error = TRUE;
  1093. break;
  1094. }
  1095. else
  1096. {
  1097. _ToggleDisabledIcon(index, bDisable);
  1098. }
  1099. }
  1100. }
  1101. pObj->Release();
  1102. }
  1103. else
  1104. {
  1105. // prep for display by getting obj name
  1106. CPathCracker pathCracker;
  1107. hr2 = pathCracker.Set(CComBSTR(m_objectNamesFormat.GetName(index)), ADS_SETTYPE_FULL);
  1108. ASSERT(SUCCEEDED(hr2));
  1109. hr2 = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  1110. ASSERT(SUCCEEDED(hr2));
  1111. CComBSTR ObjName;
  1112. hr2 = pathCracker.GetElement( 0, &ObjName );
  1113. ASSERT(SUCCEEDED(hr2));
  1114. PVOID apv[1] = {(LPWSTR)ObjName};
  1115. ReportErrorEx (m_hwnd,IDS_12_USER_OBJECT_NOT_ACCESSABLE,hr,
  1116. MB_OK | MB_ICONERROR, apv, 1);
  1117. }
  1118. }
  1119. }
  1120. if (error)
  1121. {
  1122. if (bDisable)
  1123. ReportErrorEx (m_hwnd,IDS_DISABLES_FAILED,hr,
  1124. MB_OK | MB_ICONERROR, NULL, 0);
  1125. else
  1126. ReportErrorEx (m_hwnd,IDS_ENABLES_FAILED,hr,
  1127. MB_OK | MB_ICONERROR, NULL, 0);
  1128. }
  1129. else
  1130. {
  1131. if (bDisable)
  1132. {
  1133. ReportErrorEx (m_hwnd, IDS_DISABLED_SUCCESSFULLY, S_OK,
  1134. MB_OK | MB_ICONINFORMATION, NULL, 0);
  1135. }
  1136. else
  1137. {
  1138. ReportErrorEx (m_hwnd, IDS_ENABLED_SUCCESSFULLY, S_OK,
  1139. MB_OK | MB_ICONINFORMATION, NULL, 0);
  1140. }
  1141. }
  1142. }
  1143. }
  1144. void CDSContextMenu::ModifyPassword()
  1145. {
  1146. HRESULT hr = S_OK;
  1147. CString NewPwd, CfmPwd;
  1148. CComVariant Var;
  1149. BOOL error;
  1150. LPCWSTR lpszClass, lpszPath;
  1151. CChangePassword ChgDlg;
  1152. CWaitCursor CWait;
  1153. lpszPath = m_objectNamesFormat.GetName(0);
  1154. // prep for display by getting obj name
  1155. CPathCracker pathCracker;
  1156. hr = pathCracker.Set(CComBSTR(lpszPath), ADS_SETTYPE_FULL);
  1157. hr = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  1158. hr = pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_OFF_EX);
  1159. CComBSTR ObjName;
  1160. hr = pathCracker.Retrieve(ADS_FORMAT_LEAF, &ObjName );
  1161. PVOID apv[1] = {(LPWSTR)ObjName};
  1162. if (!m_pDsObject) {
  1163. hr = DSAdminOpenObject(lpszPath,
  1164. IID_IADsUser,
  1165. (void **)&m_pDsObject,
  1166. TRUE /*bServer*/);
  1167. if (FAILED(hr)) {
  1168. ReportErrorEx (m_hwnd,IDS_12_USER_OBJECT_NOT_ACCESSABLE,hr,
  1169. MB_OK | MB_ICONERROR, apv, 1);
  1170. goto exit_gracefully;
  1171. }
  1172. }
  1173. lpszClass = m_objectNamesFormat.GetClass(0);
  1174. //
  1175. // Get the userAccountControl
  1176. //
  1177. ASSERT(SUCCEEDED(hr));
  1178. hr = m_pDsObject->Get(CComBSTR(L"userAccountControl"), &Var);
  1179. if (wcscmp(lpszClass, L"computer") == 0)
  1180. {
  1181. if (FAILED(hr) || ((Var.lVal & UF_SERVER_TRUST_ACCOUNT) != 0))
  1182. {
  1183. ReportErrorEx (m_hwnd, IDS_1_CANT_RESET_DOMAIN_CONTROLLER, S_OK,
  1184. MB_OK | MB_ICONERROR, apv, 1);
  1185. }
  1186. else
  1187. {
  1188. DWORD Response = IDYES;
  1189. Response = ReportMessageEx (m_hwnd, IDS_CONFIRM_PASSWORD,
  1190. MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2);
  1191. if (Response == IDYES)
  1192. {
  1193. hr = m_pDsObject->Get(CComBSTR(L"sAMAccountName"), &Var);
  1194. ASSERT(SUCCEEDED(hr));
  1195. NewPwd = Var.bstrVal;
  1196. NewPwd = NewPwd.Left(14);
  1197. INT loc = NewPwd.Find(L"$");
  1198. if (loc > 0)
  1199. {
  1200. NewPwd = NewPwd.Left(loc);
  1201. }
  1202. // NTRAID#NTBUG9-483038-10/18/2001-JeffJon
  1203. // CString::MakeLower() doesn't lower case German characters
  1204. // correctly. Using _wcslwr instead. setlocale must be
  1205. // called before calling _wcslwr so that it properly lowercases
  1206. // extended characters. Store the result and call setlocale
  1207. // again when done to set it back to the original so as not
  1208. // to affect other snapins in the process
  1209. PWSTR oldLocale = _wsetlocale(LC_ALL, L"");
  1210. CString lowerCaseNewPwd = _wcslwr((LPWSTR)(LPCWSTR)NewPwd);
  1211. _wsetlocale(LC_ALL, oldLocale);
  1212. if (SUCCEEDED(hr))
  1213. {
  1214. hr = m_pDsObject->SetPassword(CComBSTR(lowerCaseNewPwd));
  1215. if (SUCCEEDED(hr))
  1216. {
  1217. ReportErrorEx (m_hwnd,IDS_1_RESET_ACCOUNT_SUCCESSFULL,hr,
  1218. MB_OK | MB_ICONINFORMATION, apv, 1);
  1219. }
  1220. else
  1221. {
  1222. ReportErrorEx (m_hwnd,IDS_12_RESET_ACCOUNT_FAILED,hr,
  1223. MB_OK | MB_ICONERROR, apv, 1);
  1224. }
  1225. }
  1226. }
  1227. }
  1228. }
  1229. else // Not computer object
  1230. {
  1231. //
  1232. // If password doesn't expire don't allow the checkbox for
  1233. // requiring the user to change the password at next logon
  1234. //
  1235. if (Var.lVal & UF_DONT_EXPIRE_PASSWD)
  1236. {
  1237. ChgDlg.AllowMustChangePasswordCheck(FALSE);
  1238. }
  1239. //
  1240. // NTRAID#Windows Bugs-278296-2001/01/12-jeffjon
  1241. // Checking "user must change password" on the Reset Pwd dialog
  1242. // is silently ignored when Write PwdLastSet not granted
  1243. //
  1244. // Disable the checkbox if the admin doesn't have the right
  1245. // to write the pwdLastSet attribute
  1246. //
  1247. BOOL bAllowMustChangePassword = FALSE;
  1248. CComPtr<IDirectoryObject> spDirObject;
  1249. hr = m_pDsObject->QueryInterface(IID_IDirectoryObject, (void**)&spDirObject);
  1250. if (SUCCEEDED(hr))
  1251. {
  1252. PWSTR ppAttrs[] = { (PWSTR)g_pszAllowedAttributesEffective };
  1253. DWORD dwAttrsReturned = 0;
  1254. PADS_ATTR_INFO pAttrInfo = 0;
  1255. hr = spDirObject->GetObjectAttributes(ppAttrs, 1, &pAttrInfo, &dwAttrsReturned);
  1256. if (SUCCEEDED(hr) && dwAttrsReturned == 1 && pAttrInfo)
  1257. {
  1258. if (pAttrInfo->pszAttrName &&
  1259. 0 == _wcsicmp(pAttrInfo->pszAttrName, g_pszAllowedAttributesEffective) &&
  1260. pAttrInfo->pADsValues)
  1261. {
  1262. for (DWORD dwIdx = 0; dwIdx < pAttrInfo->dwNumValues; ++dwIdx)
  1263. {
  1264. if (pAttrInfo->pADsValues[dwIdx].CaseIgnoreString &&
  1265. _wcsicmp(pAttrInfo->pADsValues[dwIdx].CaseIgnoreString, g_pszPwdLastSet))
  1266. {
  1267. bAllowMustChangePassword = TRUE;
  1268. break;
  1269. }
  1270. }
  1271. }
  1272. }
  1273. //
  1274. // Disable the checkbox if the user object doesn't have rights
  1275. // to change their password
  1276. //
  1277. if (!CanUserChangePassword(spDirObject))
  1278. {
  1279. bAllowMustChangePassword = FALSE;
  1280. }
  1281. }
  1282. if (!bAllowMustChangePassword)
  1283. {
  1284. ChgDlg.AllowMustChangePasswordCheck(FALSE);
  1285. }
  1286. do
  1287. {
  1288. error = FALSE;
  1289. CThemeContextActivator activator;
  1290. if (ChgDlg.DoModal() == IDOK)
  1291. {
  1292. // NTRAID#NTBUG9-635046-2002/06/10-artm
  1293. hr = ChgDlg.GetLastEncryptionResult();
  1294. if (FAILED(hr))
  1295. {
  1296. // For whatever reason, we failed to correctly store
  1297. // the password(s) the user typed. Tell the user that
  1298. // the operation failed, and retry getting password.
  1299. ReportErrorEx(
  1300. m_hwnd,
  1301. IDS_12_PASSWORD_CHANGE_FAILED,
  1302. hr,
  1303. MB_OK | MB_ICONERROR,
  1304. apv,
  1305. 1);
  1306. error = TRUE;
  1307. continue;
  1308. }
  1309. CWaitCursor CWait2;
  1310. const EncryptedString newPwd = ChgDlg.GetNew();
  1311. const EncryptedString cfmPwd = ChgDlg.GetConfirm();
  1312. if (newPwd == cfmPwd)
  1313. {
  1314. if (SUCCEEDED(hr))
  1315. {
  1316. WCHAR* clearText = newPwd.GetClearTextCopy();
  1317. if (NULL == clearText)
  1318. {
  1319. // Ran out of memory!
  1320. hr = E_OUTOFMEMORY;
  1321. newPwd.DestroyClearTextCopy(clearText);
  1322. ReportErrorEx(
  1323. m_hwnd,
  1324. IDS_12_PASSWORD_CHANGE_FAILED,
  1325. hr,
  1326. MB_OK | MB_ICONERROR,
  1327. apv,
  1328. 1);
  1329. return;
  1330. }
  1331. hr = m_pDsObject->SetPassword(CComBSTR(clearText));
  1332. if (SUCCEEDED(hr))
  1333. {
  1334. hr = ModifyNetWareUserPassword(m_pDsObject, lpszPath, clearText);
  1335. }
  1336. // Zero out memory used for clear text copy and free its memory.
  1337. newPwd.DestroyClearTextCopy(clearText);
  1338. clearText = NULL;
  1339. if (SUCCEEDED(hr))
  1340. {
  1341. HRESULT hr2 = S_OK;
  1342. BOOL ForceChange = ChgDlg.GetChangePwd();
  1343. if (ForceChange)
  1344. {
  1345. //Check to see if the user password does not expire
  1346. BOOL bContinueToForceChange = TRUE;
  1347. IADs* pIADs = NULL;
  1348. HRESULT hr3 = m_pDsObject->QueryInterface(IID_IADs, OUT (void **)&pIADs);
  1349. if (SUCCEEDED(hr3))
  1350. {
  1351. ASSERT(pIADs != NULL);
  1352. CComVariant var;
  1353. hr3 = pIADs->Get(CComBSTR(gsz_userAccountControl), OUT &var);
  1354. if (SUCCEEDED(hr3))
  1355. {
  1356. ASSERT(var.vt == VT_I4);
  1357. if (var.lVal & UF_DONT_EXPIRE_PASSWD)
  1358. {
  1359. ReportErrorEx (m_hwnd,IDS_12_PASSWORD_DOES_NOT_EXPIRE,hr,
  1360. MB_OK | MB_ICONWARNING, apv, 1);
  1361. bContinueToForceChange = FALSE;
  1362. }
  1363. pIADs->Release();
  1364. }
  1365. }
  1366. // If password can expire then force the change at next logon
  1367. if (bContinueToForceChange)
  1368. {
  1369. IDirectoryObject * pIDSObject = NULL;
  1370. LPWSTR szPwdLastSet = L"pwdLastSet";
  1371. ADSVALUE ADsValuePwdLastSet = {ADSTYPE_LARGE_INTEGER, NULL};
  1372. ADS_ATTR_INFO AttrInfoPwdLastSet = {szPwdLastSet, ADS_ATTR_UPDATE,
  1373. ADSTYPE_LARGE_INTEGER,
  1374. &ADsValuePwdLastSet, 1};
  1375. ADsValuePwdLastSet.LargeInteger.QuadPart = 0;
  1376. hr2 = m_pDsObject->QueryInterface(IID_IDirectoryObject,
  1377. OUT (void **)&pIDSObject);
  1378. if (SUCCEEDED(hr2))
  1379. {
  1380. ASSERT(pIDSObject != NULL);
  1381. DWORD cAttrModified = 0;
  1382. hr2 = pIDSObject->SetObjectAttributes(&AttrInfoPwdLastSet,
  1383. 1, &cAttrModified);
  1384. pIDSObject->Release();
  1385. if (FAILED(hr2))
  1386. {
  1387. ReportErrorEx(
  1388. m_hwnd,
  1389. IDS_PASSWORD_CHANGE_SUCCESS_FORCE_CHANGE_FAIL,
  1390. hr,
  1391. MB_OK | MB_ICONERROR, apv, 2);
  1392. }
  1393. }
  1394. }
  1395. }
  1396. if (SUCCEEDED(hr2))
  1397. {
  1398. ReportErrorEx (m_hwnd,IDS_12_PASSWORD_CHANGE_SUCCESSFUL,hr,
  1399. MB_OK | MB_ICONINFORMATION, apv, 1);
  1400. }
  1401. }
  1402. else
  1403. {
  1404. ReportErrorEx (m_hwnd,IDS_12_PASSWORD_CHANGE_FAILED,hr,
  1405. MB_OK | MB_ICONERROR, apv, 1);
  1406. }
  1407. }
  1408. }
  1409. else
  1410. {
  1411. ReportErrorEx (m_hwnd,IDS_NEW_AND_CONFIRM_NOT_SAME,hr,
  1412. MB_OK | MB_ICONERROR, NULL, 0);
  1413. ChgDlg.Clear();
  1414. error = TRUE;
  1415. }
  1416. }
  1417. } while (error);
  1418. }
  1419. exit_gracefully:
  1420. return;
  1421. }
  1422. #define BREAK_ON_FAIL if (FAILED(hr)) { break; }
  1423. #define BREAK_AND_ASSERT_ON_FAIL if (FAILED(hr)) { ASSERT(FALSE); break; }
  1424. #define RETURN_AND_ASSERT_ON_FAIL if (FAILED(hr)) { ASSERT(FALSE); return; }
  1425. void CDSContextMenu::MoveObject()
  1426. {
  1427. // REVIEW_MARCOC: need to make sure the LDAP path has the SERVER or DOMAIN in it
  1428. // if called in the context of DS Admin, guard against property sheet open on this cookie
  1429. if (_WarningOnSheetsUp())
  1430. return;
  1431. // get the first path in the data object
  1432. ASSERT(m_objectNamesFormat.HasData());
  1433. // now do crack name to get root path for the browse dialog
  1434. CString szRootPath;
  1435. if (m_pCD != NULL)
  1436. {
  1437. szRootPath = m_pCD->GetBasePathsInfo()->GetProviderAndServerName();
  1438. szRootPath += m_pCD->GetRootPath();
  1439. }
  1440. else
  1441. {
  1442. LPCWSTR lpszObjPath = m_objectNamesFormat.GetName(0);
  1443. // make sure there's no strange escaping in the path
  1444. CComBSTR bstrPath;
  1445. CComBSTR bstrProvider;
  1446. CComBSTR bstrServer;
  1447. CPathCracker pathCracker;
  1448. pathCracker.Set(CComBSTR(lpszObjPath), ADS_SETTYPE_FULL);
  1449. pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
  1450. pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_OFF);
  1451. pathCracker.Retrieve( ADS_FORMAT_X500_DN, &bstrPath);
  1452. pathCracker.Retrieve( ADS_FORMAT_SERVER, &bstrServer);
  1453. pathCracker.Retrieve( ADS_FORMAT_PROVIDER, &bstrProvider);
  1454. LPWSTR pwszDomainPath;
  1455. HRESULT hr = CrackName(const_cast<LPWSTR>((LPCWSTR)bstrPath),
  1456. &pwszDomainPath,
  1457. GET_FQDN_DOMAIN_NAME,
  1458. m_hwnd);
  1459. if ((FAILED(hr)) || (HRESULT_CODE(hr) == DS_NAME_ERROR_NO_MAPPING))
  1460. {
  1461. TRACE(_T("CrackNames failed to get domain for %s.\n"),
  1462. lpszObjPath);
  1463. szRootPath = L"";
  1464. }
  1465. else
  1466. {
  1467. CPathCracker pathCrackerOther;
  1468. hr = pathCrackerOther.Set( CComBSTR(pwszDomainPath), ADS_SETTYPE_DN );
  1469. RETURN_AND_ASSERT_ON_FAIL;
  1470. hr = pathCrackerOther.Set( bstrProvider, ADS_SETTYPE_PROVIDER );
  1471. RETURN_AND_ASSERT_ON_FAIL;
  1472. hr = pathCrackerOther.Set( bstrServer, ADS_SETTYPE_SERVER );
  1473. RETURN_AND_ASSERT_ON_FAIL;
  1474. CComBSTR sbstrRootPath;
  1475. hr = pathCrackerOther.Retrieve( ADS_FORMAT_X500, &sbstrRootPath );
  1476. RETURN_AND_ASSERT_ON_FAIL;
  1477. szRootPath = sbstrRootPath;
  1478. }
  1479. if (pwszDomainPath != NULL)
  1480. ::LocalFreeStringW(&pwszDomainPath);
  1481. }
  1482. CMultiselectMoveHandler moveHandler(m_pCD, m_hwnd, szRootPath);
  1483. HRESULT hr = moveHandler.Initialize(m_spDataObject, &m_objectNamesFormat,
  1484. &m_internalFormat);
  1485. ASSERT(SUCCEEDED(hr));
  1486. moveHandler.Move();
  1487. }
  1488. void CDSContextMenu::DeleteObject()
  1489. {
  1490. _ASSERTE(m_objectNamesFormat.HasData());
  1491. // if called in the context of DS Admin, guard against property sheet open on this cookie
  1492. if (_WarningOnSheetsUp())
  1493. return;
  1494. UINT nObjectCount = m_objectNamesFormat.GetCount();
  1495. if (nObjectCount == 0)
  1496. {
  1497. ASSERT(nObjectCount != 0);
  1498. return;
  1499. }
  1500. UINT nDeletedCount = 0;
  1501. PCWSTR* pszNameDelArr = 0;
  1502. PCWSTR* pszClassDelArr = 0;
  1503. DWORD* dwFlagsDelArr = 0;
  1504. DWORD* dwProviderFlagsDelArr = 0;
  1505. do // false loop
  1506. {
  1507. pszNameDelArr = new PCWSTR[nObjectCount];
  1508. pszClassDelArr = new PCWSTR[nObjectCount];
  1509. dwFlagsDelArr = new DWORD[nObjectCount];
  1510. dwProviderFlagsDelArr = new DWORD[nObjectCount];
  1511. if (!pszNameDelArr ||
  1512. !pszClassDelArr ||
  1513. !dwFlagsDelArr ||
  1514. !dwProviderFlagsDelArr)
  1515. {
  1516. break;
  1517. }
  1518. switch(nObjectCount)
  1519. {
  1520. case 1:
  1521. {
  1522. // single selection delete
  1523. CContextMenuSingleDeleteHandler deleteHandler(m_pCD, m_hwnd,
  1524. m_objectNamesFormat.GetName(0),
  1525. m_objectNamesFormat.GetClass(0),
  1526. m_objectNamesFormat.IsContainer(0),
  1527. this);
  1528. HRESULT hr = deleteHandler.Delete();
  1529. if (SUCCEEDED(hr) && (hr != S_FALSE))
  1530. {
  1531. nDeletedCount = 1;
  1532. pszNameDelArr[0] = m_objectNamesFormat.GetName(0);
  1533. pszClassDelArr[0] = m_objectNamesFormat.GetClass(0);
  1534. dwFlagsDelArr[0] = m_objectNamesFormat.GetFlags(0);
  1535. dwProviderFlagsDelArr[0] = m_objectNamesFormat.GetProviderFlags(0);
  1536. }
  1537. }
  1538. break;
  1539. default:
  1540. {
  1541. // multiple selection
  1542. CContextMenuMultipleDeleteHandler deleteHandler(m_pCD, m_hwnd, m_spDataObject,
  1543. &m_objectNamesFormat, this);
  1544. deleteHandler.Delete();
  1545. for (UINT k=0; k< nObjectCount; k++)
  1546. {
  1547. if (deleteHandler.WasItemDeleted(k))
  1548. {
  1549. pszNameDelArr[nDeletedCount] = m_objectNamesFormat.GetName(k);
  1550. pszClassDelArr[nDeletedCount] = m_objectNamesFormat.GetClass(k);
  1551. dwFlagsDelArr[nDeletedCount] = m_objectNamesFormat.GetFlags(k);
  1552. dwProviderFlagsDelArr[nDeletedCount] = m_objectNamesFormat.GetProviderFlags(k);
  1553. nDeletedCount++;
  1554. } // if
  1555. } // for
  1556. }
  1557. }; // switch
  1558. _NotifyDsFind((PCWSTR*)pszNameDelArr,
  1559. (PCWSTR*)pszClassDelArr,
  1560. dwFlagsDelArr,
  1561. dwProviderFlagsDelArr,
  1562. nDeletedCount);
  1563. } while (false);
  1564. if (pszNameDelArr)
  1565. {
  1566. delete[] pszNameDelArr;
  1567. pszNameDelArr = 0;
  1568. }
  1569. if (pszClassDelArr)
  1570. {
  1571. delete[] pszClassDelArr;
  1572. pszClassDelArr = 0;
  1573. }
  1574. if (dwFlagsDelArr)
  1575. {
  1576. delete[] dwFlagsDelArr;
  1577. dwFlagsDelArr = 0;
  1578. }
  1579. if (dwProviderFlagsDelArr)
  1580. {
  1581. delete[] dwProviderFlagsDelArr;
  1582. dwProviderFlagsDelArr = 0;
  1583. }
  1584. }
  1585. void CDSContextMenu::_NotifyDsFind(LPCWSTR* lpszNameDelArr,
  1586. LPCWSTR* lpszClassDelArr,
  1587. DWORD* dwFlagsDelArr,
  1588. DWORD* dwProviderFlagsDelArr,
  1589. UINT nDeletedCount)
  1590. {
  1591. if (nDeletedCount == 0)
  1592. {
  1593. // nothing to delete
  1594. return;
  1595. }
  1596. if (m_internalFormat.HasData())
  1597. {
  1598. // called from DS Admin directly, not from DS Find
  1599. return;
  1600. }
  1601. // ask DS Find about the notification interface
  1602. CComPtr<IQueryFrame> spIQueryFrame;
  1603. if ( !::SendMessage(m_hwnd, CQFWM_GETFRAME, 0, (LPARAM)&spIQueryFrame) )
  1604. {
  1605. // interface not found
  1606. return;
  1607. }
  1608. CComPtr<IDsQueryHandler> spDsQueryHandler;
  1609. HRESULT hr = spIQueryFrame->GetHandler(IID_IDsQueryHandler, (void **)&spDsQueryHandler);
  1610. if (FAILED(hr))
  1611. {
  1612. // interface not found
  1613. return;
  1614. }
  1615. // we finally have the interface, build the data structures
  1616. // figure out how much storage we need
  1617. DWORD cbStruct = sizeof(DSOBJECTNAMES) +
  1618. ((nDeletedCount - 1) * sizeof(DSOBJECT));
  1619. size_t cbStorage = 0;
  1620. for (UINT index = 0; index < nDeletedCount; index++)
  1621. {
  1622. cbStorage += sizeof(WCHAR)*(wcslen(lpszNameDelArr[index])+1);
  1623. cbStorage += sizeof(WCHAR)*(wcslen(lpszClassDelArr[index])+1);
  1624. }
  1625. // allocate memory
  1626. LPDSOBJECTNAMES pDSObj = (LPDSOBJECTNAMES)::malloc(cbStruct + cbStorage);
  1627. if (pDSObj == NULL)
  1628. {
  1629. ASSERT(FALSE);
  1630. return;
  1631. }
  1632. // fill in the structs
  1633. pDSObj->clsidNamespace = m_CallerSnapin;
  1634. pDSObj->cItems = nDeletedCount;
  1635. DWORD NextOffset = cbStruct;
  1636. for (index = 0; index < nDeletedCount; index++)
  1637. {
  1638. pDSObj->aObjects[index].dwFlags = dwFlagsDelArr[index];
  1639. pDSObj->aObjects[index].dwProviderFlags = dwProviderFlagsDelArr[index];
  1640. pDSObj->aObjects[index].offsetName = NextOffset;
  1641. pDSObj->aObjects[index].offsetClass = static_cast<ULONG>(NextOffset +
  1642. (wcslen(lpszNameDelArr[index])+1) * sizeof(WCHAR));
  1643. _tcscpy((LPTSTR)((BYTE *)pDSObj + NextOffset), lpszNameDelArr[index]);
  1644. NextOffset += static_cast<ULONG>((wcslen(lpszNameDelArr[index]) + 1) * sizeof(WCHAR));
  1645. _tcscpy((LPTSTR)((BYTE *)pDSObj + NextOffset), lpszClassDelArr[index]);
  1646. NextOffset += static_cast<ULONG>((wcslen(lpszClassDelArr[index]) + 1) * sizeof(WCHAR));
  1647. }
  1648. // make the call
  1649. hr = spDsQueryHandler->UpdateView(DSQRVF_ITEMSDELETED, pDSObj);
  1650. ::free(pDSObj);
  1651. }
  1652. HRESULT
  1653. CDSContextMenu::_Delete(LPCWSTR lpszPath, LPCWSTR lpszClass,
  1654. CString * csName)
  1655. {
  1656. CComBSTR strParent;
  1657. CComBSTR strThisRDN;
  1658. IADsContainer * pDSContainer = NULL;
  1659. IADs * pDSObject = NULL;
  1660. HRESULT hr = S_OK;
  1661. hr = DSAdminOpenObject(lpszPath,
  1662. IID_IADs,
  1663. (void **) &pDSObject,
  1664. TRUE /*bServer*/);
  1665. if (!SUCCEEDED(hr)) {
  1666. goto error;
  1667. }
  1668. hr = pDSObject->get_Parent(&strParent);
  1669. if (!SUCCEEDED(hr)) {
  1670. goto error;
  1671. }
  1672. hr = pDSObject->get_Name (&strThisRDN);
  1673. if (!SUCCEEDED(hr)) {
  1674. goto error;
  1675. }
  1676. pDSObject->Release();
  1677. pDSObject = NULL;
  1678. hr = DSAdminOpenObject(strParent,
  1679. IID_IADsContainer,
  1680. (void **) &pDSContainer,
  1681. TRUE /*bServer*/);
  1682. if (!SUCCEEDED(hr)) {
  1683. goto error;
  1684. }
  1685. hr = pDSContainer->Delete (CComBSTR(lpszClass),
  1686. CComBSTR(strThisRDN));
  1687. error:
  1688. if (pDSContainer)
  1689. pDSContainer->Release();
  1690. if (pDSObject)
  1691. pDSObject->Release();
  1692. if (FAILED(hr)) {
  1693. *csName = strThisRDN;
  1694. }
  1695. return hr;
  1696. }
  1697. HRESULT
  1698. CDSContextMenu::_DeleteSubtree(LPCWSTR lpszPath,
  1699. CString * csName)
  1700. {
  1701. HRESULT hr = S_OK;
  1702. IADsDeleteOps * pObj = NULL;
  1703. IADs * pObj2 = NULL;
  1704. hr = DSAdminOpenObject(lpszPath,
  1705. IID_IADsDeleteOps,
  1706. (void **)&pObj,
  1707. TRUE /*bServer*/);
  1708. if (SUCCEEDED(hr)) {
  1709. TIMER(_T("Call to Deleteobject (to do subtree delete).\n"));
  1710. hr = pObj->DeleteObject(NULL); //flag is reserved by ADSI
  1711. TIMER(_T("Call to Deleteobject completed.\n"));
  1712. }
  1713. if (FAILED(hr)) {
  1714. CComBSTR strName;
  1715. HRESULT hr2 = pObj->QueryInterface (IID_IADs, (void **)&pObj2);
  1716. if (SUCCEEDED(hr2)) {
  1717. hr2 = pObj2->get_Name(&strName);
  1718. if (SUCCEEDED(hr2)) {
  1719. *csName = strName;
  1720. } else {
  1721. csName->LoadString (IDS_UNKNOWN);
  1722. }
  1723. }
  1724. }
  1725. if (pObj2) {
  1726. pObj2->Release();
  1727. }
  1728. if (pObj) {
  1729. pObj->Release();
  1730. }
  1731. return hr;
  1732. }
  1733. // code from JeffParh
  1734. NTSTATUS RetrieveRootDomainName( LPCWSTR lpcwszTargetDC, BSTR* pbstrRootDomainName )
  1735. {
  1736. if (NULL == pbstrRootDomainName)
  1737. {
  1738. ASSERT(FALSE);
  1739. return STATUS_INVALID_PARAMETER;
  1740. }
  1741. ASSERT( NULL == *pbstrRootDomainName );
  1742. NTSTATUS ntStatus = STATUS_SUCCESS;
  1743. LSA_HANDLE hPolicy = NULL;
  1744. POLICY_DNS_DOMAIN_INFO* pDnsDomainInfo = NULL;
  1745. do { // false loop
  1746. UNICODE_STRING unistrTargetDC;
  1747. if (NULL != lpcwszTargetDC)
  1748. {
  1749. unistrTargetDC.Length = (USHORT)(::lstrlen(lpcwszTargetDC)*sizeof(WCHAR));
  1750. unistrTargetDC.MaximumLength = unistrTargetDC.Length;
  1751. unistrTargetDC.Buffer = (LPWSTR)lpcwszTargetDC;
  1752. }
  1753. LSA_OBJECT_ATTRIBUTES oa;
  1754. ZeroMemory( &oa, sizeof(oa) );
  1755. ntStatus = LsaOpenPolicy(
  1756. (NULL != lpcwszTargetDC) ? &unistrTargetDC : NULL,
  1757. &oa,
  1758. POLICY_VIEW_LOCAL_INFORMATION,
  1759. &hPolicy
  1760. );
  1761. if ( !LSA_SUCCESS( ntStatus ) )
  1762. {
  1763. ASSERT(FALSE);
  1764. break;
  1765. }
  1766. ntStatus = LsaQueryInformationPolicy(
  1767. hPolicy,
  1768. PolicyDnsDomainInformation,
  1769. (PVOID*)&pDnsDomainInfo
  1770. );
  1771. if ( !LSA_SUCCESS( ntStatus ) )
  1772. {
  1773. ASSERT(FALSE);
  1774. break;
  1775. }
  1776. *pbstrRootDomainName = ::SysAllocStringLen(
  1777. pDnsDomainInfo->DnsForestName.Buffer,
  1778. pDnsDomainInfo->DnsForestName.Length / sizeof(WCHAR) );
  1779. if (NULL == *pbstrRootDomainName)
  1780. {
  1781. ntStatus = STATUS_NO_MEMORY;
  1782. break;
  1783. }
  1784. } while (false); // false loop
  1785. if (NULL != pDnsDomainInfo)
  1786. {
  1787. NTSTATUS ntstatus2 = LsaFreeMemory( pDnsDomainInfo );
  1788. ASSERT( LSA_SUCCESS(ntstatus2) );
  1789. }
  1790. if (NULL != hPolicy)
  1791. {
  1792. NTSTATUS ntstatus2 = LsaClose( hPolicy );
  1793. ASSERT( LSA_SUCCESS(ntstatus2) );
  1794. }
  1795. return ntStatus;
  1796. }
  1797. void AddMatchingNCs(
  1798. IN OUT CStringList& refstrlist,
  1799. IN const PADS_ATTR_INFO padsattrinfo1,
  1800. IN const PADS_ATTR_INFO padsattrinfo2 )
  1801. {
  1802. if ( !padsattrinfo1 || !padsattrinfo2 )
  1803. return;
  1804. for (DWORD iTarget = 0; iTarget < padsattrinfo1[0].dwNumValues; iTarget++)
  1805. {
  1806. LPWSTR lpszTargetNC = padsattrinfo1[0].pADsValues[iTarget].DNString;
  1807. ASSERT( NULL != lpszTargetNC );
  1808. bool fFound = false;
  1809. for (DWORD iSource = 0; iSource < padsattrinfo2[0].dwNumValues; iSource++)
  1810. {
  1811. LPWSTR lpszSourceNC = padsattrinfo2[0].pADsValues[iSource].DNString;
  1812. ASSERT( NULL != lpszSourceNC );
  1813. if ( !lstrcmpiW( lpszTargetNC, lpszSourceNC ) )
  1814. {
  1815. fFound = true;
  1816. break;
  1817. }
  1818. }
  1819. if (fFound)
  1820. refstrlist.AddHead( lpszTargetNC ); // CODEWORK can throw
  1821. }
  1822. }
  1823. HRESULT PrepareReplicaSyncParameters(
  1824. IN LPCWSTR strNTDSConnection,
  1825. IN BSTR bstrRootDomainName,
  1826. OUT BSTR* pbstrDsBindName,
  1827. OUT UUID* puuidSourceObjectGUID,
  1828. OUT CStringList& refstrlistCommonNCs,
  1829. OUT ULONG* pulDsSyncOptions,
  1830. OUT BSTR* pbstrFromServer
  1831. )
  1832. {
  1833. ASSERT( NULL != strNTDSConnection
  1834. && NULL != bstrRootDomainName
  1835. && NULL != pbstrDsBindName
  1836. && NULL == *pbstrDsBindName
  1837. && NULL != puuidSourceObjectGUID
  1838. && refstrlistCommonNCs.IsEmpty()
  1839. && NULL != pulDsSyncOptions
  1840. );
  1841. HRESULT hr = S_OK;
  1842. do { // false loop
  1843. CComPtr<IADs> spIADs;
  1844. // read attributes of nTDSConnection object
  1845. hr = DSAdminOpenObject(strNTDSConnection,
  1846. IID_IADs,
  1847. (void **) &spIADs,
  1848. TRUE /*bServer*/);
  1849. BREAK_ON_FAIL;
  1850. hr = GetStringAttr( spIADs, L"fromServer", pbstrFromServer);
  1851. BREAK_AND_ASSERT_ON_FAIL; // required attribute
  1852. spIADs.Release(); // method of CComPtr<>, also sets pointer to NULL
  1853. // get the path to the target nTDSDSA object
  1854. CPathCracker pathCracker;
  1855. hr = pathCracker.Set( const_cast<BSTR>(strNTDSConnection), ADS_SETTYPE_FULL );
  1856. BREAK_AND_ASSERT_ON_FAIL;
  1857. hr = pathCracker.RemoveLeafElement();
  1858. BREAK_AND_ASSERT_ON_FAIL;
  1859. CComBSTR sbstrTargetNTDSDSAPath;
  1860. hr = pathCracker.Retrieve( ADS_FORMAT_X500, &sbstrTargetNTDSDSAPath );
  1861. BREAK_AND_ASSERT_ON_FAIL;
  1862. // get the sitename for the target NTDSA object
  1863. hr = pathCracker.SetDisplayType( ADS_DISPLAY_VALUE_ONLY );
  1864. BREAK_AND_ASSERT_ON_FAIL;
  1865. CComBSTR sbstrTargetSite;
  1866. hr = pathCracker.GetElement( 3L, &sbstrTargetSite );
  1867. BREAK_AND_ASSERT_ON_FAIL;
  1868. hr = pathCracker.SetDisplayType( ADS_DISPLAY_FULL );
  1869. BREAK_AND_ASSERT_ON_FAIL;
  1870. // read objectGUID of the target nTDSDSA object
  1871. hr = DSAdminOpenObject(sbstrTargetNTDSDSAPath,
  1872. IID_IADs,
  1873. (void **) &spIADs,
  1874. TRUE /*bServer*/);
  1875. BREAK_ON_FAIL;
  1876. CComBSTR sbstrTargetObjectGUID;
  1877. hr = GetObjectGUID( spIADs, &sbstrTargetObjectGUID );
  1878. // The objectGUID attribute should be set for nTDSDSA objects
  1879. BREAK_AND_ASSERT_ON_FAIL;
  1880. // read hasMasterNCs of the target nTDSDSA object
  1881. Smart_PADS_ATTR_INFO spTargetMasterNCAttrs;
  1882. // 531591 JonN 2002/04/01 .NET Server domains use msDS-hasMasterNCs
  1883. hr = GetAttr( spIADs, L"msDS-hasMasterNCs", &spTargetMasterNCAttrs );
  1884. if (FAILED(hr) || !spTargetMasterNCAttrs)
  1885. {
  1886. // 531591 JonN 2002/04/01 W2K domains fallback to hasMasterNCs
  1887. spTargetMasterNCAttrs.Empty();
  1888. hr = GetAttr( spIADs, L"hasMasterNCs", &spTargetMasterNCAttrs );
  1889. }
  1890. // At least the hasMasterNCs attribute should be set for nTDSDSA objects,
  1891. // even those on W2K domains
  1892. BREAK_AND_ASSERT_ON_FAIL;
  1893. // read hasPartialReplicaNCs of the target nTDSDSA object
  1894. Smart_PADS_ATTR_INFO spTargetPartialNCAttrs;
  1895. (void) GetAttr( spIADs, L"hasPartialReplicaNCs", &spTargetPartialNCAttrs );
  1896. // The hasPartialReplicaNCs attribute may or may not be set for nTDSDSA objects
  1897. spIADs.Release(); // method of CComPtr<>, also sets pointer to NULL
  1898. /*
  1899. hr = spIADsPathname->RemoveLeafElement();
  1900. BREAK_AND_ASSERT_ON_FAIL;
  1901. CComBSTR sbstrTargetServerPath;
  1902. hr = spIADsPathname->Retrieve( ADS_FORMAT_X500, &sbstrTargetServerPath );
  1903. BREAK_AND_ASSERT_ON_FAIL;
  1904. hr = DSAdminOpenObject(sbstrTargetServerPath,
  1905. IID_IADs,
  1906. (void **) &spIADs,
  1907. TRUE);
  1908. BREAK_ON_FAIL;
  1909. CComVariant var;
  1910. hr = spIADs->Get(L"dNSHostName", &var);
  1911. BREAK_ON_FAIL; // can be missing for brand-new DCs
  1912. spIADs.Release(); // method of CComPtr<>, also sets pointer to NULL
  1913. ASSERT((var.vt == VT_BSTR) && var.bstrVal && *(var.bstrVal));
  1914. LPWSTR lpszDNSHostName = var.bstrVal;
  1915. */
  1916. // get the path to the source nTDSDSA object
  1917. hr = pathCracker.Set(
  1918. (pbstrFromServer) ? *pbstrFromServer : NULL,
  1919. ADS_SETTYPE_DN );
  1920. BREAK_AND_ASSERT_ON_FAIL;
  1921. CComBSTR sbstrSourceNTDSDSAPath;
  1922. hr = pathCracker.Retrieve( ADS_FORMAT_X500, &sbstrSourceNTDSDSAPath );
  1923. BREAK_AND_ASSERT_ON_FAIL;
  1924. // get the sitename for the source NTDSA object
  1925. hr = pathCracker.SetDisplayType( ADS_DISPLAY_VALUE_ONLY );
  1926. BREAK_AND_ASSERT_ON_FAIL;
  1927. CComBSTR sbstrSourceSite;
  1928. hr = pathCracker.GetElement( 3L, &sbstrSourceSite );
  1929. BREAK_AND_ASSERT_ON_FAIL;
  1930. hr = pathCracker.SetDisplayType( ADS_DISPLAY_FULL );
  1931. BREAK_AND_ASSERT_ON_FAIL;
  1932. // determine whether the two DCs are in the same site
  1933. *pulDsSyncOptions = (lstrcmpi(sbstrSourceSite, sbstrTargetSite))
  1934. ? DS_REPSYNC_ASYNCHRONOUS_OPERATION
  1935. : 0;
  1936. // read objectGUID of the source NTDSDSA object
  1937. hr = DSAdminOpenObject(sbstrSourceNTDSDSAPath,
  1938. IID_IADs,
  1939. (void **) &spIADs,
  1940. TRUE /*bServer*/);
  1941. BREAK_ON_FAIL;
  1942. hr = GetObjectGUID( spIADs, puuidSourceObjectGUID );
  1943. // The objectGUID attribute should be set for nTDSDSA objects
  1944. BREAK_AND_ASSERT_ON_FAIL;
  1945. // read hasMasterNCs of the source nTDSDSA object
  1946. Smart_PADS_ATTR_INFO spSourceMasterNCAttrs;
  1947. // 531591 JonN 2002/04/01 .NET Server domains use msDS-hasMasterNCs
  1948. hr = GetAttr( spIADs, L"msDS-hasMasterNCs", &spSourceMasterNCAttrs );
  1949. if (FAILED(hr) || !spSourceMasterNCAttrs)
  1950. {
  1951. // 531591 JonN 2002/04/01 W2K domains fallback to hasMasterNCs
  1952. spSourceMasterNCAttrs.Empty();
  1953. hr = GetAttr( spIADs, L"hasMasterNCs", &spSourceMasterNCAttrs );
  1954. }
  1955. // At least the hasMasterNCs attribute should be set for nTDSDSA objects,
  1956. // even those on W2K domains.
  1957. // read hasMasterNCs of the source nTDSDSA object
  1958. Smart_PADS_ATTR_INFO spSourcePartialNCAttrs;
  1959. (void) GetAttr( spIADs, L"hasPartialReplicaNCs", &spSourcePartialNCAttrs );
  1960. // The hasPartialReplicaNCs attribute may or may not be set for nTDSDSA objects
  1961. spIADs.Release(); // method of CComPtr<>, also sets pointer to NULL
  1962. // Determine which NCs the two NTDSDSAs have in common
  1963. AddMatchingNCs( refstrlistCommonNCs, spTargetMasterNCAttrs, spSourceMasterNCAttrs );
  1964. AddMatchingNCs( refstrlistCommonNCs, spTargetPartialNCAttrs, spSourceMasterNCAttrs );
  1965. AddMatchingNCs( refstrlistCommonNCs, spTargetPartialNCAttrs, spSourcePartialNCAttrs );
  1966. // Build the name of the inbound domain controller for this connection
  1967. CString csGUID( sbstrTargetObjectGUID );
  1968. ASSERT( L'{' == csGUID[0] && L'}' == csGUID[csGUID.GetLength()-1] );
  1969. CString csDC = csGUID.Mid( 1, csGUID.GetLength()-2 );
  1970. csDC += L"._msdcs.";
  1971. csDC += bstrRootDomainName;
  1972. *pbstrDsBindName = ::SysAllocString( csDC );
  1973. /*
  1974. *pbstrDsBindName = ::SysAllocString( lpszDNSHostName );
  1975. */
  1976. if (NULL == *pbstrDsBindName)
  1977. {
  1978. hr = E_OUTOFMEMORY;
  1979. BREAK_AND_ASSERT_ON_FAIL;
  1980. }
  1981. } while (false); // false loop
  1982. return hr;
  1983. }
  1984. void CDSContextMenu::AddToGroup()
  1985. {
  1986. CWaitCursor waitcursor;
  1987. HRESULT hr = S_OK;
  1988. TRACE (_T("CDSContextMenu::AddToGroup\n"));
  1989. hr = AddDataObjListToGroup (&m_objectNamesFormat, m_hwnd, m_pCD);
  1990. return;
  1991. }
  1992. bool IsRPCError( NTSTATUS ntstatus )
  1993. {
  1994. switch (ntstatus)
  1995. {
  1996. case RPC_S_SERVER_UNAVAILABLE:
  1997. case HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE):
  1998. case ERROR_DS_DNS_LOOKUP_FAILURE:
  1999. case HRESULT_FROM_WIN32(ERROR_DS_DNS_LOOKUP_FAILURE):
  2000. case ERROR_NO_SUCH_DOMAIN:
  2001. case HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN):
  2002. case SEC_E_NO_AUTHENTICATING_AUTHORITY: // already an HRESULT
  2003. case ERROR_DOMAIN_CONTROLLER_NOT_FOUND:
  2004. case HRESULT_FROM_WIN32(ERROR_DOMAIN_CONTROLLER_NOT_FOUND):
  2005. return true;
  2006. default:
  2007. break;
  2008. }
  2009. return false;
  2010. }
  2011. // This level takes care of displaying the error messages
  2012. // CODEWORK should this try to replicate other domains to GCs?
  2013. void CDSContextMenu::ReplicateNow()
  2014. {
  2015. CWaitCursor waitcursor;
  2016. CComBSTR sbstrRootDomainName;
  2017. LPCWSTR lpcwszTargetDC = NULL;
  2018. if ( NULL != m_pCD && NULL != m_pCD->GetBasePathsInfo() )
  2019. lpcwszTargetDC = m_pCD->GetBasePathsInfo()->GetServerName();
  2020. NTSTATUS ntstatus = RetrieveRootDomainName( lpcwszTargetDC, &sbstrRootDomainName );
  2021. if ( !LSA_SUCCESS(ntstatus) )
  2022. {
  2023. // error in RetrieveRootDomainName against DSADMIN target DC
  2024. PVOID apv[1] = {(LPWSTR)(lpcwszTargetDC) };
  2025. (void) ReportErrorEx( m_hwnd,
  2026. (IsRPCError(ntstatus)) ? IDS_REPLNOW_1_RPC_PARAMLOAD_ERROR
  2027. : IDS_REPLNOW_1_PARAMLOAD_ERROR,
  2028. ntstatus, // CODEWORK
  2029. MB_OK | MB_ICONEXCLAMATION,
  2030. apv,
  2031. 1,
  2032. IDS_REPLNOW_TITLE,
  2033. FALSE);
  2034. return;
  2035. }
  2036. CComBSTR sbstrFailingConnection;
  2037. CComBSTR sbstrFromServer;
  2038. CComBSTR sbstrFailingNC;
  2039. HRESULT hr = S_OK;
  2040. bool fSyncError = false;
  2041. ULONG ulOptionsUsed = 0;
  2042. // loop through the array of objects
  2043. UINT cCount;
  2044. for (cCount=0; cCount < m_objectNamesFormat.GetCount(); cCount++) {
  2045. if (wcscmp(m_objectNamesFormat.GetClass(cCount), L"nTDSConnection") !=0)
  2046. continue;
  2047. // get the replication parameters for this connection object
  2048. CComBSTR sbstrDsBindName;
  2049. UUID uuidSourceObjectGUID;
  2050. CStringList strlistCommonNCs;
  2051. ULONG ulDsSyncOptions = 0L;
  2052. sbstrFromServer.Empty();
  2053. sbstrFailingConnection = m_objectNamesFormat.GetName(cCount);
  2054. hr = PrepareReplicaSyncParameters(
  2055. sbstrFailingConnection,
  2056. sbstrRootDomainName,
  2057. &sbstrDsBindName,
  2058. &uuidSourceObjectGUID,
  2059. strlistCommonNCs,
  2060. &ulDsSyncOptions,
  2061. &sbstrFromServer
  2062. );
  2063. BREAK_ON_FAIL;
  2064. // now bind to the target DC
  2065. Smart_DsHandle shDS;
  2066. DWORD dwWinError = DsBind( sbstrDsBindName, // DomainControllerAddress
  2067. NULL, // DnsDomainName
  2068. &shDS );
  2069. if (ERROR_SUCCESS != dwWinError)
  2070. {
  2071. hr = HRESULT_FROM_WIN32(dwWinError);
  2072. ASSERT( FAILED(hr) );
  2073. break;
  2074. }
  2075. // sync all common naming contexts for this connection
  2076. CString strCommonNC;
  2077. POSITION pos = strlistCommonNCs.GetHeadPosition();
  2078. while (NULL != pos)
  2079. {
  2080. strCommonNC = strlistCommonNCs.GetNext( pos ) ;
  2081. ASSERT( 0 != strCommonNC.GetLength() );
  2082. dwWinError = DsReplicaSync( shDS,
  2083. const_cast<LPWSTR>((LPCTSTR)strCommonNC),
  2084. &uuidSourceObjectGUID,
  2085. ulDsSyncOptions );
  2086. if (ERROR_SUCCESS != dwWinError)
  2087. {
  2088. sbstrFailingNC = strCommonNC;
  2089. hr = HRESULT_FROM_WIN32(dwWinError);
  2090. ASSERT( FAILED(hr) );
  2091. break;
  2092. }
  2093. }
  2094. if ( FAILED(hr) )
  2095. {
  2096. fSyncError = true;
  2097. break;
  2098. }
  2099. ulOptionsUsed |= ulDsSyncOptions;
  2100. } // for
  2101. if ( SUCCEEDED(hr) )
  2102. {
  2103. (void) ReportMessageEx( m_hwnd,
  2104. (ulOptionsUsed & DS_REPSYNC_ASYNCHRONOUS_OPERATION)
  2105. ? IDS_REPLNOW_SUCCEEDED_DELAYED
  2106. : IDS_REPLNOW_SUCCEEDED_IMMEDIATE,
  2107. MB_OK | MB_ICONINFORMATION,
  2108. NULL,
  2109. 0,
  2110. IDS_REPLNOW_TITLE );
  2111. }
  2112. else
  2113. {
  2114. // JonN 3/30/00
  2115. // 6793: SITEREPL: ReplicateNow should provide more error information
  2116. // retrieve name of target DC
  2117. CComBSTR sbstrToServerRDN;
  2118. CPathCracker pathCracker;
  2119. HRESULT hr2 = pathCracker.Set(sbstrFailingConnection, ADS_SETTYPE_FULL);
  2120. ASSERT( SUCCEEDED(hr2) );
  2121. hr2 = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  2122. ASSERT( SUCCEEDED(hr2) );
  2123. hr2 = pathCracker.GetElement(2, &sbstrToServerRDN);
  2124. ASSERT( SUCCEEDED(hr2) );
  2125. if (fSyncError)
  2126. {
  2127. // error in DsReplicaSync against connection target DC
  2128. // retrieve name of source DC
  2129. CComBSTR sbstrFromServerRDN;
  2130. hr2 = pathCracker.Set(sbstrFromServer, ADS_SETTYPE_DN);
  2131. ASSERT( SUCCEEDED(hr2) );
  2132. hr2 = pathCracker.GetElement(1, &sbstrFromServerRDN);
  2133. ASSERT( SUCCEEDED(hr2) );
  2134. // retrieve name of naming context
  2135. if (sbstrFailingNC && !wcsncmp(L"CN=",sbstrFailingNC,3))
  2136. {
  2137. hr2 = pathCracker.Set(sbstrFailingNC, ADS_SETTYPE_DN);
  2138. ASSERT( SUCCEEDED(hr2) );
  2139. hr2 = pathCracker.GetElement( 0, &sbstrFailingNC );
  2140. ASSERT( SUCCEEDED(hr2) );
  2141. } else {
  2142. LPWSTR pwzDomainNC = NULL;
  2143. hr2 = CrackName(sbstrFailingNC, &pwzDomainNC, GET_DNS_DOMAIN_NAME, NULL);
  2144. ASSERT( SUCCEEDED(hr2) && NULL != pwzDomainNC );
  2145. sbstrFailingNC = pwzDomainNC;
  2146. LocalFreeStringW(&pwzDomainNC);
  2147. }
  2148. PVOID apv[3] = { sbstrToServerRDN, sbstrFromServerRDN, sbstrFailingNC };
  2149. (void) ReportErrorEx( m_hwnd,
  2150. (IsRPCError(hr)) ? IDS_REPLNOW_3_RPC_FORCESYNC_ERROR
  2151. : IDS_REPLNOW_3_FORCESYNC_ERROR,
  2152. hr,
  2153. MB_OK | MB_ICONEXCLAMATION,
  2154. apv,
  2155. 3,
  2156. IDS_REPLNOW_TITLE );
  2157. }
  2158. else
  2159. {
  2160. // error in PrepareReplicaSyncParameters against connection target DC
  2161. PVOID apv[1] = { sbstrToServerRDN };
  2162. (void) ReportErrorEx( m_hwnd,
  2163. (IsRPCError(hr)) ? IDS_REPLNOW_1_RPC_PARAMLOAD_ERROR
  2164. : IDS_REPLNOW_1_PARAMLOAD_ERROR,
  2165. hr,
  2166. MB_OK | MB_ICONEXCLAMATION,
  2167. apv,
  2168. 1,
  2169. IDS_REPLNOW_TITLE );
  2170. }
  2171. }
  2172. }
  2173. void CDSContextMenu::CopyObject()
  2174. {
  2175. if (m_pCD != NULL)
  2176. {
  2177. m_pCD->_CopyDSObject(m_spDataObject);
  2178. }
  2179. }
  2180. void CDSContextMenu::_GetExtraInfo(LPDATAOBJECT pDataObj)
  2181. {
  2182. FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  2183. ASSERT(m_objectNamesFormat.HasData());
  2184. //we assume these are all the same
  2185. m_Advanced = (m_objectNamesFormat.GetProviderFlags(0) & DSPROVIDER_ADVANCED) != 0;
  2186. // set classes flag
  2187. for (UINT index = 0; index < m_objectNamesFormat.GetCount(); index++)
  2188. {
  2189. if (wcscmp(m_objectNamesFormat.GetClass(index), L"user") == 0
  2190. #ifdef INETORGPERSON
  2191. || wcscmp(m_objectNamesFormat.GetClass(index), L"inetOrgPerson") == 0
  2192. #endif
  2193. )
  2194. m_fClasses |= Type_User;
  2195. else if (wcscmp(m_objectNamesFormat.GetClass(index), L"group") == 0)
  2196. m_fClasses |= Type_Group;
  2197. else if (wcscmp(m_objectNamesFormat.GetClass(index), L"computer") == 0)
  2198. m_fClasses |= Type_Computer;
  2199. else if (wcscmp(m_objectNamesFormat.GetClass(index), L"nTDSConnection") == 0)
  2200. m_fClasses |= Type_NTDSConnection;
  2201. else if (wcscmp(m_objectNamesFormat.GetClass(index), L"domainDNS") == 0)
  2202. m_fClasses |= Type_Domain;
  2203. else if (wcscmp(m_objectNamesFormat.GetClass(index), L"contact") == 0)
  2204. m_fClasses |= Type_Contact;
  2205. else if (wcscmp(m_objectNamesFormat.GetClass(index), L"group") == 0)
  2206. m_fClasses |= Type_Group;
  2207. else if (wcscmp(m_objectNamesFormat.GetClass(index), L"organizationalUnit") == 0)
  2208. m_fClasses |= Type_OU;
  2209. else
  2210. m_fClasses |= Type_Others;
  2211. } // for
  2212. // set classid
  2213. g_cfCoClass = (CLIPFORMAT)RegisterClipboardFormat(CCF_SNAPIN_CLASSID);
  2214. fmte.cfFormat = g_cfCoClass;
  2215. STGMEDIUM Stg;
  2216. Stg.tymed = TYMED_HGLOBAL;
  2217. //NTRAID#NTBUG9-571991-2002/03/10-jmessec Not checking failure of GlobalAlloc, possible leading to NULL ptr dereference
  2218. Stg.hGlobal = GlobalAlloc (GPTR, sizeof(CLSID));
  2219. HRESULT hr = pDataObj->GetDataHere(&fmte, &Stg);
  2220. if ( SUCCEEDED(hr) )
  2221. {
  2222. memcpy (&m_CallerSnapin, Stg.hGlobal, sizeof(GUID));
  2223. }
  2224. else
  2225. {
  2226. m_CallerSnapin = GUID_NULL;
  2227. }
  2228. GlobalFree(Stg.hGlobal);
  2229. //NTRAID#NTBUG9-571992-2002/03/10-jmessec Should not bypass the published MMC COM APIs in this manner; container
  2230. //structure could change in the future
  2231. // get HWND (MMC mainframe window)
  2232. g_cfParentHwnd = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_DS_PARENTHWND);
  2233. fmte.cfFormat = g_cfParentHwnd;
  2234. Stg.tymed = TYMED_NULL;
  2235. if ( SUCCEEDED(pDataObj->GetData(&fmte, &Stg)) )
  2236. {
  2237. memcpy (&m_hwnd, Stg.hGlobal, sizeof(HWND));
  2238. ReleaseStgMedium(&Stg);
  2239. }
  2240. else
  2241. {
  2242. // need an HWND anyway
  2243. m_hwnd = ::GetActiveWindow();
  2244. }
  2245. TRACE(L"HWND = 0x%x\n", m_hwnd);
  2246. ASSERT((m_hwnd != NULL) && ::IsWindow(m_hwnd));
  2247. // get component data (if in the context of DS Admin)
  2248. g_cfComponentData = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_DS_COMPDATA);
  2249. fmte.cfFormat = g_cfComponentData;
  2250. Stg.tymed = TYMED_NULL;
  2251. if ( SUCCEEDED(pDataObj->GetData(&fmte, &Stg)) )
  2252. {
  2253. memcpy (&m_pCD, Stg.hGlobal, sizeof(CDSComponentData*));
  2254. ReleaseStgMedium(&Stg);
  2255. } else
  2256. {
  2257. m_pCD = NULL;
  2258. }
  2259. // get component data (if in the context of DS Find)
  2260. if (m_pCD == NULL)
  2261. {
  2262. m_pCD = g_pCD;
  2263. }
  2264. }
  2265. BOOL
  2266. CDSContextMenu::_WarningOnSheetsUp()
  2267. {
  2268. // if called in the context of DS Admin, guard against property sheet open on this cookie
  2269. if ( (m_pCD != NULL) && m_internalFormat.HasData() )
  2270. {
  2271. return m_pCD->_WarningOnSheetsUp(&m_internalFormat);
  2272. }
  2273. return FALSE;
  2274. }
  2275. void
  2276. CDSContextMenu::Rename()
  2277. {
  2278. CThemeContextActivator activator;
  2279. HRESULT hr = S_OK;
  2280. INT_PTR answer = IDOK;
  2281. LPWSTR pszDomain = NULL;
  2282. LPWSTR pwzLocalDomain = NULL;
  2283. IDirectoryObject * pObj = NULL;
  2284. IADs * pObj2 = NULL;
  2285. IADs * pPartitions = NULL;
  2286. CString csLogin;
  2287. CString csTemp;
  2288. CString csSam;
  2289. CWaitCursor cwait;
  2290. BOOL error = FALSE;
  2291. BOOL fAccessDenied = FALSE;
  2292. LPWSTR pszNewName = NULL;
  2293. LPWSTR pszFirstName = NULL;
  2294. LPWSTR pszDispName = NULL;
  2295. LPWSTR pszSurName = NULL;
  2296. LPWSTR pszSAMName = NULL;
  2297. LPWSTR pszUPN = NULL;
  2298. BOOL NoRename = FALSE;
  2299. CString serverName;
  2300. CComVariant Var;
  2301. // guard against property sheet open on this cookie
  2302. if (_WarningOnSheetsUp())
  2303. return;
  2304. CString strClass = m_objectNamesFormat.GetClass(0);
  2305. if (strClass == L"user"
  2306. #ifdef INETORGPERSON
  2307. || strClass == L"inetOrgPerson"
  2308. #endif
  2309. )
  2310. {
  2311. // rename user
  2312. CRenameUserDlg dlgRename(m_pCD);
  2313. LPWSTR pAttrNames[] = {L"distinguishedName",
  2314. L"userPrincipalName",
  2315. L"sAMAccountName",
  2316. L"givenName",
  2317. L"displayName",
  2318. L"sn",
  2319. L"cn"};
  2320. PADS_ATTR_INFO pAttrs = NULL;
  2321. ULONG cAttrs = 0;
  2322. CString szPath = m_objectNamesFormat.GetName(0);
  2323. hr = DSAdminOpenObject(szPath,
  2324. IID_IDirectoryObject,
  2325. (void **)&pObj,
  2326. TRUE /*bServer*/);
  2327. if (SUCCEEDED(hr)) {
  2328. hr = pObj->GetObjectAttributes (pAttrNames, 7, &pAttrs, &cAttrs);
  2329. if (SUCCEEDED(hr)) {
  2330. for (UINT i = 0; i < cAttrs; i++) {
  2331. if (_wcsicmp (L"distinguishedName", pAttrs[i].pszAttrName) == 0) {
  2332. hr = CrackName (pAttrs[i].pADsValues->CaseIgnoreString,
  2333. &pszDomain, GET_NT4_DOMAIN_NAME, NULL);
  2334. if (SUCCEEDED(hr)) {
  2335. dlgRename.m_dldomain = pszDomain;
  2336. dlgRename.m_dldomain += L'\\';
  2337. }
  2338. // get the Domain of this object, need it later.
  2339. CComBSTR bsDN;
  2340. CPathCracker pathCracker;
  2341. pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
  2342. pathCracker.Set(CComBSTR(szPath), ADS_SETTYPE_FULL);
  2343. pathCracker.Retrieve(ADS_FORMAT_X500_DN, &bsDN);
  2344. // NTRAID#NTBUG9-698115-2002/09/04-artm
  2345. // Get the server name we're connected to, we'll need it later for getting root domains.
  2346. // If we fail to get it that's okay, we'll still get the root domains
  2347. // unless the user is running dsadmin under "runas". If that's the case,
  2348. // the we won't show parent domains (but everything else will work).
  2349. CComBSTR tempServerName;
  2350. hr = pathCracker.Retrieve(ADS_FORMAT_SERVER, &tempServerName);
  2351. if (SUCCEEDED(hr))
  2352. {
  2353. serverName = tempServerName;
  2354. }
  2355. // get the NT 5 (dns) domain name
  2356. TRACE(L"CrackName(%s, &pwzLocalDomain, GET_DNS_DOMAIN_NAME, NULL);\n", bsDN);
  2357. hr = CrackName(bsDN, &pwzLocalDomain, GET_DNS_DOMAIN_NAME, NULL);
  2358. TRACE(L"CrackName returned hr = 0x%x, pwzLocalDomain = <%s>\n", hr, pwzLocalDomain);
  2359. }
  2360. if (_wcsicmp (L"userPrincipalName", pAttrs[i].pszAttrName) == 0) {
  2361. csTemp = pAttrs[i].pADsValues->CaseIgnoreString;
  2362. INT loc = csTemp.Find (L'@');
  2363. if (loc > 0) {
  2364. dlgRename.m_login = csTemp.Left(loc);
  2365. dlgRename.m_domain = csTemp.Right (csTemp.GetLength() - loc);
  2366. } else {
  2367. dlgRename.m_login = csTemp;
  2368. ASSERT (0 && L"can't find @ in upn");
  2369. }
  2370. }
  2371. if (_wcsicmp (L"sAMAccountName", pAttrs[i].pszAttrName) == 0) {
  2372. dlgRename.m_samaccountname = pAttrs[i].pADsValues->CaseIgnoreString;
  2373. }
  2374. if (_wcsicmp (L"givenName", pAttrs[i].pszAttrName) == 0) {
  2375. dlgRename.m_first = pAttrs[i].pADsValues->CaseIgnoreString;
  2376. }
  2377. if (_wcsicmp (L"displayName", pAttrs[i].pszAttrName) == 0) {
  2378. dlgRename.m_displayname = pAttrs[i].pADsValues->CaseIgnoreString;
  2379. }
  2380. if (_wcsicmp (L"sn", pAttrs[i].pszAttrName) == 0) {
  2381. dlgRename.m_last = pAttrs[i].pADsValues->CaseIgnoreString;
  2382. }
  2383. if (_wcsicmp (L"cn", pAttrs[i].pszAttrName) == 0) {
  2384. dlgRename.m_cn = pAttrs[i].pADsValues->CaseIgnoreString;
  2385. dlgRename.m_oldcn = dlgRename.m_cn;
  2386. }
  2387. }
  2388. }
  2389. // get UPN suffixes from this OU, if present
  2390. IADs * pObjADs = NULL;
  2391. IADs * pCont = NULL;
  2392. BSTR bsParentPath;
  2393. CStringList UPNs;
  2394. CString strAtDomain;
  2395. hr = pObj->QueryInterface (IID_IADs, (void **)&pObjADs);
  2396. ASSERT (SUCCEEDED(hr));
  2397. hr = pObjADs->get_Parent(&bsParentPath);
  2398. ASSERT (SUCCEEDED(hr));
  2399. hr = DSAdminOpenObject(bsParentPath,
  2400. IID_IADs,
  2401. (void **)&pCont,
  2402. TRUE /*bServer*/);
  2403. CComVariant sVar;
  2404. hr = pCont->Get ( CComBSTR(L"uPNSuffixes"), &sVar);
  2405. if (SUCCEEDED(hr)) {
  2406. hr = HrVariantToStringList (IN sVar, UPNs);
  2407. if (SUCCEEDED(hr)) {
  2408. POSITION pos = UPNs.GetHeadPosition();
  2409. CString csSuffix;
  2410. while (pos != NULL) {
  2411. csSuffix = L"@";
  2412. csSuffix += UPNs.GetNext(INOUT pos);
  2413. TRACE(_T("UPN suffix: %s\n"), csSuffix);
  2414. if (wcscmp (csSuffix, dlgRename.m_domain) &&
  2415. !dlgRename.m_domains.Find(csSuffix))
  2416. {
  2417. dlgRename.m_domains.AddTail (csSuffix);
  2418. }
  2419. }
  2420. }
  2421. } else {// now get the domain options
  2422. CComPtr<IDsBrowseDomainTree> pDsDomains = NULL;
  2423. PDOMAIN_TREE pNewDomains = NULL;
  2424. do // false while loop
  2425. {
  2426. hr = ::CoCreateInstance(CLSID_DsDomainTreeBrowser,
  2427. NULL,
  2428. CLSCTX_INPROC_SERVER,
  2429. IID_IDsBrowseDomainTree,
  2430. (LPVOID*)&pDsDomains);
  2431. if (FAILED(hr) || pDsDomains == NULL)
  2432. {
  2433. ASSERT(SUCCEEDED(hr) && pDsDomains != NULL);
  2434. break;
  2435. }
  2436. // NTRAID#NTBUG9-698115-2002/09/04-artm
  2437. // Ensure that the domains we request are correctly scoped.
  2438. hr = pDsDomains->SetComputer(serverName, NULL, NULL);
  2439. if (FAILED(hr))
  2440. {
  2441. ASSERT(SUCCEEDED(hr));
  2442. break;
  2443. }
  2444. hr = pDsDomains->GetDomains(&pNewDomains, 0);
  2445. if (FAILED(hr) || pNewDomains == NULL)
  2446. {
  2447. // Only expect to get here with failed hresult.
  2448. ASSERT(FAILED(hr));
  2449. break;
  2450. }
  2451. for (UINT index = 0; index < pNewDomains->dwCount; index++)
  2452. {
  2453. if (pNewDomains->aDomains[index].pszTrustParent == NULL)
  2454. {
  2455. // Add the root domain only if it is a substring of the current
  2456. // domain.
  2457. //
  2458. size_t cchRoot = wcslen(pNewDomains->aDomains[index].pszName);
  2459. PWSTR pRoot = pwzLocalDomain + wcslen(pwzLocalDomain) - cchRoot;
  2460. if (pRoot >= pwzLocalDomain &&
  2461. !_wcsicmp(pRoot, pNewDomains->aDomains[index].pszName))
  2462. {
  2463. strAtDomain = "@";
  2464. strAtDomain += pNewDomains->aDomains[index].pszName;
  2465. if (_wcsicmp(pNewDomains->aDomains[index].pszName, dlgRename.m_domain) &&
  2466. !dlgRename.m_domains.Find(strAtDomain))
  2467. {
  2468. dlgRename.m_domains.AddTail (strAtDomain);
  2469. }
  2470. }
  2471. }
  2472. } // end for loop
  2473. } while (false);
  2474. if (pDsDomains != NULL && pNewDomains != NULL)
  2475. {
  2476. pDsDomains->FreeDomains(&pNewDomains);
  2477. pNewDomains = NULL;
  2478. }
  2479. // If the local domain isn't the same as the root, then add it
  2480. CString strAtLocalDomain = L"@";
  2481. strAtLocalDomain += pwzLocalDomain;
  2482. if (!dlgRename.m_domains.Find(strAtLocalDomain))
  2483. {
  2484. dlgRename.m_domains.AddTail(strAtLocalDomain);
  2485. }
  2486. LocalFreeStringW(&pszDomain);
  2487. // get UPN suffixes
  2488. CString csPartitions;
  2489. CStringList UPNsToo;
  2490. // get config path from main object
  2491. csPartitions = m_pCD->GetBasePathsInfo()->GetProviderAndServerName();
  2492. csPartitions += L"CN=Partitions,";
  2493. csPartitions += m_pCD->GetBasePathsInfo()->GetConfigNamingContext();
  2494. hr = DSAdminOpenObject(csPartitions,
  2495. IID_IADs,
  2496. (void **)&pPartitions,
  2497. TRUE /*bServer*/);
  2498. if (SUCCEEDED(hr)) {
  2499. CComVariant sVarToo;
  2500. hr = pPartitions->Get ( CComBSTR(L"uPNSuffixes"), &sVarToo);
  2501. if (SUCCEEDED(hr)) {
  2502. hr = HrVariantToStringList (IN sVarToo, UPNsToo);
  2503. if (SUCCEEDED(hr)) {
  2504. POSITION pos = UPNsToo.GetHeadPosition();
  2505. CString csSuffix;
  2506. while (pos != NULL) {
  2507. csSuffix = L"@";
  2508. csSuffix += UPNsToo.GetNext(INOUT pos);
  2509. TRACE(_T("UPN suffix: %s\n"), csSuffix);
  2510. if (wcscmp (csSuffix, dlgRename.m_domain) &&
  2511. !dlgRename.m_domains.Find(csSuffix))
  2512. {
  2513. dlgRename.m_domains.AddTail (csSuffix);
  2514. }
  2515. }
  2516. }
  2517. }
  2518. pPartitions->Release();
  2519. }
  2520. }
  2521. error = TRUE;
  2522. while ((error) && (!fAccessDenied))
  2523. {
  2524. answer = dlgRename.DoModal();
  2525. if (answer == IDOK)
  2526. {
  2527. ADSVALUE avUPN = {ADSTYPE_CASE_IGNORE_STRING, NULL};
  2528. ADS_ATTR_INFO aiUPN = {L"userPrincipalName", ADS_ATTR_UPDATE,
  2529. ADSTYPE_CASE_IGNORE_STRING, &avUPN, 1};
  2530. ADSVALUE avSAMName = {ADSTYPE_CASE_IGNORE_STRING, NULL};
  2531. ADS_ATTR_INFO aiSAMName = {L"sAMAccountName", ADS_ATTR_UPDATE,
  2532. ADSTYPE_CASE_IGNORE_STRING, &avSAMName, 1};
  2533. ADSVALUE avGiven = {ADSTYPE_CASE_IGNORE_STRING, NULL};
  2534. ADS_ATTR_INFO aiGiven = {L"givenName", ADS_ATTR_UPDATE,
  2535. ADSTYPE_CASE_IGNORE_STRING, &avGiven, 1};
  2536. ADSVALUE avSurName = {ADSTYPE_CASE_IGNORE_STRING, NULL};
  2537. ADS_ATTR_INFO aiSurName = {L"sn", ADS_ATTR_UPDATE,
  2538. ADSTYPE_CASE_IGNORE_STRING, &avSurName, 1};
  2539. ADSVALUE avDispName = {ADSTYPE_CASE_IGNORE_STRING, NULL};
  2540. ADS_ATTR_INFO aiDispName = {L"displayName", ADS_ATTR_UPDATE,
  2541. ADSTYPE_CASE_IGNORE_STRING, &avDispName, 1};
  2542. ADS_ATTR_INFO rgAttrs[5];
  2543. ULONG cModified = 0;
  2544. cAttrs = 0;
  2545. if (!dlgRename.m_login.IsEmpty() &&
  2546. !dlgRename.m_domain.IsEmpty())
  2547. {
  2548. dlgRename.m_login.TrimRight();
  2549. dlgRename.m_login.TrimLeft();
  2550. dlgRename.m_domain.TrimRight();
  2551. dlgRename.m_domain.TrimLeft();
  2552. csTemp = (dlgRename.m_login + dlgRename.m_domain);
  2553. pszUPN = new WCHAR[wcslen(csTemp) + 1];
  2554. if (pszUPN)
  2555. {
  2556. wcscpy (pszUPN, csTemp);
  2557. avUPN.CaseIgnoreString = pszUPN;
  2558. }
  2559. }
  2560. else
  2561. {
  2562. aiUPN.dwControlCode = ADS_ATTR_CLEAR;
  2563. }
  2564. rgAttrs[cAttrs++] = aiUPN;
  2565. // test UPN for duplication
  2566. // test UPN for duplication
  2567. // validate UPN with GC before doing the put.
  2568. BOOL fDomainSearchFailed = FALSE;
  2569. BOOL fGCSearchFailed = FALSE;
  2570. BOOL dup = FALSE;
  2571. CString strFilter;
  2572. LPWSTR pAttributes[1] = {L"cn"};
  2573. IDirectorySearch * pGCObj = NULL;
  2574. CDSSearch DSS (m_pCD->m_pClassCache, m_pCD);
  2575. hr = DSPROP_GetGCSearchOnDomain(pwzLocalDomain,
  2576. IID_IDirectorySearch,
  2577. (void **)&pGCObj);
  2578. if (FAILED(hr)) {
  2579. fGCSearchFailed = TRUE;
  2580. } else {
  2581. DSS.Init (pGCObj);
  2582. LPWSTR pUserAttributes[1] = {L"cn"};
  2583. strFilter = L"(userPrincipalName=";
  2584. strFilter += pszUPN;
  2585. strFilter += L")";
  2586. DSS.SetAttributeList (pUserAttributes, 1);
  2587. DSS.SetFilterString ((LPWSTR)(LPCWSTR)strFilter);
  2588. DSS.SetSearchScope (ADS_SCOPE_SUBTREE);
  2589. DSS.DoQuery();
  2590. hr = DSS.GetNextRow();
  2591. dup = FALSE;
  2592. while ((hr == S_OK) && (dup == FALSE)) { // this means a row was returned, so we're dup
  2593. ADS_SEARCH_COLUMN Col;
  2594. hr = DSS.GetColumn(pUserAttributes[0], &Col);
  2595. if (_wcsicmp(Col.pADsValues->CaseIgnoreString, dlgRename.m_oldcn)) {
  2596. dup = TRUE;
  2597. ReportErrorEx (m_hwnd, IDS_UPN_DUP, hr,
  2598. MB_OK, NULL, 0);
  2599. }
  2600. hr = DSS.GetNextRow();
  2601. }
  2602. if (hr != S_ADS_NOMORE_ROWS) {
  2603. fGCSearchFailed = TRUE;
  2604. }
  2605. }
  2606. HRESULT hr2 = S_OK;
  2607. if (dup)
  2608. continue;
  2609. else {
  2610. CString strInitPath = L"LDAP://";
  2611. strInitPath += pwzLocalDomain;
  2612. TRACE(_T("Initialize Domain search object with: %s...\n"), strInitPath);
  2613. hr2 = DSS.Init (strInitPath);
  2614. if (SUCCEEDED(hr2)) {
  2615. LPWSTR pAttributes2[1] = {L"cn"};
  2616. strFilter = L"(userPrincipalName=";
  2617. strFilter += pszUPN;
  2618. strFilter += L")";
  2619. TRACE(_T("searching current domain for %s...\n"), pszUPN);
  2620. DSS.SetAttributeList (pAttributes2, 1);
  2621. DSS.SetFilterString ((LPWSTR)(LPCWSTR)strFilter);
  2622. DSS.SetSearchScope (ADS_SCOPE_SUBTREE);
  2623. DSS.DoQuery();
  2624. hr2 = DSS.GetNextRow();
  2625. TRACE(_T("done searching current domain for %s...\n"), pszUPN);
  2626. }
  2627. while ((hr2 == S_OK) && (dup == FALSE)) { // this means a row was returned, so we're dup
  2628. ADS_SEARCH_COLUMN Col;
  2629. HRESULT hr3 = DSS.GetColumn(pAttributes[0], &Col);
  2630. ASSERT(hr3 == S_OK);
  2631. if (_wcsicmp(Col.pADsValues->CaseIgnoreString, dlgRename.m_oldcn)) {
  2632. dup = TRUE;
  2633. ReportErrorEx (m_hwnd, IDS_UPN_DUP, hr,
  2634. MB_OK, NULL, 0);
  2635. }
  2636. hr2 = DSS.GetNextRow();
  2637. }
  2638. if (hr2 != S_ADS_NOMORE_ROWS) { // oops, had another problem
  2639. fDomainSearchFailed = TRUE;
  2640. }
  2641. }
  2642. if (dup)
  2643. continue;
  2644. else {
  2645. if (fDomainSearchFailed || fGCSearchFailed) {
  2646. HRESULT hrSearch = S_OK;
  2647. if (fDomainSearchFailed) {
  2648. hrSearch = hr2;
  2649. } else {
  2650. hrSearch = hr;
  2651. }
  2652. ReportErrorEx (m_hwnd,IDS_UPN_SEARCH_FAILED2,hrSearch,
  2653. MB_OK | MB_ICONWARNING, NULL, 0);
  2654. }
  2655. }
  2656. if (pGCObj) {
  2657. pGCObj->Release();
  2658. pGCObj = NULL;
  2659. }
  2660. //NTRAID#NTBUG9-569671-2002/03/10-jmessec this should be + 1, not + sizeof(WCHAR)
  2661. pszNewName = new WCHAR[wcslen(dlgRename.m_cn) + 1];
  2662. dlgRename.m_cn.TrimRight();
  2663. dlgRename.m_cn.TrimLeft();
  2664. wcscpy (pszNewName, dlgRename.m_cn);
  2665. if (dlgRename.m_cn == dlgRename.m_oldcn)
  2666. NoRename = TRUE;
  2667. if (!dlgRename.m_displayname.IsEmpty()) {
  2668. dlgRename.m_displayname.TrimLeft();
  2669. dlgRename.m_displayname.TrimRight();
  2670. //NTRAID#NTBUG9-569671-2002/03/10-jmessec this should be + 1, not + sizeof(WCHAR)
  2671. pszDispName = new WCHAR[wcslen(dlgRename.m_displayname) + 1];
  2672. wcscpy (pszDispName, dlgRename.m_displayname);
  2673. avDispName.CaseIgnoreString = pszDispName;
  2674. } else {
  2675. aiDispName.dwControlCode = ADS_ATTR_CLEAR;
  2676. }
  2677. rgAttrs[cAttrs++] = aiDispName;
  2678. if (!dlgRename.m_first.IsEmpty()) {
  2679. dlgRename.m_first.TrimLeft();
  2680. dlgRename.m_first.TrimRight();
  2681. //NTRAID#NTBUG9-569671-2002/03/10-jmessec this should be + 1, not + sizeof(WCHAR)
  2682. pszFirstName = new WCHAR[wcslen(dlgRename.m_first) + 1];
  2683. wcscpy (pszFirstName, dlgRename.m_first);
  2684. avGiven.CaseIgnoreString = pszFirstName;
  2685. } else {
  2686. aiGiven.dwControlCode = ADS_ATTR_CLEAR;
  2687. }
  2688. rgAttrs[cAttrs++] = aiGiven;
  2689. if (!dlgRename.m_last.IsEmpty()) {
  2690. dlgRename.m_last.TrimLeft();
  2691. dlgRename.m_last.TrimRight();
  2692. //NTRAID#NTBUG9-569671-2002/03/10-jmessec sizeof(WCHAR) below should be 1
  2693. pszSurName = new WCHAR[wcslen(dlgRename.m_last) + 1];
  2694. wcscpy (pszSurName, dlgRename.m_last);
  2695. avSurName.CaseIgnoreString = pszSurName;
  2696. } else {
  2697. aiSurName.dwControlCode = ADS_ATTR_CLEAR;
  2698. }
  2699. rgAttrs[cAttrs++] = aiSurName;
  2700. if (!dlgRename.m_samaccountname.IsEmpty()) {
  2701. dlgRename.m_samaccountname.TrimLeft();
  2702. dlgRename.m_samaccountname.TrimRight();
  2703. //NTRAID#NTBUG9-569671-2002/03/10-jmessec sizeof(WCHAR) below should be 1
  2704. pszSAMName = new WCHAR[wcslen(dlgRename.m_samaccountname) + 1];
  2705. wcscpy (pszSAMName, dlgRename.m_samaccountname);
  2706. avSAMName.CaseIgnoreString = pszSAMName;
  2707. } else {
  2708. aiSAMName.dwControlCode = ADS_ATTR_CLEAR;
  2709. }
  2710. rgAttrs[cAttrs++] = aiSAMName;
  2711. hr = pObj->SetObjectAttributes (rgAttrs, cAttrs, &cModified);
  2712. if (FAILED(hr)) {
  2713. if (hr == E_ACCESSDENIED) {
  2714. fAccessDenied = TRUE;
  2715. NoRename = TRUE;
  2716. } else {
  2717. ReportErrorEx (m_hwnd, IDS_NAME_CHANGE_FAILED, hr,
  2718. MB_OK|MB_ICONERROR, NULL, 0, TRUE);
  2719. }
  2720. } else {
  2721. error = FALSE;
  2722. }
  2723. } else {
  2724. error = FALSE;
  2725. }
  2726. }
  2727. } else {
  2728. answer = IDCANCEL;
  2729. PVOID apv[1] = {(BSTR)(LPWSTR)(LPCWSTR)m_objectNamesFormat.GetName(0)};
  2730. ReportErrorEx (m_hwnd,IDS_12_USER_OBJECT_NOT_ACCESSABLE,hr,
  2731. MB_OK | MB_ICONERROR, apv, 1);
  2732. }
  2733. } else if (strClass == L"group") {
  2734. CRenameGroupDlg * pdlgRename = new CRenameGroupDlg;
  2735. CString szPath;
  2736. szPath = m_objectNamesFormat.GetName(0);
  2737. hr = DSAdminOpenObject(szPath,
  2738. IID_IADs,
  2739. (void **)&pObj2,
  2740. TRUE /*bServer*/);
  2741. if (SUCCEEDED(hr)) {
  2742. hr = pObj2->Get (CComBSTR(L"sAMAccountName"), &Var);
  2743. ASSERT (SUCCEEDED(hr));
  2744. csSam = Var.bstrVal;
  2745. if (strClass == L"computer") {
  2746. INT loc = csSam.Find(L"$");
  2747. if (loc > 0) {
  2748. csSam = csSam.Left(loc);
  2749. }
  2750. }
  2751. hr = pObj2->Get (CComBSTR(L"cn"), &Var);
  2752. ASSERT (SUCCEEDED(hr));
  2753. pdlgRename->m_cn = Var.bstrVal;
  2754. // figure out group type
  2755. if (strClass == L"group") {
  2756. CComVariant varType;
  2757. hr = pObj2->Get(CComBSTR(L"groupType"), &varType);
  2758. ASSERT(SUCCEEDED(hr));
  2759. INT GroupType = (varType.lVal & ~GROUP_TYPE_SECURITY_ENABLED);
  2760. if (GroupType == GROUP_TYPE_RESOURCE_GROUP) {
  2761. pdlgRename->m_samtextlimit = 64;
  2762. }
  2763. }
  2764. pdlgRename->m_samaccountname = csSam;
  2765. error = TRUE;
  2766. while ((error) && (!fAccessDenied))
  2767. {
  2768. answer = pdlgRename->DoModal();
  2769. if (answer == IDOK)
  2770. {
  2771. pdlgRename->m_cn.TrimRight();
  2772. pdlgRename->m_cn.TrimLeft();
  2773. //NTRAID#NTBUG9-569671-2002/03/10-jmessec 1 * sizeof(WCHAR) below should be 1
  2774. pszNewName = new WCHAR[wcslen(pdlgRename->m_cn) + (1 * sizeof(WCHAR))];
  2775. wcscpy (pszNewName, pdlgRename->m_cn);
  2776. Var.vt = VT_BSTR;
  2777. pdlgRename->m_samaccountname.TrimLeft();
  2778. pdlgRename->m_samaccountname.TrimRight();
  2779. csSam = pdlgRename->m_samaccountname;
  2780. if (strClass == L"computer")
  2781. {
  2782. csSam += L"$";
  2783. }
  2784. Var.bstrVal = SysAllocString(csSam);
  2785. hr = pObj2->Put (CComBSTR(L"sAMAccountName"), Var);
  2786. ASSERT (SUCCEEDED(hr));
  2787. if (FAILED(hr)) {
  2788. continue;
  2789. }
  2790. hr = pObj2->SetInfo();
  2791. if (FAILED(hr)) {
  2792. if (hr == E_ACCESSDENIED) {
  2793. fAccessDenied = TRUE;
  2794. NoRename = TRUE;
  2795. } else {
  2796. ReportErrorEx (m_hwnd, IDS_NAME_CHANGE_FAILED, hr,
  2797. MB_OK|MB_ICONERROR, NULL, 0, TRUE);
  2798. }
  2799. } else {
  2800. error = FALSE;
  2801. }
  2802. } else {
  2803. error = FALSE;
  2804. }
  2805. }
  2806. } else {
  2807. answer = IDCANCEL;
  2808. }
  2809. if (pdlgRename) {
  2810. delete pdlgRename;
  2811. }
  2812. } else if (strClass == L"contact") {
  2813. // rename contact
  2814. CRenameContactDlg dlgRename;
  2815. CString szPath;
  2816. szPath = m_objectNamesFormat.GetName(0);
  2817. hr = DSAdminOpenObject(szPath,
  2818. IID_IADs,
  2819. (void **)&pObj2,
  2820. TRUE /*bServer*/);
  2821. if (SUCCEEDED(hr)) {
  2822. hr = pObj2->Get (CComBSTR(L"givenName"), &Var);
  2823. ASSERT (SUCCEEDED(hr) || (hr == E_ADS_PROPERTY_NOT_FOUND));
  2824. if (SUCCEEDED(hr)) {
  2825. dlgRename.m_first = Var.bstrVal;
  2826. }
  2827. hr = pObj2->Get (CComBSTR(L"sn"), &Var);
  2828. ASSERT (SUCCEEDED(hr) || (hr == E_ADS_PROPERTY_NOT_FOUND));
  2829. if (SUCCEEDED(hr)) {
  2830. dlgRename.m_last = Var.bstrVal;
  2831. }
  2832. hr = pObj2->Get (CComBSTR(L"displayName"), &Var);
  2833. ASSERT (SUCCEEDED(hr) || (hr == E_ADS_PROPERTY_NOT_FOUND));
  2834. if (SUCCEEDED(hr)) {
  2835. dlgRename.m_disp = Var.bstrVal;
  2836. }
  2837. hr = pObj2->Get (CComBSTR(L"cn"), &Var);
  2838. ASSERT (SUCCEEDED(hr) || (hr == E_ADS_PROPERTY_NOT_FOUND));
  2839. if (SUCCEEDED(hr)) {
  2840. dlgRename.m_cn = Var.bstrVal;
  2841. }
  2842. error = TRUE;
  2843. while ((error) && (!fAccessDenied))
  2844. {
  2845. answer = dlgRename.DoModal();
  2846. if (answer == IDOK)
  2847. {
  2848. dlgRename.m_cn.TrimRight();
  2849. dlgRename.m_cn.TrimLeft();
  2850. //NTRAID#NTBUG9-569671-2002/03/10-jmessec 1 * sizeof(WCHAR) below should be 1
  2851. pszNewName = new WCHAR[wcslen(dlgRename.m_cn) + (1 * sizeof(WCHAR))];
  2852. wcscpy (pszNewName, dlgRename.m_cn);
  2853. Var.vt = VT_BSTR;
  2854. if (!dlgRename.m_first.IsEmpty())
  2855. {
  2856. dlgRename.m_first.TrimLeft();
  2857. dlgRename.m_first.TrimRight();
  2858. Var.bstrVal = SysAllocString (dlgRename.m_first);
  2859. hr = pObj2->Put (CComBSTR(L"givenName"), Var);
  2860. ASSERT (SUCCEEDED(hr));
  2861. }
  2862. if (!dlgRename.m_last.IsEmpty()) {
  2863. dlgRename.m_last.TrimLeft();
  2864. dlgRename.m_last.TrimRight();
  2865. Var.bstrVal = SysAllocString(dlgRename.m_last);
  2866. hr = pObj2->Put (CComBSTR(L"sn"), Var);
  2867. ASSERT (SUCCEEDED(hr));
  2868. }
  2869. if (!dlgRename.m_disp.IsEmpty()) {
  2870. dlgRename.m_disp.TrimLeft();
  2871. dlgRename.m_disp.TrimRight();
  2872. Var.bstrVal = SysAllocString(dlgRename.m_disp);
  2873. hr = pObj2->Put (CComBSTR(L"displayName"), Var);
  2874. ASSERT (SUCCEEDED(hr));
  2875. }
  2876. hr = pObj2->SetInfo();
  2877. if (FAILED(hr)) {
  2878. if (hr == E_ACCESSDENIED) {
  2879. fAccessDenied = TRUE;
  2880. NoRename = TRUE;
  2881. } else {
  2882. ReportErrorEx (m_hwnd, IDS_NAME_CHANGE_FAILED, hr,
  2883. MB_OK|MB_ICONERROR, NULL, 0, TRUE);
  2884. }
  2885. } else {
  2886. error = FALSE;
  2887. }
  2888. } else {
  2889. error = FALSE;
  2890. }
  2891. }
  2892. } else {
  2893. answer = IDCANCEL;
  2894. }
  2895. } else {
  2896. // need generic dialog here.
  2897. CRenameGenericDlg dlgRename (CWnd::FromHandle(m_hwnd));
  2898. CString szPath;
  2899. szPath = m_objectNamesFormat.GetName(0);
  2900. hr = DSAdminOpenObject(szPath,
  2901. IID_IADs,
  2902. (void **)&pObj2,
  2903. TRUE /*bServer*/);
  2904. if (SUCCEEDED(hr)) {
  2905. CDSClassCacheItemBase* pItem = NULL;
  2906. pItem = m_pCD->m_pClassCache->FindClassCacheItem(m_pCD, (LPCWSTR)strClass, szPath);
  2907. ASSERT (pItem != NULL);
  2908. //get the naming attribute
  2909. CString csNewAttrName;
  2910. csNewAttrName = pItem->GetNamingAttribute();
  2911. hr = pObj2->Get (CComBSTR(csNewAttrName), &Var);
  2912. ASSERT (SUCCEEDED(hr) || (hr == E_ADS_PROPERTY_NOT_FOUND));
  2913. if (SUCCEEDED(hr)) {
  2914. dlgRename.m_cn = Var.bstrVal;
  2915. }
  2916. //NTRAID#NTBUG9-571993-2002/03/10-jmessec what is all of this while (error) rigamarole for? it never loops
  2917. error = TRUE;
  2918. while (error)
  2919. {
  2920. CThemeContextActivator activator;
  2921. answer = dlgRename.DoModal();
  2922. if (answer == IDOK)
  2923. {
  2924. dlgRename.m_cn.TrimRight();
  2925. dlgRename.m_cn.TrimLeft();
  2926. //NTRAID#NTBUG9-569671-2002/03/10-jmessec 1 * sizeof(WCHAR) below should be 1
  2927. pszNewName = new WCHAR[wcslen(dlgRename.m_cn) + (1 * sizeof(WCHAR))];
  2928. wcscpy (pszNewName, dlgRename.m_cn);
  2929. error = FALSE;
  2930. }
  2931. else
  2932. {
  2933. error = FALSE;
  2934. }
  2935. }
  2936. }
  2937. }
  2938. if ((answer == IDOK) && (error == FALSE) && (NoRename == FALSE)) {
  2939. CString csObjectPath = m_objectNamesFormat.GetName(0);
  2940. CDSClassCacheItemBase* pItem = NULL;
  2941. pItem = m_pCD->m_pClassCache->FindClassCacheItem(m_pCD, (LPCWSTR)strClass, csObjectPath);
  2942. ASSERT (pItem != NULL);
  2943. // get the new name in the form "cn=foo" or "ou=foo"
  2944. CString csNewAttrName;
  2945. csNewAttrName = pItem->GetNamingAttribute();
  2946. csNewAttrName += L"=";
  2947. csNewAttrName += pszNewName;
  2948. TRACE(_T("_RenameObject: Attributed name is %s.\n"), csNewAttrName);
  2949. // bind to object
  2950. IADs *pDSObject = NULL;
  2951. hr = DSAdminOpenObject(csObjectPath,
  2952. IID_IADs,
  2953. (void **)&pDSObject,
  2954. TRUE /*bServer*/);
  2955. if (!SUCCEEDED(hr)) {
  2956. goto error;
  2957. }
  2958. BSTR bsParentPath;
  2959. // get the path of the object container
  2960. hr = pDSObject->get_Parent (&bsParentPath);
  2961. if (!SUCCEEDED(hr)) {
  2962. goto error;
  2963. }
  2964. pDSObject->Release();
  2965. pDSObject = NULL;
  2966. IADsContainer * pContainer = NULL;
  2967. // bind to the object container
  2968. hr = DSAdminOpenObject(bsParentPath,
  2969. IID_IADsContainer,
  2970. (void **)&pContainer,
  2971. TRUE /*bServer*/);
  2972. if (!SUCCEEDED(hr)) {
  2973. goto error;
  2974. }
  2975. // build the new LDAP path
  2976. CString csNewNamingContext, csNewPath, szPath;
  2977. BSTR bsEscapedName;
  2978. csNewNamingContext = csNewAttrName;
  2979. csNewNamingContext += L",";
  2980. StripADsIPath(bsParentPath, szPath);
  2981. csNewNamingContext += szPath;
  2982. m_pCD->GetBasePathsInfo()->ComposeADsIPath(csNewPath, csNewNamingContext);
  2983. // create a transaction object, the destructor will call End() on it
  2984. CDSNotifyHandlerTransaction transaction(m_pCD);
  2985. transaction.SetEventType(DSA_NOTIFY_REN);
  2986. // start the transaction
  2987. hr = transaction.Begin(m_objectNamesFormat.GetName(0),
  2988. m_objectNamesFormat.GetClass(0),
  2989. m_objectNamesFormat.IsContainer(0),
  2990. csNewPath,
  2991. m_objectNamesFormat.GetClass(0),
  2992. m_objectNamesFormat.IsContainer(0));
  2993. // ask for confirmation
  2994. if (transaction.NeedNotifyCount() > 0)
  2995. {
  2996. CString szMessage, szAssocData;
  2997. szMessage.LoadString(IDS_CONFIRM_RENAME);
  2998. szAssocData.LoadString(IDS_EXTENS_RENAME);
  2999. CConfirmOperationDialog dlg(::GetParent(m_hwnd), &transaction);
  3000. dlg.SetStrings(szMessage, szAssocData);
  3001. if (IDNO == dlg.DoModal())
  3002. {
  3003. transaction.End();
  3004. hr = S_OK;
  3005. goto error;
  3006. }
  3007. }
  3008. CPathCracker pathCracker;
  3009. hr = pathCracker.GetEscapedElement(0, //reserved
  3010. (BSTR)(LPCWSTR)csNewAttrName,
  3011. &bsEscapedName);
  3012. if (FAILED(hr))
  3013. goto error;
  3014. IDispatch * pDispObj = NULL;
  3015. // do the actual rename
  3016. hr = pContainer->MoveHere(CComBSTR(csObjectPath),
  3017. CComBSTR(bsEscapedName),
  3018. &pDispObj);
  3019. if (SUCCEEDED(hr) && (hr != S_FALSE)) {
  3020. // let extensions know
  3021. transaction.Notify(0);
  3022. // send notify to diz
  3023. }
  3024. if (pDispObj) {
  3025. pDispObj->Release();
  3026. }
  3027. }
  3028. if (fAccessDenied) {
  3029. PVOID apv[1] = {(LPWSTR)m_objectNamesFormat.GetName(0)};
  3030. ReportErrorEx(::GetParent(m_hwnd),IDS_12_RENAME_NOT_ALLOWED,hr,
  3031. MB_OK | MB_ICONERROR, apv, 1);
  3032. }
  3033. error:
  3034. // transaction.End() will be called by the transaction's destructor
  3035. if (pwzLocalDomain) {
  3036. LocalFreeStringW(&pwzLocalDomain);
  3037. }
  3038. if (pszNewName) {
  3039. delete[] pszNewName;
  3040. }
  3041. if (pszFirstName) {
  3042. delete[] pszFirstName;
  3043. }
  3044. if (pszDispName) {
  3045. delete[] pszDispName;
  3046. }
  3047. if (pszSurName) {
  3048. delete[] pszSurName;
  3049. }
  3050. if (pszSAMName){
  3051. delete[] pszSAMName;
  3052. }
  3053. if (pszUPN) {
  3054. delete[] pszUPN;
  3055. }
  3056. if (pObj) {
  3057. pObj->Release();
  3058. }
  3059. if (pObj2) {
  3060. pObj2->Release();
  3061. }
  3062. }