Windows2000/private/shell/shell32/netdsfnd.cpp
2020-09-30 17:12:32 +02:00

345 lines
8.7 KiB
C++

#include "shellprv.h"
#pragma hdrstop
#include "docfind.h"
#include "dsgetdc.h"
#include "ntdsapi.h"
#include "activeds.h"
#include "iadsp.h"
#include "lm.h"
#ifdef WINNT
// search the DS for computer objects
// BUGBUG: this should be const, but ADSI
LPTSTR c_aszAttributes[] = { TEXT("DNShostname"), };
class CNetFindInDS : public IDFEnum
{
private:
LPTSTR _pszCompName;
IDocFindFolder *_pdfFolder;
LONG _cRef;
IDirectorySearch* _pds;
IADsPathname* _padp;
ADS_SEARCH_HANDLE _hSearch;
// helper methods
HRESULT _StrFromRow(LPTSTR pszProperty, LPTSTR pszBuffer, INT cchBuffer);
HRESULT _InitSearch(LPCTSTR pszName);
public:
CNetFindInDS(LPCTSTR pszCompName, IShellFolder *psf);
~CNetFindInDS();
// *** IUnknown methods ***
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// *** IDFEnum methods ***
STDMETHODIMP Next(LPITEMIDLIST *ppidl,
int *pcObjectSearched, int *pcFoldersSearched, BOOL *pfContinue,
int *pState, HWND hwnd);
STDMETHODIMP Skip(int celt)
{ return E_NOTIMPL; };
STDMETHODIMP Reset()
{ return E_NOTIMPL; };
STDMETHODIMP StopSearch()
{ return E_NOTIMPL; };
STDMETHODIMP_(BOOL) FQueryIsAsync()
{ return FALSE; };
STDMETHODIMP GetAsyncCount(DBCOUNTITEM *pdwTotalAsync, int *pnPercentComplete, BOOL *pfQueryDone)
{ return E_NOTIMPL; };
STDMETHODIMP GetItemIDList(UINT iItem, LPITEMIDLIST *ppidl)
{ return E_NOTIMPL; };
STDMETHODIMP GetExtendedDetailsOf(LPCITEMIDLIST pidl, UINT iCol, LPSHELLDETAILS pdi)
{ return E_NOTIMPL; };
STDMETHODIMP GetExtendedDetailsULong(LPCITEMIDLIST pidl, UINT iCol, ULONG *pul)
{ return E_NOTIMPL; };
STDMETHODIMP GetItemID(UINT iItem, DWORD *puWorkID)
{ return E_NOTIMPL; };
STDMETHODIMP SortOnColumn(UINT iCol, BOOL fAscending)
{ return E_NOTIMPL; };
};
// IUnknown
STDMETHODIMP CNetFindInDS::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] =
{
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
STDMETHODIMP_(ULONG) CNetFindInDS::AddRef()
{
return InterlockedIncrement(&_cRef);
}
STDMETHODIMP_(ULONG) CNetFindInDS::Release()
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
// construction / destruction
CNetFindInDS::CNetFindInDS(LPCTSTR pszCompName, IShellFolder* psf) :
_pszCompName(NULL),
_pdfFolder(NULL),
_cRef(1),
_pds(NULL),
_hSearch(NULL)
{
Str_SetPtr(&_pszCompName, pszCompName);
psf->QueryInterface(IID_IDocFindFolder, (void **)&_pdfFolder);
}
CNetFindInDS::~CNetFindInDS()
{
Str_SetPtr(&_pszCompName, NULL);
if ( _hSearch )
_pds->CloseSearchHandle(_hSearch);
if ( _pds )
_pds->Release();
if ( _padp )
_padp->Release();
_pdfFolder->Release();
}
// given the ADS_SEARCH_COLUMN get a string back from it.
HRESULT CNetFindInDS::_StrFromRow(LPTSTR pszProperty, LPTSTR pszBuffer, INT cchBuffer)
{
HRESULT hres = S_OK;
ADS_SEARCH_COLUMN asc;
hres = _pds->GetColumn(_hSearch, pszProperty, &asc);
if ( SUCCEEDED(hres) )
{
switch ( asc.dwADsType )
{
case ADSTYPE_DN_STRING:
case ADSTYPE_CASE_EXACT_STRING:
case ADSTYPE_CASE_IGNORE_STRING:
case ADSTYPE_PRINTABLE_STRING:
case ADSTYPE_NUMERIC_STRING:
StrCpyN(pszBuffer, asc.pADsValues[0].DNString, cchBuffer);
break;
default:
hres = E_INVALIDARG; // bad column type
break;
}
}
return hres;
}
// initialize the search ready with the path the GC:
HRESULT CNetFindInDS::_InitSearch(LPCTSTR pszName)
{
HRESULT hres = E_FAIL;
PDOMAIN_CONTROLLER_INFO pdci = NULL;
// get the DNS of the domain forest we are part of
DWORD dwres = DsGetDcName(NULL, NULL, NULL, NULL, DS_RETURN_DNS_NAME|DS_DIRECTORY_SERVICE_REQUIRED, &pdci);
if ( (NO_ERROR == dwres) && pdci->DnsForestName )
{
TCHAR szBuffer[MAX_PATH];
wnsprintf(szBuffer, ARRAYSIZE(szBuffer), TEXT("GC://%s"), pdci->DnsForestName);
hres = ADsOpenObject(szBuffer,
NULL, NULL, ADS_SECURE_AUTHENTICATION,
IID_IDirectorySearch, (void **)&_pds);
if ( SUCCEEDED(hres) )
{
ADS_SEARCHPREF_INFO prefInfo[3];
// do a sub tree, async paged search.
prefInfo[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE; // sub-tree search
prefInfo[0].vValue.dwType = ADSTYPE_INTEGER;
prefInfo[0].vValue.Integer = ADS_SCOPE_SUBTREE;
prefInfo[1].dwSearchPref = ADS_SEARCHPREF_ASYNCHRONOUS; // async
prefInfo[1].vValue.dwType = ADSTYPE_BOOLEAN;
prefInfo[1].vValue.Boolean = TRUE;
prefInfo[2].dwSearchPref = ADS_SEARCHPREF_PAGESIZE; // paged results
prefInfo[2].vValue.dwType = ADSTYPE_INTEGER;
prefInfo[2].vValue.Integer = 32;
hres = _pds->SetSearchPreference(prefInfo, ARRAYSIZE(prefInfo));
if ( SUCCEEDED(hres) )
{
// build a filter that will find all the computer objects whose name starts
// or ends with the string we have been given, the DS is bad at "contains"
wnsprintf(szBuffer, ARRAYSIZE(szBuffer),
TEXT("(&(sAMAccountType=805306369)(|(SAMAccountName=%s*)(SAMAccountName=*%s)))"),
pszName, pszName);
hres = _pds->ExecuteSearch(szBuffer, c_aszAttributes, ARRAYSIZE(c_aszAttributes), &_hSearch);
}
}
NetApiBufferFree(pdci);
}
return hres;
}
// itterate over results from a DS search
STDMETHODIMP CNetFindInDS::Next(LPITEMIDLIST *ppidl, int *pcObjectSearched, int *pcFoldersSearched,
BOOL *pfContinue, int *pState, HWND hwnd)
{
HRESULT hres = S_OK;
WCHAR szName[MAX_PATH], szUNC[MAX_PATH+2];
*pState = GNF_DONE;
*pfContinue = FALSE;
// if _hSearch == NULL then we have not searched yet, therefore initialize the
// query against the DS.
if ( !_hSearch )
hres = _InitSearch(_pszCompName);
while ( SUCCEEDED(hres) && _hSearch )
{
hres = _pds->GetNextRow(_hSearch);
if ( SUCCEEDED(hres) )
{
if ( (hres == S_ADS_NOMORE_ROWS) )
break;
*pcObjectSearched += 1; // we have another object
// get the DNSHostName of the object, this we can then use to construct a
// UNC name for the object. If this fails then we skip the result (the
// column may not be defined, or perhaps its not a string, eitherway
// we should ignore it).
if ( SUCCEEDED(_StrFromRow(TEXT("DNShostName"), szName, ARRAYSIZE(szName))) )
{
LPITEMIDLIST pidl;
INT iFolder;
wnsprintf(szUNC, ARRAYSIZE(szUNC), TEXT("\\\\%s"), szName);
pidl = ILCreateFromPath(szUNC);
if ( !pidl )
continue;
LPITEMIDLIST pidlParent = ILCloneParent(pidl);
if (!pidlParent)
continue;
hres = _pdfFolder->AddFolderToFolderList(pidl, FALSE, &iFolder);
ILFree(pidlParent);
if ( SUCCEEDED(hres) )
{
// append attempts to resize an existing pidl
// it will return NULL on failure.
*ppidl = DocFind_AppendIFolder(ILClone(ILFindLastID(pidl)), iFolder);
if ( *ppidl )
{
ILFree(pidl);
*pState = GNF_MATCH;
*pfContinue = TRUE;
break; // success we have a result
}
}
ILFree(pidl);
ILFree(*ppidl);
}
}
}
return hres;
}
#endif
// return an enumerator if the user is logged into the DS, if they are
// not then we return S_FALSE.
STDAPI CNetFindInDS_CreateInstance(LPCTSTR pszCompName, IShellFolder *psf, IDFEnum **ppdfe)
{
#ifdef WINNT
*ppdfe = NULL;
if ( !GetEnvironmentVariable(TEXT("USERDNSDOMAIN"), NULL, 0) )
return S_FALSE;
*ppdfe = new CNetFindInDS(pszCompName, psf);
if ( !*ppdfe )
return E_OUTOFMEMORY;
return S_OK;
#else
return S_FALSE; // S_FALSE == use old search
#endif
}