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.

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