windows-nt/Source/XPSP1/NT/shell/ext/dsui/dsquery/qf_dmctl.cpp
2020-09-26 16:20:57 +08:00

410 lines
11 KiB
C++

#include "pch.h"
#pragma hdrstop
#include "atlbase.h"
extern CComModule _Module;
#include "atlcom.h"
#include <ntdsapi.h>
/*-----------------------------------------------------------------------------
/ Local functions / data
/----------------------------------------------------------------------------*/
static WCHAR c_szQueryPrefix[] = L"(objectClass=nTDSDSA)";
static LPWSTR c_szClassList[] =
{
L"nTDSDSA",
};
static COLUMNINFO columns[] =
{
0, 0, IDS_SERVERNAME, 0, L"ADsPath,{2C875213-FCE5-11d1-A0B0-00C04FA31A86}",
0, 0, IDS_SITE, 0, L"ADsPath,{25be9228-00af-11d2-bf87-00c04fd8d5b0}",
0, DEFAULT_WIDTH_DESCRIPTION, IDS_DOMAIN, 0, L"hasMasterNCs,{1cedc5da-3614-11d2-bf96-00c04fd8d5b0}",
};
//
// Help ID mappings
//
static DWORD const aFormHelpIDs[] =
{
0, 0
};
/*-----------------------------------------------------------------------------
/ PageProc_DomainController
/ -------------------------
/ PageProc for handling the messages for this object.
/
/ In:
/ pPage -> instance data for this form
/ hwnd = window handle for the form dialog
/ uMsg, wParam, lParam = message parameters
/
/ Out:
/ HRESULT (E_NOTIMPL) if not handled
/----------------------------------------------------------------------------*/
HRESULT CALLBACK PageProc_DomainController(LPCQPAGE pPage, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HRESULT hr = S_OK;
LPWSTR pQuery = NULL;
TraceEnter(TRACE_FORMS, "PageProc_DomainController");
switch (uMsg)
{
case CQPM_INITIALIZE:
case CQPM_RELEASE:
break;
case CQPM_ENABLE:
EnablePageControls(hwnd, NULL, 0, (BOOL)wParam);
break;
case CQPM_GETPARAMETERS:
{
hr = GetQueryString(&pQuery, c_szQueryPrefix, hwnd, NULL, 0);
if (SUCCEEDED(hr))
{
hr = QueryParamsAlloc((LPDSQUERYPARAMS*)lParam, pQuery, GLOBAL_HINSTANCE, ARRAYSIZE(columns), columns);
LocalFreeStringW(&pQuery);
}
FailGracefully(hr, "Failed to build DS argument block");
break;
}
case CQPM_CLEARFORM:
ResetPageControls(hwnd, NULL, 0);
break;
case CQPM_PERSIST:
{
BOOL fRead = (BOOL)wParam;
IPersistQuery* pPersistQuery = (IPersistQuery*)lParam;
hr = PersistQuery(pPersistQuery, fRead, c_szMsDomainControllers, hwnd, NULL, 0);
FailGracefully(hr, "Failed to persist page");
break;
}
case CQPM_HELP:
{
LPHELPINFO pHelpInfo = (LPHELPINFO)lParam;
WinHelp((HWND)pHelpInfo->hItemHandle,
DSQUERY_HELPFILE,
HELP_WM_HELP,
(DWORD_PTR)aFormHelpIDs);
break;
}
case DSQPM_GETCLASSLIST:
{
hr = ClassListAlloc((LPDSQUERYCLASSLIST*)lParam, c_szClassList, ARRAYSIZE(c_szClassList));
FailGracefully(hr, "Failed to allocate class list");
break;
}
case DSQPM_HELPTOPICS:
{
HWND hwndFrame = (HWND)lParam;
HtmlHelp(hwndFrame, TEXT("omc.chm::/adfind_dc.htm"), HH_HELP_FINDER, 0);
break;
}
default:
hr = E_NOTIMPL;
break;
}
exit_gracefully:
TraceLeaveResult(hr);
}
/*-----------------------------------------------------------------------------
/ DlgProc_DomainController
/ ------------
/ Handle dialog specific message for the Domain Controllers page.
/
/ In:
/ hwnd, uMsg, wParam, lParam = standard parameters
/
/ Out:
/ INT_PTR
/----------------------------------------------------------------------------*/
INT_PTR CALLBACK DlgProc_DomainController(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
INT_PTR fResult = 0;
LPCQPAGE pQueryPage;
if (uMsg == WM_INITDIALOG)
{
pQueryPage = (LPCQPAGE)lParam;
SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)pQueryPage);
}
return fResult;
}
/*-----------------------------------------------------------------------------
/ CDomainCH
/ -------------------
/ Column handler which converts the given property and value into a
/ string the user can understand.
/----------------------------------------------------------------------------*/
class CDomainCH : public IDsQueryColumnHandler
{
private:
LONG _cRef;
CComPtr<IADsPathname> m_spPathCracker;
HRESULT m_hrPathCrackerLoadError;
long m_lElement;
BOOL m_fFindDN;
HRESULT GetTextFromADSVALUE(const PADSVALUE pADsValue, LPWSTR pBuffer, INT cchBuffer);
public:
CDomainCH(REFCLSID rCLSID);
~CDomainCH();
// IUnkown
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppvObject);
// IDsQueryColumnHandler
STDMETHOD(Initialize)(THIS_ DWORD dwFlags, LPCWSTR pszServer, LPCWSTR pszUserName, LPCWSTR pszPassword);
STDMETHOD(GetText)(THIS_ ADS_SEARCH_COLUMN* pSearchColumn, LPWSTR pBuffer, INT cchBuffer);
};
ULONG CDomainCH::AddRef()
{
return InterlockedIncrement(&_cRef);
}
ULONG CDomainCH::Release()
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
HRESULT CDomainCH::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] =
{
QITABENT(CDomainCH, IDsQueryColumnHandler), // IID_IDsQueryColumnHandler
{0, 0 },
};
return QISearch(this, qit, riid, ppv);
}
//
// construction
//
CDomainCH::CDomainCH(REFCLSID rCLSID)
: m_hrPathCrackerLoadError(0), m_lElement (1), m_fFindDN(FALSE), _cRef(1)
{
if (IsEqualCLSID(rCLSID, CLSID_PathElement1CH))
{
}
else if (IsEqualCLSID(rCLSID, CLSID_PathElement3CH))
{
m_lElement = 3;
}
else if (IsEqualCLSID(rCLSID, CLSID_PathElementDomainCH))
{
m_lElement = 0;
m_fFindDN = true;
}
DllAddRef();
}
CDomainCH::~CDomainCH()
{
DllRelease();
}
//
// handle class factory stuff
//
STDAPI CDomainCH_CreateInstance(IUnknown* punkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
{
CDomainCH *pdch = new CDomainCH(*poi->pclsid);
if (!pdch)
return E_OUTOFMEMORY;
HRESULT hres = pdch->QueryInterface(IID_IUnknown, (void **)ppunk);
pdch->Release();
return hres;
}
// IDsQueryColumnHandler
STDMETHODIMP CDomainCH::Initialize(THIS_ DWORD dwFlags, LPCWSTR pszServer, LPCWSTR pszUserName, LPCWSTR pszPassword)
{
return S_OK;
}
STDMETHODIMP CDomainCH::GetText(ADS_SEARCH_COLUMN* pSearchColumn, LPWSTR pBuffer, INT cchBuffer)
{
HRESULT hr = S_OK;
DWORD iValue = 0;
TraceEnter(TRACE_FORMS, "CDomainCH::GetText");
if (!pSearchColumn || !pBuffer)
ExitGracefully(hr, E_UNEXPECTED,
"DSQUERY.DLL: Bad parameters passed to handler");
if (pSearchColumn->dwNumValues < 1
|| NULL == pSearchColumn->pADsValues
)
ExitGracefully(hr, S_OK,
"DSQUERY.DLL: no values in handler");
if (m_fFindDN)
{
//
// This section handles CLSID_CH_PathElementDomainCH
//
PADSVALUE pADsValue = NULL;
LPWSTR pwzResultName = NULL;
PDS_NAME_RESULTW pDsNameResult = NULL;
for (iValue = 0; iValue < pSearchColumn->dwNumValues; iValue++)
{
pADsValue = &(pSearchColumn->pADsValues[iValue]);
if (NULL == pADsValue
|| (pADsValue->dwType != ADSTYPE_CASE_IGNORE_STRING
&& pADsValue->dwType != ADSTYPE_DN_STRING)
)
ExitGracefully(hr, S_OK,
"DSQUERY.DLL: not a DN value in handler");
if (0 == StrCmpNW(L"DC=",pADsValue->CaseIgnoreString,3))
break;
}
if (iValue >= pSearchColumn->dwNumValues)
{
// no value found
StrCpyNW(pBuffer, L"", cchBuffer);
ExitGracefully(hr, S_OK,
"DSQUERY.DLL: no domain values in handler");
}
//
// We found the value, now try DsCrackNames to convert it to
// a DNS name. If this fails, fall back to path element 0.
//
TraceAssert(pADsValue);
DWORD dwErr = ::DsCrackNamesW(
(HANDLE)-1,
DS_NAME_FLAG_SYNTACTICAL_ONLY,
DS_FQDN_1779_NAME,
DS_CANONICAL_NAME,
1,
&(pADsValue->CaseIgnoreString),
&pDsNameResult);
hr = HRESULT_FROM_WIN32(dwErr);
if (SUCCEEDED(hr))
{
TraceAssert(pDsNameResult);
TraceAssert(1 == pDsNameResult->cItems);
if (DS_NAME_NO_ERROR == pDsNameResult->rItems->status)
{
TraceAssert(pDsNameResult->rItems->pDomain);
StrCpyNW(pBuffer, pDsNameResult->rItems->pDomain, cchBuffer);
DsFreeNameResultW(pDsNameResult);
goto exit_gracefully;
}
}
//
// This is the fallback scenario if DsCrackNames fails.
// If the domain is "CN=jonndom,CN=nttest,CN=microsoft,CN=com",
// the name displayed will be "jonndom".
//
}
hr = GetTextFromADSVALUE(
&(pSearchColumn->pADsValues[iValue]),
pBuffer,
cchBuffer);
exit_gracefully:
TraceLeaveResult(hr);
}
HRESULT CDomainCH::GetTextFromADSVALUE(const PADSVALUE pADsValue, LPWSTR pBuffer, INT cchBuffer)
{
HRESULT hr = S_OK;
CComBSTR sbstr;
TraceEnter(TRACE_FORMS, "CDomainCH::GetTextFromADSVALUE");
if (NULL == pADsValue
|| (pADsValue->dwType != ADSTYPE_CASE_IGNORE_STRING
&& pADsValue->dwType != ADSTYPE_DN_STRING)
|| !(pADsValue->CaseIgnoreString)
)
ExitGracefully(hr, S_OK,
"DSQUERY.DLL: not a DN value in handler");
if (!m_spPathCracker)
{
FailGracefully(m_hrPathCrackerLoadError,
"DSQUERY.DLL: Subsequent failure to load Path Cracker");
m_hrPathCrackerLoadError = CoCreateInstance(
CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER,
IID_IADsPathname, (PVOID *)&m_spPathCracker);
FailGracefully(m_hrPathCrackerLoadError,
"DSQUERY.DLL: First failure to load Path Cracker");
if (!m_spPathCracker)
{
m_hrPathCrackerLoadError = E_UNEXPECTED;
FailGracefully(m_hrPathCrackerLoadError,
"DSQUERY.DLL: CreateInstance did not load");
}
m_hrPathCrackerLoadError = m_spPathCracker->SetDisplayType(
ADS_DISPLAY_VALUE_ONLY);
FailGracefully(m_hrPathCrackerLoadError,
"DSQUERY.DLL: SetDisplayType failed");
}
// ADsPath starts with "LDAP://" but hasMasterNCs doesn't
hr = m_spPathCracker->Set(pADsValue->CaseIgnoreString,
(m_fFindDN) ? ADS_SETTYPE_DN : ADS_SETTYPE_FULL);
FailGracefully(hr, "DSQUERY.DLL: Set() failed");
hr = m_spPathCracker->GetElement(m_lElement, &sbstr);
FailGracefully(hr, "DSQUERY.DLL: GetElement() failed");
StrCpyNW(pBuffer, sbstr, cchBuffer);
exit_gracefully:
TraceLeaveResult(hr);
}