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.

1687 lines
34 KiB

  1. #include "StdAfx.h"
  2. #include "ADMTScript.h"
  3. #include "DomainContainer.h"
  4. #include "Error.h"
  5. #include "AdsiHelpers.h"
  6. #include "NameCracker.h"
  7. #include <map>
  8. #include <memory>
  9. #include <string>
  10. #include <LM.h>
  11. #include <DsGetDC.h>
  12. #include <DsRole.h>
  13. #include <NtLdap.h>
  14. #include <NtDsAPI.h>
  15. #include <ActiveDS.h>
  16. #include <Sddl.h>
  17. #define NO_WBEM
  18. #include "T_SafeVector.h"
  19. #ifndef tstring
  20. typedef std::basic_string<_TCHAR> tstring;
  21. #endif
  22. using namespace _com_util;
  23. namespace _DomainContainer
  24. {
  25. tstring __stdcall CreateFilter(LPCTSTR pszFilter, const StringSet& setExcludeNames);
  26. bool __stdcall IsClass(LPCTSTR pszClass, const _variant_t& vntClass);
  27. #define MIN_NON_RESERVED_RID 1000
  28. bool __stdcall IsUserRid(const _variant_t& vntSid);
  29. IDispatchPtr GetADsObject(_bstr_t strPath);
  30. void ReportADsError(HRESULT hr, const IID& iid = GUID_NULL);
  31. } // namespace _DomainContainer
  32. using namespace _DomainContainer;
  33. //---------------------------------------------------------------------------
  34. // Domain Class
  35. //---------------------------------------------------------------------------
  36. // Constructors and Destructor ----------------------------------------------
  37. CDomain::CDomain() :
  38. m_bUpLevel(false),
  39. m_bNativeMode(false)
  40. {
  41. }
  42. CDomain::~CDomain()
  43. {
  44. }
  45. // Implementation -----------------------------------------------------------
  46. // Initialize Method
  47. //
  48. // Initializes domain parameters such as DNS domain name, Flat (NETBIOS) domain name,
  49. // forest name, domain controller name.
  50. void CDomain::Initialize(_bstr_t strDomainName)
  51. {
  52. if (!strDomainName)
  53. {
  54. AdmtThrowError(
  55. GUID_NULL, GUID_NULL,
  56. E_INVALIDARG,
  57. IDS_E_DOMAIN_NAME_NOT_SPECIFIED
  58. );
  59. }
  60. // retrieve name of a domain controller in the domain
  61. m_strDcName = GetDcName(strDomainName);
  62. // retrieve domain information
  63. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC ppdib;
  64. DWORD dwError = DsRoleGetPrimaryDomainInformation(
  65. m_strDcName,
  66. DsRolePrimaryDomainInfoBasic,
  67. (BYTE**)&ppdib
  68. );
  69. if (dwError != NO_ERROR)
  70. {
  71. AdmtThrowError(
  72. GUID_NULL, GUID_NULL,
  73. HRESULT_FROM_WIN32(dwError),
  74. IDS_E_CANT_GET_DOMAIN_INFORMATION,
  75. (LPCTSTR)strDomainName
  76. );
  77. }
  78. // initialize data members from domain information
  79. m_bUpLevel = (ppdib->Flags & DSROLE_PRIMARY_DS_RUNNING) ? true : false;
  80. m_bNativeMode = (m_bUpLevel && !(ppdib->Flags & DSROLE_PRIMARY_DS_MIXED_MODE)) ? true : false;
  81. if (ppdib->DomainNameDns)
  82. {
  83. m_strDomainNameDns = ppdib->DomainNameDns;
  84. }
  85. else
  86. {
  87. m_strDomainNameDns = _bstr_t();
  88. }
  89. if (ppdib->DomainNameFlat)
  90. {
  91. m_strDomainNameFlat = ppdib->DomainNameFlat;
  92. }
  93. else
  94. {
  95. m_strDomainNameFlat = _bstr_t();
  96. }
  97. if (ppdib->DomainForestName)
  98. {
  99. m_strForestName = ppdib->DomainForestName;
  100. }
  101. else
  102. {
  103. m_strForestName = _bstr_t();
  104. }
  105. DsRoleFreeMemory(ppdib);
  106. // initialize ADsPath
  107. if (m_bUpLevel)
  108. {
  109. m_strADsPath = _T("LDAP://") + m_strDomainNameDns;
  110. // retrieve global catalog server name for uplevel domains
  111. // m_strGcName = GetGcName();
  112. }
  113. else
  114. {
  115. m_strADsPath = _T("WinNT://") + m_strDomainNameFlat;
  116. }
  117. // retrieve domain sid
  118. m_strDomainSid = GetSid();
  119. // initialize dispatch interface pointer to active directory object
  120. m_sp = GetADsObject(m_strADsPath);
  121. }
  122. // GetDcName Method
  123. //
  124. // Retrieves name of domain controller in the given domain.
  125. _bstr_t CDomain::GetDcName(_bstr_t strDomainName)
  126. {
  127. _bstr_t strName;
  128. PDOMAIN_CONTROLLER_INFO pdci;
  129. // attempt to retrieve DNS name of domain controller supporting active directory service
  130. DWORD dwError = DsGetDcName(NULL, strDomainName, NULL, NULL, DS_DIRECTORY_SERVICE_REQUIRED|DS_RETURN_DNS_NAME, &pdci);
  131. // if domain controller not found, attempt to retrieve flat name of domain controller
  132. if (dwError == ERROR_NO_SUCH_DOMAIN)
  133. {
  134. dwError = DsGetDcName(NULL, strDomainName, NULL, NULL, DS_RETURN_FLAT_NAME, &pdci);
  135. }
  136. // if domain controller found then save name otherwise generate error
  137. if (dwError == NO_ERROR)
  138. {
  139. strName = pdci->DomainControllerName;
  140. NetApiBufferFree(pdci);
  141. }
  142. else
  143. {
  144. AdmtThrowError(
  145. GUID_NULL, GUID_NULL,
  146. HRESULT_FROM_WIN32(dwError),
  147. IDS_E_CANT_GET_DOMAIN_CONTROLLER,
  148. (LPCTSTR)strDomainName
  149. );
  150. }
  151. return strName;
  152. }
  153. // GetGcName Method
  154. //
  155. // Retrieves name of global catalog server.
  156. _bstr_t CDomain::GetGcName()
  157. {
  158. _bstr_t strName;
  159. PDOMAIN_CONTROLLER_INFO pdci;
  160. DWORD dwError = DsGetDcName(NULL, m_strForestName, NULL, NULL, DS_GC_SERVER_REQUIRED, &pdci);
  161. if (dwError == NO_ERROR)
  162. {
  163. strName = pdci->DomainControllerName;
  164. NetApiBufferFree(pdci);
  165. }
  166. else
  167. {
  168. AdmtThrowError(
  169. GUID_NULL, GUID_NULL,
  170. HRESULT_FROM_WIN32(dwError),
  171. IDS_E_CANT_GET_GLOBAL_CATALOG_SERVER,
  172. (LPCTSTR)m_strForestName
  173. );
  174. }
  175. return strName;
  176. }
  177. // GetSid Method
  178. _bstr_t CDomain::GetSid()
  179. {
  180. _bstr_t strSid;
  181. PUSER_MODALS_INFO_2 pumi2;
  182. if (NetUserModalsGet(m_strDcName, 2, (LPBYTE*)&pumi2) == NERR_Success)
  183. {
  184. if (IsValidSid(pumi2->usrmod2_domain_id))
  185. {
  186. LPTSTR pszSid;
  187. if (ConvertSidToStringSid(pumi2->usrmod2_domain_id, &pszSid))
  188. {
  189. strSid = pszSid;
  190. LocalFree(LocalHandle(pszSid));
  191. }
  192. }
  193. NetApiBufferFree(pumi2);
  194. }
  195. return strSid;
  196. }
  197. // GetContainer Method
  198. //
  199. // Retrieves a container given it's relative canonical path. Will
  200. // optionally create container if create parameter is true and container
  201. // does not already exist.
  202. CContainer CDomain::GetContainer(_bstr_t strRelativeCanonicalPath, bool bCreate)
  203. {
  204. CContainer aContainer;
  205. // return a non-empty container only if the domain is uplevel and a
  206. // relative canonical path is supplied
  207. if (m_bUpLevel && (strRelativeCanonicalPath.length() > 0))
  208. {
  209. if (bCreate)
  210. {
  211. tstring strPath = strRelativeCanonicalPath;
  212. // initialize parent container
  213. // if path separator is specified than initialize parent
  214. // container from ADsPath otherwise this container is the
  215. // parent container
  216. CContainer aParent;
  217. UINT pos = strPath.find_last_of(_T("/\\"));
  218. if (pos != tstring::npos)
  219. {
  220. aParent = GetLDAPPath(GetDistinguishedName(strPath.substr(0, pos).c_str()));
  221. }
  222. else
  223. {
  224. aParent = *this;
  225. }
  226. tstring strName = strPath.substr(pos + 1);
  227. CADsPathName aPathName(aParent.GetPath());
  228. tstring strRDN = _T("CN=") + strName;
  229. aPathName.AddLeafElement(strRDN.c_str());
  230. IDispatchPtr spDispatch;
  231. HRESULT hr = ADsGetObject(aPathName.Retrieve(ADS_FORMAT_X500), __uuidof(IDispatch), (void**)&spDispatch);
  232. if (SUCCEEDED(hr))
  233. {
  234. aContainer = CContainer(spDispatch);
  235. }
  236. else
  237. {
  238. strRDN = _T("OU=") + strName;
  239. aContainer = aParent.CreateContainer(strRDN.c_str());
  240. }
  241. }
  242. else
  243. {
  244. try
  245. {
  246. aContainer = GetLDAPPath(GetDistinguishedName(strRelativeCanonicalPath));
  247. }
  248. catch (_com_error& ce)
  249. {
  250. AdmtThrowError(GUID_NULL, GUID_NULL, ce, IDS_E_CANNOT_GET_CONTAINER, (LPCTSTR)strRelativeCanonicalPath);
  251. }
  252. }
  253. }
  254. return aContainer;
  255. }
  256. // GetLDAPPath
  257. _bstr_t CDomain::GetLDAPPath(_bstr_t strDN)
  258. {
  259. _bstr_t strPath = _T("LDAP://") + m_strDomainNameDns;
  260. if (strDN.length() > 0)
  261. {
  262. strPath += _T("/") + strDN;
  263. }
  264. return strPath;
  265. }
  266. // GetWinNTPath
  267. _bstr_t CDomain::GetWinNTPath(_bstr_t strName)
  268. {
  269. const _TCHAR c_chEscape = _T('\\');
  270. static _TCHAR s_chSpecial[] = _T("\",/<>");
  271. std::auto_ptr<_TCHAR> spEscapedName(new _TCHAR[strName.length() * 2 + 1]);
  272. if (spEscapedName.get() == NULL)
  273. {
  274. _com_issue_error(E_OUTOFMEMORY);
  275. }
  276. _TCHAR* pchOld = strName;
  277. _TCHAR* pchNew = spEscapedName.get();
  278. while (*pchOld)
  279. {
  280. if (_tcschr(s_chSpecial, *pchOld))
  281. {
  282. *pchNew++ = c_chEscape;
  283. }
  284. *pchNew++ = *pchOld++;
  285. }
  286. *pchNew = _T('\0');
  287. tstring strPath;
  288. strPath += _T("WinNT://");
  289. strPath += m_strDomainNameFlat;
  290. strPath += _T("/");
  291. strPath += spEscapedName.get();
  292. return strPath.c_str();
  293. }
  294. // GetDistinguishedName Method
  295. _bstr_t CDomain::GetDistinguishedName(_bstr_t strRelativeCanonicalPath)
  296. {
  297. _bstr_t strDN;
  298. HRESULT hr = S_OK;
  299. HANDLE hDS;
  300. DWORD dwError = DsBind(m_strDcName, NULL, &hDS);
  301. if (dwError == NO_ERROR)
  302. {
  303. _bstr_t strCanonicalName = m_strDomainNameDns + _T("/") + strRelativeCanonicalPath;
  304. LPTSTR psz = strCanonicalName;
  305. PDS_NAME_RESULT pnr;
  306. dwError = DsCrackNames(hDS, DS_NAME_NO_FLAGS, DS_CANONICAL_NAME, DS_FQDN_1779_NAME, 1, &psz, &pnr);
  307. if (dwError == NO_ERROR)
  308. {
  309. if (pnr->rItems[0].status == DS_NAME_NO_ERROR)
  310. {
  311. strDN = pnr->rItems[0].pName;
  312. }
  313. else
  314. {
  315. hr = AdmtSetError(
  316. GUID_NULL, GUID_NULL,
  317. E_INVALIDARG,
  318. IDS_E_CANT_GET_DISTINGUISHED_NAME,
  319. (LPCTSTR)strCanonicalName
  320. );
  321. }
  322. DsFreeNameResult(pnr);
  323. }
  324. else
  325. {
  326. hr = AdmtSetError(
  327. GUID_NULL, GUID_NULL,
  328. HRESULT_FROM_WIN32(dwError),
  329. IDS_E_CANT_GET_DISTINGUISHED_NAME,
  330. (LPCTSTR)strCanonicalName
  331. );
  332. }
  333. DsUnBind(&hDS);
  334. }
  335. else
  336. {
  337. hr = AdmtSetError(
  338. GUID_NULL, GUID_NULL,
  339. HRESULT_FROM_WIN32(dwError),
  340. IDS_E_CANT_CONNECT_TO_DIRECTORY_SERVICE,
  341. (LPCTSTR)m_strDomainNameDns
  342. );
  343. }
  344. if (hr != S_OK)
  345. {
  346. _com_issue_error(hr);
  347. }
  348. return strDN;
  349. }
  350. // CreateContainer Method
  351. CContainer CDomain::CreateContainer(_bstr_t strRDN)
  352. {
  353. CContainer aContainer;
  354. if (m_bUpLevel)
  355. {
  356. aContainer = CContainer::CreateContainer(strRDN);
  357. }
  358. else
  359. {
  360. AdmtThrowError(GUID_NULL, GUID_NULL, E_FAIL, IDS_E_CANT_CREATE_CONTAINER_NT4);
  361. }
  362. return aContainer;
  363. }
  364. // QueryContainers Method
  365. void CDomain::QueryContainers(ContainerVector& rContainers)
  366. {
  367. if (m_bUpLevel)
  368. {
  369. CContainer::QueryContainers(rContainers);
  370. }
  371. }
  372. // QueryUsers Method
  373. void CDomain::QueryUsers(bool bRecurse, StringSet& setExcludeNames, CDomainAccounts& rUsers)
  374. {
  375. if (m_bUpLevel)
  376. {
  377. CContainer::QueryUsers(bRecurse, setExcludeNames, rUsers);
  378. }
  379. else
  380. {
  381. QueryUsers4(setExcludeNames, rUsers);
  382. }
  383. }
  384. // QueryUsers Method
  385. void CDomain::QueryUsers(CContainer& rContainer, StringSet& setIncludeNames, StringSet& setExcludeNames, CDomainAccounts& rUsers)
  386. {
  387. if (m_bUpLevel)
  388. {
  389. QueryObjects(rContainer, setIncludeNames, setExcludeNames, _T("user"), rUsers);
  390. }
  391. else
  392. {
  393. QueryUsers4(setIncludeNames, setExcludeNames, rUsers);
  394. }
  395. }
  396. // QueryGroups Method
  397. void CDomain::QueryGroups(bool bRecurse, StringSet& setExcludeNames, CDomainAccounts& rGroups)
  398. {
  399. if (m_bUpLevel)
  400. {
  401. CContainer::QueryGroups(bRecurse, setExcludeNames, rGroups);
  402. }
  403. else
  404. {
  405. QueryGroups4(setExcludeNames, rGroups);
  406. }
  407. }
  408. // QueryGroups Method
  409. void CDomain::QueryGroups(CContainer& rContainer, StringSet& setIncludeNames, StringSet& setExcludeNames, CDomainAccounts& rGroups)
  410. {
  411. if (m_bUpLevel)
  412. {
  413. QueryObjects(rContainer, setIncludeNames, setExcludeNames, _T("group"), rGroups);
  414. }
  415. else
  416. {
  417. QueryGroups4(setIncludeNames, setExcludeNames, rGroups);
  418. }
  419. }
  420. // QueryComputers Method
  421. void CDomain::QueryComputers(bool bIncludeDCs, bool bRecurse, StringSet& setExcludeNames, CDomainAccounts& rComputers)
  422. {
  423. if (m_bUpLevel)
  424. {
  425. CContainer::QueryComputers(bIncludeDCs, bRecurse, setExcludeNames, rComputers);
  426. }
  427. else
  428. {
  429. QueryComputers4(bIncludeDCs, setExcludeNames, rComputers);
  430. }
  431. }
  432. // QueryComputers Method
  433. void CDomain::QueryComputers(CContainer& rContainer, bool bIncludeDCs, StringSet& setIncludeNames, StringSet& setExcludeNames, CDomainAccounts& rComputers)
  434. {
  435. if (m_bUpLevel)
  436. {
  437. QueryObjects(rContainer, setIncludeNames, setExcludeNames, _T("computer"), rComputers);
  438. if (!bIncludeDCs)
  439. {
  440. for (CDomainAccounts::iterator it = rComputers.begin(); it != rComputers.end();)
  441. {
  442. long lUserAccountControl = it->GetUserAccountControl();
  443. if (lUserAccountControl & ADS_UF_SERVER_TRUST_ACCOUNT)
  444. {
  445. _Module.Log(ErrW, IDS_E_CANNOT_MIGRATE_DOMAIN_CONTROLLERS, (LPCTSTR)it->GetADsPath());
  446. it = rComputers.erase(it);
  447. }
  448. else
  449. {
  450. it++;
  451. }
  452. }
  453. }
  454. }
  455. else
  456. {
  457. QueryComputers4(bIncludeDCs, setIncludeNames, setExcludeNames, rComputers);
  458. }
  459. }
  460. // QueryComputersAcrossDomains Method
  461. void CDomain::QueryComputersAcrossDomains(CContainer& rContainer, bool bIncludeDCs, StringSet& setIncludeNames, StringSet& setExcludeNames, CDomainAccounts& rComputers)
  462. {
  463. CDomainToPathMap mapDomainToPath;
  464. mapDomainToPath.Initialize(m_strDomainNameDns, m_strDomainNameFlat, setIncludeNames);
  465. for (CDomainToPathMap::iterator it = mapDomainToPath.begin(); it != mapDomainToPath.end(); it++)
  466. {
  467. _bstr_t strDomainName = it->first;
  468. try
  469. {
  470. CDomain domain;
  471. domain.Initialize(strDomainName);
  472. domain.QueryComputers(rContainer, bIncludeDCs, it->second, setExcludeNames, rComputers);
  473. }
  474. catch (_com_error& ce)
  475. {
  476. _Module.Log(ErrE, IDS_E_CANNOT_PROCESS_ACCOUNTS_IN_DOMAIN, (LPCTSTR)strDomainName, ce.ErrorMessage(), ce.Error());
  477. }
  478. catch (...)
  479. {
  480. _Module.Log(ErrE, IDS_E_CANNOT_PROCESS_ACCOUNTS_IN_DOMAIN, (LPCTSTR)strDomainName, _com_error(E_FAIL).ErrorMessage(), E_FAIL);
  481. }
  482. }
  483. }
  484. // QueryObjects Method
  485. void CDomain::QueryObjects(CContainer& rContainer, StringSet& setIncludeNames, StringSet& setExcludeNames, LPCTSTR pszClass, CDomainAccounts& rAccounts)
  486. {
  487. // copy specified include names to vector
  488. StringVector vecNames;
  489. for (StringSet::const_iterator itInclude = setIncludeNames.begin(); itInclude != setIncludeNames.end(); itInclude++)
  490. {
  491. vecNames.push_back(tstring(*itInclude));
  492. }
  493. // crack names
  494. CNameCracker cracker;
  495. cracker.SetDomainNames(m_strDomainNameDns, m_strDomainNameFlat, m_strDcName);
  496. cracker.SetDefaultContainer(IADsContainerPtr(rContainer.GetInterface()));
  497. cracker.CrackNames(vecNames);
  498. // log un-resolved names
  499. const StringVector& vecUnResolved = cracker.GetUnResolvedNames();
  500. for (StringVector::const_iterator itUnResolved = vecUnResolved.begin(); itUnResolved != vecUnResolved.end(); itUnResolved++)
  501. {
  502. _Module.Log(ErrW, IDS_E_CANNOT_RESOLVE_NAME, itUnResolved->c_str());
  503. }
  504. // initialize compare exclude names
  505. CCompareStrings csExclude(setExcludeNames);
  506. // add resolved accounts
  507. const CStringSet& setResolved = cracker.GetResolvedNames();
  508. CADsPathName pathname;
  509. pathname.Set(_T("LDAP"), ADS_SETTYPE_PROVIDER);
  510. pathname.Set(m_strDomainNameDns, ADS_SETTYPE_SERVER);
  511. CDirectoryObject doObject;
  512. doObject.AddAttribute(ATTRIBUTE_OBJECT_CLASS);
  513. doObject.AddAttribute(ATTRIBUTE_OBJECT_SID);
  514. doObject.AddAttribute(ATTRIBUTE_NAME);
  515. doObject.AddAttribute(ATTRIBUTE_USER_PRINCIPAL_NAME);
  516. doObject.AddAttribute(ATTRIBUTE_SAM_ACCOUNT_NAME);
  517. doObject.AddAttribute(ATTRIBUTE_USER_ACCOUNT_CONTROL);
  518. for (CStringSet::const_iterator itResolved = setResolved.begin(); itResolved != setResolved.end(); itResolved++)
  519. {
  520. try
  521. {
  522. // get active directory service path
  523. // Note: the pathname component will, if necessary, escape any special characters
  524. pathname.Set(itResolved->c_str(), ADS_SETTYPE_DN);
  525. _bstr_t strADsPath = pathname.Retrieve(ADS_FORMAT_X500);
  526. // get object attributes
  527. doObject = (LPCTSTR)strADsPath;
  528. doObject.GetAttributes();
  529. // if the object is of the specified account class...
  530. _variant_t vntClass = doObject.GetAttributeValue(ATTRIBUTE_OBJECT_CLASS);
  531. if (IsClass(pszClass, vntClass))
  532. {
  533. // and it does not represent a built-in account...
  534. _variant_t vntSid = doObject.GetAttributeValue(ATTRIBUTE_OBJECT_SID);
  535. if (IsUserRid(vntSid))
  536. {
  537. // then if name is not in exclusion list...
  538. _bstr_t strName = doObject.GetAttributeValue(ATTRIBUTE_NAME);
  539. if (csExclude.IsMatch(strName) == false)
  540. {
  541. //
  542. // then add account to account list
  543. //
  544. CDomainAccount daAccount;
  545. // active directory service path
  546. daAccount.SetADsPath(strADsPath);
  547. // name attribute
  548. daAccount.SetName(strName);
  549. // user principal name attribute
  550. _variant_t vntUserPrincipalName = doObject.GetAttributeValue(ATTRIBUTE_USER_PRINCIPAL_NAME);
  551. if (V_VT(&vntUserPrincipalName) != VT_EMPTY)
  552. {
  553. daAccount.SetUserPrincipalName(_bstr_t(vntUserPrincipalName));
  554. }
  555. // sam account name attribute
  556. _variant_t vntSamAccountName = doObject.GetAttributeValue(ATTRIBUTE_SAM_ACCOUNT_NAME);
  557. if (V_VT(&vntSamAccountName) != VT_EMPTY)
  558. {
  559. daAccount.SetSamAccountName(_bstr_t(vntSamAccountName));
  560. }
  561. // user account control attribute
  562. _variant_t vntUserAccountControl = doObject.GetAttributeValue(ATTRIBUTE_USER_ACCOUNT_CONTROL);
  563. if (V_VT(&vntUserAccountControl) != VT_EMPTY)
  564. {
  565. daAccount.SetUserAccountControl(vntUserAccountControl);
  566. }
  567. rAccounts.insert(daAccount);
  568. }
  569. else
  570. {
  571. _Module.Log(ErrW, IDS_E_ACCOUNT_EXCLUDED, itResolved->c_str());
  572. }
  573. }
  574. else
  575. {
  576. _Module.Log(ErrW, IDS_E_CANT_DO_BUILTIN, itResolved->c_str());
  577. }
  578. }
  579. else
  580. {
  581. _Module.Log(ErrW, IDS_E_OBJECT_NOT_OF_CLASS, itResolved->c_str());
  582. }
  583. }
  584. catch (_com_error& ce)
  585. {
  586. ATLTRACE(_T("'%s' : %s : 0x%08lX\n"), itResolved->c_str(), ce.ErrorMessage(), ce.Error());
  587. }
  588. catch (...)
  589. {
  590. ATLTRACE(_T("'%s' : %s : 0x%08lX\n"), itResolved->c_str(), _com_error(E_FAIL).ErrorMessage(), E_FAIL);
  591. }
  592. }
  593. }
  594. // QueryUsers4 Method
  595. void CDomain::QueryUsers4(StringSet& setExcludeNames, CDomainAccounts& rUsers)
  596. {
  597. CCompareStrings aExclude(setExcludeNames);
  598. DWORD dwIndex = 0;
  599. NET_API_STATUS status;
  600. CDomainAccount aUser;
  601. do
  602. {
  603. DWORD dwCount = 0;
  604. PNET_DISPLAY_USER pdu = NULL;
  605. status = NetQueryDisplayInformation(m_strDcName, 1, dwIndex, 1000, 32768, &dwCount, (PVOID*)&pdu);
  606. if ((status == ERROR_SUCCESS) || (status == ERROR_MORE_DATA))
  607. {
  608. for (PNET_DISPLAY_USER p = pdu; dwCount > 0; dwCount--, p++)
  609. {
  610. if (p->usri1_user_id >= MIN_NON_RESERVED_RID)
  611. {
  612. _bstr_t strName(p->usri1_name);
  613. if (aExclude.IsMatch(strName) == false)
  614. {
  615. aUser.SetADsPath(GetWinNTPath(strName));
  616. aUser.SetName(strName);
  617. rUsers.insert(aUser);
  618. }
  619. }
  620. dwIndex = p->usri1_next_index;
  621. }
  622. }
  623. if (pdu)
  624. {
  625. NetApiBufferFree(pdu);
  626. }
  627. }
  628. while (status == ERROR_MORE_DATA);
  629. }
  630. // QueryUsers4 Method
  631. void CDomain::QueryUsers4(StringSet& setIncludeNames, StringSet& setExcludeNames, CDomainAccounts& rUsers)
  632. {
  633. CCompareStrings aExclude(setExcludeNames);
  634. CDomainAccount aUser;
  635. for (StringSet::iterator it = setIncludeNames.begin(); it != setIncludeNames.end(); it++)
  636. {
  637. _bstr_t strName = *it;
  638. if (aExclude.IsMatch(strName) == false)
  639. {
  640. _bstr_t strADsPath = GetWinNTPath(strName) + _T(",user");
  641. IADsPtr spADs;
  642. HRESULT hr = ADsGetObject(strADsPath, IID_IADs, (VOID**)&spADs);
  643. if (SUCCEEDED(hr))
  644. {
  645. BSTR bstr;
  646. // The WinNT: provider does not return all ADsPaths correctly escaped
  647. // (ie. it does not escape the double quote (") character)
  648. // The member method GetWinNTPath does escape all known special characters.
  649. #if 0
  650. spADs->get_ADsPath(&bstr);
  651. aUser.SetADsPath(_bstr_t(bstr, false));
  652. #else
  653. aUser.SetADsPath(GetWinNTPath(strName));
  654. #endif
  655. spADs->get_Name(&bstr);
  656. aUser.SetName(_bstr_t(bstr, false));
  657. rUsers.insert(aUser);
  658. }
  659. else
  660. {
  661. _Module.Log(ErrE, IDS_E_CANT_ADD_USER, (LPCTSTR)strADsPath, _com_error(hr).ErrorMessage());
  662. }
  663. }
  664. }
  665. }
  666. // QueryGroups4 Method
  667. void CDomain::QueryGroups4(StringSet& setExcludeNames, CDomainAccounts& rGroups)
  668. {
  669. CCompareStrings aExclude(setExcludeNames);
  670. DWORD dwIndex = 0;
  671. NET_API_STATUS status;
  672. CDomainAccount aGroup;
  673. do
  674. {
  675. DWORD dwCount = 0;
  676. PNET_DISPLAY_GROUP pdg = NULL;
  677. status = NetQueryDisplayInformation(m_strDcName, 3, dwIndex, 1000, 32768, &dwCount, (PVOID*)&pdg);
  678. if ((status == ERROR_SUCCESS) || (status == ERROR_MORE_DATA))
  679. {
  680. for (PNET_DISPLAY_GROUP p = pdg; dwCount > 0; dwCount--, p++)
  681. {
  682. if (p->grpi3_group_id >= MIN_NON_RESERVED_RID)
  683. {
  684. _bstr_t strName(p->grpi3_name);
  685. if (aExclude.IsMatch(strName) == false)
  686. {
  687. aGroup.SetADsPath(GetWinNTPath(strName));
  688. aGroup.SetName(strName);
  689. rGroups.insert(aGroup);
  690. }
  691. }
  692. dwIndex = p->grpi3_next_index;
  693. }
  694. }
  695. if (pdg)
  696. {
  697. NetApiBufferFree(pdg);
  698. }
  699. }
  700. while (status == ERROR_MORE_DATA);
  701. }
  702. // QueryGroups4 Method
  703. void CDomain::QueryGroups4(StringSet& setIncludeNames, StringSet& setExcludeNames, CDomainAccounts& rGroups)
  704. {
  705. CCompareStrings aExclude(setExcludeNames);
  706. CDomainAccount aGroup;
  707. for (StringSet::iterator it = setIncludeNames.begin(); it != setIncludeNames.end(); it++)
  708. {
  709. _bstr_t strName = *it;
  710. if (aExclude.IsMatch(strName) == false)
  711. {
  712. _bstr_t strADsPath = GetWinNTPath(strName) + _T(",group");
  713. IADsPtr spADs;
  714. HRESULT hr = ADsGetObject(strADsPath, IID_IADs, (VOID**)&spADs);
  715. if (SUCCEEDED(hr))
  716. {
  717. BSTR bstr;
  718. spADs->get_ADsPath(&bstr);
  719. aGroup.SetADsPath(_bstr_t(bstr, false));
  720. spADs->get_Name(&bstr);
  721. aGroup.SetName(_bstr_t(bstr, false));
  722. rGroups.insert(aGroup);
  723. }
  724. else
  725. {
  726. _Module.Log(ErrE, IDS_E_CANT_ADD_GROUP, (LPCTSTR)strADsPath, _com_error(hr).ErrorMessage());
  727. }
  728. }
  729. }
  730. }
  731. // QueryComputers4 Method
  732. void CDomain::QueryComputers4(bool bIncludeDCs, StringSet& setExcludeNames, CDomainAccounts& rComputers)
  733. {
  734. CCompareStrings aExclude(setExcludeNames);
  735. DWORD dwIndex = 0;
  736. NET_API_STATUS status;
  737. CDomainAccount aComputer;
  738. DWORD dwflags = bIncludeDCs ? UF_WORKSTATION_TRUST_ACCOUNT|UF_SERVER_TRUST_ACCOUNT : UF_WORKSTATION_TRUST_ACCOUNT;
  739. do
  740. {
  741. DWORD dwCount = 0;
  742. PNET_DISPLAY_MACHINE pdm = NULL;
  743. status = NetQueryDisplayInformation(m_strDcName, 2, dwIndex, 1000, 32768, &dwCount, (PVOID*)&pdm);
  744. if ((status == ERROR_SUCCESS) || (status == ERROR_MORE_DATA))
  745. {
  746. for (PNET_DISPLAY_MACHINE p = pdm; dwCount > 0; dwCount--, p++)
  747. {
  748. if ((p->usri2_user_id >= MIN_NON_RESERVED_RID) && (p->usri2_flags & dwflags))
  749. {
  750. _bstr_t strName(p->usri2_name);
  751. if (aExclude.IsMatch(strName) == false)
  752. {
  753. aComputer.SetADsPath(GetWinNTPath(strName));
  754. aComputer.SetName(strName);
  755. aComputer.SetSamAccountName(strName);
  756. rComputers.insert(aComputer);
  757. }
  758. }
  759. dwIndex = p->usri2_next_index;
  760. }
  761. }
  762. if (pdm)
  763. {
  764. NetApiBufferFree(pdm);
  765. }
  766. }
  767. while (status == ERROR_MORE_DATA);
  768. }
  769. // QueryComputers4 Method
  770. void CDomain::QueryComputers4(bool bIncludeDCs, StringSet& setIncludeNames, StringSet& setExcludeNames, CDomainAccounts& rComputers)
  771. {
  772. typedef std::map<_bstr_t, DWORD, IgnoreCaseStringLess> CMachineMap;
  773. PNET_DISPLAY_MACHINE pndmMachine = NULL;
  774. try
  775. {
  776. CMachineMap map;
  777. DWORD dwIndex = 0;
  778. NET_API_STATUS nasStatus;
  779. do
  780. {
  781. DWORD dwCount = 0;
  782. nasStatus = NetQueryDisplayInformation(m_strDcName, 2, dwIndex, 256, 32768, &dwCount, (PVOID*)&pndmMachine);
  783. if ((nasStatus == ERROR_SUCCESS) || (nasStatus == ERROR_MORE_DATA))
  784. {
  785. for (PNET_DISPLAY_MACHINE p = pndmMachine; dwCount > 0; dwCount--, p++)
  786. {
  787. map.insert(CMachineMap::value_type(p->usri2_name, p->usri2_flags));
  788. dwIndex = p->usri2_next_index;
  789. }
  790. }
  791. if (pndmMachine)
  792. {
  793. NetApiBufferFree(pndmMachine);
  794. pndmMachine = NULL;
  795. }
  796. }
  797. while (nasStatus == ERROR_MORE_DATA);
  798. if (nasStatus != ERROR_SUCCESS)
  799. {
  800. AdmtThrowError(
  801. GUID_NULL,
  802. GUID_NULL,
  803. HRESULT_FROM_WIN32(nasStatus),
  804. IDS_E_CANT_ENUMERATE_COMPUTERS,
  805. (LPCTSTR)m_strDomainNameFlat
  806. );
  807. }
  808. CCompareStrings aExclude(setExcludeNames);
  809. for (StringSet::iterator it = setIncludeNames.begin(); it != setIncludeNames.end(); it++)
  810. {
  811. tstring str = *it;
  812. if ((str[0] == _T('\\')) || (str[0] == _T('/')))
  813. {
  814. str = str.substr(1);
  815. }
  816. _bstr_t strName = str.c_str();
  817. if (aExclude.IsMatch(strName) == false)
  818. {
  819. _bstr_t strPath = GetWinNTPath(strName);
  820. CMachineMap::iterator it = map.find(strName + _T("$"));
  821. if (it != map.end())
  822. {
  823. if (bIncludeDCs || !(it->second & UF_SERVER_TRUST_ACCOUNT))
  824. {
  825. CDomainAccount aComputer;
  826. aComputer.SetADsPath(strPath);
  827. aComputer.SetName(strName);
  828. aComputer.SetSamAccountName(strName + _T("$"));
  829. rComputers.insert(aComputer);
  830. }
  831. else
  832. {
  833. _Module.Log(ErrW, IDS_E_CANT_MIGRATE_DOMAIN_CONTROLLERS, (LPCTSTR)strPath);
  834. }
  835. }
  836. else
  837. {
  838. _Module.Log(ErrW, IDS_E_CANT_FIND_COMPUTER, (LPCTSTR)strPath);
  839. }
  840. }
  841. }
  842. }
  843. catch (...)
  844. {
  845. if (pndmMachine)
  846. {
  847. NetApiBufferFree(pndmMachine);
  848. }
  849. throw;
  850. }
  851. }
  852. //---------------------------------------------------------------------------
  853. // Container Class
  854. //---------------------------------------------------------------------------
  855. // Constructors and Destructor ----------------------------------------------
  856. CContainer::CContainer()
  857. {
  858. }
  859. CContainer::CContainer(IDispatchPtr sp) :
  860. m_sp(sp)
  861. {
  862. }
  863. CContainer::CContainer(_bstr_t strPath)
  864. {
  865. HRESULT hr = ADsGetObject(strPath, __uuidof(IDispatch), (void**)&m_sp);
  866. if (FAILED(hr))
  867. {
  868. ReportADsError(hr);
  869. _com_issue_error(hr);
  870. }
  871. }
  872. CContainer::CContainer(const CContainer& r) :
  873. m_sp(r.m_sp)
  874. {
  875. }
  876. CContainer::~CContainer()
  877. {
  878. if (m_sp)
  879. {
  880. m_sp.Release();
  881. }
  882. }
  883. // Implementation -----------------------------------------------------------
  884. // operator =
  885. CContainer& CContainer::operator =(_bstr_t strPath)
  886. {
  887. HRESULT hr = ADsGetObject(strPath, __uuidof(IDispatch), (void**)&m_sp);
  888. if (FAILED(hr))
  889. {
  890. ReportADsError(hr);
  891. _com_issue_error(hr);
  892. }
  893. return *this;
  894. }
  895. // operator =
  896. CContainer& CContainer::operator =(const CContainer& r)
  897. {
  898. m_sp = r.m_sp;
  899. return *this;
  900. }
  901. // GetPath Method
  902. _bstr_t CContainer::GetPath()
  903. {
  904. IDirectoryObjectPtr spObject(m_sp);
  905. PADS_OBJECT_INFO poi;
  906. CheckError(spObject->GetObjectInformation(&poi));
  907. // the ADS_OBJECT_INFO member pszObjectDN actually
  908. // specifies the ADsPath not the distinguished name
  909. _bstr_t strPath = poi->pszObjectDN;
  910. FreeADsMem(poi);
  911. return strPath;
  912. }
  913. // GetDomain Method
  914. _bstr_t CContainer::GetDomain()
  915. {
  916. CADsPathName aPathName(GetPath());
  917. return aPathName.Retrieve(ADS_FORMAT_SERVER);
  918. }
  919. // GetName Method
  920. _bstr_t CContainer::GetName()
  921. {
  922. CDirectoryObject aObject(m_sp);
  923. aObject.AddAttribute(ATTRIBUTE_NAME);
  924. aObject.GetAttributes();
  925. return aObject.GetAttributeValue(ATTRIBUTE_NAME);
  926. }
  927. // GetRDN Method
  928. _bstr_t CContainer::GetRDN()
  929. {
  930. IDirectoryObjectPtr spObject(m_sp);
  931. PADS_OBJECT_INFO poi;
  932. CheckError(spObject->GetObjectInformation(&poi));
  933. _bstr_t strRDN = poi->pszRDN;
  934. FreeADsMem(poi);
  935. return strRDN;
  936. }
  937. // CreateContainerHierarchy Method
  938. void CContainer::CreateContainerHierarchy(CContainer& rSource)
  939. {
  940. ContainerVector cvContainers;
  941. rSource.QueryContainers(cvContainers);
  942. for (ContainerVector::iterator it = cvContainers.begin(); it != cvContainers.end(); it++)
  943. {
  944. CContainer aTarget = CreateContainer(_T("OU=") + it->GetName());
  945. aTarget.CreateContainerHierarchy(*it);
  946. }
  947. }
  948. // GetContainer Method
  949. CContainer CContainer::GetContainer(_bstr_t strName)
  950. {
  951. IDispatchPtr spDispatch;
  952. CADsPathName aPathName(GetPath());
  953. // try organizational unit first
  954. aPathName.AddLeafElement(_T("OU=") + strName);
  955. HRESULT hr = ADsGetObject(aPathName.Retrieve(ADS_FORMAT_X500), __uuidof(IDispatch), (void**)&spDispatch);
  956. if (FAILED(hr))
  957. {
  958. // if (hr == ?)
  959. // {
  960. // then try container
  961. aPathName.RemoveLeafElement();
  962. aPathName.AddLeafElement(_T("CN=") + strName);
  963. CheckError(ADsGetObject(aPathName.Retrieve(ADS_FORMAT_X500), __uuidof(IDispatch), (void**)&spDispatch));
  964. // }
  965. // else
  966. // {
  967. // _com_issue_error(hr);
  968. // }
  969. }
  970. return CContainer(spDispatch);
  971. }
  972. // CreateContainer Method
  973. CContainer CContainer::CreateContainer(_bstr_t strRDN)
  974. {
  975. IDispatchPtr spDispatch;
  976. CADsPathName aPathName(GetPath());
  977. aPathName.AddLeafElement(strRDN);
  978. _bstr_t strPath = aPathName.Retrieve(ADS_FORMAT_X500);
  979. HRESULT hr = ADsGetObject(strPath, __uuidof(IDispatch), (void**)&spDispatch);
  980. if (FAILED(hr))
  981. {
  982. ADSVALUE valueClass;
  983. valueClass.dwType = ADSTYPE_CASE_IGNORE_STRING;
  984. valueClass.CaseIgnoreString = L"organizationalUnit";
  985. ADS_ATTR_INFO aiAttrs[] =
  986. {
  987. { L"objectClass", ADS_ATTR_UPDATE, ADSTYPE_CASE_IGNORE_STRING, &valueClass, 1 },
  988. };
  989. DWORD dwAttrCount = sizeof(aiAttrs) / sizeof(aiAttrs[0]);
  990. IDirectoryObjectPtr spObject(m_sp);
  991. HRESULT hr = spObject->CreateDSObject(strRDN, aiAttrs, dwAttrCount, &spDispatch);
  992. if (FAILED(hr))
  993. {
  994. ReportADsError(hr, IID_IDirectoryObject);
  995. _com_issue_error(hr);
  996. }
  997. }
  998. return CContainer(spDispatch);
  999. }
  1000. // QueryContainers Method
  1001. void CContainer::QueryContainers(ContainerVector& rContainers)
  1002. {
  1003. CDirectorySearch aSearch(m_sp);
  1004. aSearch.SetFilter(_T("(|(objectCategory=OrganizationalUnit)(&(objectCategory=Container)(|(cn=Computers)(cn=Users))))"));
  1005. aSearch.SetPreferences(ADS_SCOPE_ONELEVEL);
  1006. aSearch.AddAttribute(ATTRIBUTE_ADS_PATH);
  1007. aSearch.Search();
  1008. for (bool bGet = aSearch.GetFirstRow(); bGet; bGet = aSearch.GetNextRow())
  1009. {
  1010. CContainer aContainer(_bstr_t(aSearch.GetAttributeValue(ATTRIBUTE_ADS_PATH)));
  1011. rContainers.push_back(aContainer);
  1012. }
  1013. }
  1014. // QueryUsers Method
  1015. void CContainer::QueryUsers(bool bRecurse, StringSet& setExcludeNames, CDomainAccounts& rUsers)
  1016. {
  1017. tstring strFilter = CreateFilter(
  1018. _T("(objectCategory=Person)(objectClass=user)")
  1019. _T("(userAccountControl:") LDAP_MATCHING_RULE_BIT_OR_W _T(":=512)"),
  1020. setExcludeNames
  1021. );
  1022. CDirectorySearch aSearch(m_sp);
  1023. aSearch.SetFilter(strFilter.c_str());
  1024. aSearch.SetPreferences(bRecurse ? ADS_SCOPE_SUBTREE : ADS_SCOPE_ONELEVEL);
  1025. aSearch.AddAttribute(ATTRIBUTE_OBJECT_SID);
  1026. aSearch.AddAttribute(ATTRIBUTE_ADS_PATH);
  1027. aSearch.AddAttribute(ATTRIBUTE_NAME);
  1028. aSearch.AddAttribute(ATTRIBUTE_USER_PRINCIPAL_NAME);
  1029. aSearch.Search();
  1030. CDomainAccount aUser;
  1031. for (bool bGet = aSearch.GetFirstRow(); bGet; bGet = aSearch.GetNextRow())
  1032. {
  1033. // if not a built-in or well known account
  1034. if (IsUserRid(aSearch.GetAttributeValue(ATTRIBUTE_OBJECT_SID)))
  1035. {
  1036. // add user
  1037. aUser.SetADsPath(_bstr_t(aSearch.GetAttributeValue(ATTRIBUTE_ADS_PATH)));
  1038. aUser.SetName(_bstr_t(aSearch.GetAttributeValue(ATTRIBUTE_NAME)));
  1039. _variant_t vntUserPrincipalName = aSearch.GetAttributeValue(ATTRIBUTE_USER_PRINCIPAL_NAME);
  1040. if (V_VT(&vntUserPrincipalName) != VT_EMPTY)
  1041. {
  1042. aUser.SetUserPrincipalName(_bstr_t(vntUserPrincipalName));
  1043. }
  1044. rUsers.insert(aUser);
  1045. }
  1046. }
  1047. }
  1048. // QueryGroups Method
  1049. void CContainer::QueryGroups(bool bRecurse, StringSet& setExcludeNames, CDomainAccounts& rGroups)
  1050. {
  1051. tstring strFilter = CreateFilter(_T("(objectCategory=Group)"), setExcludeNames);
  1052. CDirectorySearch aSearch(m_sp);
  1053. aSearch.SetFilter(strFilter.c_str());
  1054. aSearch.SetPreferences(bRecurse ? ADS_SCOPE_SUBTREE : ADS_SCOPE_ONELEVEL);
  1055. aSearch.AddAttribute(ATTRIBUTE_OBJECT_SID);
  1056. aSearch.AddAttribute(ATTRIBUTE_ADS_PATH);
  1057. aSearch.AddAttribute(ATTRIBUTE_NAME);
  1058. aSearch.Search();
  1059. CDomainAccount aGroup;
  1060. for (bool bGet = aSearch.GetFirstRow(); bGet; bGet = aSearch.GetNextRow())
  1061. {
  1062. // if not a built-in or well known account
  1063. if (IsUserRid(aSearch.GetAttributeValue(ATTRIBUTE_OBJECT_SID)))
  1064. {
  1065. // add group
  1066. aGroup.SetADsPath(_bstr_t(aSearch.GetAttributeValue(ATTRIBUTE_ADS_PATH)));
  1067. aGroup.SetName(_bstr_t(aSearch.GetAttributeValue(ATTRIBUTE_NAME)));
  1068. rGroups.insert(aGroup);
  1069. }
  1070. }
  1071. }
  1072. // QueryComputers Method
  1073. void CContainer::QueryComputers(bool bIncludeDCs, bool bRecurse, StringSet& setExcludeNames, CDomainAccounts& rComputers)
  1074. {
  1075. tstring strFilter;
  1076. // ADS_UF_WORKSTATION_TRUST_ACCOUNT = 0x1000
  1077. // ADS_UF_SERVER_TRUST_ACCOUNT = 0x2000
  1078. if (bIncludeDCs)
  1079. {
  1080. strFilter = CreateFilter(
  1081. _T("(objectCategory=Computer)")
  1082. _T("(userAccountControl:") LDAP_MATCHING_RULE_BIT_OR_W _T(":=4096)"),
  1083. setExcludeNames
  1084. );
  1085. }
  1086. else
  1087. {
  1088. strFilter = CreateFilter(
  1089. _T("(objectCategory=Computer)")
  1090. _T("(|(userAccountControl:") LDAP_MATCHING_RULE_BIT_OR_W _T(":=4096)")
  1091. _T("(userAccountControl:") LDAP_MATCHING_RULE_BIT_OR_W _T(":=8192))"),
  1092. setExcludeNames
  1093. );
  1094. }
  1095. CDirectorySearch aSearch(m_sp);
  1096. aSearch.SetFilter(strFilter.c_str());
  1097. aSearch.SetPreferences(bRecurse ? ADS_SCOPE_SUBTREE : ADS_SCOPE_ONELEVEL);
  1098. aSearch.AddAttribute(ATTRIBUTE_OBJECT_SID);
  1099. aSearch.AddAttribute(ATTRIBUTE_ADS_PATH);
  1100. aSearch.AddAttribute(ATTRIBUTE_NAME);
  1101. aSearch.AddAttribute(ATTRIBUTE_SAM_ACCOUNT_NAME);
  1102. aSearch.Search();
  1103. CDomainAccount aComputer;
  1104. for (bool bGet = aSearch.GetFirstRow(); bGet; bGet = aSearch.GetNextRow())
  1105. {
  1106. // if not a built-in or well known account
  1107. if (IsUserRid(aSearch.GetAttributeValue(ATTRIBUTE_OBJECT_SID)))
  1108. {
  1109. // add computer
  1110. aComputer.SetADsPath(_bstr_t(aSearch.GetAttributeValue(ATTRIBUTE_ADS_PATH)));
  1111. aComputer.SetName(_bstr_t(aSearch.GetAttributeValue(ATTRIBUTE_NAME)));
  1112. aComputer.SetSamAccountName(_bstr_t(aSearch.GetAttributeValue(ATTRIBUTE_SAM_ACCOUNT_NAME)));
  1113. rComputers.insert(aComputer);
  1114. }
  1115. }
  1116. }
  1117. //---------------------------------------------------------------------------
  1118. namespace _DomainContainer
  1119. {
  1120. // CreateFilter Method
  1121. tstring __stdcall CreateFilter(LPCTSTR pszFilter, const StringSet& setExcludeNames)
  1122. {
  1123. tstring strFilter;
  1124. strFilter += _T("(&");
  1125. strFilter += pszFilter;
  1126. if (!setExcludeNames.empty())
  1127. {
  1128. strFilter += _T("(!(|");
  1129. for (StringSet::const_iterator it = setExcludeNames.begin(); it != setExcludeNames.end(); it++)
  1130. {
  1131. strFilter += _T("(name=");
  1132. strFilter += *it;
  1133. strFilter += _T(")");
  1134. }
  1135. strFilter += _T("))");
  1136. }
  1137. strFilter += _T(")");
  1138. return strFilter;
  1139. }
  1140. // IsClass
  1141. bool __stdcall IsClass(LPCTSTR pszClass, const _variant_t& vntClass)
  1142. {
  1143. bool bIs = false;
  1144. if (pszClass)
  1145. {
  1146. if (V_VT(&vntClass) == VT_BSTR)
  1147. {
  1148. if (V_BSTR(&vntClass))
  1149. {
  1150. if (_tcsicmp(pszClass, V_BSTR(&vntClass)) == 0)
  1151. {
  1152. bIs = true;
  1153. }
  1154. }
  1155. }
  1156. else
  1157. {
  1158. if (V_VT(&vntClass) == (VT_ARRAY|VT_BSTR))
  1159. {
  1160. SAFEARRAY* psa = V_ARRAY(&vntClass);
  1161. if (psa->cDims == 1)
  1162. {
  1163. BSTR* pbstr = reinterpret_cast<BSTR*>(psa->pvData);
  1164. DWORD cbstr = psa->rgsabound[0].cElements;
  1165. if (pbstr)
  1166. {
  1167. BSTR bstrClass = pbstr[cbstr - 1];
  1168. if (bstrClass)
  1169. {
  1170. if (_tcsicmp(pszClass, bstrClass) == 0)
  1171. {
  1172. bIs = true;
  1173. }
  1174. }
  1175. }
  1176. }
  1177. /*
  1178. typedef std::vector<_bstr_t> ClassVector;
  1179. ClassVector vec = T_SafeVector2<VT_BSTR, _bstr_t, ClassVector, T_Extract_bstr_t<ClassVector> >(const_cast<_variant_t&>(vntClass));
  1180. if (vec.size() > 0)
  1181. {
  1182. _bstr_t strClass = vec[vec.size() - 1];
  1183. if (strClass.length() > 0)
  1184. {
  1185. if (_tcsicmp(strClass, pszClass) == 0)
  1186. {
  1187. bIs = true;
  1188. }
  1189. }
  1190. }
  1191. */
  1192. }
  1193. }
  1194. }
  1195. return bIs;
  1196. }
  1197. // IsUserRid
  1198. bool __stdcall IsUserRid(const _variant_t& vntSid)
  1199. {
  1200. bool bUser = false;
  1201. if (V_VT(&vntSid) == (VT_ARRAY|VT_UI1))
  1202. {
  1203. PSID pSid = (PSID)vntSid.parray->pvData;
  1204. if (IsValidSid(pSid))
  1205. {
  1206. PUCHAR puch = GetSidSubAuthorityCount(pSid);
  1207. DWORD dwCount = static_cast<DWORD>(*puch);
  1208. DWORD dwIndex = dwCount - 1;
  1209. PDWORD pdw = GetSidSubAuthority(pSid, dwIndex);
  1210. DWORD dwRid = *pdw;
  1211. if (dwRid >= MIN_NON_RESERVED_RID)
  1212. {
  1213. bUser = true;
  1214. }
  1215. }
  1216. }
  1217. return bUser;
  1218. }
  1219. // GetADsObject
  1220. IDispatchPtr GetADsObject(_bstr_t strPath)
  1221. {
  1222. IDispatch* pdisp;
  1223. HRESULT hr = ADsGetObject(strPath, __uuidof(IDispatch), (void**)&pdisp);
  1224. if (FAILED(hr))
  1225. {
  1226. ReportADsError(hr);
  1227. _com_issue_error(hr);
  1228. }
  1229. return IDispatchPtr(pdisp, false);
  1230. }
  1231. // ReportADsError
  1232. void ReportADsError(HRESULT hr, const IID& iid)
  1233. {
  1234. DWORD dwError;
  1235. WCHAR szName[256];
  1236. WCHAR szError[256];
  1237. ADsGetLastError(&dwError, szError, sizeof(szError) / sizeof(szError[0]), szName, sizeof(szName) / sizeof(szName[0]));
  1238. AtlReportError(GUID_NULL, szError, iid, hr);
  1239. }
  1240. }