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.

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