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.

827 lines
24 KiB

  1. // query.cpp
  2. #include "stdafx.h"
  3. #include <cmnquery.h>
  4. #include <dsquery.h>
  5. #include <shlobj.h>
  6. #include <dsclient.h>
  7. #include <iads.h>
  8. #include <adshlp.h>
  9. #define SECURITY_WIN32
  10. #include <security.h> // TranslateName
  11. #include <lmcons.h>
  12. #include <lmapibuf.h> // NetApiBufferFree
  13. #include <dsgetdc.h> // DsGetDCName
  14. #include "query.h"
  15. #include "rowitem.h"
  16. #include "resource.h"
  17. #include "namemap.h"
  18. #include "atlgdi.h"
  19. #include "util.h"
  20. #include <list>
  21. struct __declspec( uuid("ab50dec0-6f1d-11d0-a1c4-00aa00c16e65")) ICommonQuery;
  22. typedef const BYTE* LPCBYTE;
  23. HRESULT GetQuery(tstring& strScope, tstring& strQuery, byte_string& bsQueryData, HWND hWnd)
  24. {
  25. // Get instance of common query object
  26. CComQIPtr<ICommonQuery, &IID_ICommonQuery> spQuery;
  27. HRESULT hr = spQuery.CoCreateInstance(CLSID_CommonQuery, NULL, CLSCTX_INPROC_SERVER);
  28. RETURN_ON_FAILURE(hr);
  29. // Structure for DSQuery handler
  30. DSQUERYINITPARAMS dqip;
  31. memset(&dqip, 0, sizeof(dqip));
  32. dqip.cbStruct = sizeof(dqip);
  33. dqip.dwFlags = DSQPF_NOSAVE | DSQPF_ENABLEADMINFEATURES | DSQPF_ENABLEADVANCEDFEATURES;
  34. dqip.pDefaultScope = (LPTSTR)strScope.c_str();
  35. // Structure for common query
  36. OPENQUERYWINDOW oqw;
  37. memset(&oqw, 0, sizeof(oqw));
  38. oqw.cbStruct = sizeof(oqw);
  39. oqw.dwFlags = OQWF_SHOWOPTIONAL | OQWF_OKCANCEL | OQWF_HIDESEARCHUI | OQWF_SAVEQUERYONOK | OQWF_HIDEMENUS;
  40. oqw.clsidHandler = CLSID_DsQuery;
  41. oqw.pHandlerParameters = &dqip;
  42. CPersistQuery persistQuery;
  43. oqw.pPersistQuery = (IPersistQuery*)&persistQuery;
  44. if( !bsQueryData.empty() )
  45. {
  46. persistQuery.Load(bsQueryData, strScope);
  47. oqw.dwFlags |= OQWF_LOADQUERY;
  48. }
  49. CComPtr<IDataObject> spDO;
  50. hr = spQuery->OpenQueryWindow(hWnd, &oqw, &spDO);
  51. // if failed to open query window on persisted query
  52. if( FAILED(hr) && !bsQueryData.empty() )
  53. {
  54. // See if there is a problem with the scope
  55. CComPtr<IUnknown> spUnk;
  56. if( ADsOpenObject(strScope.c_str(), NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IUnknown, (LPVOID*)&spUnk) != S_OK )
  57. {
  58. // if so, try again with a null scope
  59. tstring strNullScope;
  60. persistQuery.Load(bsQueryData, strNullScope);
  61. hr = spQuery->OpenQueryWindow(hWnd, &oqw, &spDO);
  62. }
  63. }
  64. if( SUCCEEDED(hr) && spDO != NULL )
  65. {
  66. FORMATETC fmte = {0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  67. STGMEDIUM medium = { TYMED_NULL, NULL, NULL};
  68. static UINT s_cfDsQueryParams = 0;
  69. if( !s_cfDsQueryParams )
  70. s_cfDsQueryParams = RegisterClipboardFormat(CFSTR_DSQUERYPARAMS);
  71. fmte.cfFormat = (CLIPFORMAT)s_cfDsQueryParams;
  72. if( SUCCEEDED(spDO->GetData(&fmte, &medium)) )
  73. {
  74. LPDSQUERYPARAMS pDsQueryParams = (LPDSQUERYPARAMS)medium.hGlobal;
  75. LPWSTR pFilter = (LPWSTR)((CHAR*)pDsQueryParams + pDsQueryParams->offsetQuery);
  76. strQuery = pFilter;
  77. ReleaseStgMedium(&medium);
  78. }
  79. static UINT s_cfDsQueryScope = 0;
  80. if( !s_cfDsQueryScope )
  81. s_cfDsQueryScope = RegisterClipboardFormat(CFSTR_DSQUERYSCOPE);
  82. fmte.cfFormat = (CLIPFORMAT)s_cfDsQueryScope;
  83. if( SUCCEEDED(spDO->GetData(&fmte, &medium)) )
  84. {
  85. strScope = (LPWSTR)medium.hGlobal;
  86. ReleaseStgMedium(&medium);
  87. }
  88. persistQuery.Save(bsQueryData);
  89. }
  90. return hr;
  91. }
  92. /////////////////////////////////////////////////////////////////////////////////////////
  93. // CPersistQuery
  94. //
  95. /*-----------------------------------------------------------------------------
  96. / Constructor / IUnknown methods
  97. /----------------------------------------------------------------------------*/
  98. CPersistQuery::CPersistQuery()
  99. {
  100. m_cRefCount = 1;
  101. }
  102. //
  103. // IUnknown methods
  104. //
  105. STDMETHODIMP CPersistQuery::QueryInterface(REFIID riid, LPVOID* ppvObject)
  106. {
  107. VALIDATE_POINTER( ppvObject );
  108. if( IsEqualIID(riid, IID_IPersistQuery) )
  109. {
  110. *ppvObject = (LPVOID)(IPersistQuery*)this;
  111. return S_OK;
  112. }
  113. return E_NOTIMPL;
  114. }
  115. STDMETHODIMP_(ULONG) CPersistQuery::AddRef()
  116. {
  117. return ++m_cRefCount;
  118. }
  119. STDMETHODIMP_(ULONG) CPersistQuery::Release()
  120. {
  121. if( --m_cRefCount == 0 )
  122. {
  123. delete this;
  124. return 0;
  125. }
  126. return m_cRefCount;
  127. }
  128. /*-----------------------------------------------------------------------------
  129. / IPersist methods
  130. /----------------------------------------------------------------------------*/
  131. STDMETHODIMP CPersistQuery::GetClassID(THIS_ CLSID* pClassID)
  132. {
  133. return E_NOTIMPL;
  134. }
  135. /*-----------------------------------------------------------------------------
  136. / IPersistQuery methods
  137. /----------------------------------------------------------------------------*/
  138. STDMETHODIMP CPersistQuery::WriteString(LPCTSTR pSection, LPCTSTR pKey, LPCTSTR pValue)
  139. {
  140. if( pValue == NULL )
  141. return E_INVALIDARG;
  142. return WriteStruct(pSection, pKey, (LPVOID)pValue, (wcslen(pValue) + 1) * sizeof(WCHAR));
  143. }
  144. STDMETHODIMP CPersistQuery::WriteInt(LPCTSTR pSection, LPCTSTR pKey, INT value)
  145. {
  146. return WriteStruct(pSection, pKey, (LPVOID)&value, sizeof(int));
  147. }
  148. STDMETHODIMP CPersistQuery::WriteStruct(LPCTSTR pSection, LPCTSTR pKey, LPVOID pStruct, DWORD cbStruct)
  149. {
  150. if( pSection == NULL || pKey == NULL || pStruct == NULL )
  151. return E_INVALIDARG;
  152. LPBYTE pData = (LPBYTE)malloc(cbStruct + sizeof(DWORD));
  153. if( !pData ) return E_OUTOFMEMORY;
  154. *(LPDWORD)pData = cbStruct;
  155. memcpy(pData + sizeof(DWORD), pStruct, cbStruct);
  156. m_mapQueryData[pSection][pKey] = std::auto_ptr<BYTE>(pData);
  157. return S_OK;
  158. }
  159. STDMETHODIMP CPersistQuery::ReadString(LPCTSTR pSection, LPCTSTR pKey, LPTSTR pBuffer, INT cchBuffer)
  160. {
  161. return ReadStruct(pSection, pKey, (LPVOID)pBuffer, cchBuffer);
  162. }
  163. STDMETHODIMP CPersistQuery::ReadInt(LPCTSTR pSection, LPCTSTR pKey, LPINT pValue)
  164. {
  165. return ReadStruct(pSection, pKey, (LPVOID)pValue, sizeof(INT));
  166. }
  167. STDMETHODIMP CPersistQuery::ReadStruct(LPCTSTR pSection, LPCTSTR pKey, LPVOID pStruct, DWORD cbStruct)
  168. {
  169. VALIDATE_POINTER( pStruct );
  170. QueryDataMap::iterator itDataMap = m_mapQueryData.find(pSection);
  171. if( itDataMap == m_mapQueryData.end() )
  172. return E_FAIL;
  173. QuerySectionMap::iterator itSecMap = itDataMap->second.find(pKey);
  174. if( itSecMap == itDataMap->second.end() )
  175. return E_FAIL;
  176. LPBYTE pData = itSecMap->second.get();
  177. DWORD cbData = pData ? *(LPDWORD)pData : 0;
  178. if( cbData > cbStruct )
  179. return E_FAIL;
  180. // return value
  181. memcpy(pStruct, pData + sizeof(DWORD), cbData);
  182. return S_OK;
  183. }
  184. STDMETHODIMP CPersistQuery::Clear()
  185. {
  186. m_mapQueryData.clear();
  187. return S_OK;
  188. }
  189. void PutString(byte_string& strOut, const tstring& strData)
  190. {
  191. DWORD dwLen = strData.size();
  192. strOut.append((LPBYTE)&dwLen, sizeof(DWORD));
  193. strOut.append((LPBYTE)strData.data(), dwLen * sizeof(WCHAR));
  194. }
  195. HRESULT CPersistQuery::Save(byte_string& strOut)
  196. {
  197. strOut.resize(0);
  198. DWORD dwSize;
  199. QueryDataMap::iterator itDataMap;
  200. for( itDataMap = m_mapQueryData.begin(); itDataMap != m_mapQueryData.end(); itDataMap++ )
  201. {
  202. const tstring& strSecName = itDataMap->first;
  203. QuerySectionMap& SecMap = itDataMap->second;
  204. PutString(strOut, strSecName);
  205. QuerySectionMap::iterator itSecMap;
  206. for( itSecMap = SecMap.begin(); itSecMap != SecMap.end(); itSecMap++ )
  207. {
  208. const tstring& strValueName = itSecMap->first;
  209. LPBYTE pData = itSecMap->second.get();
  210. if( pData )
  211. {
  212. PutString(strOut, strValueName);
  213. strOut.append(pData, *(LPDWORD)pData + sizeof(DWORD));
  214. }
  215. }
  216. dwSize = 0;
  217. strOut.append((LPBYTE)&dwSize, sizeof(DWORD));
  218. }
  219. dwSize = 0;
  220. strOut.append((LPBYTE)&dwSize, sizeof(DWORD));
  221. return S_OK;
  222. }
  223. BOOL GetString(LPCBYTE& pbIn, tstring& strData)
  224. {
  225. if( !pbIn ) return FALSE;
  226. DWORD dwLen = *(LPDWORD)pbIn;
  227. pbIn += sizeof(DWORD);
  228. if( dwLen != 0 )
  229. {
  230. strData.assign((LPWSTR)pbIn, dwLen);
  231. pbIn += dwLen * sizeof(WCHAR);
  232. }
  233. return(dwLen != 0);
  234. }
  235. HRESULT CPersistQuery::Load(byte_string& strIn, tstring& strScope)
  236. {
  237. m_mapQueryData.clear();
  238. LPCBYTE pData = strIn.data();
  239. if( !pData ) return E_INVALIDARG;
  240. tstring strSecName;
  241. while( GetString(pData, strSecName) )
  242. {
  243. QuerySectionMap& SecMap = m_mapQueryData[strSecName];
  244. tstring strName;
  245. while( GetString(pData, strName) )
  246. {
  247. DWORD dwSize = *(LPDWORD)pData + sizeof(DWORD);
  248. if( strName == _T("Value0") )
  249. {
  250. tstring strQueryTmp = (LPCWSTR)(pData+sizeof(DWORD));
  251. ExpandDCWildCard(strQueryTmp);
  252. DWORD dwStringSize = strQueryTmp.size() ? ((strQueryTmp.size() + 1) * sizeof(wchar_t)) : 0;
  253. LPDWORD pdwBuf = (LPDWORD)malloc(dwStringSize + sizeof(DWORD));
  254. if( pdwBuf == NULL )
  255. {
  256. return E_OUTOFMEMORY;
  257. }
  258. pdwBuf[0] = dwStringSize;
  259. memcpy(pdwBuf+1, strQueryTmp.c_str(), dwStringSize);
  260. SecMap[strName] = std::auto_ptr<BYTE>((LPBYTE)pdwBuf);
  261. }
  262. else
  263. {
  264. LPBYTE pBuf = (LPBYTE)malloc(dwSize);
  265. if( pBuf == NULL )
  266. return E_OUTOFMEMORY;
  267. memcpy(pBuf, pData, dwSize);
  268. SecMap[strName] = std::auto_ptr<BYTE>(pBuf);
  269. }
  270. pData += dwSize;
  271. }
  272. // if DsQuery section, override the persisted scope & scope size values
  273. // with our own. This is necessary when the local scope option is specified
  274. // because then the scope is determined at run-time and may be different than
  275. // the persisted value.
  276. if( strSecName == _T("DsQuery") )
  277. {
  278. DWORD dwScopeSize = strScope.size() ? ((strScope.size() + 1) * sizeof(wchar_t)) : 0;
  279. // add scope size integer equal to byte length of scope string
  280. LPDWORD pdwBuf = (LPDWORD)malloc(2 * sizeof(DWORD));
  281. if( pdwBuf == NULL )
  282. {
  283. return E_OUTOFMEMORY;
  284. }
  285. pdwBuf[0] = sizeof(DWORD);
  286. pdwBuf[1] = dwScopeSize;
  287. SecMap[_T("ScopeSize")] = std::auto_ptr<BYTE>((LPBYTE)pdwBuf);
  288. // add scope string value
  289. if( dwScopeSize )
  290. {
  291. pdwBuf = (LPDWORD)malloc(dwScopeSize + sizeof(DWORD));
  292. if( pdwBuf == NULL )
  293. {
  294. return E_OUTOFMEMORY;
  295. }
  296. pdwBuf[0] = dwScopeSize;
  297. memcpy(pdwBuf+1, strScope.c_str(), dwScopeSize);
  298. SecMap[_T("Scope")] = std::auto_ptr<BYTE>((LPBYTE)pdwBuf);
  299. }
  300. }
  301. }
  302. return S_OK;
  303. }
  304. /////////////////////////////////////////////////////////////////////////////////////////////////////////
  305. // Query Utility Functions
  306. //
  307. HRESULT GetQueryScope(HWND hDlg, tstring& strScope)
  308. {
  309. DSBROWSEINFO dsbi;
  310. TCHAR szBuffer[MAX_PATH] = {0};
  311. tstring strCaption = StrLoadString(IDS_SCOPEBROWSE_CAPTION);
  312. tstring strTitle = StrLoadString(IDS_SELECTSCOPE);
  313. dsbi.cbStruct = sizeof(dsbi);
  314. dsbi.hwndOwner = hDlg;
  315. dsbi.pszCaption = strCaption.c_str();
  316. dsbi.pszTitle = strTitle.c_str();
  317. dsbi.pszRoot = NULL;
  318. dsbi.pszPath = szBuffer;
  319. dsbi.cchPath = lengthof(szBuffer);
  320. dsbi.dwFlags = DSBI_ENTIREDIRECTORY;
  321. dsbi.pfnCallback = NULL;
  322. dsbi.lParam = (LPARAM)0;
  323. if( !strScope.empty() && strScope.size() < MAX_PATH )
  324. {
  325. lstrcpyn( szBuffer, strScope.c_str(), MAX_PATH );
  326. dsbi.dwFlags |= DSBI_EXPANDONOPEN;
  327. }
  328. HRESULT hr = S_FALSE;
  329. if( IDOK == DsBrowseForContainer(&dsbi) )
  330. {
  331. strScope = szBuffer;
  332. hr = S_OK;
  333. }
  334. return hr;
  335. }
  336. void GetScopeDisplayString(tstring& strScope, tstring& strDisplay)
  337. {
  338. strDisplay.erase();
  339. if( !strScope.empty() )
  340. {
  341. LPCWSTR pszScope = strScope.c_str();
  342. // Special case for GC: use display name "Entire Directory"
  343. if( _wcsnicmp(L"GC:", pszScope, 3) == 0 )
  344. {
  345. CString strDir;
  346. strDir.LoadString(IDS_ENTIRE_DIRECTORY);
  347. strDisplay = strDir;
  348. }
  349. else
  350. {
  351. if( _wcsnicmp(L"LDAP://", pszScope, 7) == 0 )
  352. pszScope += 7;
  353. WCHAR szBuf[MAX_PATH];
  354. ULONG cBuf = MAX_PATH;
  355. BOOL bStat = TranslateName(pszScope, NameFullyQualifiedDN, NameCanonical, szBuf, &cBuf);
  356. if( bStat )
  357. {
  358. int nLen = wcslen(szBuf);
  359. if( (nLen > 0) && (szBuf[nLen-1] == L'/') )
  360. nLen--;
  361. strDisplay.assign(szBuf, nLen);
  362. }
  363. else
  364. {
  365. strDisplay = strScope;
  366. }
  367. }
  368. }
  369. }
  370. void GetFullyQualifiedScopeString(tstring& strScope, tstring& strQualified)
  371. {
  372. strQualified.erase();
  373. if( !strScope.empty() )
  374. {
  375. // TranslateName expects a trailing '/' on a canonical domain name
  376. tstring strTmp = strScope;
  377. strTmp += L"/";
  378. WCHAR* pszBuf = NULL;
  379. ULONG cBuf = 0;
  380. BOOL bStat = TranslateName(strTmp.c_str(), NameCanonical, NameFullyQualifiedDN, pszBuf, &cBuf);
  381. if( cBuf )
  382. {
  383. pszBuf = new WCHAR[cBuf];
  384. if( pszBuf )
  385. {
  386. bStat = TranslateName(strTmp.c_str(), NameCanonical, NameFullyQualifiedDN, pszBuf, &cBuf);
  387. }
  388. }
  389. if( bStat )
  390. {
  391. strQualified = L"LDAP://";
  392. strQualified += pszBuf;
  393. }
  394. else
  395. {
  396. strQualified = strScope;
  397. }
  398. if( pszBuf )
  399. {
  400. delete [] pszBuf;
  401. }
  402. }
  403. }
  404. LPCWSTR GetLocalDomain()
  405. {
  406. static tstring strLocDomain;
  407. if( !strLocDomain.empty() )
  408. return strLocDomain.c_str();
  409. DOMAIN_CONTROLLER_INFO* pDcInfo = NULL;
  410. DWORD dwStat = DsGetDcName(NULL, NULL, NULL, NULL, DS_DIRECTORY_SERVICE_REQUIRED|DS_RETURN_DNS_NAME, &pDcInfo);
  411. if( dwStat == NO_ERROR && pDcInfo != NULL )
  412. {
  413. tstring str = pDcInfo->DomainName;
  414. GetFullyQualifiedScopeString(str, strLocDomain);
  415. NetApiBufferFree(pDcInfo);
  416. }
  417. return strLocDomain.c_str();
  418. }
  419. HRESULT GetNamingContext(NameContextType ctx, LPCWSTR* ppszContextDN)
  420. {
  421. VALIDATE_POINTER( ppszContextDN );
  422. const static LPCWSTR pszContextName[NAMECTX_COUNT] = { L"schemaNamingContext", L"configurationNamingContext"};
  423. static tstring strContextDN[NAMECTX_COUNT];
  424. HRESULT hr = S_OK;
  425. if( strContextDN[ctx].empty() )
  426. {
  427. CComVariant var;
  428. CComPtr<IADs> pObj;
  429. hr = ADsGetObject(L"LDAP://rootDSE", IID_IADs, (void**)&pObj);
  430. if( SUCCEEDED(hr) )
  431. {
  432. CComBSTR bstrProp = const_cast<LPWSTR>(pszContextName[ctx]);
  433. hr = pObj->Get( bstrProp, &var );
  434. if( SUCCEEDED(hr) )
  435. {
  436. strContextDN[ctx] = var.bstrVal;
  437. *ppszContextDN = strContextDN[ctx].c_str();
  438. }
  439. }
  440. }
  441. else
  442. {
  443. *ppszContextDN = strContextDN[ctx].c_str();
  444. hr = S_OK;
  445. }
  446. return hr;
  447. }
  448. HRESULT GetClassesOfCategory(IDirectorySearch* pDirSrch, tstring& strCategory, std::set<tstring>& setClasses)
  449. {
  450. VALIDATE_POINTER( pDirSrch );
  451. // Form query filter for class with class/category name
  452. tstring strFilter = L"(&(objectCategory=classSchema)(ldapDisplayName=";
  453. strFilter += strCategory;
  454. strFilter += L"))";
  455. // Query for category that class belongs to
  456. ADS_SEARCH_HANDLE hSearch;
  457. LPWSTR pszDn = L"defaultObjectCategory";
  458. HRESULT hr = pDirSrch->ExecuteSearch(const_cast<LPWSTR>(strFilter.c_str()), &pszDn, 1, &hSearch);
  459. if( SUCCEEDED(hr) )
  460. {
  461. hr = pDirSrch->GetFirstRow(hSearch);
  462. if( hr == S_OK )
  463. {
  464. ADS_SEARCH_COLUMN col;
  465. hr = pDirSrch->GetColumn(hSearch, pszDn, &col);
  466. if( SUCCEEDED(hr) )
  467. {
  468. // Form query filter for all structure classes belonging to this category
  469. strFilter = L"(&(objectCategory=classSchema)(objectClassCategory=1)(defaultObjectCategory=";
  470. strFilter += col.pADsValues->DNString;
  471. strFilter += L"))";
  472. // Query for LDAP name of each class
  473. ADS_SEARCH_HANDLE hSearch2;
  474. LPWSTR pszName = L"ldapDisplayName";
  475. hr = pDirSrch->ExecuteSearch(const_cast<LPWSTR>(strFilter.c_str()), &pszName, 1, &hSearch2);
  476. if( SUCCEEDED(hr) )
  477. {
  478. HRESULT hr2;
  479. while( (hr2 = pDirSrch->GetNextRow(hSearch2)) == S_OK )
  480. {
  481. ADS_SEARCH_COLUMN col2;
  482. hr2 = pDirSrch->GetColumn(hSearch2, pszName, &col2);
  483. if( SUCCEEDED(hr2) )
  484. {
  485. setClasses.insert(col2.pADsValues->CaseIgnoreString);
  486. pDirSrch->FreeColumn(&col2);
  487. }
  488. }
  489. pDirSrch->CloseSearchHandle(hSearch2);
  490. }
  491. pDirSrch->FreeColumn(&col);
  492. }
  493. }
  494. pDirSrch->CloseSearchHandle(hSearch);
  495. }
  496. return hr;
  497. }
  498. HRESULT GetSubclassesOfClass(IDirectorySearch* pDirSrch, tstring& strClass, std::set<tstring>& setClasses)
  499. {
  500. VALIDATE_POINTER( pDirSrch );
  501. // Form query filter for classes that derive from this class
  502. tstring strFilter = L"(&(objectCategory=classSchema)(subClassOf=";
  503. strFilter += strClass;
  504. strFilter += L"))";
  505. // Get display names of subclasses
  506. ADS_SEARCH_HANDLE hSearch;
  507. LPWSTR pszName = L"lDAPDisplayName";
  508. HRESULT hr = pDirSrch->ExecuteSearch(const_cast<LPWSTR>(strFilter.c_str()), &pszName, 1, &hSearch);
  509. if( SUCCEEDED(hr) )
  510. {
  511. while( (hr = pDirSrch->GetNextRow(hSearch)) == S_OK )
  512. {
  513. ADS_SEARCH_COLUMN col;
  514. hr = pDirSrch->GetColumn(hSearch, pszName, &col);
  515. if( SUCCEEDED(hr) )
  516. {
  517. tstring strSubclass = col.pADsValues->CaseIgnoreString;
  518. pDirSrch->FreeColumn(&col);
  519. setClasses.insert(strSubclass);
  520. GetSubclassesOfClass(pDirSrch, strSubclass, setClasses);
  521. }
  522. }
  523. pDirSrch->CloseSearchHandle( hSearch );
  524. }
  525. return hr;
  526. }
  527. HRESULT GetQueryClasses(tstring& strQuery, std::set<tstring>& setClasses)
  528. {
  529. // Create a schema directory search object
  530. LPCWSTR pszSchemaDN;
  531. HRESULT hr = GetNamingContext(NAMECTX_SCHEMA, &pszSchemaDN);
  532. RETURN_ON_FAILURE(hr);
  533. tstring strScope = L"LDAP://";
  534. strScope += pszSchemaDN;
  535. CComPtr<IDirectorySearch> spDirSrch;
  536. hr = ADsOpenObject(strScope.c_str(), NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (LPVOID*)&spDirSrch);
  537. RETURN_ON_FAILURE(hr)
  538. // Set search preferences
  539. ADS_SEARCHPREF_INFO prefInfo[2];
  540. prefInfo[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE; // sub-tree search
  541. prefInfo[0].vValue.dwType = ADSTYPE_INTEGER;
  542. prefInfo[0].vValue.Integer = ADS_SCOPE_ONELEVEL;
  543. prefInfo[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE; // paged results
  544. prefInfo[1].vValue.dwType = ADSTYPE_INTEGER;
  545. prefInfo[1].vValue.Integer = 64;
  546. hr = spDirSrch->SetSearchPreference( prefInfo, lengthof(prefInfo) );
  547. RETURN_ON_FAILURE(hr)
  548. #define CAT_PROP L"(objectCategory="
  549. #define CLS_PROP L"(objectClass="
  550. UINT uPos = 0;
  551. while( (uPos = strQuery.find(CAT_PROP, uPos)) != tstring::npos )
  552. {
  553. uPos += wcslen(CAT_PROP);
  554. UINT uEnd = strQuery.find(L")", uPos);
  555. if( uEnd != tstring::npos )
  556. {
  557. tstring strCat = strQuery.substr(uPos, uEnd - uPos);
  558. hr = GetClassesOfCategory(spDirSrch, strCat, setClasses);
  559. }
  560. uPos = uEnd;
  561. }
  562. uPos = 0;
  563. while( (uPos = strQuery.find(CLS_PROP, uPos)) != tstring::npos )
  564. {
  565. uPos += wcslen(CLS_PROP);
  566. UINT uEnd = strQuery.find(L")", uPos);
  567. if( uEnd != tstring::npos )
  568. {
  569. tstring strClass = strQuery.substr(uPos, uEnd - uPos);
  570. setClasses.insert(strClass);
  571. hr = GetSubclassesOfClass(spDirSrch, strClass, setClasses);
  572. }
  573. uPos = uEnd;
  574. }
  575. // get lower case version of query string
  576. LPWSTR pszQueryLC = new WCHAR[(strQuery.size() + 1)];
  577. if( !pszQueryLC ) return E_OUTOFMEMORY;
  578. wcscpy(pszQueryLC, strQuery.c_str());
  579. _wcslwr(pszQueryLC);
  580. // check for non-class related queries generated by DSQuery
  581. if( wcsstr(pszQueryLC, L"(ou>=\"\")") != NULL )
  582. setClasses.insert(L"organizationalUnit");
  583. if( wcsstr(pszQueryLC, L"(samaccounttype=805306369)") != NULL ||
  584. wcsstr(pszQueryLC, L"(primarygroupid=516)") != NULL )
  585. setClasses.insert(L"computer");
  586. delete [] pszQueryLC;
  587. return hr;
  588. }
  589. HRESULT FindClassObject(LPCWSTR pszClass, tstring& strObjPath)
  590. {
  591. VALIDATE_POINTER( pszClass );
  592. CComPtr<IDirectorySearch> spDirSrch;
  593. HRESULT hr = ADsOpenObject(GetLocalDomain(), NULL, NULL, ADS_SECURE_AUTHENTICATION, IID_IDirectorySearch, (LPVOID*)&spDirSrch);
  594. RETURN_ON_FAILURE(hr)
  595. // Set search preferences - search sub-tree for single object
  596. ADS_SEARCHPREF_INFO prefInfo[2];
  597. prefInfo[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE; // sub-tree search
  598. prefInfo[0].vValue.dwType = ADSTYPE_INTEGER;
  599. prefInfo[0].vValue.Integer = ADS_SCOPE_SUBTREE;
  600. prefInfo[1].dwSearchPref = ADS_SEARCHPREF_SIZE_LIMIT; // single object
  601. prefInfo[1].vValue.dwType = ADSTYPE_INTEGER;
  602. prefInfo[1].vValue.Integer = 1;
  603. hr = spDirSrch->SetSearchPreference(prefInfo, lengthof(prefInfo));
  604. RETURN_ON_FAILURE(hr)
  605. // Set filter string to (&(ObjectCategory=class_name)(objectClass=class_name))
  606. tstring strFilter = L"(&(objectCategory=";
  607. strFilter += pszClass;
  608. strFilter += L")(objectClass=";
  609. strFilter += pszClass;
  610. strFilter += L"))";
  611. // Query for distinguished name of class
  612. ADS_SEARCH_HANDLE hSearch;
  613. LPWSTR pszDn = L"distinguishedName";
  614. hr = spDirSrch->ExecuteSearch(const_cast<LPWSTR>(strFilter.c_str()), &pszDn, 1, &hSearch);
  615. if( SUCCEEDED(hr) )
  616. {
  617. hr = spDirSrch->GetFirstRow(hSearch);
  618. if( hr == S_OK )
  619. {
  620. ADS_SEARCH_COLUMN col;
  621. hr = spDirSrch->GetColumn(hSearch, pszDn, &col);
  622. if( SUCCEEDED(hr) )
  623. {
  624. strObjPath = col.pADsValues->DNString;
  625. spDirSrch->FreeColumn(&col);
  626. }
  627. }
  628. spDirSrch->CloseSearchHandle(hSearch);
  629. }
  630. return hr;
  631. }