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.

1585 lines
33 KiB

  1. // ipsecparser.cpp: interface for the IPSec provider implemented parser (query and path)
  2. // Copyright (c)1997-2001 Microsoft Corporation
  3. //
  4. //////////////////////////////////////////////////////////////////////
  5. #include "precomp.h"
  6. #include "ipsecparser.h"
  7. // IIPSecPathParser
  8. /*
  9. Routine Description:
  10. Name:
  11. CIPSecPathParser::CIPSecPathParser
  12. Functionality:
  13. Constructor. Initialize pointer members.
  14. Virtual:
  15. No.
  16. Arguments:
  17. None.
  18. Return Value:
  19. None.
  20. Notes:
  21. If you add more members, please initialize them here.
  22. */
  23. CIPSecPathParser::CIPSecPathParser ()
  24. :
  25. m_pszNamespace(NULL),
  26. m_pszClassName(NULL)
  27. {
  28. }
  29. /*
  30. Routine Description:
  31. Name:
  32. CIPSecPathParser::~CIPSecPathParser
  33. Functionality:
  34. Destructor. Do clean up (free memory).
  35. Virtual:
  36. No.
  37. Arguments:
  38. None.
  39. Return Value:
  40. None.
  41. Notes:
  42. If you add more members, please consider do clean up in the Cleanup function.
  43. */
  44. CIPSecPathParser::~CIPSecPathParser()
  45. {
  46. Cleanup();
  47. }
  48. /*
  49. Routine Description:
  50. Name:
  51. CIPSecPathParser::ParsePath
  52. Functionality:
  53. Parsing given path and store results in our members.
  54. Virtual:
  55. Yes.
  56. Arguments:
  57. pszObjectPath - the path to be parsed.
  58. Return Value:
  59. Success: S_OK
  60. Failure: various error code. Any such error indicates the failure to parse the path.
  61. (1) E_INVALIDARG
  62. (2) E_OUTOFMEMORY
  63. (3) E_UNEXPECTED for syntax error
  64. Notes:
  65. (1) Since this is regular COM server interface function, we use regular COM errors
  66. instead of WMI errors. However, we can't guarantee what WMI returns.
  67. */
  68. STDMETHODIMP
  69. CIPSecPathParser::ParsePath (
  70. IN LPCWSTR pszObjectPath
  71. )
  72. {
  73. if (pszObjectPath == NULL || *pszObjectPath == L'\0')
  74. {
  75. return E_INVALIDARG;
  76. }
  77. //
  78. // just in case, this object has already parsed before. This allows repeated use of the same
  79. // CIPSecPathParser for parsing different paths.
  80. //
  81. Cleanup();
  82. //
  83. // Ask WMI for their path parser
  84. //
  85. CComPtr<IWbemPath> srpPathParser;
  86. HRESULT hr = ::CoCreateInstance(CLSID_WbemDefPath, 0, CLSCTX_INPROC_SERVER, IID_IWbemPath, (void**) &srpPathParser);
  87. if (FAILED(hr))
  88. {
  89. return hr;
  90. }
  91. //
  92. // This is the parsing function.
  93. //
  94. hr = srpPathParser->SetText(WBEMPATH_CREATE_ACCEPT_ALL | WBEMPATH_TREAT_SINGLE_IDENT_AS_NS, pszObjectPath);
  95. if (FAILED(hr))
  96. {
  97. return hr;
  98. }
  99. //
  100. // Get the results...
  101. //
  102. ULONG uBufSize = 0;
  103. DWORD dwCount = 0;
  104. //
  105. // get namespace count
  106. //
  107. hr = srpPathParser->GetNamespaceCount(&dwCount);
  108. if (dwCount > 0)
  109. {
  110. //
  111. // get the length needed for the namespace
  112. //
  113. hr = srpPathParser->GetNamespaceAt(0, &uBufSize, NULL);
  114. if (FAILED(hr))
  115. {
  116. return hr;
  117. }
  118. //
  119. // we will free this memory.
  120. //
  121. m_pszNamespace = new WCHAR[uBufSize];
  122. if (m_pszNamespace == NULL)
  123. {
  124. return E_OUTOFMEMORY;
  125. }
  126. //
  127. // will ignore the result
  128. //
  129. hr = srpPathParser->GetNamespaceAt(0, &uBufSize, m_pszNamespace);
  130. }
  131. //
  132. // get the buffer size needed for the class name
  133. //
  134. uBufSize = 0;
  135. hr = srpPathParser->GetClassName(&uBufSize, NULL);
  136. if (SUCCEEDED(hr))
  137. {
  138. //
  139. // we will free this memory.
  140. //
  141. m_pszClassName = new WCHAR[uBufSize];
  142. if (m_pszClassName == NULL)
  143. {
  144. return E_OUTOFMEMORY;
  145. }
  146. //
  147. // WMI path parser don't have a documented behavior as when the class name
  148. // will be missing.
  149. //
  150. hr = srpPathParser->GetClassName(&uBufSize, m_pszClassName);
  151. }
  152. else
  153. {
  154. //
  155. // this clearly don't have a class name, then the namespace should be the class name.
  156. // for some reason, Query parser doesn't give us class name in case of singleton
  157. // and the class name ends up in the namespace member. Obviously, in this case, there is no
  158. // key properties.
  159. //
  160. //
  161. // must have a namespace
  162. //
  163. if (m_pszNamespace)
  164. {
  165. //
  166. // prepare to switch m_pszClassName to point to what the namesapce does.
  167. //
  168. delete [] m_pszClassName;
  169. m_pszClassName = m_pszNamespace;
  170. m_pszNamespace = NULL;
  171. //
  172. // we can return because there is no key property
  173. //
  174. return S_OK;
  175. }
  176. else
  177. {
  178. hr = E_UNEXPECTED;
  179. }
  180. }
  181. if (FAILED(hr))
  182. {
  183. return hr;
  184. }
  185. //
  186. // get key properties
  187. //
  188. CComPtr<IWbemPathKeyList> srpKeyList;
  189. hr = srpPathParser->GetKeyList(&srpKeyList);
  190. if (FAILED(hr))
  191. {
  192. return hr;
  193. }
  194. //
  195. // now get the Key and value pairs
  196. //
  197. ULONG uKeyCount = 0;
  198. hr = srpKeyList->GetCount(&uKeyCount);
  199. if (FAILED(hr) || uKeyCount == 0)
  200. {
  201. return hr;
  202. }
  203. for (ULONG i = 0; i < uKeyCount; i++)
  204. {
  205. //
  206. // this pKeyVal will cache the (name, value) pair
  207. //
  208. CPropValuePair* pKeyVal = NULL;
  209. uBufSize = 0;
  210. //
  211. // now get the size of buffer needed
  212. //
  213. CComVariant var;
  214. ULONG uCimType = CIM_EMPTY;
  215. hr = srpKeyList->GetKey2(i,
  216. 0,
  217. &uBufSize,
  218. NULL,
  219. &var,
  220. &uCimType);
  221. if (SUCCEEDED(hr))
  222. {
  223. //
  224. // our vector will manage the memory used by pKeyVal
  225. //
  226. pKeyVal = new CPropValuePair;
  227. if (pKeyVal == NULL)
  228. {
  229. hr = E_OUTOFMEMORY;
  230. break;
  231. }
  232. //
  233. // need the name buffer
  234. //
  235. pKeyVal->pszKey = new WCHAR[uBufSize];
  236. //
  237. // variant member of pKeyVal needs to be initialized as well.
  238. //
  239. ::VariantInit(&(pKeyVal->varVal));
  240. //
  241. // secondary allocation fails, need to free the first level pointer
  242. //
  243. if (pKeyVal->pszKey == NULL)
  244. {
  245. delete pKeyVal;
  246. pKeyVal = NULL;
  247. hr = E_OUTOFMEMORY;
  248. break;
  249. }
  250. }
  251. if (SUCCEEDED(hr))
  252. {
  253. hr = srpKeyList->GetKey2(i,
  254. 0,
  255. &uBufSize,
  256. pKeyVal->pszKey,
  257. &(pKeyVal->varVal),
  258. &uCimType);
  259. }
  260. if (SUCCEEDED(hr))
  261. {
  262. m_vecKeyValueList.push_back(pKeyVal);
  263. }
  264. else
  265. {
  266. //
  267. // for any failure, we need to free the resource already partially allocated
  268. // for the pKeyVal. This pKeyVal is pointing to our class, which knows how to free its members,
  269. // this delete is enough.
  270. //
  271. delete pKeyVal;
  272. break;
  273. }
  274. }
  275. if (SUCCEEDED(hr))
  276. {
  277. hr = S_OK;
  278. }
  279. return hr;
  280. }
  281. /*
  282. Routine Description:
  283. Name:
  284. CIPSecPathParser::GetKeyPropertyCount
  285. Functionality:
  286. Get the key proeprty count contained in the path.
  287. Virtual:
  288. Yes.
  289. Arguments:
  290. pCount - receives the count.
  291. Return Value:
  292. Success: S_OK
  293. Failure: E_INVALIDARG.
  294. Notes:
  295. (1) Since this is regular COM server interface function, we use regular COM errors
  296. instead of WMI errors. However, we can't guarantee what WMI returns.
  297. */
  298. STDMETHODIMP
  299. CIPSecPathParser::GetKeyPropertyCount (
  300. OUT DWORD *pCount
  301. )
  302. {
  303. if (pCount == NULL)
  304. {
  305. return E_INVALIDARG;
  306. }
  307. *pCount = m_vecKeyValueList.size();
  308. return S_OK;
  309. }
  310. /*
  311. Routine Description:
  312. Name:
  313. CIPSecPathParser::GetNamespace
  314. Functionality:
  315. Get the namespace.
  316. Virtual:
  317. Yes.
  318. Arguments:
  319. pbstrNamespace - receives the namespace string.
  320. Return Value:
  321. Success: S_OK
  322. Failure:
  323. (1) E_INVALIDARG
  324. (2) E_OUTOFMEMORY
  325. (3) E_UNEXPECTED for syntax error
  326. Notes:
  327. (1) Since this is regular COM server interface function, we use regular COM errors
  328. instead of WMI errors. However, we can't guarantee what WMI returns.
  329. */
  330. STDMETHODIMP
  331. CIPSecPathParser::GetNamespace (
  332. OUT BSTR *pbstrNamespace
  333. )
  334. {
  335. if (pbstrNamespace == NULL)
  336. {
  337. return E_INVALIDARG;
  338. }
  339. if (m_pszNamespace)
  340. {
  341. *pbstrNamespace = ::SysAllocString(m_pszNamespace);
  342. }
  343. else
  344. {
  345. return E_UNEXPECTED;
  346. }
  347. return (*pbstrNamespace) ? S_OK : E_OUTOFMEMORY;
  348. }
  349. /*
  350. Routine Description:
  351. Name:
  352. CIPSecPathParser::GetClassName
  353. Functionality:
  354. Get the class name.
  355. Virtual:
  356. Yes.
  357. Arguments:
  358. pbstrClassName - receives the class name string.
  359. Return Value:
  360. Success: S_OK
  361. Failure:
  362. (1) E_INVALIDARG
  363. (2) E_OUTOFMEMORY
  364. (3) E_UNEXPECTED for syntax error
  365. Notes:
  366. (1) Since this is regular COM server interface function, we use regular COM errors
  367. instead of WMI errors. However, we can't guarantee what WMI returns.
  368. */
  369. STDMETHODIMP
  370. CIPSecPathParser::GetClassName (
  371. OUT BSTR *pbstrClassName
  372. )
  373. {
  374. if (pbstrClassName == NULL)
  375. {
  376. return E_INVALIDARG;
  377. }
  378. if (m_pszClassName)
  379. {
  380. *pbstrClassName = ::SysAllocString(m_pszClassName);
  381. }
  382. else
  383. {
  384. return E_UNEXPECTED;
  385. }
  386. return (*pbstrClassName) ? S_OK : E_OUTOFMEMORY;
  387. }
  388. /*
  389. Routine Description:
  390. Name:
  391. CIPSecPathParser::GetKeyPropertyValue
  392. Functionality:
  393. Get the named property's value
  394. Virtual:
  395. Yes.
  396. Arguments:
  397. pszKeyPropName - The key property's name whose value is to be retrieved.
  398. pvarValue - receives the value.
  399. Return Value:
  400. Success: S_OK if the property value is properly retrieved.
  401. WBEM_S_FALSE if the property value can't be found.
  402. Failure:
  403. (1) E_INVALIDARG
  404. (2) E_OUTOFMEMORY
  405. (5) Or errors from VariantCopy
  406. Notes:
  407. (1) Since this is regular COM server interface function, we use regular COM errors
  408. instead of WMI errors. However, we can't guarantee what WMI returns.
  409. */
  410. STDMETHODIMP
  411. CIPSecPathParser::GetKeyPropertyValue (
  412. IN LPCWSTR pszKeyPropName,
  413. OUT VARIANT *pvarValue
  414. )
  415. {
  416. if (pszKeyPropName == NULL || *pszKeyPropName == L'\0' || pvarValue == NULL)
  417. {
  418. return E_INVALIDARG;
  419. }
  420. //
  421. // set the variant to a valid empty initial state
  422. //
  423. ::VariantInit(pvarValue);
  424. //
  425. // assume we can't find the property
  426. //
  427. HRESULT hr = WBEM_S_FALSE;
  428. std::vector<CPropValuePair*>::iterator it;
  429. //
  430. // find the property (case-insensitive name comparison) and copy the value
  431. //
  432. for (it = m_vecKeyValueList.begin(); it != m_vecKeyValueList.end(); it++)
  433. {
  434. if (_wcsicmp((*it)->pszKey, pszKeyPropName) == 0)
  435. {
  436. hr = ::VariantCopy(pvarValue, &((*it)->varVal));
  437. break;
  438. }
  439. }
  440. return hr;
  441. }
  442. /*
  443. Routine Description:
  444. Name:
  445. CIPSecPathParser::GetKeyPropertyValueByIndex
  446. Functionality:
  447. Get the indexed property name and value.
  448. Virtual:
  449. Yes.
  450. Arguments:
  451. dwIndex - the (name, value) pair's index.
  452. pbstrKeyPropName - receives key property's name.
  453. pvarValue - receives the value. In caller not interested, this can be NULL.
  454. Return Value:
  455. Success: S_OK
  456. Failure:
  457. (1) E_INVALIDARG (illegal null or index out of range)
  458. (2) E_OUTOFMEMORY
  459. (3) E_UNEXPECTED for can't find the property
  460. (4) Or errors from VariantCopy
  461. Notes:
  462. (1) Since this is regular COM server interface function, we use regular COM errors
  463. instead of WMI errors. However, we can't guarantee what WMI returns.
  464. */
  465. STDMETHODIMP CIPSecPathParser::GetKeyPropertyValueByIndex (
  466. IN DWORD dwIndex,
  467. OUT BSTR* pbstrKeyPropName,
  468. OUT VARIANT *pvarValue OPTIONAL
  469. )
  470. {
  471. if (dwIndex >= m_vecKeyValueList.size() || pbstrKeyPropName == NULL)
  472. {
  473. return E_INVALIDARG;
  474. }
  475. //
  476. // assume we can't find it
  477. //
  478. HRESULT hr = E_UNEXPECTED;
  479. //
  480. // initialize the out parameters
  481. //
  482. *pbstrKeyPropName = NULL;
  483. if (pvarValue)
  484. {
  485. ::VariantInit(pvarValue);
  486. }
  487. CPropValuePair *pKV = m_vecKeyValueList[dwIndex];
  488. if (pKV)
  489. {
  490. *pbstrKeyPropName = ::SysAllocString(pKV->pszKey);
  491. if (pbstrKeyPropName == NULL)
  492. {
  493. hr = E_OUTOFMEMORY;
  494. }
  495. if (SUCCEEDED(hr) && pvarValue)
  496. {
  497. hr = ::VariantCopy(pvarValue, &(pKV->varVal));
  498. //
  499. // don't want to return partial results
  500. //
  501. if (FAILED(hr))
  502. {
  503. ::SysFreeString(*pbstrKeyPropName);
  504. *pbstrKeyPropName = NULL;
  505. }
  506. }
  507. }
  508. return hr;
  509. }
  510. /*
  511. Routine Description:
  512. Name:
  513. CIPSecPathParser::Cleanup
  514. Functionality:
  515. Free memory resources.
  516. Virtual:
  517. No.
  518. Arguments:
  519. None.
  520. Return Value:
  521. None.
  522. Notes:
  523. Consider adding your clean up code here should you need to add members.
  524. */
  525. void CIPSecPathParser::Cleanup()
  526. {
  527. //
  528. // empty the vector. Since the vector manages the (name, value) pair,
  529. // its contents need to be deleted!
  530. //
  531. std::vector<CPropValuePair*>::iterator it;
  532. for (it = m_vecKeyValueList.begin(); it != m_vecKeyValueList.end(); ++it)
  533. {
  534. delete *it;
  535. }
  536. m_vecKeyValueList.empty();
  537. //
  538. // This function may be called not just inside the destructor,
  539. // so, properly reset the pointer values after free its memory.
  540. //
  541. delete [] m_pszNamespace;
  542. m_pszNamespace = NULL;
  543. delete [] m_pszClassName;
  544. m_pszClassName = NULL;
  545. }
  546. //================================================================================================
  547. // implementations for CIPSecQueryParser
  548. //================================================================================================
  549. /*
  550. Routine Description:
  551. Name:
  552. CIPSecQueryParser::CIPSecQueryParser
  553. Functionality:
  554. Constructor. All members are classes. They initialize automatically.
  555. Virtual:
  556. No.
  557. Arguments:
  558. None.
  559. Return Value:
  560. None.
  561. Notes:
  562. If you add more members, please initialize them here.
  563. */
  564. CIPSecQueryParser::CIPSecQueryParser()
  565. {
  566. }
  567. /*
  568. Routine Description:
  569. Name:
  570. CIPSecQueryParser::~CIPSecQueryParser
  571. Functionality:
  572. Destructor. do clean up.
  573. Virtual:
  574. No.
  575. Arguments:
  576. None.
  577. Return Value:
  578. None.
  579. Notes:
  580. If you add more members, please initialize them here.
  581. */
  582. CIPSecQueryParser::~CIPSecQueryParser()
  583. {
  584. Cleanup();
  585. }
  586. /*
  587. Routine Description:
  588. Name:
  589. CIPSecQueryParser::GetClassName
  590. Functionality:
  591. Get the class's name for the given index.
  592. Virtual:
  593. Yes.
  594. Arguments:
  595. iIndex - The index of the class. Currently, this is not used because WMI only
  596. support unary query - query that spans over one class. What we won't
  597. design our interface into that.
  598. pbstrClassName - Receives the class name.
  599. Return Value:
  600. Success: S_OK
  601. Failure:
  602. (1) E_INVALIDARG (illegal null or index out of range)
  603. (2) E_OUTOFMEMORY
  604. (3) E_UNEXPECTED for can't find the property
  605. (4) Or errors from VariantCopy
  606. Notes:
  607. (1) Since this is regular COM server interface function, we use regular COM errors
  608. instead of WMI errors. However, we can't guarantee what WMI returns.
  609. */
  610. STDMETHODIMP
  611. CIPSecQueryParser::GetClassName (
  612. IN int iIndex,
  613. OUT BSTR * pbstrClassName
  614. )
  615. {
  616. if (pbstrClassName == NULL || iIndex >= m_vecClassList.size())
  617. {
  618. return E_INVALIDARG;
  619. }
  620. if (m_vecClassList[iIndex])
  621. {
  622. *pbstrClassName = ::SysAllocString(m_vecClassList[iIndex]);
  623. }
  624. else
  625. {
  626. return E_UNEXPECTED;
  627. }
  628. return (*pbstrClassName) ? S_OK : E_OUTOFMEMORY;
  629. }
  630. /*
  631. Routine Description:
  632. Name:
  633. CIPSecQueryParser::GetGetQueryingPropertyValue
  634. Functionality:
  635. Get querying property's value given the index.
  636. Virtual:
  637. Yes.
  638. Arguments:
  639. iIndex - Since the same querying property may have multiple values in the where clause
  640. this is to get the iIndex-th value of the querying property. If you have a query
  641. like this:
  642. select * from Foo where FooVal = 1 AND BarVal = 5 OR FooVal = 2 AND BarVal = 6
  643. you will end up only with FooVal's. The reason for this limitation is that WMI
  644. doesn't have a full support on it (parser is maturing) and it's way too complicated
  645. for our IPSec parser. For users who needs that kind of support, please use WMI's query
  646. parser directly.
  647. pbstrQPValue - Receives the querying property's value in string format.
  648. Return Value:
  649. Success: S_OK
  650. Failure:
  651. (1) E_INVALIDARG (illegal null or index out of range)
  652. (2) E_OUTOFMEMORY
  653. (3) E_UNEXPECTED for can't find the property
  654. Notes:
  655. (1) Since this is regular COM server interface function, we use regular COM errors
  656. instead of WMI errors. However, we can't guarantee what WMI returns.
  657. */
  658. STDMETHODIMP
  659. CIPSecQueryParser::GetQueryingPropertyValue (
  660. IN int iIndex,
  661. OUT BSTR * pbstrQPValue
  662. )
  663. {
  664. if (pbstrQPValue == NULL || iIndex >= m_vecQueryingPropValueList.size())
  665. {
  666. return E_INVALIDARG;
  667. }
  668. if (m_vecQueryingPropValueList[iIndex])
  669. {
  670. *pbstrQPValue = ::SysAllocString(m_vecQueryingPropValueList[iIndex]);
  671. }
  672. else
  673. {
  674. return E_UNEXPECTED;
  675. }
  676. return (*pbstrQPValue) ? S_OK : E_OUTOFMEMORY;
  677. }
  678. /*
  679. Routine Description:
  680. Name:
  681. CIPSecQueryParser::Cleanup
  682. Functionality:
  683. free the resources held by our members.
  684. Virtual:
  685. No.
  686. Arguments:
  687. None.
  688. Return Value:
  689. None.
  690. Notes:
  691. (1) Consider add clean up code here should you need to add more members.
  692. */
  693. void CIPSecQueryParser::Cleanup()
  694. {
  695. //
  696. // both vectors are storing heap strings, need to delete the contents!
  697. //
  698. std::vector<LPWSTR>::iterator it;
  699. for (it = m_vecClassList.begin(); it != m_vecClassList.end(); it++)
  700. {
  701. delete [] (*it);
  702. }
  703. m_vecClassList.empty();
  704. for (it = m_vecQueryingPropValueList.begin(); it != m_vecQueryingPropValueList.end(); it++)
  705. {
  706. delete [] (*it);
  707. }
  708. m_vecQueryingPropValueList.empty();
  709. m_bstrQueryingPropName.Empty();
  710. }
  711. /*
  712. Routine Description:
  713. Name:
  714. CIPSecQueryParser::ParseQuery
  715. Functionality:
  716. Given the property name we are looking for, this function will parsing the query.
  717. Virtual:
  718. Yes.
  719. Arguments:
  720. strQuery - The query to be parsed.
  721. strQueryPropName - The querying property (the property we are looking for in the query).
  722. Return Value:
  723. Success: S_OK
  724. Failure:
  725. (1) E_INVALIDARG (illegal null or index out of range)
  726. (2) E_OUTOFMEMORY
  727. (3) E_UNEXPECTED for can't find the property
  728. (4) Other errors from WMI query parser.
  729. Notes:
  730. (1) Since this is regular COM server interface function, we use regular COM errors
  731. instead of WMI errors. However, we can't guarantee what WMI returns.
  732. */
  733. STDMETHODIMP CIPSecQueryParser::ParseQuery (
  734. IN LPCWSTR strQuery,
  735. IN LPCWSTR strQueryPropName
  736. )
  737. {
  738. if (strQuery == NULL || *strQuery == L'\0')
  739. {
  740. return E_INVALIDARG;
  741. }
  742. CComPtr<IWbemQuery> srpQuery;
  743. //
  744. // Get the WMI query object
  745. //
  746. HRESULT hr = ::CoCreateInstance(CLSID_WbemQuery, 0, CLSCTX_INPROC_SERVER, IID_IWbemQuery, (void**) &srpQuery);
  747. if (FAILED(hr))
  748. {
  749. return hr;
  750. }
  751. //
  752. // Set up the query parser to use
  753. //
  754. ULONG uFeatures[] = {WMIQ_LF1_BASIC_SELECT, WMIQ_LF2_CLASS_NAME_IN_QUERY};
  755. hr = srpQuery->SetLanguageFeatures(0, sizeof(uFeatures)/sizeof(*uFeatures), uFeatures);
  756. if (FAILED(hr))
  757. {
  758. return hr;
  759. }
  760. //
  761. // we are ready to parse, so, cleanup
  762. //
  763. Cleanup();
  764. //
  765. // parse the query
  766. //
  767. hr = srpQuery->Parse(L"WQL", strQuery, 0);
  768. if (FAILED(hr))
  769. {
  770. return hr;
  771. }
  772. //
  773. // Get the parsing results
  774. //
  775. //
  776. // need to free memory. Don't do it ourselves. Ask query to free it!
  777. //
  778. SWbemRpnEncodedQuery *pRpn = 0;
  779. hr = srpQuery->GetAnalysis(WMIQ_ANALYSIS_RPN_SEQUENCE, 0, (LPVOID *) &pRpn);
  780. if (SUCCEEDED(hr))
  781. {
  782. //
  783. // Need the class name from the results
  784. //
  785. hr = ExtractClassNames(pRpn);
  786. //
  787. // need the querying property values
  788. //
  789. if (SUCCEEDED(hr) && strQueryPropName && *strQueryPropName != L'\0')
  790. {
  791. m_bstrQueryingPropName = strQueryPropName;
  792. hr = ExtractQueryingProperties(pRpn, strQueryPropName);
  793. }
  794. srpQuery->FreeMemory(pRpn);
  795. }
  796. return SUCCEEDED(hr) ? S_OK : hr;
  797. }
  798. /*
  799. Routine Description:
  800. Name:
  801. CIPSecQueryParser::ExtractClassNames
  802. Functionality:
  803. Private helper to get the class name(s) from the query results.
  804. Virtual:
  805. No.
  806. Arguments:
  807. pRpn - The query result.
  808. Return Value:
  809. Success: S_OK
  810. Failure:
  811. (1) E_INVALIDARG (illegal null or index out of range)
  812. (2) E_OUTOFMEMORY.
  813. Notes:
  814. (1) Since this is regular COM server interface function, we use regular COM errors
  815. instead of WMI errors. However, we can't guarantee what WMI returns.
  816. */
  817. HRESULT CIPSecQueryParser::ExtractClassNames (
  818. SWbemRpnEncodedQuery *pRpn
  819. )
  820. {
  821. if (pRpn == NULL)
  822. {
  823. return E_INVALIDARG;
  824. }
  825. HRESULT hr = S_OK;
  826. int iLen = 0;
  827. LPWSTR pszClassName = NULL;
  828. //
  829. // get the from clause, i.e., the class names
  830. //
  831. if (pRpn->m_uFromTargetType & WMIQ_RPN_FROM_UNARY)
  832. {
  833. //
  834. // only one class
  835. //
  836. //
  837. // copy the class name and push it to our list
  838. //
  839. iLen = wcslen(pRpn->m_ppszFromList[0]);
  840. pszClassName = new WCHAR[iLen + 1];
  841. if (pszClassName != NULL)
  842. {
  843. //
  844. // won't overrun buffer, see size above
  845. //
  846. wcscpy(pszClassName, pRpn->m_ppszFromList[0]);
  847. m_vecClassList.push_back(pszClassName);
  848. }
  849. else
  850. {
  851. hr = E_OUTOFMEMORY;
  852. }
  853. }
  854. else if (pRpn->m_uFromTargetType & WMIQ_RPN_FROM_CLASS_LIST)
  855. {
  856. //
  857. // multiple classes. Won't happen for the time being. But we want to be ready
  858. // for WMI parser's enhancement.
  859. //
  860. for (ULONG uIndex = 0; uIndex < pRpn->m_uFromListSize; uIndex++)
  861. {
  862. iLen = wcslen(pRpn->m_ppszFromList[uIndex]);
  863. pszClassName = new WCHAR[iLen + 1];
  864. if (pszClassName != NULL)
  865. {
  866. //
  867. // won't overrun buffer, see size above
  868. //
  869. wcscpy(pszClassName, pRpn->m_ppszFromList[uIndex]);
  870. m_vecClassList.push_back(pszClassName);
  871. }
  872. else
  873. {
  874. hr = E_OUTOFMEMORY;
  875. break;
  876. }
  877. }
  878. }
  879. return hr;
  880. }
  881. /*
  882. Routine Description:
  883. Name:
  884. CIPSecQueryParser::ExtractQueryingProperties
  885. Functionality:
  886. Private helper to get the class name(s) from the query results.
  887. Virtual:
  888. No.
  889. Arguments:
  890. pRpn - The query result.
  891. strQueryPropName - the querying property's name
  892. Return Value:
  893. Success: S_OK
  894. Failure:
  895. (1) E_INVALIDARG (illegal null or index out of range)
  896. (2) E_OUTOFMEMORY.
  897. Notes:
  898. (1) Since this is regular COM server interface function, we use regular COM errors
  899. instead of WMI errors. However, we can't guarantee what WMI returns.
  900. (2) We only care about one querying property. Each subexpression will only have one querying property.
  901. Plus, if the subexpressions are AND'ed together, we will skip the rest subexpressions until we
  902. sees an OR again.
  903. (3) We can't support NOT very well. For example, how can we answer:
  904. select * from where NOT (IPSecStorePath = "c:\\test.inf")
  905. Fundamentally, we can't do that because we don't know the score of files not equal "c:\\test.inf".
  906. */
  907. //------------------------------------------------------------------------------------------------
  908. //------------------------------------------------------------------------------------------------
  909. HRESULT CIPSecQueryParser::ExtractQueryingProperties (
  910. IN SWbemRpnEncodedQuery * pRpn,
  911. IN LPCWSTR strQueryPropName
  912. )
  913. {
  914. if (pRpn == NULL)
  915. {
  916. return E_INVALIDARG;
  917. }
  918. HRESULT hr = S_OK;
  919. SWbemRpnQueryToken *pQueryToken = NULL;
  920. //
  921. // flags if we should ignore the next token
  922. //
  923. bool bSkip = false;
  924. for (ULONG uIndex = 0; uIndex < pRpn->m_uWhereClauseSize; uIndex++)
  925. {
  926. pQueryToken = pRpn->m_ppRpnWhereClause[uIndex];
  927. switch (pQueryToken->m_uTokenType)
  928. {
  929. case WMIQ_RPN_TOKEN_EXPRESSION:
  930. //
  931. // there is a subexpression, potentially a querying property here
  932. //
  933. if (!bSkip)
  934. {
  935. hr = GetQueryPropFromToken(pQueryToken, strQueryPropName);
  936. }
  937. //
  938. // if hr == S_FALSE, then it means it doesn't find any Store path
  939. // see it's use in case WMIQ_RPN_TOKEN_AND bellow
  940. //
  941. if (FAILED(hr))
  942. {
  943. return hr;
  944. }
  945. break;
  946. case WMIQ_RPN_TOKEN_OR:
  947. //
  948. // we see an OR, next tokens should NOT been skipped
  949. //
  950. bSkip = false;
  951. break;
  952. case WMIQ_RPN_TOKEN_AND:
  953. //
  954. // see comments about S_FALSE in case WMIQ_RPN_TOKEN_EXPRESSION above
  955. //
  956. bSkip = (hr == S_FALSE) ? false : true;
  957. //
  958. // fall through
  959. //
  960. case WMIQ_RPN_TOKEN_NOT:
  961. default:
  962. //
  963. // don't support parsing these tokens, so skip
  964. //
  965. bSkip = true;
  966. break;
  967. }
  968. }
  969. return S_OK;
  970. }
  971. /*
  972. Routine Description:
  973. Name:
  974. CIPSecQueryParser::GetQueryPropFromToken
  975. Functionality:
  976. Private helper analyze the token and get the querying property's value if found.
  977. Virtual:
  978. No.
  979. Arguments:
  980. pRpnQueryToken - The token to analyze.
  981. strQueryPropName - the querying property's name
  982. Return Value:
  983. Success: S_OK if a querying property's value is successfully retrieved.
  984. S_FALSE if no querying property name if found in the token.
  985. Failure:
  986. (1) E_INVALIDARG (illegal null or index out of range)
  987. (2) E_OUTOFMEMORY.
  988. (3) Other errors only defined by WMI, such as WBEM_E_INVALID_SYNTAX, WBEM_E_NOT_SUPPORTED.
  989. Notes:
  990. (1) Since this is regular COM server interface function, we use regular COM errors
  991. instead of WMI errors. However, we can't guarantee what WMI returns.
  992. (2) We only care about one querying property. Each subexpression will only have one querying property.
  993. Plus, if the subexpressions are AND'ed together, we will skip the rest subexpressions until we
  994. sees an OR again.
  995. (3) We can't support NOT very well. For example, how can we answer:
  996. select * from where NOT (IPSecStorePath = "c:\\test.inf")
  997. Fundamentally, we can't do that because we don't know the score of files not equal "c:\\test.inf".
  998. */
  999. HRESULT
  1000. CIPSecQueryParser::GetQueryPropFromToken (
  1001. IN SWbemRpnQueryToken * pRpnQueryToken,
  1002. IN LPCWSTR strQueryPropName
  1003. )
  1004. {
  1005. HRESULT hr = S_OK;
  1006. //
  1007. // we only support <propertyName> = <value> and
  1008. // <value> should be string
  1009. //
  1010. if (pRpnQueryToken->m_uOperator != WMIQ_RPN_OP_EQ ||
  1011. pRpnQueryToken->m_uConstApparentType != VT_LPWSTR )
  1012. {
  1013. return WBEM_E_NOT_SUPPORTED;
  1014. }
  1015. //
  1016. // must have left identifier, we don't support it if it doesn't have one.
  1017. //
  1018. if (pRpnQueryToken->m_pLeftIdent == NULL)
  1019. {
  1020. hr = WBEM_E_NOT_SUPPORTED;
  1021. }
  1022. else
  1023. {
  1024. SWbemQueryQualifiedName *pLeft = pRpnQueryToken->m_pLeftIdent;
  1025. //
  1026. // no left, invalid
  1027. //
  1028. if (pLeft == NULL)
  1029. {
  1030. return WBEM_E_INVALID_SYNTAX;
  1031. }
  1032. if (pLeft->m_uNameListSize != 1)
  1033. {
  1034. return WBEM_E_NOT_SUPPORTED;
  1035. }
  1036. // if the right is StoreName, then this is what we need
  1037. if (_wcsicmp(strQueryPropName, pLeft->m_ppszNameList[0]) == 0)
  1038. {
  1039. int iLen = wcslen(pRpnQueryToken->m_Const.m_pszStrVal);
  1040. LPWSTR pName = new WCHAR[iLen + 1];
  1041. if (pName)
  1042. {
  1043. //
  1044. // won't overrun the buffer
  1045. //
  1046. wcscpy(pName, pRpnQueryToken->m_Const.m_pszStrVal);
  1047. m_vecQueryingPropValueList.push_back(pName);
  1048. }
  1049. else
  1050. {
  1051. return E_OUTOFMEMORY;
  1052. }
  1053. }
  1054. else
  1055. {
  1056. //
  1057. // no match for querying property name
  1058. //
  1059. hr = S_FALSE;
  1060. }
  1061. }
  1062. return hr;
  1063. }
  1064. /*
  1065. Routine Description:
  1066. Name:
  1067. CIPSecQueryParser::GetQueryPropFromToken
  1068. Functionality:
  1069. Get key proeprty value parsed from the query. Due to our query limitation, the property name
  1070. should really be the querying property name.
  1071. Virtual:
  1072. Yes.
  1073. Arguments:
  1074. pszKeyPropName - The key property name.
  1075. pvarValue - receives the value.
  1076. Return Value:
  1077. Success: S_OK if a key property's value is successfully retrieved.
  1078. WBEM_S_FALSE if the property can't be found.
  1079. Failure:
  1080. (1) E_INVALIDARG (illegal null or index out of range)
  1081. (2) E_OUTOFMEMORY.
  1082. (3) Other errors only defined by WMI, such as WBEM_E_INVALID_SYNTAX, WBEM_E_NOT_SUPPORTED.
  1083. Notes:
  1084. (1) Since this is regular COM server interface function, we use regular COM errors
  1085. instead of WMI errors. However, we can't guarantee what WMI returns.
  1086. */
  1087. STDMETHODIMP
  1088. CIPSecQueryParser::GetKeyPropertyValue (
  1089. IN LPCWSTR pszKeyPropName,
  1090. OUT VARIANT * pvarValue
  1091. )
  1092. {
  1093. if (pvarValue == NULL)
  1094. {
  1095. return E_INVALIDARG;
  1096. }
  1097. //
  1098. // ready to say that we can't find it
  1099. //
  1100. HRESULT hr = WBEM_S_FALSE;
  1101. ::VariantInit(pvarValue);
  1102. //
  1103. // If you are asking for the querying property's value, we certainly can give you one.
  1104. //
  1105. if ((LPCWSTR)m_bstrQueryingPropName != NULL && _wcsicmp(pszKeyPropName, m_bstrQueryingPropName) == 0)
  1106. {
  1107. CComBSTR bstrVal;
  1108. if (SUCCEEDED(GetQueryingPropertyValue(0, &bstrVal)))
  1109. {
  1110. //
  1111. // hand it over to the out parameter
  1112. //
  1113. pvarValue->vt = VT_BSTR;
  1114. pvarValue->bstrVal = bstrVal.Detach();
  1115. hr = S_OK;
  1116. }
  1117. else
  1118. {
  1119. hr = WBEM_S_FALSE;
  1120. }
  1121. }
  1122. return hr;
  1123. }