Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1000 lines
31 KiB

  1. #include "pch.h"
  2. #include "lm.h" // NET_API_STATUS
  3. #include <dsgetdc.h> // DsEnumerateDomainTrusts
  4. #include <subauth.h>
  5. #include <ntlsa.h> // TRUST_TYPE_XXX
  6. #pragma hdrstop
  7. /*-----------------------------------------------------------------------------
  8. / Misc data
  9. /----------------------------------------------------------------------------*/
  10. //
  11. // Globally cached domain list, this is cached an free'd as required
  12. //
  13. PDOMAIN_TREE g_pDomainTree = NULL;
  14. DWORD g_dwFlags = 0;
  15. //
  16. // CDsBrowseDomainTree
  17. //
  18. class CDsDomainTreeBrowser : public IDsBrowseDomainTree
  19. {
  20. private:
  21. STDMETHODIMP _GetDomains(PDOMAIN_TREE *ppDomainTree, DWORD dwFlags);
  22. LONG _cRef;
  23. LPWSTR _pComputerName;
  24. LPWSTR _pUserName;
  25. LPWSTR _pPassword;
  26. LPDOMAINTREE _pDomainTree;
  27. DWORD _dwFlags;
  28. public:
  29. CDsDomainTreeBrowser();
  30. ~CDsDomainTreeBrowser();
  31. // IUnknown members
  32. STDMETHODIMP_(ULONG) AddRef();
  33. STDMETHODIMP_(ULONG) Release();
  34. STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObject);
  35. // IDsBrowseDomainTree
  36. STDMETHODIMP BrowseTo(HWND hwndParent, LPWSTR *ppszTargetPath, DWORD dwFlags);
  37. STDMETHODIMP GetDomains(PDOMAIN_TREE *ppDomainTree, DWORD dwFlags);
  38. STDMETHODIMP FreeDomains(PDOMAIN_TREE* ppDomainTree);
  39. STDMETHODIMP FlushCachedDomains();
  40. STDMETHODIMP SetComputer(LPCWSTR pComputerName, LPCWSTR pUserName, LPCWSTR pPassword);
  41. };
  42. CDsDomainTreeBrowser::CDsDomainTreeBrowser() :
  43. _cRef(1),
  44. _pComputerName(NULL),
  45. _pUserName(NULL),
  46. _pPassword(NULL),
  47. _pDomainTree(NULL),
  48. _dwFlags(0)
  49. {
  50. DllAddRef();
  51. }
  52. CDsDomainTreeBrowser::~CDsDomainTreeBrowser()
  53. {
  54. FreeDomains(&_pDomainTree);
  55. LocalFreeStringW(&_pComputerName);
  56. LocalFreeStringW(&_pUserName);
  57. LocalFreeStringW(&_pPassword);
  58. DllRelease();
  59. }
  60. // IUnknown
  61. ULONG CDsDomainTreeBrowser::AddRef()
  62. {
  63. return InterlockedIncrement(&_cRef);
  64. }
  65. ULONG CDsDomainTreeBrowser::Release()
  66. {
  67. if (InterlockedDecrement(&_cRef))
  68. return _cRef;
  69. delete this;
  70. return 0;
  71. }
  72. HRESULT CDsDomainTreeBrowser::QueryInterface(REFIID riid, void **ppv)
  73. {
  74. static const QITAB qit[] =
  75. {
  76. QITABENT(CDsDomainTreeBrowser, IDsBrowseDomainTree), // IID_IID_IDsBrowseDomainTree
  77. {0, 0 },
  78. };
  79. return QISearch(this, qit, riid, ppv);
  80. }
  81. //
  82. // handle create instance
  83. //
  84. STDAPI CDsDomainTreeBrowser_CreateInstance(IUnknown* punkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  85. {
  86. CDsDomainTreeBrowser *pddtb = new CDsDomainTreeBrowser();
  87. if ( !pddtb )
  88. return E_OUTOFMEMORY;
  89. HRESULT hres = pddtb->QueryInterface(IID_IUnknown, (void **)ppunk);
  90. pddtb->Release();
  91. return hres;
  92. }
  93. //---------------------------------------------------------------------------//
  94. // IDsBrowseDomainTree
  95. //---------------------------------------------------------------------------//
  96. STDMETHODIMP CDsDomainTreeBrowser::SetComputer(LPCWSTR pComputerName, LPCWSTR pUserName, LPCWSTR pPassword)
  97. {
  98. HRESULT hres;
  99. TraceEnter(TRACE_DOMAIN, "CDsDomainTreeBrowser::SetComputer");
  100. LocalFreeStringW(&_pComputerName);
  101. LocalFreeStringW(&_pUserName);
  102. LocalFreeStringW(&_pPassword);
  103. hres = LocalAllocStringW(&_pComputerName, pComputerName);
  104. if ( SUCCEEDED(hres) )
  105. hres = LocalAllocStringW(&_pUserName, pUserName);
  106. if ( SUCCEEDED(hres) )
  107. hres = LocalAllocStringW(&_pPassword, pPassword);
  108. if ( FAILED(hres) )
  109. {
  110. LocalFreeStringW(&_pComputerName);
  111. LocalFreeStringW(&_pUserName);
  112. LocalFreeStringW(&_pPassword);
  113. }
  114. TraceLeaveResult(hres);
  115. }
  116. //---------------------------------------------------------------------------//
  117. #define BROWSE_CTX_HELP_FILE _T("dsadmin.hlp")
  118. #define IDH_DOMAIN_TREE 300000800
  119. const DWORD aBrowseHelpIDs[] =
  120. {
  121. IDC_DOMAIN_TREE,IDH_DOMAIN_TREE,
  122. 0, 0
  123. };
  124. struct DIALOG_STUFF
  125. {
  126. LPWSTR pszName; // domain name (if no dns, use netbios)
  127. LPWSTR pszNCName; // FQDN
  128. PDOMAIN_TREE pDomains;
  129. };
  130. //
  131. // recursive tree filling stuff
  132. //
  133. HTREEITEM
  134. _AddOneItem( HTREEITEM hParent, LPWSTR szText, HTREEITEM hInsAfter,
  135. int iImage, int cChildren, HWND hwndTree, LPARAM Domain)
  136. {
  137. HTREEITEM hItem;
  138. TV_ITEM tvI = { 0 };
  139. TV_INSERTSTRUCT tvIns = { 0 };
  140. USES_CONVERSION;
  141. // The .pszText, .iImage, and .iSelectedImage are filled in.
  142. tvI.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN | TVIF_PARAM;
  143. tvI.pszText = W2T(szText);
  144. tvI.cchTextMax = lstrlen(tvI.pszText);
  145. tvI.iImage = iImage;
  146. tvI.iSelectedImage = iImage;
  147. tvI.cChildren = cChildren;
  148. tvI.lParam = Domain;
  149. tvIns.item = tvI;
  150. tvIns.hInsertAfter = hInsAfter;
  151. tvIns.hParent = hParent;
  152. return TreeView_InsertItem(hwndTree, &tvIns);;
  153. }
  154. void
  155. _AddChildren(DOMAIN_DESC *pDomain, HWND hTree, HTREEITEM hParent)
  156. {
  157. DOMAIN_DESC * pChild = pDomain->pdChildList;
  158. for ( pChild = pDomain->pdChildList ; pChild ; pChild = pChild->pdNextSibling )
  159. {
  160. HTREEITEM hThis = _AddOneItem (hParent, pChild->pszName, TVI_SORT, 0,
  161. (pChild->pdChildList ? 1 : 0), hTree, (LPARAM)pChild);
  162. if (pChild->pdChildList != NULL)
  163. _AddChildren (pChild, hTree, hThis);
  164. }
  165. }
  166. //
  167. // DlgProc for the simple browser
  168. //
  169. INT_PTR CALLBACK
  170. _BrowserDlgProc (HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
  171. {
  172. HWND hTree = GetDlgItem (hwnd, IDC_DOMAIN_TREE);
  173. DIALOG_STUFF *pDialogInfo = (DIALOG_STUFF *)GetWindowLongPtr(hwnd, DWLP_USER);
  174. switch (Msg)
  175. {
  176. case WM_INITDIALOG:
  177. {
  178. pDialogInfo = (DIALOG_STUFF *)lParam;
  179. PDOMAIN_TREE pDomains = pDialogInfo->pDomains;
  180. SetWindowLongPtr(hwnd, DWLP_USER, lParam);
  181. // assume all images are the same for the tree view so load it and set accordingly
  182. CLASSCACHEENTRY *pcce = NULL;
  183. CLASSCACHEGETINFO ccgi = { 0 };
  184. HICON hIcon = NULL;
  185. ccgi.dwFlags = CLASSCACHE_ICONS;
  186. ccgi.pObjectClass = pDomains->aDomains[0].pszObjectClass;
  187. // should be pasing computer name to get correct display specifier
  188. // ccgi.pServer = _pComputerName;
  189. if ( SUCCEEDED(ClassCache_GetClassInfo(&ccgi, &pcce)) )
  190. {
  191. WCHAR szBuffer[MAX_PATH];
  192. INT resid;
  193. HRESULT hres = _GetIconLocation(pcce, DSGIF_GETDEFAULTICON, szBuffer, ARRAYSIZE(szBuffer), &resid);
  194. ClassCache_ReleaseClassInfo(&pcce);
  195. if ( hres == S_OK )
  196. {
  197. HICON hIcon;
  198. INT cxSmIcon = GetSystemMetrics(SM_CXSMICON);
  199. INT cySmIcon = GetSystemMetrics(SM_CYSMICON);
  200. if ( 1 == PrivateExtractIcons(szBuffer, resid, cxSmIcon, cySmIcon, &hIcon, NULL, 1, LR_LOADFROMFILE) )
  201. {
  202. HIMAGELIST himl = ImageList_Create(cxSmIcon, cySmIcon, ILC_COLOR|ILC_MASK, 0, 1);
  203. if ( himl )
  204. {
  205. ImageList_AddIcon(himl, hIcon);
  206. TreeView_SetImageList(hTree, himl, TVSIL_NORMAL);
  207. }
  208. DestroyIcon(hIcon);
  209. }
  210. }
  211. }
  212. // now populate the tree with the items in the domain structure
  213. for (PDOMAIN_DESC pRootDomain = pDomains->aDomains; pRootDomain; pRootDomain = pRootDomain->pdNextSibling)
  214. {
  215. HTREEITEM hRoot = _AddOneItem(TVI_ROOT, pRootDomain->pszName, TVI_SORT, 0,
  216. (pRootDomain->pdChildList ? 1 : 0), hTree, (LPARAM) pRootDomain);
  217. if (pRootDomain->pdChildList != NULL)
  218. _AddChildren(pRootDomain, hTree, hRoot);
  219. }
  220. return TRUE;
  221. }
  222. case WM_HELP:
  223. {
  224. WinHelp((HWND)(((LPHELPINFO)lParam)->hItemHandle),
  225. BROWSE_CTX_HELP_FILE,
  226. HELP_WM_HELP,
  227. (DWORD_PTR)(PVOID)aBrowseHelpIDs);
  228. return TRUE;
  229. }
  230. case WM_CONTEXTMENU:
  231. {
  232. WinHelp((HWND)wParam,
  233. BROWSE_CTX_HELP_FILE,
  234. HELP_CONTEXTMENU,
  235. (DWORD_PTR)(PVOID)aBrowseHelpIDs);
  236. return TRUE;
  237. }
  238. case WM_NOTIFY:
  239. {
  240. NMHDR* pnmhdr = (NMHDR*)lParam;
  241. if (IDC_DOMAIN_TREE != pnmhdr->idFrom || NM_DBLCLK != pnmhdr->code)
  242. return TRUE;
  243. TV_ITEM tvi;
  244. tvi.hItem = TreeView_GetSelection(hTree);
  245. tvi.mask = TVIF_CHILDREN;
  246. if ( TreeView_GetItem(hTree, &tvi) == TRUE )
  247. {
  248. if (tvi.cChildren == 0)
  249. PostMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDOK, (WORD)0), (LPARAM)0);
  250. }
  251. return TRUE;
  252. }
  253. case WM_COMMAND:
  254. {
  255. switch (LOWORD(wParam))
  256. {
  257. case IDOK:
  258. {
  259. TV_ITEM tvi;
  260. tvi.hItem = TreeView_GetSelection(hTree);
  261. tvi.mask = TVIF_PARAM;
  262. if ( TreeView_GetItem(hTree, &tvi) == TRUE )
  263. {
  264. DOMAIN_DESC *pDomain = (DOMAIN_DESC *)tvi.lParam;
  265. pDialogInfo->pszName = pDomain->pszName;
  266. pDialogInfo->pszNCName = pDomain->pszNCName;
  267. EndDialog (hwnd, TRUE);
  268. }
  269. else
  270. {
  271. pDialogInfo->pszName = NULL;
  272. pDialogInfo->pszNCName = NULL;
  273. EndDialog (hwnd, FALSE);
  274. }
  275. return TRUE;
  276. }
  277. case IDCANCEL:
  278. {
  279. pDialogInfo->pszName = NULL;
  280. pDialogInfo->pszNCName = NULL;
  281. EndDialog (hwnd, FALSE);
  282. return TRUE;
  283. }
  284. }
  285. }
  286. }
  287. return FALSE;
  288. }
  289. //
  290. // exposed API for browsing the tree
  291. //
  292. STDMETHODIMP CDsDomainTreeBrowser::BrowseTo(HWND hwndParent, LPWSTR *ppszTargetPath, DWORD dwFlags)
  293. {
  294. if (!ppszTargetPath)
  295. return E_INVALIDARG;
  296. HRESULT hr;
  297. PDOMAIN_TREE pDomainTree = NULL;
  298. DIALOG_STUFF DlgInfo;
  299. *ppszTargetPath = NULL; // result is NULL
  300. hr = GetDomains(&pDomainTree, dwFlags);
  301. if (SUCCEEDED(hr))
  302. {
  303. DlgInfo.pDomains = pDomainTree;
  304. DWORD res = (DWORD)DialogBoxParam(g_hInstance, MAKEINTRESOURCE(IDD_DOMAINBROWSER),
  305. hwndParent, _BrowserDlgProc, (LPARAM)&DlgInfo);
  306. if (res == IDOK)
  307. {
  308. LPWSTR pszPath = DlgInfo.pszName;
  309. if (dwFlags & DBDTF_RETURNFQDN)
  310. pszPath = DlgInfo.pszNCName;
  311. if (pszPath)
  312. {
  313. *ppszTargetPath = (LPWSTR)CoTaskMemAlloc(StringByteSizeW(pszPath));
  314. if (!*ppszTargetPath)
  315. hr = E_OUTOFMEMORY;
  316. else
  317. StrCpyW(*ppszTargetPath, pszPath);
  318. } else
  319. {
  320. hr = S_FALSE;
  321. }
  322. }
  323. else
  324. {
  325. hr = S_FALSE;
  326. }
  327. }
  328. FreeDomains(&pDomainTree);
  329. return hr;
  330. }
  331. //---------------------------------------------------------------------------//
  332. // keep using old values for win9x
  333. // the following comments are for nt when using new api
  334. struct DOMAIN_DATA
  335. {
  336. WCHAR szName[MAX_PATH]; // domain name (if no dns, use netbios)
  337. WCHAR szPath[MAX_PATH]; // set to blank
  338. WCHAR szTrustParent[MAX_PATH]; // parent domain name (if no dns, use netbios)
  339. WCHAR szNCName[MAX_PATH]; // FQDN: DC=mydomain,DC=microsoft,DC=com
  340. BOOL fConnected;
  341. BOOL fRoot; // true if root
  342. ULONG ulFlags; // type of domain, e.g., external trusted domain
  343. BOOL fDownLevel; // if NT4 domain
  344. DOMAIN_DATA * pNext;
  345. };
  346. #define FIX_UP(cast, p, pOriginal, pNew) p ? ((cast)(((LPBYTE)p-(LPBYTE)pOriginal)+(LPBYTE)pNew)):NULL
  347. #define DOMAIN_OBJECT_CLASS L"domainDNS" // fixed class for domain.
  348. STDMETHODIMP CDsDomainTreeBrowser::GetDomains(PDOMAIN_TREE *ppDomainTree, DWORD dwFlags)
  349. {
  350. HRESULT hr;
  351. LPDOMAINTREE pDomainTree = NULL;
  352. LPDOMAINTREE pSrcDomainTree = NULL;
  353. LPDOMAINDESC pDomainDesc = NULL;
  354. DWORD i;
  355. TraceEnter(TRACE_DOMAIN, "CDsDomainTreeBrowser::GetDomains");
  356. if ( !ppDomainTree )
  357. ExitGracefully(hr, E_INVALIDARG, "ppDomainTree == NULL");
  358. *ppDomainTree = NULL;
  359. // we support the user giving us a search root (::SetSearchRoot) so if we have
  360. // one then lets cache in this object the domain tree, otherwise fall back
  361. // to the global one.
  362. if ( _pComputerName )
  363. {
  364. TraceMsg("We have a computer name, so checking instance cached object");
  365. if ( !_pDomainTree || _dwFlags != dwFlags)
  366. {
  367. TraceMsg("Caching instance domain list");
  368. if (_pDomainTree)
  369. FreeDomains(&_pDomainTree);
  370. hr = _GetDomains(&_pDomainTree, dwFlags);
  371. FailGracefully(hr, "Failed to get cached domain list");
  372. _dwFlags = dwFlags;
  373. }
  374. pSrcDomainTree = _pDomainTree;
  375. }
  376. else
  377. {
  378. TraceMsg("Checking globally cached domain tree (no search root)");
  379. if ( !g_pDomainTree || g_dwFlags != dwFlags)
  380. {
  381. TraceMsg("Caching global domain list");
  382. if (g_pDomainTree)
  383. FreeDomains(&g_pDomainTree);
  384. hr = _GetDomains(&g_pDomainTree, dwFlags);
  385. FailGracefully(hr, "Failed to get cached domain list");
  386. g_dwFlags = dwFlags;
  387. }
  388. pSrcDomainTree = g_pDomainTree;
  389. }
  390. if ( !pSrcDomainTree )
  391. ExitGracefully(hr, E_FAIL, "Failed to get cached tree");
  392. // move and relocate the domain tree, walk all the pointers and offset
  393. // them from the original to the new.
  394. TraceMsg("Allocating buffer to copy the domain list");
  395. pDomainTree = (LPDOMAINTREE)CoTaskMemAlloc(pSrcDomainTree->dsSize);
  396. TraceAssert(pDomainTree);
  397. if ( !pDomainTree )
  398. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to allocate copy of the domain tree");
  399. memcpy(pDomainTree, pSrcDomainTree, pSrcDomainTree->dsSize);
  400. Trace(TEXT("Fixing up %d domains"), pDomainTree->dwCount);
  401. for ( i = 0 ; i != pDomainTree->dwCount ; i++ )
  402. {
  403. pDomainTree->aDomains[i].pszName = FIX_UP(LPWSTR, pDomainTree->aDomains[i].pszName, pSrcDomainTree, pDomainTree);
  404. pDomainTree->aDomains[i].pszPath = FIX_UP(LPWSTR, pDomainTree->aDomains[i].pszPath, pSrcDomainTree, pDomainTree);
  405. pDomainTree->aDomains[i].pszNCName = FIX_UP(LPWSTR, pDomainTree->aDomains[i].pszNCName, pSrcDomainTree, pDomainTree);
  406. pDomainTree->aDomains[i].pszTrustParent = FIX_UP(LPWSTR, pDomainTree->aDomains[i].pszTrustParent, pSrcDomainTree, pDomainTree);
  407. pDomainTree->aDomains[i].pszObjectClass = FIX_UP(LPWSTR, pDomainTree->aDomains[i].pszObjectClass, pSrcDomainTree, pDomainTree);
  408. pDomainTree->aDomains[i].pdChildList = FIX_UP(LPDOMAINDESC, pDomainTree->aDomains[i].pdChildList, pSrcDomainTree, pDomainTree);
  409. pDomainTree->aDomains[i].pdNextSibling = FIX_UP(LPDOMAINDESC, pDomainTree->aDomains[i].pdNextSibling, pSrcDomainTree, pDomainTree);
  410. }
  411. *ppDomainTree = pDomainTree;
  412. hr = S_OK;
  413. exit_gracefully:
  414. if ( FAILED(hr) )
  415. CoTaskMemFree(pDomainTree);
  416. TraceLeaveResult(hr);
  417. }
  418. //
  419. // Real _GetDomains that does the work of finding the trusted domains
  420. //
  421. STDMETHODIMP CDsDomainTreeBrowser::_GetDomains(PDOMAIN_TREE *ppDomainTree, DWORD dwFlags)
  422. {
  423. HRESULT hr = S_OK;
  424. UINT cbSize = 0;
  425. UINT cDomains = 0, cRootDomains =0, cbStringStorage = 0;
  426. struct DOMAIN_DATA * pCurrentDomain = NULL;
  427. struct DOMAIN_DATA * pFirstDomain = NULL;
  428. DOMAIN_DESC * pDestDomain = NULL;
  429. DOMAIN_DESC * pDestRootDomain = NULL;
  430. LPWSTR pNextFree;
  431. UINT index, index_inner;
  432. DOMAIN_DESC * pPotentialChild, * pPotentialParent;
  433. USES_CONVERSION;
  434. ULONG ulParentIndex = 0;
  435. ULONG ulCurrentIndex = 0;
  436. ULONG ulEntryCount = 0;
  437. PDS_DOMAIN_TRUSTS pDomainList = NULL;
  438. PDS_DOMAIN_TRUSTS pDomain = NULL;
  439. NET_API_STATUS NetStatus = NO_ERROR;
  440. ULONG ulFlags = DS_DOMAIN_PRIMARY | DS_DOMAIN_IN_FOREST;
  441. BOOL bDownLevelTrust = FALSE;
  442. BOOL bUpLevelTrust = FALSE;
  443. BOOL bExternalTrust = FALSE;
  444. TraceEnter(TRACE_DOMAIN, "CDsDomainTreeBrowser::_GetDomains");
  445. *ppDomainTree = NULL;
  446. if (dwFlags & DBDTF_RETURNINOUTBOUND)
  447. {
  448. ulFlags |= (DS_DOMAIN_DIRECT_INBOUND | DS_DOMAIN_DIRECT_OUTBOUND);
  449. }
  450. else if (dwFlags & DBDTF_RETURNINBOUND)
  451. {
  452. ulFlags |= DS_DOMAIN_DIRECT_INBOUND;
  453. }
  454. else
  455. {
  456. ulFlags |= DS_DOMAIN_DIRECT_OUTBOUND;
  457. }
  458. // wack off the port number if we have server:<n> specified
  459. LPWSTR pszPort = NULL;
  460. if (NULL != _pComputerName)
  461. {
  462. pszPort = StrChrW(_pComputerName, L':');
  463. if ( pszPort )
  464. *pszPort = L'\0';
  465. }
  466. // get the domain list
  467. NetStatus = DsEnumerateDomainTrusts(
  468. _pComputerName,
  469. ulFlags,
  470. &pDomainList,
  471. &ulEntryCount );
  472. if (ERROR_ACCESS_DENIED == NetStatus &&
  473. _pComputerName && *_pComputerName &&
  474. _pUserName && *_pUserName)
  475. {
  476. //
  477. // make the connection, try one more time
  478. //
  479. WCHAR wszIPC[MAX_PATH];
  480. if (L'\\' == *_pComputerName)
  481. {
  482. StrCpyW(wszIPC, _pComputerName);
  483. }
  484. else
  485. {
  486. StrCpyW(wszIPC, L"\\\\");
  487. StrCatW(wszIPC, _pComputerName);
  488. }
  489. StrCatW(wszIPC, L"\\IPC$");
  490. NETRESOURCEW nr = {0};
  491. nr.dwType = RESOURCETYPE_ANY;
  492. nr.lpLocalName = NULL;
  493. nr.lpRemoteName = wszIPC;
  494. nr.lpProvider = NULL;
  495. DWORD dwErr = WNetAddConnection2W(&nr, _pPassword, _pUserName, 0);
  496. if (NO_ERROR == dwErr || ERROR_SESSION_CREDENTIAL_CONFLICT == dwErr)
  497. {
  498. NetStatus = DsEnumerateDomainTrusts(
  499. _pComputerName,
  500. ulFlags,
  501. &pDomainList,
  502. &ulEntryCount );
  503. } else
  504. {
  505. NetStatus = dwErr;
  506. }
  507. //
  508. // soft close the connection opened by us
  509. //
  510. if (NO_ERROR == dwErr)
  511. {
  512. (void) WNetCancelConnection2W(wszIPC, 0, FALSE);
  513. }
  514. }
  515. // restore the port seperator
  516. if ( pszPort )
  517. *pszPort = L':';
  518. if ( NetStatus != NO_ERROR )
  519. ExitGracefully(hr, HRESULT_FROM_WIN32(NetStatus), "Failed to enum trusted domains");
  520. for (ulCurrentIndex=0; ulCurrentIndex<ulEntryCount; ulCurrentIndex++ )
  521. {
  522. pDomain = &(pDomainList[ulCurrentIndex]);
  523. bDownLevelTrust = pDomain->TrustType & TRUST_TYPE_DOWNLEVEL;
  524. bUpLevelTrust = pDomain->TrustType & TRUST_TYPE_UPLEVEL; // trust between 2 NT5 domains
  525. //
  526. // we don't consider other type of trusts, e.g, MIT
  527. //
  528. if (!bDownLevelTrust && !bUpLevelTrust)
  529. continue;
  530. //
  531. // skip if caller has no interest in downlevel trust
  532. //
  533. if ( !(dwFlags & DBDTF_RETURNMIXEDDOMAINS) && bDownLevelTrust)
  534. continue;
  535. bExternalTrust = !(pDomain->Flags & DS_DOMAIN_IN_FOREST);
  536. //
  537. // skip if caller has no interest in external trust
  538. //
  539. if ( !(dwFlags & DBDTF_RETURNEXTERNAL) && bExternalTrust)
  540. continue;
  541. cDomains++;
  542. if (pFirstDomain == NULL)
  543. {
  544. pCurrentDomain = new DOMAIN_DATA;
  545. TraceAssert(pCurrentDomain);
  546. if ( !pCurrentDomain )
  547. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to allocate DOMAIN_DATA structure");
  548. ZeroMemory(pCurrentDomain, sizeof(DOMAIN_DATA));
  549. pFirstDomain = pCurrentDomain;
  550. }
  551. else
  552. {
  553. pCurrentDomain->pNext = new DOMAIN_DATA;
  554. TraceAssert(pCurrentDomain->pNext);
  555. if ( !pCurrentDomain->pNext )
  556. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to allocate DOMAIN_DATA structure (not first item)");
  557. pCurrentDomain = pCurrentDomain->pNext;
  558. ZeroMemory(pCurrentDomain, sizeof(DOMAIN_DATA));
  559. }
  560. // fill the structure with data from the queried object.
  561. pCurrentDomain->pNext = NULL;
  562. pCurrentDomain->ulFlags = pDomain->Flags;
  563. pCurrentDomain->szPath[0] = L'\0';
  564. pCurrentDomain->fDownLevel = bDownLevelTrust;
  565. if (pDomain->DnsDomainName)
  566. {
  567. StrCpyW(pCurrentDomain->szName,
  568. pDomain->DnsDomainName);
  569. // remove the last dot
  570. int i = 0;
  571. PWSTR p = NULL;
  572. int nLength = lstrlenW(pCurrentDomain->szName);
  573. if ( L'.' == pCurrentDomain->szName[nLength-1] )
  574. {
  575. pCurrentDomain->szName[nLength-1] = L'\0';
  576. nLength--;
  577. }
  578. if (dwFlags & DBDTF_RETURNFQDN)
  579. {
  580. // if switch to DsCrackName in the future,
  581. // 1. append trailing '/' to the dns domain name
  582. // 2. use DS_NAME_NO_FLAGS as flags
  583. // 3. use DS_CANONICAL_NAME as formatOffered
  584. // 4. use DS_FQDN_1779_NAME as formatDesired
  585. // what is hDS???
  586. StrCpyW(pCurrentDomain->szNCName, L"DC=");
  587. p = pCurrentDomain->szNCName + 3;
  588. for (i=0; i<nLength; i++)
  589. {
  590. if ( L'.' == pCurrentDomain->szName[i] )
  591. {
  592. StrCpyW(p, L",DC=");
  593. p += 4;
  594. }
  595. else
  596. {
  597. *p = pCurrentDomain->szName[i];
  598. p++;
  599. }
  600. }
  601. }
  602. else
  603. {
  604. pCurrentDomain->szNCName[0] = L'\0';
  605. }
  606. }
  607. else
  608. {
  609. StrCpyW(pCurrentDomain->szName,
  610. pDomain->NetbiosDomainName);
  611. pCurrentDomain->szNCName[0] = L'\0'; // downlevel domain has no FQDN
  612. }
  613. // treat external trusted domain as root domain
  614. pCurrentDomain->fRoot =
  615. ( ( !bExternalTrust && (pDomain->Flags & DS_DOMAIN_TREE_ROOT) ) ||
  616. bExternalTrust );
  617. if ( pCurrentDomain->fRoot )
  618. {
  619. cRootDomains++;
  620. } else {
  621. ulParentIndex = pDomain->ParentIndex;
  622. if (pDomainList[ulParentIndex].DnsDomainName)
  623. StrCpyW(pCurrentDomain->szTrustParent, pDomainList[ulParentIndex].DnsDomainName);
  624. else
  625. StrCpyW(pCurrentDomain->szTrustParent, pDomainList[ulParentIndex].NetbiosDomainName);
  626. }
  627. cbStringStorage += StringByteSizeW(pCurrentDomain->szName);
  628. cbStringStorage += StringByteSizeW(pCurrentDomain->szPath);
  629. cbStringStorage += StringByteSizeW(pCurrentDomain->szTrustParent);
  630. cbStringStorage += StringByteSizeW(pCurrentDomain->szNCName);
  631. // hard-coded domainDNS should get from object
  632. cbStringStorage += StringByteSizeW(DOMAIN_OBJECT_CLASS);
  633. }
  634. Trace(TEXT("cDomains %d, cRootDomains %d"), cDomains, cRootDomains);
  635. if ( cRootDomains == 0 )
  636. ExitGracefully(hr, HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_DOMAIN_INFO), "No root domains, so failing _GetDomains call");
  637. TraceMsg("Building structure information");
  638. // REVIEW_MARCOC: we allocate more memory than strictly necessary...
  639. cbSize = sizeof(DOMAIN_TREE) + (cDomains * sizeof(DOMAIN_DESC)) + cbStringStorage;
  640. *ppDomainTree = (PDOMAIN_TREE)CoTaskMemAlloc(cbSize);
  641. TraceAssert(*ppDomainTree);
  642. if ( !*ppDomainTree )
  643. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to allocate DOMAINDTREE structure");
  644. memset(*ppDomainTree, 0, cbSize);
  645. pNextFree = (LPWSTR)ByteOffset((*ppDomainTree), sizeof(DOMAIN_TREE) + (cDomains * sizeof(DOMAIN_DESC)) );
  646. // loop to copy the nodes, roots first
  647. pDestRootDomain = &((*ppDomainTree)->aDomains[0]);
  648. pDestDomain = &((*ppDomainTree)->aDomains[cRootDomains]);
  649. for ( pCurrentDomain = pFirstDomain; pCurrentDomain; pCurrentDomain = pCurrentDomain->pNext )
  650. {
  651. if (pCurrentDomain->fRoot)
  652. {
  653. Trace(TEXT("Object is a domain root: %s"), pCurrentDomain->szName);
  654. pDestRootDomain->pszName = pNextFree;
  655. StrCpyW(pDestRootDomain->pszName, pCurrentDomain->szName);
  656. pNextFree += lstrlenW(pCurrentDomain->szName) + 1;
  657. pDestRootDomain->pszPath = pNextFree;
  658. StrCpyW(pDestRootDomain->pszPath, pCurrentDomain->szPath);
  659. pNextFree += lstrlenW(pCurrentDomain->szPath) + 1;
  660. pDestRootDomain->pszNCName = pNextFree;
  661. StrCpyW(pDestRootDomain->pszNCName, pCurrentDomain->szNCName);
  662. pNextFree += lstrlenW(pCurrentDomain->szNCName) + 1;
  663. pDestRootDomain->pszTrustParent = NULL;
  664. // hard-coded domainDNS should get from object
  665. pDestRootDomain->pszObjectClass = pNextFree;
  666. StrCpyW(pDestRootDomain->pszObjectClass, DOMAIN_OBJECT_CLASS);
  667. pNextFree += lstrlenW(DOMAIN_OBJECT_CLASS) + 1;
  668. pDestRootDomain->ulFlags = pCurrentDomain->ulFlags;
  669. pDestRootDomain->fDownLevel = pCurrentDomain->fDownLevel;
  670. pDestRootDomain->pdNextSibling = NULL;
  671. if (pDestRootDomain > &((*ppDomainTree)->aDomains[0]))
  672. {
  673. (&(pDestRootDomain[-1]))->pdNextSibling = pDestRootDomain;
  674. }
  675. pDestRootDomain++;
  676. }
  677. else
  678. {
  679. Trace(TEXT("Object is not a domain root: %s"), pCurrentDomain->szName);
  680. pDestDomain->pszName = pNextFree;
  681. StrCpyW(pDestDomain->pszName, pCurrentDomain->szName);
  682. pNextFree += lstrlenW(pDestDomain->pszName) + 1;
  683. pDestDomain->pszPath = pNextFree;
  684. StrCpyW(pDestDomain->pszPath, pCurrentDomain->szPath);
  685. pNextFree += lstrlenW(pDestDomain->pszPath) + 1;
  686. pDestDomain->pszNCName = pNextFree;
  687. StrCpyW(pDestDomain->pszNCName, pCurrentDomain->szNCName);
  688. pNextFree += lstrlenW(pDestDomain->pszNCName) + 1;
  689. pDestDomain->pszTrustParent = pNextFree;
  690. StrCpyW(pDestDomain->pszTrustParent, pCurrentDomain->szTrustParent);
  691. pNextFree += lstrlenW(pDestDomain->pszTrustParent) + 1;
  692. // hard-coded domainDNS should get from object
  693. pDestDomain->pszObjectClass = pNextFree;
  694. StrCpyW(pDestDomain->pszObjectClass, DOMAIN_OBJECT_CLASS);
  695. pNextFree += lstrlenW(DOMAIN_OBJECT_CLASS) + 1;
  696. pDestDomain->ulFlags = pCurrentDomain->ulFlags;
  697. pDestDomain->fDownLevel = pCurrentDomain->fDownLevel;
  698. pDestDomain++;
  699. }
  700. }
  701. TraceMsg("Finished first pass creating domain structure, now building per level items");
  702. // walk list, picking up each item per level, until all items
  703. // have been placed in structure.
  704. // return structure.
  705. for (index = 0; index < cDomains; index ++)
  706. {
  707. pPotentialParent = &((*ppDomainTree)->aDomains[index]);
  708. Trace(TEXT("pPotentialParent %08x, index %d"), pPotentialParent, index);
  709. for (index_inner = 0; index_inner < cDomains; index_inner++)
  710. {
  711. pPotentialChild = &((*ppDomainTree)->aDomains[index_inner]);
  712. Trace(TEXT("pPotentialChild %08x, index_inner %d"), pPotentialChild, index_inner);
  713. if (pPotentialChild == pPotentialParent)
  714. {
  715. TraceMsg("parent == child, skipping");
  716. continue;
  717. }
  718. Trace(TEXT("Comparing %s to %s"),
  719. pPotentialChild->pszTrustParent ? W2T(pPotentialChild->pszTrustParent):TEXT("NULL"),
  720. W2T(pPotentialParent->pszPath));
  721. if ((pPotentialChild->pszTrustParent != NULL) &&
  722. (!StrCmpW(pPotentialChild->pszTrustParent, pPotentialParent->pszName)))
  723. {
  724. TraceMsg("Child found, scanning for end of child list");
  725. // this is a child. figure out where end of child chain is
  726. if (pPotentialParent->pdChildList == NULL)
  727. {
  728. TraceMsg("Parent has no children, this becomes the child");
  729. pPotentialParent->pdChildList = pPotentialChild;
  730. }
  731. else
  732. {
  733. DOMAIN_DESC * pdScan = pPotentialParent->pdChildList;
  734. Trace(TEXT("Scanning from %08x"), pdScan);
  735. while (pdScan->pdNextSibling != NULL)
  736. {
  737. pdScan = pdScan->pdNextSibling;
  738. Trace(TEXT("Advancing to %08x"), pdScan);
  739. }
  740. Trace(TEXT("Setting next sibling on %08x"), pdScan);
  741. pdScan->pdNextSibling = pPotentialChild;
  742. }
  743. }
  744. }
  745. }
  746. TraceMsg("Finished fix up, setting cbSize + domains");
  747. (*ppDomainTree)->dwCount = cDomains;
  748. (*ppDomainTree)->dsSize = cbSize;
  749. hr = S_OK; // success
  750. exit_gracefully:
  751. if (pDomainList)
  752. NetApiBufferFree(pDomainList);
  753. if (pFirstDomain != NULL)
  754. {
  755. TraceMsg("pFirstDomain != NULL");
  756. while (pFirstDomain != NULL)
  757. {
  758. Trace(TEXT("Releasing domain %08x"), pFirstDomain);
  759. pCurrentDomain = pFirstDomain;
  760. pFirstDomain = pFirstDomain->pNext;
  761. delete pCurrentDomain;
  762. }
  763. }
  764. if ( FAILED(hr) )
  765. {
  766. TraceMsg("Freeing the domain tree structure because we failed");
  767. FreeDomains(ppDomainTree);
  768. }
  769. TraceLeaveResult(hr);
  770. }
  771. //---------------------------------------------------------------------------//
  772. STDMETHODIMP CDsDomainTreeBrowser::FreeDomains(PDOMAIN_TREE* ppDomainTree)
  773. {
  774. HRESULT hr;
  775. TraceEnter(TRACE_DOMAIN, "CDsDomainTreeBrowser::FreeDomains");
  776. if ( !ppDomainTree )
  777. ExitGracefully(hr, E_INVALIDARG, "No pDomainTree");
  778. if ( *ppDomainTree )
  779. {
  780. CoTaskMemFree(*ppDomainTree);
  781. *ppDomainTree = NULL;
  782. }
  783. hr = S_OK;
  784. exit_gracefully:
  785. TraceLeaveResult(hr);
  786. }
  787. //---------------------------------------------------------------------------//
  788. STDMETHODIMP CDsDomainTreeBrowser::FlushCachedDomains()
  789. {
  790. HRESULT hr;
  791. TraceEnter(TRACE_DOMAIN, "CDsDomainTreeBrowser::FlushCachedDomains");
  792. hr = FreeDomains(&g_pDomainTree);
  793. FailGracefully(hr, "Failed to free cached domain list");
  794. hr = FreeDomains(&_pDomainTree);
  795. FailGracefully(hr, "Failed to free cached domain list (for search root)");
  796. hr = S_OK; // success
  797. exit_gracefully:
  798. TraceLeaveResult(hr);
  799. }