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.

1093 lines
30 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1999
  5. //
  6. // File: DSDirect.cpp
  7. //
  8. // Contents: ADSI wrapper object implementation
  9. //
  10. // History: 02-feb-97 jimharr Created
  11. //
  12. //
  13. //--------------------------------------------------------------------------
  14. #include "stdafx.h"
  15. #include "resource.h"
  16. #include "dsutil.h"
  17. #include "dsdirect.h"
  18. #include "cmnquery.h"
  19. #include "dsquery.h"
  20. #include "dscache.h"
  21. #include "dssnap.h"
  22. #include "dsthread.h"
  23. #include "newobj.h"
  24. #include "querysup.h"
  25. #include <lm.h>
  26. #ifdef _DEBUG
  27. #define new DEBUG_NEW
  28. #undef THIS_FILE
  29. static char THIS_FILE[] = __FILE__;
  30. #endif
  31. #define BAIL_IF_ERROR(hr) \
  32. if (FAILED(hr)) { \
  33. goto cleanup; \
  34. }\
  35. #define BAIL_ON_FAILURE(hr) \
  36. if (FAILED(hr)) { \
  37. goto error; \
  38. }\
  39. extern inline
  40. BOOL CleanName (LPWSTR pszObjectName)
  41. {
  42. WCHAR * ptr = NULL;
  43. ptr = wcschr (pszObjectName, L'=') + 1;
  44. //NTRAID#NTBUG9-571994-2002/03/10-jmessec 1) ptr is never null, since it is incremented in statement above.
  45. //NTRAID#NTBUG9-571994-2002/03/10-jmessec 2) wcscpy is undefined if source and dest buffers overlap
  46. //NTRAID#NTBUG9-571994-2002/03/10-jmessec 3) WTF? CleanName() changes string truncates everything to the left of, and including,
  47. //an equal sign? Poor naming convention
  48. //NTRAID#NTBUG9-571994-2002/03/10-jmessec 4) Possible localization issue?
  49. //NTRAID#NTBUG9-571994-2002/03/10-jmessec 5) Only cleans before the first instance of "="; is this intended behavior?
  50. //NTRAID#NTBUG9-571994-2002/03/10-jmessec 6) Appears to be dead code?
  51. //NTRAID#NTBUG9-571994-2002/03/10-jmessec 7) Possible NULL pointer dereference (pszObjectName)
  52. //NTRAID#NTBUG9-571994-2002/03/10-jmessec 8) dereferences ptr value = 1 if there is no "=" in the string
  53. if (ptr) {
  54. wcscpy (pszObjectName, ptr);
  55. return TRUE;
  56. } else
  57. return FALSE;
  58. }
  59. CDSDirect::CDSDirect()
  60. {
  61. ASSERT (FALSE);
  62. m_pCD = NULL;
  63. }
  64. // WARNING: pCD may still be in its constructor and may not be fully constructed yet
  65. CDSDirect::CDSDirect(CDSComponentData * pCD)
  66. {
  67. m_pCD = pCD;
  68. }
  69. CDSDirect::~CDSDirect()
  70. {
  71. }
  72. HRESULT CDSDirect::DeleteObject(CDSCookie* pCookie,
  73. BOOL raiseUI)
  74. {
  75. CComBSTR strParent;
  76. CComBSTR strThisRDN;
  77. CComPtr<IADsContainer> spDSContainer;
  78. CComPtr<IADs> spDSObject;
  79. // bind to the ADSI object
  80. CString strPath;
  81. m_pCD->GetBasePathsInfo()->ComposeADsIPath(strPath, pCookie->GetPath());
  82. HRESULT hr = DSAdminOpenObject(strPath,
  83. IID_IADs,
  84. (void **) &spDSObject,
  85. TRUE /*bServer*/);
  86. if (FAILED(hr))
  87. {
  88. goto error;
  89. }
  90. // retrieve the parent's path
  91. hr = spDSObject->get_Parent(&strParent);
  92. if (FAILED(hr))
  93. {
  94. goto error;
  95. }
  96. // get the RDN of this object
  97. hr = spDSObject->get_Name (&strThisRDN);
  98. if (FAILED(hr))
  99. {
  100. goto error;
  101. }
  102. // bind to the parent ADSI object
  103. hr = DSAdminOpenObject(strParent,
  104. IID_IADsContainer,
  105. (void **) &spDSContainer,
  106. TRUE /*bServer*/);
  107. if (FAILED(hr))
  108. {
  109. goto error;
  110. }
  111. hr = spDSContainer->Delete(CComBSTR(pCookie->GetClass()),
  112. CComBSTR(strThisRDN));
  113. error:
  114. if ((!SUCCEEDED(hr)) & raiseUI)
  115. {
  116. HWND hwnd;
  117. m_pCD->m_pFrame->GetMainWindow(&hwnd);
  118. PVOID apv[1] = {(LPWSTR)pCookie->GetName()};
  119. ReportErrorEx( m_pCD->m_hwnd, IDS_12_DELETE_FAILED,
  120. hr, MB_OK | MB_ICONERROR, apv, 1);
  121. }
  122. return hr;
  123. }
  124. HRESULT CDSDirect::GetParentDN(CDSCookie* pCookie, CString& szParentDN)
  125. {
  126. HRESULT hr = S_OK;
  127. CString szObjPath;
  128. CComPtr<IADs> spDSObj;
  129. m_pCD->GetBasePathsInfo()->ComposeADsIPath(szObjPath, pCookie->GetPath());
  130. hr = DSAdminOpenObject(szObjPath,
  131. IID_IADs,
  132. (void **)&spDSObj,
  133. TRUE /*bServer*/);
  134. if (SUCCEEDED(hr))
  135. {
  136. CComBSTR ParentPath;
  137. hr = spDSObj->get_Parent(&ParentPath);
  138. StripADsIPath(ParentPath, szParentDN);
  139. }
  140. return hr;
  141. }
  142. ///////////////////////////////////////////////////////////////////////////
  143. // CSnapinMoveHandler
  144. class CSnapinMoveHandler : public CMoveHandlerBase
  145. {
  146. public:
  147. CSnapinMoveHandler(CDSComponentData* pComponentData, HWND hwnd,
  148. LPCWSTR lpszBrowseRootPath, CDSCookie* pCookie)
  149. : CMoveHandlerBase(pComponentData, hwnd, lpszBrowseRootPath)
  150. {
  151. m_pCookie = pCookie;
  152. }
  153. protected:
  154. virtual UINT GetItemCount() { return (UINT)1;}
  155. virtual HRESULT BeginTransaction()
  156. {
  157. return GetTransaction()->Begin(m_pCookie,
  158. GetDestPath(), GetDestClass(), IsDestContainer());
  159. }
  160. virtual void GetNewPath(UINT, CString& szNewPath)
  161. {
  162. GetComponentData()->GetBasePathsInfo()->ComposeADsIPath(szNewPath, m_pCookie->GetPath());
  163. }
  164. virtual void GetName(UINT, CString& strref)
  165. {
  166. strref = m_pCookie->GetName();
  167. return;
  168. }
  169. virtual void GetItemPath(UINT, CString& szPath)
  170. {
  171. szPath = m_pCookie->GetPath();
  172. }
  173. virtual PCWSTR GetItemClass(UINT)
  174. {
  175. return m_pCookie->GetClass();
  176. }
  177. virtual HRESULT OnItemMoved(UINT, IADs* pIADs)
  178. {
  179. CComBSTR bsPath;
  180. HRESULT hr = pIADs->get_ADsPath(&bsPath);
  181. if (SUCCEEDED(hr))
  182. {
  183. CString szPath;
  184. StripADsIPath(bsPath, szPath);
  185. m_pCookie->SetPath(szPath);
  186. }
  187. return hr;
  188. }
  189. virtual void GetClassOfMovedItem(CString& szClass)
  190. {
  191. szClass.Empty();
  192. if (NULL != m_pCookie)
  193. szClass = m_pCookie->GetClass();
  194. }
  195. private:
  196. CDSCookie* m_pCookie;
  197. };
  198. HRESULT
  199. CDSDirect::MoveObject(CDSCookie *pCookie)
  200. {
  201. HWND hwnd;
  202. m_pCD->m_pFrame->GetMainWindow(&hwnd);
  203. HRESULT hr = S_OK;
  204. CString strPartialRootPath = m_pCD->GetRootPath();
  205. if (SNAPINTYPE_SITE == m_pCD->QuerySnapinType())
  206. {
  207. // This is where we correct the root path
  208. CPathCracker pathCracker;
  209. hr = pathCracker.Set(const_cast<BSTR>((LPCTSTR)strPartialRootPath), ADS_SETTYPE_DN);
  210. ASSERT( SUCCEEDED(hr) );
  211. long cRootPathElements = 0;
  212. hr = pathCracker.GetNumElements( &cRootPathElements );
  213. ASSERT( SUCCEEDED(hr) );
  214. CComBSTR bstr = pCookie->GetPath();
  215. hr = pathCracker.Set(bstr, ADS_SETTYPE_DN);
  216. ASSERT( SUCCEEDED(hr) );
  217. long cCookiePathElements = 0;
  218. hr = pathCracker.GetNumElements( &cCookiePathElements );
  219. ASSERT( SUCCEEDED(hr) );
  220. //
  221. // Strip off all but one path element past the base config path
  222. //
  223. for (INT i = cCookiePathElements - cRootPathElements; i > 1; i--)
  224. {
  225. hr = pathCracker.RemoveLeafElement();
  226. ASSERT( SUCCEEDED(hr) );
  227. }
  228. hr = pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
  229. ASSERT( SUCCEEDED(hr) );
  230. hr = pathCracker.Retrieve( ADS_FORMAT_X500_DN, &bstr );
  231. ASSERT( SUCCEEDED(hr) && bstr != NULL );
  232. strPartialRootPath = bstr;
  233. }
  234. CString strRootPath = m_pCD->GetBasePathsInfo()->GetProviderAndServerName();
  235. strRootPath += strPartialRootPath;
  236. CSnapinMoveHandler moveHandler(m_pCD, hwnd, strRootPath, pCookie);
  237. return moveHandler.Move();
  238. }
  239. HRESULT CDSDirect::RenameObject(CDSCookie* pCookie, LPCWSTR NewName)
  240. {
  241. HRESULT hr = S_OK;
  242. IADs * pDSObject = NULL;
  243. IDispatch * pDispObj = NULL;
  244. IADsContainer * pContainer = NULL;
  245. CComBSTR bsParentPath;
  246. CString szNewAttrName;
  247. CString szNewNamingContext;
  248. CString szClass;
  249. CString szObjectPath, szNewPath;
  250. CString csNewName;
  251. CString szPath;
  252. CDSClassCacheItemBase* pItem = NULL;
  253. CComBSTR bsEscapedName;
  254. CPathCracker pathCracker;
  255. HWND hwnd;
  256. m_pCD->m_pFrame->GetMainWindow(&hwnd);
  257. //
  258. // create a transaction object, the destructor will call End() on it
  259. //
  260. CDSNotifyHandlerTransaction transaction(m_pCD);
  261. transaction.SetEventType(DSA_NOTIFY_REN);
  262. if (pCookie == NULL)
  263. {
  264. return E_INVALIDARG;
  265. }
  266. //
  267. // Retrieve class info from cache
  268. //
  269. szClass = pCookie->GetClass();
  270. BOOL found = m_pCD->m_pClassCache->Lookup ((LPCWSTR)szClass, pItem);
  271. ASSERT (found == TRUE);
  272. csNewName = NewName;
  273. csNewName.TrimLeft();
  274. csNewName.TrimRight();
  275. //
  276. // get the new name in the form "cn=foo" or "ou=foo"
  277. //
  278. szNewAttrName = pItem->GetNamingAttribute();
  279. szNewAttrName += L"=";
  280. szNewAttrName += csNewName;
  281. TRACE(_T("_RenameObject: Attributed name is %s.\n"), szNewAttrName);
  282. //
  283. // bind to object
  284. //
  285. m_pCD->GetBasePathsInfo()->ComposeADsIPath(szObjectPath, pCookie->GetPath());
  286. hr = DSAdminOpenObject(szObjectPath,
  287. IID_IADs,
  288. (void **)&pDSObject,
  289. TRUE /*bServer*/);
  290. if (!SUCCEEDED(hr))
  291. {
  292. goto error;
  293. }
  294. //
  295. // get the path of the object container
  296. //
  297. hr = pDSObject->get_Parent (&bsParentPath);
  298. if (!SUCCEEDED(hr))
  299. {
  300. goto error;
  301. }
  302. pDSObject->Release();
  303. pDSObject = NULL;
  304. //
  305. // bind to the object container
  306. //
  307. hr = DSAdminOpenObject(bsParentPath,
  308. IID_IADsContainer,
  309. (void **)&pContainer,
  310. TRUE /*bServer*/);
  311. if (!SUCCEEDED(hr))
  312. {
  313. goto error;
  314. }
  315. //
  316. // build the new LDAP path
  317. //
  318. szNewNamingContext = szNewAttrName;
  319. szNewNamingContext += L",";
  320. StripADsIPath(bsParentPath, szPath);
  321. szNewNamingContext += szPath;
  322. m_pCD->GetBasePathsInfo()->ComposeADsIPath(szNewPath, szNewNamingContext);
  323. //
  324. // start the transaction
  325. //
  326. // It's ok for containerness to be determined from the cookie since we are concerned
  327. // whether the DS object is a container not whether it is a container in the UI
  328. //
  329. hr = transaction.Begin(pCookie, szNewPath, szClass, pCookie->IsContainerClass());
  330. //
  331. // ask for confirmation
  332. //
  333. if (transaction.NeedNotifyCount() > 0)
  334. {
  335. CString szMessage, szAssocData;
  336. szMessage.LoadString(IDS_CONFIRM_RENAME);
  337. szAssocData.LoadString(IDS_EXTENS_RENAME);
  338. CThemeContextActivator activator;
  339. CConfirmOperationDialog dlg(hwnd, &transaction);
  340. dlg.SetStrings(szMessage, szAssocData);
  341. if (IDNO == dlg.DoModal())
  342. {
  343. transaction.End();
  344. hr = S_OK;
  345. goto error;
  346. }
  347. }
  348. hr = pathCracker.GetEscapedElement(0, //reserved
  349. (BSTR)(LPCWSTR)szNewAttrName,
  350. &bsEscapedName);
  351. if (FAILED(hr))
  352. {
  353. goto error;
  354. }
  355. //
  356. // do the actual rename
  357. //
  358. hr = pContainer->MoveHere(CComBSTR(szObjectPath),
  359. CComBSTR(bsEscapedName),
  360. &pDispObj);
  361. if (SUCCEEDED(hr))
  362. {
  363. transaction.Notify(0); // let extensions know
  364. }
  365. else
  366. {
  367. TRACE(_T("Object Rename Failed with hr: %lx\n"), hr);
  368. goto error;
  369. }
  370. //
  371. // rebuild the naming info for the cookie
  372. //
  373. hr = pDispObj->QueryInterface (IID_IADs,
  374. (void **)&pDSObject);
  375. if (SUCCEEDED(hr))
  376. {
  377. CComBSTR bsPath;
  378. hr = pDSObject->get_ADsPath(&bsPath);
  379. if (SUCCEEDED(hr))
  380. {
  381. StripADsIPath(bsPath, szPath);
  382. pCookie->SetPath(szPath);
  383. //
  384. // remove escaping from name
  385. //
  386. hr = pathCracker.Set((LPWSTR)bsPath, ADS_SETTYPE_FULL);
  387. ASSERT(SUCCEEDED(hr));
  388. hr = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  389. ASSERT(SUCCEEDED(hr));
  390. hr = pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_OFF_EX);
  391. ASSERT(SUCCEEDED(hr));
  392. hr = pathCracker.GetElement( 0, &bsPath );
  393. ASSERT(SUCCEEDED(hr));
  394. pCookie->SetName((LPWSTR)bsPath);
  395. }
  396. }
  397. error:
  398. //
  399. // transaction.End() will be called by the transaction's destructor
  400. //
  401. //
  402. // clear pointers
  403. //
  404. if (pDispObj)
  405. {
  406. pDispObj->Release();
  407. }
  408. if (pDSObject)
  409. {
  410. pDSObject->Release();
  411. }
  412. return hr;
  413. }
  414. CDSComponentData* g_pCD = NULL;
  415. HRESULT
  416. CDSDirect::DSFind(HWND hwnd, LPCWSTR lpszBaseDN)
  417. {
  418. HRESULT hr;
  419. DSQUERYINITPARAMS dqip;
  420. OPENQUERYWINDOW oqw;
  421. ZeroMemory(&dqip, sizeof(DSQUERYINITPARAMS));
  422. ZeroMemory(&oqw, sizeof(OPENQUERYWINDOW));
  423. ICommonQuery * pCommonQuery = NULL;
  424. IDataObject * pDataObject = NULL;
  425. hr = CoCreateInstance(CLSID_CommonQuery, NULL, CLSCTX_INPROC_SERVER,
  426. IID_ICommonQuery, (PVOID *)&pCommonQuery);
  427. if (!SUCCEEDED(hr)) {
  428. ReportErrorEx( (m_pCD) ? m_pCD->m_hwnd : NULL, IDS_1_CANT_CREATE_FIND,
  429. hr, MB_OK | MB_ICONERROR, NULL, 0, FALSE);
  430. return hr;
  431. }
  432. CString szPath;
  433. m_pCD->GetBasePathsInfo()->ComposeADsIPath(szPath, lpszBaseDN);
  434. LPWSTR pszDefPath = (LPWSTR)(LPCWSTR)szPath;
  435. dqip.cbStruct = sizeof(dqip);
  436. dqip.dwFlags = DSQPF_NOSAVE | DSQPF_SHOWHIDDENOBJECTS |
  437. DSQPF_ENABLEADMINFEATURES;
  438. if (m_pCD->IsAdvancedView()) {
  439. dqip.dwFlags |= DSQPF_ENABLEADVANCEDFEATURES;
  440. }
  441. dqip.pDefaultScope = pszDefPath;
  442. dqip.pUserName = NULL;
  443. dqip.pPassword = NULL;
  444. dqip.pServer = (LPWSTR)(m_pCD->GetBasePathsInfo()->GetServerName());
  445. dqip.dwFlags |= DSQPF_HASCREDENTIALS;
  446. oqw.cbStruct = sizeof(oqw);
  447. oqw.dwFlags = OQWF_SHOWOPTIONAL;
  448. oqw.clsidHandler = CLSID_DsQuery;
  449. oqw.pHandlerParameters = &dqip;
  450. // oqw.clsidDefaultForm = CLSID_NULL;
  451. g_pCD = m_pCD;
  452. HWND hwndHidden = m_pCD->GetHiddenWindow();
  453. SetWindowText(hwndHidden,L"DS Find");
  454. hr = pCommonQuery->OpenQueryWindow(hwnd, &oqw, &pDataObject);
  455. SetWindowText(hwndHidden, NULL);
  456. g_pCD = NULL;
  457. if (FAILED(hr)) {
  458. ReportErrorEx( m_pCD->m_hwnd, IDS_1_FIND_ERROR,
  459. hr, MB_OK | MB_ICONERROR, NULL, 0);
  460. }
  461. pCommonQuery->Release();
  462. if (pDataObject) {
  463. pDataObject->Release();
  464. }
  465. return hr;
  466. }
  467. HRESULT CDSDirect::EnumerateContainer(CDSThreadQueryInfo* pQueryInfo,
  468. CWorkerThread* pWorkerThread)
  469. {
  470. ASSERT(!pQueryInfo->m_bTooMuchData);
  471. ASSERT((pQueryInfo->GetType() == dsFolder) || (pQueryInfo->GetType() == queryFolder));
  472. BEGIN_PROFILING_BLOCK("CDSDirect::EnumerateContainer");
  473. HRESULT hr = S_OK;
  474. CString ADsPath;
  475. UINT nCurrCount = 0;
  476. UINT nMaxCount = pQueryInfo->GetMaxItemCount();
  477. BOOL bOverLimit = FALSE;
  478. //
  479. // This wouldn't normally be the way to use the CPathCracker object
  480. // but for performance reasons we are going to create a single instance
  481. // for enumerating and pass a reference to the SetCookieFromData so
  482. // that we don't do a CoCreateInstance for each cookie
  483. //
  484. CPathCracker specialPerformancePathCracker;
  485. m_pCD->GetBasePathsInfo()->ComposeADsIPath(ADsPath, pQueryInfo->GetPath());
  486. CDSSearch ContainerSrch(m_pCD->m_pClassCache, m_pCD);
  487. CDSColumnSet* pColumnSet = NULL;
  488. CString szPath;
  489. szPath = pQueryInfo->GetPath();
  490. CPathCracker pathCracker;
  491. hr = pathCracker.Set(const_cast<BSTR>((LPCTSTR)szPath), ADS_SETTYPE_DN);
  492. if (SUCCEEDED(hr))
  493. {
  494. CComBSTR bstrLeaf;
  495. hr = pathCracker.GetElement(0, &bstrLeaf);
  496. if (SUCCEEDED(hr))
  497. {
  498. szPath = bstrLeaf;
  499. }
  500. }
  501. if (szPath.Find(_T("ForeignSecurityPrincipals")) != -1)
  502. {
  503. pColumnSet = m_pCD->FindColumnSet(L"ForeignSecurityPrincipals");
  504. }
  505. else
  506. {
  507. pColumnSet = m_pCD->FindColumnSet(pQueryInfo->GetColumnSetID());
  508. }
  509. ASSERT(pColumnSet != NULL);
  510. hr = ContainerSrch.Init (ADsPath);
  511. if (!SUCCEEDED(hr))
  512. {
  513. TRACE(L"!!!search object init failed\n");
  514. ASSERT(FALSE);
  515. goto exiting;
  516. }
  517. // CODEWORK this redoes the GetColumnsForClass calculation
  518. ContainerSrch.SetAttributeListForContainerClass (pColumnSet);
  519. ContainerSrch.SetFilterString ((LPWSTR)pQueryInfo->GetQueryString());
  520. ContainerSrch.SetSearchScope(pQueryInfo->IsOneLevel() ? ADS_SCOPE_ONELEVEL : ADS_SCOPE_SUBTREE);
  521. hr = ContainerSrch.DoQuery();
  522. if (FAILED(hr))
  523. {
  524. TRACE(L"!!!search object DoQuery failed\n");
  525. ASSERT(FALSE);
  526. goto exiting;
  527. }
  528. hr = ContainerSrch.GetNextRow ();
  529. while ((hr == S_OK) && !bOverLimit ) {
  530. CDSCookie* pNewCookie = new CDSCookie();
  531. HRESULT hr2 = ContainerSrch.SetCookieFromData(pNewCookie,
  532. specialPerformancePathCracker,
  533. pColumnSet);
  534. if (SUCCEEDED(hr2)) {
  535. CDSUINode* pDSUINode = new CDSUINode(NULL);
  536. pDSUINode->SetCookie(pNewCookie);
  537. if (pQueryInfo->GetType() == dsFolder)
  538. {
  539. if (pNewCookie->IsContainerClass())
  540. pDSUINode->MakeContainer();
  541. }
  542. pWorkerThread->AddToQueryResult(pDSUINode);
  543. if (pWorkerThread->MustQuit())
  544. break;
  545. } else {
  546. TRACE(L"!!!SetCookieFromData failed\n");
  547. // NTRAID#NTBUG9-546301-2002/03/29-JeffJon-Do not ASSERT
  548. // here because SetCookieFromData will return a failure
  549. // code if we want to ignore a cookie. This happens when
  550. // there are inter-trust accounts or some group types associated
  551. // with the security roles
  552. //ASSERT(FALSE);
  553. delete pNewCookie;
  554. }
  555. hr = ContainerSrch.GetNextRow();
  556. if (hr == S_OK) {
  557. nCurrCount++;
  558. if (nCurrCount >= nMaxCount)
  559. bOverLimit = TRUE;
  560. }
  561. }
  562. pQueryInfo->m_bTooMuchData = bOverLimit;
  563. exiting:
  564. END_PROFILING_BLOCK;
  565. return hr;
  566. }
  567. HRESULT CDSDirect::EnumerateRootContainer(CDSThreadQueryInfo* pQueryInfo,
  568. CWorkerThread* pWorkerThread)
  569. {
  570. ASSERT(pQueryInfo->GetType() == rootFolder);
  571. HRESULT hr = S_OK;
  572. m_pCD->Lock();
  573. //
  574. // build the nodes below the root
  575. //
  576. if (m_pCD->QuerySnapinType() == SNAPINTYPE_SITE)
  577. {
  578. hr = CreateRootChild(TEXT("CN=Sites,"), pQueryInfo, pWorkerThread);
  579. if (!pWorkerThread->MustQuit() && m_pCD->ViewServicesNode())
  580. {
  581. hr = CreateRootChild(TEXT("CN=Services,"), pQueryInfo, pWorkerThread);
  582. }
  583. }
  584. else
  585. {
  586. hr = CreateRootChild(TEXT(""), pQueryInfo, pWorkerThread);
  587. }
  588. if (m_pCD->m_CreateInfo.IsEmpty())
  589. {
  590. InitCreateInfo();
  591. }
  592. m_pCD->Unlock();
  593. return hr;
  594. }
  595. HRESULT CDSDirect::CreateRootChild(LPCTSTR lpcszPrefix,
  596. CDSThreadQueryInfo* pQueryInfo,
  597. CWorkerThread* pWorkerThread)
  598. {
  599. TRACE(L"CDSDirect::CreateRootChild(%s)\n", lpcszPrefix);
  600. TRACE(L"pQueryInfo->GetPath() = %s\n", pQueryInfo->GetPath());
  601. CString BasePath = lpcszPrefix;
  602. BasePath += pQueryInfo->GetPath();
  603. CString ADsPath;
  604. m_pCD->GetBasePathsInfo()->ComposeADsIPath(OUT ADsPath, IN BasePath);
  605. // create a search object and bind to it
  606. CDSSearch Search(m_pCD->m_pClassCache, m_pCD);
  607. HRESULT hr = Search.Init(ADsPath);
  608. TRACE(L"Search.Init(%s) returned hr = 0x%x\n", (LPCWSTR)ADsPath, hr);
  609. if (FAILED(hr))
  610. {
  611. return hr;
  612. }
  613. //
  614. // set query parameters
  615. //
  616. // Search for just this object
  617. //
  618. Search.SetSearchScope(ADS_SCOPE_BASE);
  619. CUIFolderInfo* pFolderInfo = m_pCD->GetRootNode()->GetFolderInfo();
  620. if (pFolderInfo == NULL)
  621. {
  622. //
  623. // This shouldn't happen, but just to be on the safe side...
  624. //
  625. ASSERT(FALSE);
  626. Search.SetAttributeList((LPWSTR *)g_pStandardAttributes,
  627. g_nStdCols);
  628. }
  629. else
  630. {
  631. CDSColumnSet* pColumnSet = m_pCD->GetRootNode()->GetColumnSet(m_pCD);
  632. Search.SetAttributeListForContainerClass(pColumnSet);
  633. }
  634. Search.SetFilterString (L"(objectClass=*)");
  635. // execute the query
  636. hr = Search.DoQuery();
  637. TRACE(L"Search.DoQuery() returned hr = 0x%x\n", hr);
  638. if (FAILED(hr))
  639. {
  640. return hr;
  641. }
  642. TRACE(L"Search.GetNextRow() returned hr = 0x%x\n", hr);
  643. hr = Search.GetNextRow();
  644. if (FAILED(hr))
  645. {
  646. return hr;
  647. }
  648. //
  649. // we got a query result, create a new cookie object
  650. // and initialize it from the query result
  651. //
  652. CDSCookie* pNewCookie = new CDSCookie;
  653. Search.SetCookieFromData(pNewCookie,NULL);
  654. TRACE(L"Got cookie, pNewCookie->GetName() = %s\n", pNewCookie->GetName());
  655. //
  656. // special case if it is a domain DNS object,
  657. // we want fo get the canonical name for display
  658. //
  659. if (wcscmp(pNewCookie->GetClass(), L"domainDNS") == 0)
  660. {
  661. ADS_SEARCH_COLUMN Column;
  662. CString csCanonicalName;
  663. int slashLocation;
  664. LPWSTR canonicalNameAttrib = L"canonicalName";
  665. Search.SetAttributeList (&canonicalNameAttrib, 1);
  666. hr = Search.DoQuery();
  667. if (FAILED(hr))
  668. {
  669. return hr;
  670. }
  671. hr = Search.GetNextRow();
  672. if (FAILED(hr))
  673. {
  674. return hr;
  675. }
  676. hr = Search.GetColumn(canonicalNameAttrib, &Column);
  677. if (FAILED(hr))
  678. {
  679. return hr;
  680. }
  681. ColumnExtractString (csCanonicalName, pNewCookie, &Column);
  682. slashLocation = csCanonicalName.Find('/');
  683. if (slashLocation != 0)
  684. {
  685. csCanonicalName = csCanonicalName.Left(slashLocation);
  686. }
  687. //
  688. pNewCookie->SetName(csCanonicalName);
  689. TRACE(L"canonical name pNewCookie->GetName() = %s\n", pNewCookie->GetName());
  690. //
  691. // Free column data
  692. //
  693. Search.FreeColumn(&Column);
  694. }
  695. //
  696. // Add the new node to the result list
  697. CDSUINode* pDSUINode = new CDSUINode(NULL);
  698. pDSUINode->SetCookie(pNewCookie);
  699. if (pNewCookie->IsContainerClass())
  700. pDSUINode->MakeContainer();
  701. pWorkerThread->AddToQueryResult(pDSUINode);
  702. return S_OK;
  703. }
  704. //+----------------------------------------------------------------------------
  705. //
  706. // Method: CDSDirect::InitCreateInfo
  707. //
  708. // Synopsis: read schema and finds all object names that for whom
  709. // defaultHidingValue is TRUE;
  710. //
  711. //-----------------------------------------------------------------------------
  712. HRESULT CDSDirect::InitCreateInfo(void)
  713. {
  714. HRESULT hr = S_OK;
  715. LPWSTR pAttrs[2] = {L"name",
  716. L"lDAPDisplayName"};
  717. CDSSearch Search (m_pCD->GetClassCache(), m_pCD);
  718. ADS_SEARCH_COLUMN Column;
  719. CString csFilter;
  720. CString szSchemaPath;
  721. m_pCD->GetBasePathsInfo()->GetSchemaPath(szSchemaPath);
  722. Search.Init (szSchemaPath);
  723. csFilter = L"(&(objectCategory=CN=Class-Schema,";
  724. csFilter += m_pCD->GetBasePathsInfo()->GetSchemaNamingContext();
  725. csFilter += L")(defaultHidingValue=FALSE))";
  726. Search.SetFilterString((LPWSTR)(LPCWSTR)csFilter);
  727. Search.SetAttributeList (pAttrs, 2);
  728. Search.SetSearchScope(ADS_SCOPE_ONELEVEL);
  729. hr = Search.DoQuery();
  730. if (SUCCEEDED(hr))
  731. {
  732. hr = Search.GetNextRow();
  733. if(FAILED(hr))
  734. {
  735. TRACE(_T("Search::GetNextRow failed \n"));
  736. goto error;
  737. }
  738. while (hr == S_OK)
  739. {
  740. hr = Search.GetColumn (pAttrs[1], &Column);
  741. if (SUCCEEDED(hr))
  742. {
  743. if (!((!wcscmp(Column.pADsValues->CaseIgnoreString, L"builtinDomain")) ||
  744. (!wcscmp(Column.pADsValues->CaseIgnoreString, L"localGroup")) ||
  745. (!wcscmp(Column.pADsValues->CaseIgnoreString, L"domainDNS")) ||
  746. (!wcscmp(Column.pADsValues->CaseIgnoreString, L"domain")) ||
  747. (!wcscmp(Column.pADsValues->CaseIgnoreString, L"organization")) ||
  748. (!wcscmp(Column.pADsValues->CaseIgnoreString, L"locality"))))
  749. {
  750. m_pCD->m_CreateInfo.AddTail (Column.pADsValues->CaseIgnoreString);
  751. TRACE(_T("added to createinfo: %s\n"),
  752. Column.pADsValues->CaseIgnoreString);
  753. }
  754. Search.FreeColumn (&Column);
  755. }
  756. else
  757. {
  758. goto error;
  759. }
  760. hr = Search.GetNextRow();
  761. }
  762. }
  763. error:
  764. if (m_pCD->m_CreateInfo.IsEmpty())
  765. {
  766. ReportErrorEx (m_pCD->m_hwnd,IDS_1_CANT_GET_SCHEMA_CREATE_INFO,hr,
  767. MB_OK | MB_ICONERROR, NULL, 0);
  768. }
  769. return hr;
  770. }
  771. HRESULT CDSDirect::ReadDSObjectCookie(IN CDSUINode* pContainerDSUINode, // IN: container where to create object
  772. IN LPCWSTR lpszLdapPath, // path of the object
  773. OUT CDSCookie** ppNewCookie) // newly created cookie
  774. {
  775. CComPtr<IADs> spADs;
  776. HRESULT hr = DSAdminOpenObject(lpszLdapPath,
  777. IN IID_IADs,
  778. OUT (LPVOID *) &spADs,
  779. TRUE /*bServer*/);
  780. if (FAILED(hr))
  781. {
  782. return hr;
  783. }
  784. return ReadDSObjectCookie(pContainerDSUINode, spADs, ppNewCookie);
  785. }
  786. HRESULT CDSDirect::ReadDSObjectCookie(IN CDSUINode* pContainerDSUINode, // IN: container where to create object
  787. IN IADs* pADs, // pointer to an already bound ADSI object
  788. OUT CDSCookie** ppNewCookie) // newly created cookie
  789. {
  790. ASSERT(pContainerDSUINode != NULL);
  791. ASSERT(pContainerDSUINode->IsContainer());
  792. ASSERT(pADs != NULL);
  793. ASSERT(ppNewCookie != NULL);
  794. // create a new cookie and load data from the DS
  795. CDSCookie * pDsCookieNew = new CDSCookie();
  796. CComPtr<IDirectorySearch> spDirSearch;
  797. CDSColumnSet* pColumnSet = pContainerDSUINode->GetColumnSet(m_pCD);
  798. ASSERT(pColumnSet != NULL);
  799. HRESULT hr = pADs->QueryInterface (IID_IDirectorySearch, (void **)&spDirSearch);
  800. ASSERT (hr == S_OK);
  801. CDSSearch Search(m_pCD->GetClassCache(), m_pCD);
  802. Search.Init(spDirSearch);
  803. Search.SetSearchScope(ADS_SCOPE_BASE);
  804. Search.SetAttributeListForContainerClass(pColumnSet);
  805. Search.SetFilterString (L"(objectClass=*)");
  806. Search.DoQuery();
  807. hr = Search.GetNextRow();
  808. if (SUCCEEDED(hr) && (hr != S_ADS_NOMORE_ROWS))
  809. {
  810. // we got the data, set the cookie
  811. Search.SetCookieFromData(pDsCookieNew, pColumnSet);
  812. *ppNewCookie = pDsCookieNew;
  813. pDsCookieNew = NULL;
  814. }
  815. if (pDsCookieNew != NULL)
  816. {
  817. delete pDsCookieNew;
  818. }
  819. return hr;
  820. }
  821. /////////////////////////////////////////////////////////////////////
  822. // CDSDirect::CreateDSObject()
  823. //
  824. // Create a new ADs object.
  825. //
  826. HRESULT CDSDirect::CreateDSObject(CDSUINode* pContainerDSUINode, // IN: container where to create object
  827. LPCWSTR lpszObjectClass, // IN: class of the object to be created
  828. IN CDSUINode* pCopyFromDSUINode, // IN: (optional) object to be copied
  829. OUT CDSCookie** ppSUINodeNew) // OUT: OPTIONAL: Pointer to new node
  830. {
  831. CThemeContextActivator activator;
  832. ASSERT(pContainerDSUINode != NULL);
  833. ASSERT(pContainerDSUINode->IsContainer());
  834. ASSERT(lpszObjectClass != NULL);
  835. ASSERT(ppSUINodeNew != NULL);
  836. CDSCookie* pContainerDsCookie = pContainerDSUINode->GetCookie();
  837. ASSERT(pContainerDsCookie != NULL);
  838. CComPtr<IADsContainer> spIADsContainer;
  839. IADs* pIADs = NULL;
  840. CDSClassCacheItemBase* pDsCacheItem = NULL;
  841. HRESULT hr;
  842. // Data structure to hold temporary attribute information to create object
  843. CNewADsObjectCreateInfo createinfo(m_pCD->GetBasePathsInfo(), lpszObjectClass);
  844. {
  845. CWaitCursor wait;
  846. CString strContainerADsIPath;
  847. m_pCD->GetBasePathsInfo()->ComposeADsIPath(strContainerADsIPath, pContainerDsCookie->GetPath());
  848. hr = DSAdminOpenObject(strContainerADsIPath,
  849. IN IID_IADsContainer,
  850. OUT (LPVOID *) &spIADsContainer,
  851. TRUE /*bServer*/);
  852. if (FAILED(hr))
  853. {
  854. PVOID apv[1] = {(LPWSTR)pContainerDsCookie->GetName()};
  855. ReportErrorEx (m_pCD->m_hwnd,IDS_12_CONTAINER_NOT_FOUND,hr,
  856. MB_OK | MB_ICONERROR, apv, 1);
  857. hr = S_FALSE; // Avoid display another error message to user
  858. goto CleanUp;
  859. }
  860. // Lookup if the object classname is in the cache
  861. pDsCacheItem = m_pCD->GetClassCache()->FindClassCacheItem(m_pCD, lpszObjectClass, NULL);
  862. ASSERT(pDsCacheItem != NULL);
  863. }
  864. createinfo.SetContainerInfo(IN spIADsContainer, IN pDsCacheItem, IN m_pCD);
  865. if (pCopyFromDSUINode != NULL)
  866. {
  867. CDSCookie* pCopyFromDsCookie = pCopyFromDSUINode->GetCookie();
  868. CComPtr<IADs> spIADsCopyFrom;
  869. CString szPath;
  870. m_pCD->GetBasePathsInfo()->ComposeADsIPath(szPath, pCopyFromDsCookie->GetPath());
  871. hr = createinfo.SetCopyInfo(szPath);
  872. if (FAILED(hr))
  873. {
  874. PVOID apv[1] = {(LPWSTR)pCopyFromDsCookie->GetName()};
  875. ReportErrorEx (m_pCD->m_hwnd,IDS_12_COPY_READ_FAILED,hr,
  876. MB_OK | MB_ICONERROR, apv, 1);
  877. hr = S_FALSE; // Avoid display another error message to user
  878. goto CleanUp;
  879. }
  880. }
  881. hr = createinfo.HrLoadCreationInfo();
  882. if (FAILED(hr))
  883. {
  884. goto CleanUp;
  885. }
  886. // launch the creation DS object creation wizard
  887. hr = createinfo.HrDoModal(m_pCD->m_hwnd);
  888. // now examine the results of the call
  889. pIADs = createinfo.PGetIADsPtr();
  890. if (hr != S_OK)
  891. {
  892. // Object was not created because user hit "Cancel" or an error occured.
  893. goto CleanUp;
  894. }
  895. if (pIADs == NULL)
  896. {
  897. TRACE0("ERROR: Inconsistency between return value from HrDoModal() and IADs pointer.\n");
  898. ReportErrorEx (m_pCD->m_hwnd,IDS_ERR_FATAL,S_OK,
  899. MB_OK | MB_ICONERROR, NULL, 0);
  900. hr = S_FALSE; // Avoid display another error message to user
  901. goto CleanUp;
  902. }
  903. // successful creation, we need to create a node object for the UI
  904. if (pContainerDSUINode->GetFolderInfo()->IsExpanded())
  905. {
  906. ReadDSObjectCookie(pContainerDSUINode, pIADs, ppSUINodeNew);
  907. } // if expanded
  908. CleanUp:
  909. if (FAILED(hr))
  910. {
  911. CString Name;
  912. Name = createinfo.GetName();
  913. PVOID apv[1] = {(LPWSTR)(LPCWSTR)Name};
  914. ReportErrorEx (m_pCD->m_hwnd,IDS_12_GENERIC_CREATION_FAILURE,hr,
  915. MB_OK | MB_ICONERROR, apv, 1);
  916. }
  917. if (pIADs != NULL)
  918. pIADs->Release();
  919. return hr;
  920. }