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.

988 lines
20 KiB

  1. #include "StdAfx.h"
  2. #include "ADMTScript.h"
  3. #include "NameCracker.h"
  4. #include <LM.h>
  5. #include <NtDsApi.h>
  6. #pragma comment(lib, "NtDsApi.lib")
  7. #include <DsGetDC.h>
  8. #include "Error.h"
  9. #include "AdsiHelpers.h"
  10. namespace
  11. {
  12. const _TCHAR CANONICAL_DELIMITER = _T('/');
  13. const _TCHAR SAM_DELIMITER = _T('\\');
  14. const _TCHAR SAM_INVALID_CHARACTERS[] = _T("\"*+,./:;<=>?[\\]|");
  15. }
  16. //---------------------------------------------------------------------------
  17. // Name Cracker Class
  18. //---------------------------------------------------------------------------
  19. CNameCracker::CNameCracker()
  20. {
  21. }
  22. CNameCracker::~CNameCracker()
  23. {
  24. }
  25. void CNameCracker::CrackNames(const StringVector& vecNames)
  26. {
  27. // separate the names into canonical names,
  28. // SAM account names and relative distinguished names
  29. StringVector vecCanonicalNames;
  30. StringVector vecSamAccountNames;
  31. StringVector vecRelativeDistinguishedNames;
  32. Separate(vecNames, vecCanonicalNames, vecSamAccountNames, vecRelativeDistinguishedNames);
  33. // then crack canonical names
  34. CrackCanonicalNames(vecCanonicalNames, vecRelativeDistinguishedNames);
  35. // then crack SAM account names
  36. CrackSamAccountNames(vecSamAccountNames, vecRelativeDistinguishedNames);
  37. // then crack relative distinguished names
  38. CrackRelativeDistinguishedNames(vecRelativeDistinguishedNames, m_vecUnResolvedNames);
  39. }
  40. void CNameCracker::Separate(
  41. const StringVector& vecNames,
  42. StringVector& vecCanonicalNames,
  43. StringVector& vecSamAccountNames,
  44. StringVector& vecRelativeDistinguishedNames
  45. )
  46. {
  47. // for each name in vector...
  48. for (StringVector::const_iterator it = vecNames.begin(); it != vecNames.end(); it++)
  49. {
  50. const tstring& strName = *it;
  51. // if non empty name...
  52. if (strName.empty() == false)
  53. {
  54. LPCTSTR pszName = strName.c_str();
  55. // then if name contains a solidus '/' character...
  56. if (_tcschr(pszName, CANONICAL_DELIMITER))
  57. {
  58. // then assume canonical name
  59. vecCanonicalNames.push_back(strName);
  60. }
  61. else
  62. {
  63. // otherwise if name contains a reverse solidus '\'
  64. // character and no invalid SAM account name characters...
  65. LPCTSTR pchDelimiter = _tcschr(pszName, SAM_DELIMITER);
  66. if (pchDelimiter && (_tcspbrk(pchDelimiter + 1, SAM_INVALID_CHARACTERS) == NULL))
  67. {
  68. // then assume SAM account name
  69. vecSamAccountNames.push_back(strName);
  70. }
  71. else
  72. {
  73. // otherwise assume relative distinguished name
  74. vecRelativeDistinguishedNames.push_back(strName);
  75. }
  76. }
  77. }
  78. }
  79. }
  80. void CNameCracker::CrackCanonicalNames(const StringVector& vecCanonicalNames, StringVector& vecUnResolvedNames)
  81. {
  82. //
  83. // for each name generate a complete canonical name
  84. //
  85. CNameVector vecNames;
  86. tstring strCanonical;
  87. for (StringVector::const_iterator it = vecCanonicalNames.begin(); it != vecCanonicalNames.end(); it++)
  88. {
  89. const tstring& strName = *it;
  90. // if first character is the solidus '/' character...
  91. if (strName[0] == CANONICAL_DELIMITER)
  92. {
  93. // then generate complete canonical name
  94. strCanonical = m_strDnsName + strName;
  95. }
  96. else
  97. {
  98. // otherwise if already complete canonical name for this domain...
  99. if (_tcsnicmp(m_strDnsName.c_str(), strName.c_str(), m_strDnsName.length()) == 0)
  100. {
  101. // then add complete canonical name
  102. strCanonical = strName;
  103. }
  104. else
  105. {
  106. // otherwise prefix DNS domain name with solidus and add
  107. strCanonical = m_strDnsName + CANONICAL_DELIMITER + strName;
  108. }
  109. }
  110. vecNames.push_back(SName(strName.c_str(), strCanonical.c_str()));
  111. }
  112. //
  113. // crack canonical names
  114. //
  115. CrackNames(CANONICAL_NAME, vecNames);
  116. for (size_t i = 0; i < vecNames.size(); i++)
  117. {
  118. const SName& name = vecNames[i];
  119. if (name.strResolved.empty() == false)
  120. {
  121. m_setResolvedNames.insert(name.strResolved);
  122. }
  123. else
  124. {
  125. vecUnResolvedNames.push_back(name.strPartial);
  126. }
  127. }
  128. }
  129. void CNameCracker::CrackSamAccountNames(const StringVector& vecSamAccountNames, StringVector& vecUnResolvedNames)
  130. {
  131. //
  132. // for each name generate a NT4 account name
  133. //
  134. CNameVector vecNames;
  135. tstring strNT4Account;
  136. for (StringVector::const_iterator it = vecSamAccountNames.begin(); it != vecSamAccountNames.end(); it++)
  137. {
  138. const tstring& strName = *it;
  139. // if first character is the reverse solidus '\' character...
  140. if (strName[0] == SAM_DELIMITER)
  141. {
  142. // then generate downlevel name
  143. strNT4Account = m_strFlatName + strName;
  144. }
  145. else
  146. {
  147. // otherwise if already downlevel name for this domain...
  148. if (_tcsnicmp(m_strFlatName.c_str(), strName.c_str(), m_strFlatName.length()) == 0)
  149. {
  150. // then add downlevel name
  151. strNT4Account = strName;
  152. }
  153. else
  154. {
  155. // otherwise prefix flat domain name with reverse solidus and add
  156. strNT4Account = m_strFlatName + SAM_DELIMITER + strName;
  157. }
  158. }
  159. vecNames.push_back(SName(strName.c_str(), strNT4Account.c_str()));
  160. }
  161. //
  162. // crack names
  163. //
  164. CrackNames(NT4_ACCOUNT_NAME, vecNames);
  165. for (size_t i = 0; i < vecNames.size(); i++)
  166. {
  167. const SName& name = vecNames[i];
  168. if (name.strResolved.empty() == false)
  169. {
  170. m_setResolvedNames.insert(name.strResolved);
  171. }
  172. else
  173. {
  174. vecUnResolvedNames.push_back(name.strPartial);
  175. }
  176. }
  177. }
  178. void CNameCracker::CrackRelativeDistinguishedNames(const StringVector& vecRelativeDistinguishedNames, StringVector& vecUnResolvedNames)
  179. {
  180. CDirectorySearch dsSearch = IDispatchPtr(m_spDefaultContainer);
  181. dsSearch.AddAttribute(ATTRIBUTE_DISTINGUISHED_NAME);
  182. dsSearch.SetPreferences(ADS_SCOPE_ONELEVEL);
  183. for (StringVector::const_iterator it = vecRelativeDistinguishedNames.begin(); it != vecRelativeDistinguishedNames.end(); it++)
  184. {
  185. tstring strFilter = _T("(") + GetEscapedFilterName(it->c_str()) + _T(")");
  186. dsSearch.SetFilter(strFilter.c_str());
  187. dsSearch.Search();
  188. bool bFound = false;
  189. try
  190. {
  191. for (bool bGet = dsSearch.GetFirstRow(); bGet; bGet = dsSearch.GetNextRow())
  192. {
  193. m_setResolvedNames.insert(tstring(_bstr_t(dsSearch.GetAttributeValue(ATTRIBUTE_DISTINGUISHED_NAME))));
  194. bFound = true;
  195. }
  196. }
  197. catch (_com_error& ce)
  198. {
  199. #ifdef _DEBUG
  200. _TCHAR sz[2048];
  201. _stprintf(sz, _T("'%s' : %s : 0x%08lX\n"), it->c_str(), ce.ErrorMessage(), ce.Error());
  202. OutputDebugString(sz);
  203. #endif
  204. bFound = false;
  205. }
  206. catch (...)
  207. {
  208. bFound = false;
  209. }
  210. if (!bFound)
  211. {
  212. vecUnResolvedNames.push_back(*it);
  213. }
  214. }
  215. }
  216. void CNameCracker::CrackNames(NAME_FORMAT eFormat, CNameVector& vecNames)
  217. {
  218. HANDLE hDs = NULL;
  219. LPTSTR apszNames = NULL;
  220. PDS_NAME_RESULT pdnrResult = NULL;
  221. try
  222. {
  223. if (vecNames.size() > 0)
  224. {
  225. DWORD dwError = DsBind(m_strDomainController.c_str(), NULL, &hDs);
  226. if (dwError == NO_ERROR)
  227. {
  228. DWORD dwCount = vecNames.size();
  229. LPCTSTR* apszNames = new LPCTSTR[dwCount];
  230. if (apszNames != NULL)
  231. {
  232. for (DWORD dwIndex = 0; dwIndex < dwCount; dwIndex++)
  233. {
  234. apszNames[dwIndex] = vecNames[dwIndex].strComplete.c_str();
  235. }
  236. dwError = DsCrackNames(
  237. hDs,
  238. DS_NAME_NO_FLAGS,
  239. (eFormat == CANONICAL_NAME) ? DS_CANONICAL_NAME : (eFormat == NT4_ACCOUNT_NAME) ? DS_NT4_ACCOUNT_NAME : DS_UNKNOWN_NAME,
  240. DS_FQDN_1779_NAME,
  241. dwCount,
  242. const_cast<LPTSTR*>(apszNames),
  243. &pdnrResult
  244. );
  245. if (dwError == NO_ERROR)
  246. {
  247. DWORD c = pdnrResult->cItems;
  248. for (DWORD i = 0; i < c; i++)
  249. {
  250. DS_NAME_RESULT_ITEM& dnriItem = pdnrResult->rItems[i];
  251. if (dnriItem.status == DS_NAME_NO_ERROR)
  252. {
  253. vecNames[i].strResolved = dnriItem.pName;
  254. }
  255. }
  256. DsFreeNameResult(pdnrResult);
  257. }
  258. else
  259. {
  260. _com_issue_error(HRESULT_FROM_WIN32(dwError));
  261. }
  262. delete [] apszNames;
  263. }
  264. else
  265. {
  266. _com_issue_error(E_OUTOFMEMORY);
  267. }
  268. DsUnBind(&hDs);
  269. }
  270. else
  271. {
  272. _com_issue_error(HRESULT_FROM_WIN32(dwError));
  273. }
  274. }
  275. }
  276. catch (...)
  277. {
  278. if (pdnrResult)
  279. {
  280. DsFreeNameResult(pdnrResult);
  281. }
  282. delete [] apszNames;
  283. if (hDs)
  284. {
  285. DsUnBind(&hDs);
  286. }
  287. throw;
  288. }
  289. }
  290. tstring CNameCracker::GetEscapedFilterName(LPCTSTR pszName)
  291. {
  292. tstring strNameEscaped;
  293. if (pszName)
  294. {
  295. // generate escaped name
  296. for (LPCTSTR pch = pszName; *pch; pch++)
  297. {
  298. switch (*pch)
  299. {
  300. case _T('('):
  301. {
  302. strNameEscaped += _T("\\28");
  303. break;
  304. }
  305. case _T(')'):
  306. {
  307. strNameEscaped += _T("\\29");
  308. break;
  309. }
  310. case _T('*'):
  311. {
  312. strNameEscaped += _T("\\2A");
  313. break;
  314. }
  315. case _T('\\'):
  316. {
  317. if (*(pch + 1) == _T('\\'))
  318. {
  319. strNameEscaped += _T("\\5C");
  320. }
  321. break;
  322. }
  323. default:
  324. {
  325. strNameEscaped += *pch;
  326. break;
  327. }
  328. }
  329. }
  330. }
  331. return strNameEscaped;
  332. }
  333. namespace
  334. {
  335. // SplitCanonicalName Method
  336. //
  337. // Given 'a.company.com/Sales/West/Name' this method splits the complete
  338. // canonical name into its component parts Domain='a.company.com',
  339. // Path='/Sales/West/', Name='Name'.
  340. //
  341. // Given 'Sales/West/Name' this method splits the partial canonical name
  342. // into its component parts Domain='', Path='/Sales/West/', Name='Name'.
  343. //
  344. // Given 'Name' this method splits the partial canonical name into its
  345. // component parts Domain='', Path='/', Name='Name'.
  346. void SplitCanonicalName(LPCTSTR pszName, _bstr_t& strDomain, _bstr_t& strPath, _bstr_t& strName)
  347. {
  348. strDomain = (LPCTSTR)NULL;
  349. strPath = (LPCTSTR)NULL;
  350. strName = (LPCTSTR)NULL;
  351. if (pszName)
  352. {
  353. tstring str = pszName;
  354. UINT posA = 0;
  355. UINT posB = tstring::npos;
  356. do
  357. {
  358. posA = str.find_first_of(_T('/'), posA ? posA + 1 : posA);
  359. }
  360. while ((posA != 0) && (posA != tstring::npos) && (str[posA - 1] == _T('\\')));
  361. do
  362. {
  363. posB = str.find_last_of(_T('/'), (posB != tstring::npos) ? posB - 1 : posB);
  364. }
  365. while ((posB != 0) && (posB != tstring::npos) && (str[posB - 1] == _T('\\')));
  366. strDomain = str.substr(0, posA).c_str();
  367. strPath = str.substr(posA, posB - posA).c_str();
  368. strName = str.substr(posB).c_str();
  369. }
  370. }
  371. void SplitPath(LPCTSTR pszPath, _bstr_t& strPath, _bstr_t& strName)
  372. {
  373. strPath = (LPCTSTR)NULL;
  374. strName = (LPCTSTR)NULL;
  375. if (pszPath)
  376. {
  377. tstring str = pszPath;
  378. UINT pos = str.find_first_of(_T('\\'));
  379. if (pos != tstring::npos)
  380. {
  381. strName = pszPath;
  382. }
  383. else
  384. {
  385. UINT posA = str.find_first_of(_T('/'));
  386. if (posA == tstring::npos)
  387. {
  388. strName = (_T("/") + str).c_str();
  389. }
  390. else
  391. {
  392. UINT posB = str.find_last_of(_T('/'));
  393. strPath = str.substr(posA, posB - posA).c_str();
  394. strName = str.substr(posB).c_str();
  395. }
  396. }
  397. }
  398. }
  399. }
  400. //---------------------------------------------------------------------------
  401. // Ignore Case String Less
  402. //---------------------------------------------------------------------------
  403. struct SIgnoreCaseStringLess :
  404. public std::binary_function<tstring, tstring, bool>
  405. {
  406. bool operator()(const tstring& x, const tstring& y) const
  407. {
  408. bool bLess;
  409. LPCTSTR pszX = x.c_str();
  410. LPCTSTR pszY = y.c_str();
  411. if (pszX == pszY)
  412. {
  413. bLess = false;
  414. }
  415. else if (pszX == NULL)
  416. {
  417. bLess = true;
  418. }
  419. else if (pszY == NULL)
  420. {
  421. bLess = false;
  422. }
  423. else
  424. {
  425. bLess = _tcsicmp(pszX, pszY) < 0;
  426. }
  427. return bLess;
  428. }
  429. };
  430. //---------------------------------------------------------------------------
  431. // CDomainMap Implementation
  432. //---------------------------------------------------------------------------
  433. class CDomainMap :
  434. public std::map<_bstr_t, StringSet, IgnoreCaseStringLess>
  435. {
  436. public:
  437. CDomainMap()
  438. {
  439. }
  440. void Initialize(const StringSet& setNames)
  441. {
  442. _bstr_t strDefaultDns(_T("/"));
  443. _bstr_t strDefaultFlat(_T("\\"));
  444. for (StringSet::const_iterator it = setNames.begin(); it != setNames.end(); it++)
  445. {
  446. tstring strName = *it;
  447. // if not an empty name...
  448. if (strName.empty() == false)
  449. {
  450. // if name contains a canonical name delimiter...
  451. UINT posDelimiter = strName.find(CANONICAL_DELIMITER);
  452. if (posDelimiter != tstring::npos)
  453. {
  454. // then assume canonical name
  455. if (posDelimiter == 0)
  456. {
  457. // then generate complete canonical name
  458. Insert(strDefaultDns, *it);
  459. }
  460. else
  461. {
  462. // otherwise if path component before delimiter contains
  463. // a period
  464. UINT posDot = strName.find(_T('.'));
  465. if (posDot < posDelimiter)
  466. {
  467. // then assume a complete canonical name with DNS domain name prefix
  468. Insert(strName.substr(0, posDelimiter).c_str(), *it);
  469. }
  470. else
  471. {
  472. // otherwise assume domain name has not been specified
  473. Insert(strDefaultDns, *it);
  474. }
  475. }
  476. }
  477. else
  478. {
  479. // otherwise if name contains a NT account name delimiter
  480. // character and no invalid SAM account name characters...
  481. UINT posDelimiter = strName.find(SAM_DELIMITER);
  482. if (posDelimiter != tstring::npos)
  483. {
  484. if (strName.find_first_of(SAM_INVALID_CHARACTERS, posDelimiter + 1) == tstring::npos)
  485. {
  486. if (posDelimiter == 0)
  487. {
  488. Insert(strDefaultFlat, *it);
  489. }
  490. else
  491. {
  492. // then assume SAM account name
  493. Insert(strName.substr(0, posDelimiter).c_str(), *it);
  494. }
  495. }
  496. else
  497. {
  498. // otherwise assume relative distinguished name
  499. Insert(strDefaultDns, *it);
  500. }
  501. }
  502. else
  503. {
  504. Insert(strDefaultDns, *it);
  505. }
  506. }
  507. }
  508. }
  509. }
  510. protected:
  511. void Insert(_bstr_t strDomain, _bstr_t strName)
  512. {
  513. iterator it = find(strDomain);
  514. if (it == end())
  515. {
  516. std::pair<iterator, bool> pair = insert(value_type(strDomain, StringSet()));
  517. it = pair.first;
  518. }
  519. it->second.insert(strName);
  520. }
  521. };
  522. //---------------------------------------------------------------------------
  523. // CDomainToPathMap Implementation
  524. //---------------------------------------------------------------------------
  525. // Initialize Method
  526. void CDomainToPathMap::Initialize(LPCTSTR pszDefaultDomainDns, LPCTSTR pszDefaultDomainFlat, const StringSet& setNames)
  527. {
  528. CDomainMap map;
  529. map.Initialize(setNames);
  530. for (CDomainMap::const_iterator itDomain = map.begin(); itDomain != map.end(); itDomain++)
  531. {
  532. _bstr_t strDomainName = itDomain->first;
  533. LPCTSTR pszDomainName = strDomainName;
  534. if (pszDomainName && ((*pszDomainName == _T('/')) || (*pszDomainName == _T('\\'))))
  535. {
  536. strDomainName = (pszDefaultDomainDns && (_tcslen(pszDefaultDomainDns) > 0)) ? pszDefaultDomainDns : pszDefaultDomainFlat;
  537. }
  538. else
  539. {
  540. if (GetValidDomainName(strDomainName) == false)
  541. {
  542. strDomainName = (pszDefaultDomainDns && (_tcslen(pszDefaultDomainDns) > 0)) ? pszDefaultDomainDns : pszDefaultDomainFlat;
  543. }
  544. }
  545. iterator it = find(strDomainName);
  546. if (it == end())
  547. {
  548. std::pair<iterator, bool> pair = insert(value_type(strDomainName, StringSet()));
  549. it = pair.first;
  550. }
  551. StringSet& setNames = it->second;
  552. const StringSet& set = itDomain->second;
  553. for (StringSet::const_iterator itSet = set.begin(); itSet != set.end(); itSet++)
  554. {
  555. setNames.insert(*itSet);
  556. }
  557. }
  558. }
  559. // GetValidDomainName Method
  560. bool CDomainToPathMap::GetValidDomainName(_bstr_t& strDomainName)
  561. {
  562. bool bValid = false;
  563. PDOMAIN_CONTROLLER_INFO pdci;
  564. // attempt to retrieve DNS name of domain controller supporting active directory service
  565. DWORD dwError = DsGetDcName(NULL, strDomainName, NULL, NULL, DS_RETURN_DNS_NAME, &pdci);
  566. // if domain controller not found, attempt to retrieve flat name of domain controller
  567. if (dwError == ERROR_NO_SUCH_DOMAIN)
  568. {
  569. dwError = DsGetDcName(NULL, strDomainName, NULL, NULL, DS_RETURN_FLAT_NAME, &pdci);
  570. }
  571. // if domain controller found then save name otherwise generate error
  572. if (dwError == NO_ERROR)
  573. {
  574. strDomainName = pdci->DomainName;
  575. NetApiBufferFree(pdci);
  576. bValid = true;
  577. }
  578. return bValid;
  579. }
  580. //
  581. // CNameToPathMap Implementation
  582. //
  583. CNameToPathMap::CNameToPathMap()
  584. {
  585. }
  586. CNameToPathMap::CNameToPathMap(StringSet& setNames)
  587. {
  588. Initialize(setNames);
  589. }
  590. void CNameToPathMap::Initialize(StringSet& setNames)
  591. {
  592. _bstr_t strDomain;
  593. _bstr_t strPath;
  594. _bstr_t strName;
  595. for (StringSet::iterator it = setNames.begin(); it != setNames.end(); it++)
  596. {
  597. // SplitPath(*it, strPath, strName);
  598. SplitCanonicalName(*it, strDomain, strPath, strName);
  599. Add(strName, strPath);
  600. }
  601. }
  602. void CNameToPathMap::Add(_bstr_t& strName, _bstr_t& strPath)
  603. {
  604. iterator it = find(strName);
  605. if (it == end())
  606. {
  607. std::pair<iterator, bool> pair = insert(value_type(strName, StringSet()));
  608. it = pair.first;
  609. }
  610. it->second.insert(strPath);
  611. }
  612. //
  613. // IgnoreCaseStringLess Implementation
  614. //
  615. bool IgnoreCaseStringLess::operator()(const _bstr_t& x, const _bstr_t& y) const
  616. {
  617. bool bLess;
  618. LPCTSTR pszThis = x;
  619. LPCTSTR pszThat = y;
  620. if (pszThis == pszThat)
  621. {
  622. bLess = false;
  623. }
  624. else if (pszThis == NULL)
  625. {
  626. bLess = true;
  627. }
  628. else if (pszThat == NULL)
  629. {
  630. bLess = false;
  631. }
  632. else
  633. {
  634. bLess = _tcsicmp(pszThis, pszThat) < 0;
  635. }
  636. return bLess;
  637. }
  638. //
  639. // CCompareStrings Implementation
  640. //
  641. CCompareStrings::CCompareStrings()
  642. {
  643. }
  644. CCompareStrings::CCompareStrings(StringSet& setNames)
  645. {
  646. Initialize(setNames);
  647. }
  648. void CCompareStrings::Initialize(StringSet& setNames)
  649. {
  650. for (StringSet::iterator it = setNames.begin(); it != setNames.end(); it++)
  651. {
  652. m_vecCompareStrings.push_back(CCompareString(*it));
  653. }
  654. }
  655. bool CCompareStrings::IsMatch(LPCTSTR pszName)
  656. {
  657. bool bIs = false;
  658. CompareStringVector::iterator itBeg = m_vecCompareStrings.begin();
  659. CompareStringVector::iterator itEnd = m_vecCompareStrings.end();
  660. for (CompareStringVector::iterator it = itBeg; it != itEnd; it++)
  661. {
  662. if (it->IsMatch(pszName))
  663. {
  664. bIs = true;
  665. break;
  666. }
  667. }
  668. return bIs;
  669. }
  670. //
  671. // CCompareString Implementation
  672. //
  673. CCompareStrings::CCompareString::CCompareString(LPCTSTR pszCompare)
  674. {
  675. if (pszCompare)
  676. {
  677. Initialize(pszCompare);
  678. }
  679. }
  680. CCompareStrings::CCompareString::CCompareString(const CCompareString& r) :
  681. m_nType(r.m_nType),
  682. m_strCompare(r.m_strCompare)
  683. {
  684. }
  685. void CCompareStrings::CCompareString::Initialize(LPCTSTR pszCompare)
  686. {
  687. if (pszCompare)
  688. {
  689. tstring str = pszCompare;
  690. UINT uLength = str.length();
  691. bool bBeg = (str[0] == _T('*'));
  692. bool bEnd = false;
  693. if ((uLength > 1) && (str[uLength - 1] == _T('*')) && (str[uLength - 2] != _T('\\')))
  694. {
  695. bEnd = true;
  696. }
  697. if (bBeg && bEnd)
  698. {
  699. // contains
  700. m_nType = 3;
  701. str = str.substr(1, uLength - 2);
  702. }
  703. else if (bBeg)
  704. {
  705. // ends with
  706. m_nType = 2;
  707. str = str.substr(1, uLength - 1);
  708. }
  709. else if (bEnd)
  710. {
  711. // begins with
  712. m_nType = 1;
  713. str = str.substr(0, uLength - 1);
  714. }
  715. else
  716. {
  717. // equals
  718. m_nType = 0;
  719. }
  720. if (str.length() > 0)
  721. {
  722. // replace escaped asterisks with asterisk
  723. for (UINT pos = str.find(_T('*')); pos != tstring::npos; pos = str.find(_T('*'), pos))
  724. {
  725. if ((pos > 0) && (str[pos - 1] == _T('\\')))
  726. {
  727. str = str.substr(0, pos - 1) + str.substr(pos);
  728. }
  729. else
  730. {
  731. AdmtThrowError(GUID_NULL, GUID_NULL, E_INVALIDARG, IDS_E_INVALID_FILTER_STRING, pszCompare);
  732. }
  733. }
  734. m_strCompare = str.c_str();
  735. }
  736. else
  737. {
  738. AdmtThrowError(GUID_NULL, GUID_NULL, E_INVALIDARG, IDS_E_INVALID_FILTER_STRING, pszCompare);
  739. }
  740. }
  741. else
  742. {
  743. AdmtThrowError(GUID_NULL, GUID_NULL, E_INVALIDARG, IDS_E_INVALID_FILTER_STRING, _T(""));
  744. }
  745. }
  746. bool CCompareStrings::CCompareString::IsMatch(LPCTSTR psz)
  747. {
  748. bool bIs = false;
  749. if (psz)
  750. {
  751. switch (m_nType)
  752. {
  753. case 0: // equals
  754. {
  755. bIs = (_tcsicmp(psz, m_strCompare) == 0);
  756. break;
  757. }
  758. case 1: // begins with
  759. {
  760. bIs = (_tcsnicmp(psz, m_strCompare, m_strCompare.length()) == 0);
  761. break;
  762. }
  763. case 2: // ends with
  764. {
  765. UINT cchT = _tcslen(psz);
  766. UINT cchC = m_strCompare.length();
  767. if (cchT >= cchC)
  768. {
  769. bIs = (_tcsnicmp(psz + cchT - cchC, m_strCompare, cchC) == 0);
  770. }
  771. break;
  772. }
  773. case 3: // contains
  774. {
  775. LPTSTR pszT = (LPTSTR)_alloca((_tcslen(psz) + 1) * sizeof(_TCHAR));
  776. LPTSTR pszC = (LPTSTR)_alloca((m_strCompare.length() + 1) * sizeof(_TCHAR));
  777. _tcscpy(pszT, psz);
  778. _tcscpy(pszC, m_strCompare);
  779. _tcslwr(pszT);
  780. _tcslwr(pszC);
  781. bIs = (_tcsstr(pszT, pszC) != NULL);
  782. break;
  783. }
  784. }
  785. }
  786. return bIs;
  787. }