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.

451 lines
13 KiB

  1. #include "pch.h"
  2. #pragma hdrstop
  3. #include "atlbase.h"
  4. extern CComModule _Module;
  5. #include "atlcom.h"
  6. #include <ntdsapi.h>
  7. #include <string>
  8. #include <set>
  9. #include "enumNCs.hpp"
  10. using namespace std;
  11. /*-----------------------------------------------------------------------------
  12. / Local functions / data
  13. /----------------------------------------------------------------------------*/
  14. static WCHAR c_szQueryPrefix[] = L"(objectClass=nTDSDSA)";
  15. static LPWSTR c_szClassList[] =
  16. {
  17. L"nTDSDSA",
  18. };
  19. static COLUMNINFO columns[] =
  20. {
  21. 0, 0, IDS_SERVERNAME, 0, L"ADsPath,{2C875213-FCE5-11d1-A0B0-00C04FA31A86}",
  22. 0, 0, IDS_SITE, 0, L"ADsPath,{25be9228-00af-11d2-bf87-00c04fd8d5b0}",
  23. 0, DEFAULT_WIDTH_DESCRIPTION, IDS_DOMAIN, 0, L"hasMasterNCs,{1cedc5da-3614-11d2-bf96-00c04fd8d5b0}",
  24. };
  25. //
  26. // Help ID mappings
  27. //
  28. static DWORD const aFormHelpIDs[] =
  29. {
  30. 0, 0
  31. };
  32. /*-----------------------------------------------------------------------------
  33. / PageProc_DomainController
  34. / -------------------------
  35. / PageProc for handling the messages for this object.
  36. /
  37. / In:
  38. / pPage -> instance data for this form
  39. / hwnd = window handle for the form dialog
  40. / uMsg, wParam, lParam = message parameters
  41. /
  42. / Out:
  43. / HRESULT (E_NOTIMPL) if not handled
  44. /----------------------------------------------------------------------------*/
  45. HRESULT CALLBACK PageProc_DomainController(LPCQPAGE pPage, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  46. {
  47. HRESULT hr = S_OK;
  48. LPWSTR pQuery = NULL;
  49. TraceEnter(TRACE_FORMS, "PageProc_DomainController");
  50. switch (uMsg)
  51. {
  52. case CQPM_INITIALIZE:
  53. case CQPM_RELEASE:
  54. break;
  55. case CQPM_ENABLE:
  56. EnablePageControls(hwnd, NULL, 0, (BOOL)wParam);
  57. break;
  58. case CQPM_GETPARAMETERS:
  59. {
  60. hr = GetQueryString(&pQuery, c_szQueryPrefix, hwnd, NULL, 0);
  61. if (SUCCEEDED(hr))
  62. {
  63. hr = QueryParamsAlloc((LPDSQUERYPARAMS*)lParam, pQuery, GLOBAL_HINSTANCE, ARRAYSIZE(columns), columns);
  64. LocalFreeStringW(&pQuery);
  65. }
  66. FailGracefully(hr, "Failed to build DS argument block");
  67. break;
  68. }
  69. case CQPM_CLEARFORM:
  70. ResetPageControls(hwnd, NULL, 0);
  71. break;
  72. case CQPM_PERSIST:
  73. {
  74. BOOL fRead = (BOOL)wParam;
  75. IPersistQuery* pPersistQuery = (IPersistQuery*)lParam;
  76. hr = PersistQuery(pPersistQuery, fRead, c_szMsDomainControllers, hwnd, NULL, 0);
  77. FailGracefully(hr, "Failed to persist page");
  78. break;
  79. }
  80. case CQPM_HELP:
  81. {
  82. LPHELPINFO pHelpInfo = (LPHELPINFO)lParam;
  83. WinHelp((HWND)pHelpInfo->hItemHandle,
  84. DSQUERY_HELPFILE,
  85. HELP_WM_HELP,
  86. (DWORD_PTR)aFormHelpIDs);
  87. break;
  88. }
  89. case DSQPM_GETCLASSLIST:
  90. {
  91. hr = ClassListAlloc((LPDSQUERYCLASSLIST*)lParam, c_szClassList, ARRAYSIZE(c_szClassList));
  92. FailGracefully(hr, "Failed to allocate class list");
  93. break;
  94. }
  95. case DSQPM_HELPTOPICS:
  96. {
  97. HWND hwndFrame = (HWND)lParam;
  98. HtmlHelp(hwndFrame, TEXT("omc.chm::/adfind_dc.htm"), HH_HELP_FINDER, 0);
  99. break;
  100. }
  101. default:
  102. hr = E_NOTIMPL;
  103. break;
  104. }
  105. exit_gracefully:
  106. TraceLeaveResult(hr);
  107. }
  108. /*-----------------------------------------------------------------------------
  109. / DlgProc_DomainController
  110. / ------------
  111. / Handle dialog specific message for the Domain Controllers page.
  112. /
  113. / In:
  114. / hwnd, uMsg, wParam, lParam = standard parameters
  115. /
  116. / Out:
  117. / INT_PTR
  118. /----------------------------------------------------------------------------*/
  119. INT_PTR CALLBACK DlgProc_DomainController(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  120. {
  121. INT_PTR fResult = 0;
  122. LPCQPAGE pQueryPage;
  123. if (uMsg == WM_INITDIALOG)
  124. {
  125. pQueryPage = (LPCQPAGE)lParam;
  126. SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)pQueryPage);
  127. }
  128. return fResult;
  129. }
  130. /*-----------------------------------------------------------------------------
  131. / CDomainCH
  132. / -------------------
  133. / Column handler which converts the given property and value into a
  134. / string the user can understand.
  135. /----------------------------------------------------------------------------*/
  136. class CDomainCH : public IDsQueryColumnHandler
  137. {
  138. private:
  139. LONG _cRef;
  140. CComPtr<IADsPathname> m_spPathCracker;
  141. HRESULT m_hrPathCrackerLoadError;
  142. long m_lElement;
  143. BOOL m_fFindDN;
  144. BOOL m_fHasNCs;
  145. set <wstring> m_NCs;
  146. HRESULT GetTextFromADSVALUE(const PADSVALUE pADsValue, LPWSTR pBuffer, INT cchBuffer);
  147. public:
  148. CDomainCH(REFCLSID rCLSID);
  149. ~CDomainCH();
  150. // IUnkown
  151. STDMETHODIMP_(ULONG) AddRef();
  152. STDMETHODIMP_(ULONG) Release();
  153. STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppvObject);
  154. // IDsQueryColumnHandler
  155. STDMETHOD(Initialize)(THIS_ DWORD dwFlags, LPCWSTR pszServer, LPCWSTR pszUserName, LPCWSTR pszPassword);
  156. STDMETHOD(GetText)(THIS_ ADS_SEARCH_COLUMN* pSearchColumn, LPWSTR pBuffer, INT cchBuffer);
  157. };
  158. ULONG CDomainCH::AddRef()
  159. {
  160. return InterlockedIncrement(&_cRef);
  161. }
  162. ULONG CDomainCH::Release()
  163. {
  164. TraceAssert( 0 != _cRef );
  165. ULONG cRef = InterlockedDecrement(&_cRef);
  166. if ( 0 == cRef )
  167. {
  168. delete this;
  169. }
  170. return cRef;
  171. }
  172. HRESULT CDomainCH::QueryInterface(REFIID riid, void **ppv)
  173. {
  174. static const QITAB qit[] =
  175. {
  176. QITABENT(CDomainCH, IDsQueryColumnHandler), // IID_IDsQueryColumnHandler
  177. {0, 0 },
  178. };
  179. return QISearch(this, qit, riid, ppv);
  180. }
  181. //
  182. // construction
  183. //
  184. CDomainCH::CDomainCH(REFCLSID rCLSID)
  185. : m_hrPathCrackerLoadError(0), m_lElement (1),
  186. m_fFindDN(FALSE), _cRef(1), m_fHasNCs(FALSE)
  187. {
  188. if (IsEqualCLSID(rCLSID, CLSID_PathElement1CH))
  189. {
  190. }
  191. else if (IsEqualCLSID(rCLSID, CLSID_PathElement3CH))
  192. {
  193. m_lElement = 3;
  194. }
  195. else if (IsEqualCLSID(rCLSID, CLSID_PathElementDomainCH))
  196. {
  197. m_lElement = 0;
  198. m_fFindDN = true;
  199. }
  200. DllAddRef();
  201. }
  202. CDomainCH::~CDomainCH()
  203. {
  204. DllRelease();
  205. }
  206. //
  207. // handle class factory stuff
  208. //
  209. STDAPI CDomainCH_CreateInstance(IUnknown* /* punkOuter */, IUnknown** ppunk, LPCOBJECTINFO poi)
  210. {
  211. CDomainCH *pdch = new CDomainCH(*poi->pclsid);
  212. if (!pdch)
  213. return E_OUTOFMEMORY;
  214. HRESULT hres = pdch->QueryInterface(IID_IUnknown, (void **)ppunk);
  215. pdch->Release();
  216. return hres;
  217. }
  218. // IDsQueryColumnHandler
  219. STDMETHODIMP CDomainCH::Initialize(THIS_ DWORD dwFlags, LPCWSTR pszServer, LPCWSTR pszUserName, LPCWSTR pszPassword)
  220. {
  221. return S_OK;
  222. }
  223. STDMETHODIMP CDomainCH::GetText(ADS_SEARCH_COLUMN* pSearchColumn, LPWSTR pBuffer, INT cchBuffer)
  224. {
  225. HRESULT hr = S_OK;
  226. DWORD iValue = 0;
  227. TraceEnter(TRACE_FORMS, "CDomainCH::GetText");
  228. if (!pSearchColumn || !pBuffer)
  229. ExitGracefully(hr, E_UNEXPECTED,
  230. "DSQUERY.DLL: Bad parameters passed to handler");
  231. // 2002-03-04-JonN 557908 Make sure buffer is null-terminated
  232. if (1 <= cchBuffer)
  233. pBuffer[0] = L'\0';
  234. if (pSearchColumn->dwNumValues < 1
  235. || NULL == pSearchColumn->pADsValues
  236. )
  237. ExitGracefully(hr, S_OK,
  238. "DSQUERY.DLL: no values in handler");
  239. if (m_fFindDN)
  240. {
  241. //
  242. // This section handles CLSID_CH_PathElementDomainCH
  243. //
  244. PADSVALUE pADsValue = NULL;
  245. LPWSTR pwzResultName = NULL;
  246. PDS_NAME_RESULTW pDsNameResult = NULL;
  247. for (iValue = 0; iValue < pSearchColumn->dwNumValues; iValue++)
  248. {
  249. pADsValue = &(pSearchColumn->pADsValues[iValue]);
  250. if (NULL == pADsValue
  251. || (pADsValue->dwType != ADSTYPE_CASE_IGNORE_STRING
  252. && pADsValue->dwType != ADSTYPE_DN_STRING)
  253. )
  254. ExitGracefully(hr, S_OK,
  255. "DSQUERY.DLL: not a DN value in handler");
  256. if (0 == StrCmpNW(L"DC=",pADsValue->CaseIgnoreString,3))
  257. {
  258. // NTRAID#NTBUG9-472876-2001/11/30-lucios
  259. // If the NC cache is not loaded
  260. if(m_fHasNCs==FALSE)
  261. {
  262. // mark it as loaded and load.
  263. // we don't wan't to revisit this code
  264. // even in the case of enumeration failure.
  265. m_fHasNCs=TRUE;
  266. hr=enumNCsAux::enumerateNCs(m_NCs);
  267. if(FAILED(hr))
  268. {
  269. ExitGracefully
  270. (
  271. hr,
  272. S_OK,
  273. "DSQUERY.DLL: Unable to enumerate naming "
  274. L"contexts."
  275. );
  276. }
  277. };
  278. wstring server=(PCWSTR)pADsValue->CaseIgnoreString;
  279. // If this is a real naming context it will be in the cache.
  280. if(m_NCs.find(server)!=m_NCs.end())
  281. {
  282. break;
  283. }
  284. }
  285. }
  286. if (iValue >= pSearchColumn->dwNumValues)
  287. {
  288. // no value found
  289. ExitGracefully(hr, S_OK,
  290. "DSQUERY.DLL: no domain values in handler");
  291. }
  292. //
  293. // We found the value, now try DsCrackNames to convert it to
  294. // a DNS name. If this fails, fall back to path element 0.
  295. //
  296. TraceAssert(pADsValue);
  297. DWORD dwErr = ::DsCrackNamesW(
  298. (HANDLE)-1,
  299. DS_NAME_FLAG_SYNTACTICAL_ONLY,
  300. DS_FQDN_1779_NAME,
  301. DS_CANONICAL_NAME,
  302. 1,
  303. &(pADsValue->CaseIgnoreString),
  304. &pDsNameResult);
  305. hr = HRESULT_FROM_WIN32(dwErr);
  306. if (SUCCEEDED(hr))
  307. {
  308. TraceAssert(pDsNameResult);
  309. TraceAssert(1 == pDsNameResult->cItems);
  310. if (DS_NAME_NO_ERROR == pDsNameResult->rItems->status)
  311. {
  312. TraceAssert(pDsNameResult->rItems->pDomain);
  313. StrCpyNW(pBuffer, pDsNameResult->rItems->pDomain, cchBuffer);
  314. DsFreeNameResultW(pDsNameResult);
  315. goto exit_gracefully;
  316. }
  317. }
  318. //
  319. // This is the fallback scenario if DsCrackNames fails.
  320. // If the domain is "CN=jonndom,CN=nttest,CN=microsoft,CN=com",
  321. // the name displayed will be "jonndom".
  322. //
  323. }
  324. hr = GetTextFromADSVALUE(
  325. &(pSearchColumn->pADsValues[iValue]),
  326. pBuffer,
  327. cchBuffer);
  328. exit_gracefully:
  329. TraceLeaveResult(hr);
  330. }
  331. HRESULT CDomainCH::GetTextFromADSVALUE(const PADSVALUE pADsValue, LPWSTR pBuffer, INT cchBuffer)
  332. {
  333. HRESULT hr = S_OK;
  334. CComBSTR sbstr;
  335. TraceEnter(TRACE_FORMS, "CDomainCH::GetTextFromADSVALUE");
  336. if (NULL == pADsValue
  337. || (pADsValue->dwType != ADSTYPE_CASE_IGNORE_STRING
  338. && pADsValue->dwType != ADSTYPE_DN_STRING)
  339. || !(pADsValue->CaseIgnoreString)
  340. )
  341. ExitGracefully(hr, S_OK,
  342. "DSQUERY.DLL: not a DN value in handler");
  343. if (!m_spPathCracker)
  344. {
  345. FailGracefully(m_hrPathCrackerLoadError,
  346. "DSQUERY.DLL: Subsequent failure to load Path Cracker");
  347. m_hrPathCrackerLoadError = CoCreateInstance(
  348. CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER,
  349. IID_IADsPathname, (PVOID *)&m_spPathCracker);
  350. FailGracefully(m_hrPathCrackerLoadError,
  351. "DSQUERY.DLL: First failure to load Path Cracker");
  352. if (!m_spPathCracker)
  353. {
  354. m_hrPathCrackerLoadError = E_UNEXPECTED;
  355. FailGracefully(m_hrPathCrackerLoadError,
  356. "DSQUERY.DLL: CreateInstance did not load");
  357. }
  358. m_hrPathCrackerLoadError = m_spPathCracker->SetDisplayType(
  359. ADS_DISPLAY_VALUE_ONLY);
  360. FailGracefully(m_hrPathCrackerLoadError,
  361. "DSQUERY.DLL: SetDisplayType failed");
  362. }
  363. // ADsPath starts with "LDAP://" but hasMasterNCs doesn't
  364. hr = m_spPathCracker->Set(CComBSTR(pADsValue->CaseIgnoreString),
  365. (m_fFindDN) ? ADS_SETTYPE_DN : ADS_SETTYPE_FULL);
  366. FailGracefully(hr, "DSQUERY.DLL: Set() failed");
  367. hr = m_spPathCracker->GetElement(m_lElement, &sbstr);
  368. FailGracefully(hr, "DSQUERY.DLL: GetElement() failed");
  369. StrCpyNW(pBuffer, sbstr, cchBuffer);
  370. exit_gracefully:
  371. TraceLeaveResult(hr);
  372. }