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.

1369 lines
31 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: expression.CPP
  6. //
  7. // Author: Charles Ma
  8. // 2000.10.27
  9. //
  10. // Description:
  11. //
  12. // Implement function related to detection expressions
  13. //
  14. //=======================================================================
  15. #include "iuengine.h"
  16. #include "SchemaMisc.h"
  17. #include "expression.h"
  18. #include <RegUtil.h>
  19. #include <FileUtil.h>
  20. #include <StringUtil.h>
  21. #include <shlwapi.h>
  22. #include "SchemaKeys.h"
  23. #include "iucommon.h"
  24. //
  25. // include IDetection interface
  26. //
  27. #ifdef _MIDL_USE_GUIDDEF_
  28. #ifndef INITGUID
  29. #define INITGUID
  30. #include <guiddef.h>
  31. #undef INITGUID
  32. #else
  33. #include <guiddef.h>
  34. #endif
  35. #define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
  36. DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
  37. #else // !_MIDL_USE_GUIDDEF_
  38. #ifndef __IID_DEFINED__
  39. #define __IID_DEFINED__
  40. typedef struct _IID
  41. {
  42. unsigned long x;
  43. unsigned short s1;
  44. unsigned short s2;
  45. unsigned char c[8];
  46. } IID;
  47. #endif // __IID_DEFINED__
  48. #ifndef CLSID_DEFINED
  49. #define CLSID_DEFINED
  50. typedef IID CLSID;
  51. #endif // CLSID_DEFINED
  52. #define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
  53. const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
  54. #endif !_MIDL_USE_GUIDDEF_
  55. MIDL_DEFINE_GUID(IID, IID_IDetection,0x8E2EF6DC,0x0AB8,0x4FE0,0x90,0x49,0x3B,0xEA,0x45,0x06,0xBF,0x8D);
  56. #ifndef __IDetection_FWD_DEFINED__
  57. #define __IDetection_FWD_DEFINED__
  58. typedef interface IDetection IDetection;
  59. #endif /* __IDetection_FWD_DEFINED__ */
  60. #ifndef __IDetection_INTERFACE_DEFINED__
  61. #define __IDetection_INTERFACE_DEFINED__
  62. /* interface IDetection */
  63. /* [unique][helpstring][dual][uuid][object] */
  64. EXTERN_C const IID IID_IDetection;
  65. #if defined(__cplusplus) && !defined(CINTERFACE)
  66. MIDL_INTERFACE("8E2EF6DC-0AB8-4FE0-9049-3BEA4506BF8D")
  67. IDetection : public IDispatch
  68. {
  69. public:
  70. virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Detect(
  71. /* [in] */ BSTR bstrXML,
  72. /* [out] */ DWORD *pdwDetectionResult) = 0;
  73. };
  74. #else /* C style interface */
  75. typedef struct IDetectionVtbl
  76. {
  77. BEGIN_INTERFACE
  78. HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
  79. IDetection * This,
  80. /* [in] */ REFIID riid,
  81. /* [iid_is][out] */ void **ppvObject);
  82. ULONG ( STDMETHODCALLTYPE *AddRef )(
  83. IDetection * This);
  84. ULONG ( STDMETHODCALLTYPE *Release )(
  85. IDetection * This);
  86. HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )(
  87. IDetection * This,
  88. /* [out] */ UINT *pctinfo);
  89. HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )(
  90. IDetection * This,
  91. /* [in] */ UINT iTInfo,
  92. /* [in] */ LCID lcid,
  93. /* [out] */ ITypeInfo **ppTInfo);
  94. HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )(
  95. IDetection * This,
  96. /* [in] */ REFIID riid,
  97. /* [size_is][in] */ LPOLESTR *rgszNames,
  98. /* [in] */ UINT cNames,
  99. /* [in] */ LCID lcid,
  100. /* [size_is][out] */ DISPID *rgDispId);
  101. /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )(
  102. IDetection * This,
  103. /* [in] */ DISPID dispIdMember,
  104. /* [in] */ REFIID riid,
  105. /* [in] */ LCID lcid,
  106. /* [in] */ WORD wFlags,
  107. /* [out][in] */ DISPPARAMS *pDispParams,
  108. /* [out] */ VARIANT *pVarResult,
  109. /* [out] */ EXCEPINFO *pExcepInfo,
  110. /* [out] */ UINT *puArgErr);
  111. /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Detect )(
  112. IDetection * This,
  113. /* [in] */ BSTR bstrXML,
  114. /* [out] */ DWORD *pdwDetectionResult);
  115. END_INTERFACE
  116. } IDetectionVtbl;
  117. interface IDetection
  118. {
  119. CONST_VTBL struct IDetectionVtbl *lpVtbl;
  120. };
  121. #ifdef COBJMACROS
  122. #define IDetection_QueryInterface(This,riid,ppvObject) \
  123. (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
  124. #define IDetection_AddRef(This) \
  125. (This)->lpVtbl -> AddRef(This)
  126. #define IDetection_Release(This) \
  127. (This)->lpVtbl -> Release(This)
  128. #define IDetection_GetTypeInfoCount(This,pctinfo) \
  129. (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo)
  130. #define IDetection_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \
  131. (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo)
  132. #define IDetection_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \
  133. (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)
  134. #define IDetection_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \
  135. (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)
  136. #define IDetection_Detect(This,bstrXML,pdwDetectionResult) \
  137. (This)->lpVtbl -> Detect(This,bstrXML,pdwDetectionResult)
  138. #endif /* COBJMACROS */
  139. #endif /* C style interface */
  140. /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IDetection_Detect_Proxy(
  141. IDetection * This,
  142. /* [in] */ BSTR bstrXML,
  143. /* [out] */ DWORD *pdwDetectionResult);
  144. void __RPC_STUB IDetection_Detect_Stub(
  145. IRpcStubBuffer *This,
  146. IRpcChannelBuffer *_pRpcChannelBuffer,
  147. PRPC_MESSAGE _pRpcMessage,
  148. DWORD *_pdwStubPhase);
  149. #endif /* __IDetection_INTERFACE_DEFINED__ */
  150. //
  151. // deckare the constants used to manipulate the result of Detect() method
  152. //
  153. //
  154. // First group, used in <expression> tag, to tell the detection result. This result
  155. // should combined with other expression(s) at the same level
  156. //
  157. const DWORD IUDET_BOOL = 0x00000001; // mask
  158. const DWORD IUDET_FALSE = 0x00000000; // expression detect FALSE
  159. const DWORD IUDET_TRUE = 0x00000001; // expression detect TRUE
  160. const DWORD IUDET_NULL = 0x00000002; // expression detect data missing
  161. //
  162. // Second group, used in <detection> tag, to tell the detection result. This result
  163. // should overwrite the rest of <expression>, if any
  164. //
  165. extern const LONG IUDET_INSTALLED = 0x00000010; /* mask for <installed> result */
  166. extern const LONG IUDET_INSTALLED_NULL = 0x00000020; /* <installed> missing */
  167. extern const LONG IUDET_UPTODATE = 0x00000040; /* mask for <upToDate> result */
  168. extern const LONG IUDET_UPTODATE_NULL = 0x00000080; /* <upToDate> missing */
  169. extern const LONG IUDET_NEWERVERSION = 0x00000100; /* mask for <newerVersion> result */
  170. extern const LONG IUDET_NEWERVERSION_NULL = 0x00000200; /* <newerVersion> missing */
  171. extern const LONG IUDET_EXCLUDED = 0x00000400; /* mask for <excluded> result */
  172. extern const LONG IUDET_EXCLUDED_NULL = 0x00000800; /* <excluded> missing */
  173. extern const LONG IUDET_FORCE = 0x00001000; /* mask for <force> result */
  174. extern const LONG IUDET_FORCE_NULL = 0x00002000; /* <force> missing */
  175. extern const LONG IUDET_COMPUTER = 0x00004000; // mask for <computerSystem> result
  176. extern const LONG IUDET_COMPUTER_NULL = 0x00008000; // <computerSystem> missing
  177. #define GotoCleanupIfNull(p) if (NULL==p) goto CleanUp
  178. #define GotoCleanupHR(hrCode) hr = hrCode; LOG_ErrorMsg(hr); goto CleanUp
  179. // ----------------------------------------------------------------------
  180. //
  181. // public helper function to convert a bstr value to
  182. // version status enum value, if possible
  183. //
  184. // ----------------------------------------------------------------------
  185. BOOL ConvertBstrVersionToEnum(BSTR bstrVerVerb, _VER_STATUS *pEnumVerVerb)
  186. {
  187. //
  188. // convert the versionStatus in bstr into enum
  189. //
  190. if (CompareBSTRsEqual(bstrVerVerb, KEY_VERSTATUS_HI))
  191. {
  192. *pEnumVerVerb = DETX_HIGHER;
  193. }
  194. else if (CompareBSTRsEqual(bstrVerVerb,KEY_VERSTATUS_HE))
  195. {
  196. *pEnumVerVerb = DETX_HIGHER_OR_EQUAL;
  197. }
  198. else if (CompareBSTRsEqual(bstrVerVerb, KEY_VERSTATUS_EQ))
  199. {
  200. *pEnumVerVerb = DETX_SAME;
  201. }
  202. else if (CompareBSTRsEqual(bstrVerVerb, KEY_VERSTATUS_LE))
  203. {
  204. *pEnumVerVerb = DETX_LOWER_OR_EQUAL;
  205. }
  206. else if (CompareBSTRsEqual(bstrVerVerb, KEY_VERSTATUS_LO))
  207. {
  208. *pEnumVerVerb = DETX_LOWER;
  209. }
  210. else
  211. {
  212. return FALSE;
  213. }
  214. return TRUE;
  215. }
  216. //----------------------------------------------------------------------
  217. //
  218. // public function DetectExpression()
  219. // retrieve the data from the express node,
  220. // and do actual detection work
  221. //
  222. // Input:
  223. // expression node
  224. // LPCTSTR lpcsDllPath, // path that this provider saved the cust detection Dll
  225. //
  226. // Return:
  227. // TRUE/FALSE, detection result
  228. //
  229. //----------------------------------------------------------------------
  230. HRESULT DetectExpression(IXMLDOMNode* pExpression, BOOL *pfResult)
  231. {
  232. HRESULT hr = E_INVALIDARG;
  233. int iRet = -1;
  234. BOOL fRet = TRUE;
  235. IXMLDOMNodeList* pChildList = NULL;
  236. IXMLDOMNode* pCandidate = NULL;
  237. BSTR bstrName = NULL;
  238. BSTR bstrKey = NULL,
  239. bstrEntry = NULL,
  240. bstrValue = NULL;
  241. LPCTSTR lpszKeyComputer = NULL;
  242. LOG_Block("DetectExpression()");
  243. USES_IU_CONVERSION;
  244. if (NULL == pExpression || NULL == pfResult)
  245. {
  246. LOG_ErrorMsg(hr);
  247. return hr;
  248. }
  249. *pfResult = TRUE;
  250. //
  251. // retrieve all child nodes
  252. //
  253. (void)pExpression->get_childNodes(&pChildList);
  254. if (NULL == pChildList)
  255. {
  256. LOG_XML(_T("Empty expression found!"));
  257. GotoCleanupHR(E_INVALIDARG);
  258. }
  259. //
  260. // get the first child
  261. //
  262. (void)pChildList->nextNode(&pCandidate);
  263. if (NULL == pCandidate)
  264. {
  265. LOG_XML(_T("empty child list for passed in expresson node!"));
  266. GotoCleanupHR(E_INVALIDARG);
  267. }
  268. //
  269. // loop through each child node, find out the type
  270. // of node, call actual detection func accordingly
  271. //
  272. lpszKeyComputer = OLE2T(KEY_COMPUTERSYSTEM);
  273. CleanUpFailedAllocSetHrMsg(lpszKeyComputer);
  274. while (NULL != pCandidate)
  275. {
  276. CleanUpIfFailedAndSetHrMsg(pCandidate->get_nodeName(&bstrName));
  277. LPTSTR lpszName = OLE2T(bstrName);
  278. CleanUpFailedAllocSetHrMsg(lpszName);
  279. if (CSTR_EQUAL == CompareString(
  280. MAKELCID(0x0409, SORT_DEFAULT),
  281. NORM_IGNORECASE,
  282. lpszName,
  283. -1,
  284. KEY_REGKEYEXISTS,
  285. -1))
  286. {
  287. //
  288. // call detection function
  289. //
  290. hr = DetectRegKeyExists(pCandidate, pfResult);
  291. }
  292. else if (CSTR_EQUAL == CompareString(
  293. MAKELCID(0x0409, SORT_DEFAULT),
  294. NORM_IGNORECASE,
  295. lpszName,
  296. -1,
  297. KEY_REGKEYVALUE,
  298. -1))
  299. {
  300. //
  301. // process RegKeyValue expression
  302. //
  303. hr = DetectRegKeyValue(pCandidate, pfResult);
  304. }
  305. else if (CSTR_EQUAL == CompareString(
  306. MAKELCID(0x0409, SORT_DEFAULT),
  307. NORM_IGNORECASE,
  308. lpszName,
  309. -1,
  310. KEY_REGKEYSUBSTR,
  311. -1))
  312. {
  313. //
  314. // process RegKeySubstring expression
  315. //
  316. hr = DetectRegKeySubstring(pCandidate, pfResult);
  317. }
  318. else if (CSTR_EQUAL == CompareString(
  319. MAKELCID(0x0409, SORT_DEFAULT),
  320. NORM_IGNORECASE,
  321. lpszName,
  322. -1,
  323. KEY_REGKEYVERSION,
  324. -1))
  325. {
  326. //
  327. // process RegVersion expression
  328. //
  329. hr = DetectRegVersion(pCandidate, pfResult);
  330. }
  331. else if (CSTR_EQUAL == CompareString(
  332. MAKELCID(0x0409, SORT_DEFAULT),
  333. NORM_IGNORECASE,
  334. lpszName,
  335. -1,
  336. KEY_FILEVERSION,
  337. -1))
  338. {
  339. //
  340. // process FileVersion expression
  341. //
  342. hr = DetectFileVersion(pCandidate, pfResult);
  343. }
  344. else if (CSTR_EQUAL == CompareString(
  345. MAKELCID(0x0409, SORT_DEFAULT),
  346. NORM_IGNORECASE,
  347. lpszName,
  348. -1,
  349. KEY_FILEEXISTS,
  350. -1))
  351. {
  352. //
  353. // process FileExists expression
  354. //
  355. hr = DetectFileExists(pCandidate, pfResult);
  356. }
  357. else if (CSTR_EQUAL == CompareString(
  358. MAKELCID(0x0409, SORT_DEFAULT),
  359. NORM_IGNORECASE,
  360. lpszName,
  361. -1,
  362. lpszKeyComputer,
  363. -1))
  364. {
  365. //
  366. // process computerSystem check
  367. //
  368. hr = DetectComputerSystem(pCandidate, pfResult);
  369. }
  370. else if (CSTR_EQUAL == CompareString(
  371. MAKELCID(0x0409, SORT_DEFAULT),
  372. NORM_IGNORECASE,
  373. lpszName,
  374. -1,
  375. KEY_AND,
  376. -1))
  377. {
  378. //
  379. // process AND expression
  380. //
  381. IXMLDOMNodeList* pSubExpList = NULL;
  382. IXMLDOMNode* pSubExp = NULL;
  383. long lLen = 0;
  384. //
  385. // get child list
  386. //
  387. pCandidate->get_childNodes(&pSubExpList);
  388. if (NULL == pSubExpList)
  389. {
  390. LOG_XML(_T("Found no children of AND expression"));
  391. GotoCleanupHR(E_INVALIDARG);
  392. }
  393. pSubExpList->get_length(&lLen);
  394. fRet = TRUE;
  395. for (long i = 0; i < lLen && fRet; i++)
  396. {
  397. //
  398. // each child should be an expression
  399. // process it. if false, then short-cut.
  400. //
  401. pSubExpList->get_item(i, &pSubExp);
  402. if (NULL == pSubExp)
  403. {
  404. pSubExpList->Release();
  405. pSubExpList = NULL;
  406. LOG_XML(_T("Failed to get the #%d sub-expression in this AND expression"), i);
  407. GotoCleanupHR(E_INVALIDARG);
  408. }
  409. hr = DetectExpression(pSubExp, &fRet);
  410. SafeReleaseNULL(pSubExp);
  411. if (FAILED(hr))
  412. {
  413. //
  414. // if found something wrong in recursion, don't continue
  415. //
  416. break;
  417. }
  418. }
  419. SafeReleaseNULL(pSubExpList);
  420. *pfResult = fRet;
  421. }
  422. else if (CSTR_EQUAL == CompareString(
  423. MAKELCID(0x0409, SORT_DEFAULT),
  424. NORM_IGNORECASE,
  425. lpszName,
  426. -1,
  427. KEY_OR,
  428. -1))
  429. {
  430. //
  431. // process OR expression
  432. //
  433. IXMLDOMNodeList* pSubExpList = NULL;
  434. IXMLDOMNode* pSubExp = NULL;
  435. long lLen = 0;
  436. //
  437. // get child list
  438. //
  439. pCandidate->get_childNodes(&pSubExpList);
  440. if (NULL == pSubExpList)
  441. {
  442. LOG_XML(_T("Found no children of OR expression"));
  443. GotoCleanupHR(E_INVALIDARG);
  444. }
  445. pSubExpList->get_length(&lLen);
  446. fRet = FALSE;
  447. for (long i = 0; i < lLen && !fRet; i++)
  448. {
  449. //
  450. // each child is one expression
  451. // do it one by one
  452. //
  453. pSubExpList->get_item(i, &pSubExp);
  454. if (NULL == pSubExp)
  455. {
  456. pSubExpList->Release();
  457. pSubExpList = NULL;
  458. LOG_XML(_T("Failed to get the #%d sub-expression in this OR expression"), i);
  459. GotoCleanupHR(E_INVALIDARG);
  460. }
  461. hr = DetectExpression(pSubExp, &fRet);
  462. SafeReleaseNULL(pSubExp);
  463. if (FAILED(hr))
  464. {
  465. //
  466. // if found something wrong in recursion, don't continue
  467. //
  468. break;
  469. }
  470. }
  471. SafeReleaseNULL(pSubExpList);
  472. *pfResult = fRet;
  473. }
  474. else if (CSTR_EQUAL == CompareString(
  475. MAKELCID(0x0409, SORT_DEFAULT),
  476. NORM_IGNORECASE,
  477. lpszName,
  478. -1,
  479. KEY_NOT,
  480. -1))
  481. {
  482. //
  483. // process NOT expression
  484. //
  485. IXMLDOMNode* pSubExp = NULL;
  486. //
  487. // get the only child
  488. //
  489. pCandidate->get_firstChild(&pSubExp);
  490. if (NULL == pSubExp)
  491. {
  492. LOG_XML(_T("Failed to get first child in NOT expression"));
  493. GotoCleanupHR(E_INVALIDARG);
  494. }
  495. //
  496. // the child must be an expression, process it
  497. //
  498. hr = DetectExpression(pSubExp, &fRet);
  499. if (SUCCEEDED(hr))
  500. {
  501. fRet = !fRet; // flip the result for NOT expression
  502. *pfResult = fRet;
  503. }
  504. else
  505. {
  506. LOG_ErrorMsg(hr);
  507. }
  508. SafeReleaseNULL(pSubExp);
  509. }
  510. if (FAILED(hr))
  511. {
  512. goto CleanUp;
  513. }
  514. if (!*pfResult)
  515. {
  516. //
  517. // if found one expression FALSE, the whole thing false, so
  518. // no need to continue
  519. //
  520. break;
  521. }
  522. SafeReleaseNULL(pCandidate);
  523. pChildList->nextNode(&pCandidate);
  524. SafeSysFreeString(bstrName);
  525. }
  526. CleanUp:
  527. SafeReleaseNULL(pCandidate);
  528. SafeReleaseNULL(pChildList);
  529. SysFreeString(bstrName);
  530. SysFreeString(bstrKey);
  531. SysFreeString(bstrEntry);
  532. SysFreeString(bstrValue);
  533. return hr;
  534. }
  535. //----------------------------------------------------------------------
  536. //
  537. // Helper function DetectRegKeyExists()
  538. // retrieve the data from the node,
  539. // and do actual detection work
  540. //
  541. // Input:
  542. // RegKeyExists node
  543. //
  544. // Return:
  545. // int - detection result: -1=none, 0=FALSE, 1=TRUE
  546. //
  547. // Assumption:
  548. // input parameter not NULL
  549. //
  550. //----------------------------------------------------------------------
  551. HRESULT
  552. DetectRegKeyExists(
  553. IXMLDOMNode* pRegKeyExistsNode,
  554. BOOL *pfResult
  555. )
  556. {
  557. LOG_Block("DetectRegKeyExists");
  558. HRESULT hr = E_INVALIDARG;
  559. BOOL fRet = FALSE;
  560. LPTSTR lpszKey = NULL, lpszEntry = NULL;
  561. BSTR bstrKey = NULL, bstrEntry = NULL;
  562. USES_IU_CONVERSION;
  563. //
  564. // find the key value
  565. //
  566. if (FindNodeValue(pRegKeyExistsNode, KEY_KEY, &bstrKey))
  567. {
  568. lpszKey = OLE2T(bstrKey);
  569. CleanUpFailedAllocSetHrMsg(lpszKey);
  570. //
  571. // find the optional entry value
  572. //
  573. if (FindNodeValue(pRegKeyExistsNode, KEY_ENTRY, &bstrEntry))
  574. {
  575. lpszEntry = OLE2T(bstrEntry);
  576. CleanUpFailedAllocSetHrMsg(lpszEntry);
  577. }
  578. *pfResult = RegKeyExists(lpszKey, lpszEntry);
  579. hr = S_OK;
  580. }
  581. CleanUp:
  582. SysFreeString(bstrKey);
  583. SysFreeString(bstrEntry);
  584. return hr;
  585. }
  586. //----------------------------------------------------------------------
  587. //
  588. // Helper function DetectRegKeyExists()
  589. // retrieve the data from the node,
  590. // and do actual detection work
  591. //
  592. // Input:
  593. // RegKeyValue node
  594. //
  595. // Return:
  596. // int - detection result: -1=none, 0=FALSE, 1=TRUE
  597. //
  598. // Assumption:
  599. // input parameter not NULL
  600. //
  601. //----------------------------------------------------------------------
  602. HRESULT
  603. DetectRegKeyValue(
  604. IXMLDOMNode* pRegKeyValueNode,
  605. BOOL *pfResult
  606. )
  607. {
  608. LOG_Block("DetectRegKeyValue");
  609. HRESULT hr = E_INVALIDARG;
  610. BOOL fRet = FALSE;
  611. LPTSTR lpszKey = NULL,
  612. lpszEntry = NULL,
  613. lpszValue = NULL;
  614. BSTR bstrKey = NULL,
  615. bstrEntry = NULL,
  616. bstrValue = NULL;
  617. USES_IU_CONVERSION;
  618. //
  619. // find the key value
  620. //
  621. if (!FindNodeValue(pRegKeyValueNode, KEY_KEY, &bstrKey))
  622. {
  623. LOG_ErrorMsg(hr);
  624. goto CleanUp;
  625. }
  626. lpszKey = OLE2T(bstrKey);
  627. CleanUpFailedAllocSetHrMsg(lpszKey);
  628. //
  629. // find the optional entry value
  630. //
  631. if (FindNodeValue(pRegKeyValueNode, KEY_ENTRY, &bstrEntry))
  632. {
  633. lpszEntry = OLE2T(bstrEntry);
  634. CleanUpFailedAllocSetHrMsg(lpszEntry);
  635. }
  636. //
  637. // find the value to compare
  638. //
  639. if (!FindNodeValue(pRegKeyValueNode, KEY_VALUE, &bstrValue))
  640. {
  641. LOG_ErrorMsg(hr);
  642. goto CleanUp;
  643. }
  644. lpszValue = OLE2T(bstrValue);
  645. CleanUpFailedAllocSetHrMsg(lpszValue);
  646. *pfResult = RegKeyValueMatch((LPCTSTR)lpszKey, (LPCTSTR)lpszEntry, (LPCTSTR)lpszValue);
  647. hr = S_OK;
  648. CleanUp:
  649. SysFreeString(bstrKey);
  650. SysFreeString(bstrEntry);
  651. SysFreeString(bstrValue);
  652. return hr;
  653. }
  654. //----------------------------------------------------------------------
  655. //
  656. // Helper function DetectRegKeySubstring()
  657. // retrieve the data from the node,
  658. // and do actual detection work
  659. //
  660. // Input:
  661. // RegKeyValue node
  662. //
  663. // Return:
  664. // int - detection result: -1=none, 0=FALSE, 1=TRUE
  665. //
  666. // Assumption:
  667. // input parameter not NULL
  668. //
  669. //----------------------------------------------------------------------
  670. HRESULT
  671. DetectRegKeySubstring(
  672. IXMLDOMNode* pRegKeySubstringNode,
  673. BOOL *pfResult
  674. )
  675. {
  676. LOG_Block("DetectRegKeySubstring");
  677. HRESULT hr = E_INVALIDARG;
  678. BOOL fRet = FALSE;
  679. LPTSTR lpszKey = NULL,
  680. lpszEntry = NULL,
  681. lpszValue = NULL;
  682. BSTR bstrKey = NULL,
  683. bstrEntry = NULL,
  684. bstrValue = NULL;
  685. USES_IU_CONVERSION;
  686. //
  687. // find the key value
  688. //
  689. if (!FindNodeValue(pRegKeySubstringNode, KEY_KEY, &bstrKey))
  690. {
  691. LOG_ErrorMsg(hr);
  692. goto CleanUp;
  693. }
  694. lpszKey = OLE2T(bstrKey);
  695. CleanUpFailedAllocSetHrMsg(lpszKey);
  696. //
  697. // find the optional entry value
  698. //
  699. if (FindNodeValue(pRegKeySubstringNode, KEY_ENTRY, &bstrEntry))
  700. {
  701. lpszEntry = OLE2T(bstrEntry);
  702. CleanUpFailedAllocSetHrMsg(lpszEntry);
  703. }
  704. //
  705. // find the value to compare
  706. //
  707. if (!FindNodeValue(pRegKeySubstringNode, KEY_VALUE, &bstrValue))
  708. {
  709. LOG_ErrorMsg(hr);
  710. goto CleanUp;
  711. }
  712. lpszValue = OLE2T(bstrValue);
  713. CleanUpFailedAllocSetHrMsg(lpszValue);
  714. *pfResult = RegKeySubstring((LPCTSTR)lpszKey, (LPCTSTR)lpszEntry, (LPCTSTR)lpszValue);
  715. hr = S_OK;
  716. CleanUp:
  717. SysFreeString(bstrKey);
  718. SysFreeString(bstrEntry);
  719. SysFreeString(bstrValue);
  720. return hr;
  721. }
  722. //----------------------------------------------------------------------
  723. //
  724. // Helper function DetectFileVersion()
  725. // retrieve the data from the node,
  726. // and do actual detection work
  727. //
  728. // Input:
  729. // RegKeyValue node
  730. //
  731. // Return:
  732. // int - detection result: -1=none, 0=FALSE, 1=TRUE
  733. //
  734. // Assumption:
  735. // input parameter not NULL
  736. //
  737. //----------------------------------------------------------------------
  738. HRESULT
  739. DetectRegVersion(
  740. IXMLDOMNode* pRegKeyVersionNode,
  741. BOOL *pfResult
  742. )
  743. {
  744. HRESULT hr = E_INVALIDARG;
  745. BOOL fRet = FALSE;
  746. LPTSTR lpszKey = NULL,
  747. lpszEntry = NULL,
  748. lpszVersion = NULL;
  749. BSTR bstrVerVerb = NULL,
  750. bstrKey = NULL,
  751. bstrEntry = NULL,
  752. bstrVersion = NULL;
  753. _VER_STATUS verStatus;
  754. LOG_Block("DetectRegVersion()");
  755. USES_IU_CONVERSION;
  756. //
  757. // find the key value
  758. //
  759. if (!FindNodeValue(pRegKeyVersionNode, KEY_KEY, &bstrKey))
  760. {
  761. LOG_ErrorMsg(hr);
  762. goto CleanUp;
  763. }
  764. lpszKey = OLE2T(bstrKey);
  765. CleanUpFailedAllocSetHrMsg(lpszKey);
  766. LOG_XML(_T("Found Key=%s"), lpszKey);
  767. //
  768. // find the optional entry value
  769. //
  770. if (FindNodeValue(pRegKeyVersionNode, KEY_ENTRY, &bstrEntry))
  771. {
  772. lpszEntry = OLE2T(bstrEntry);
  773. CleanUpFailedAllocSetHrMsg(lpszEntry);
  774. LOG_XML(_T("Found optional entry=%s"), lpszEntry);
  775. }
  776. //
  777. // find the value to compare
  778. //
  779. if (!FindNodeValue(pRegKeyVersionNode, KEY_VERSION, &bstrVersion))
  780. {
  781. goto CleanUp;
  782. }
  783. lpszVersion = OLE2T(bstrVersion);
  784. CleanUpFailedAllocSetHrMsg(lpszVersion);
  785. LOG_XML(_T("Version found from node: %s"), lpszVersion);
  786. //
  787. // get the attribute versionStatus, a version compare verb
  788. //
  789. if (S_OK != (hr = GetAttribute(pRegKeyVersionNode, KEY_VERSIONSTATUS, &bstrVerVerb)))
  790. {
  791. LOG_ErrorMsg(hr);
  792. goto CleanUp;
  793. }
  794. LOG_XML(_T("Version verb found from node: %s"), OLE2T(bstrVerVerb));
  795. //
  796. // convert the versionStatus in bstr into enum
  797. //
  798. if (!ConvertBstrVersionToEnum(bstrVerVerb, &verStatus))
  799. {
  800. SafeSysFreeString(bstrVerVerb);
  801. goto CleanUp;
  802. }
  803. *pfResult = RegKeyVersion((LPCTSTR)lpszKey, (LPCTSTR)lpszEntry, (LPCTSTR)lpszVersion, verStatus);
  804. hr = S_OK;
  805. CleanUp:
  806. SysFreeString(bstrKey);
  807. SysFreeString(bstrEntry);
  808. SysFreeString(bstrVersion);
  809. SysFreeString(bstrVerVerb);
  810. return hr;
  811. }
  812. //----------------------------------------------------------------------
  813. //
  814. // Helper function DetectFileVersion()
  815. // retrieve the data from the node,
  816. // and do actual detection work
  817. //
  818. // Input:
  819. // RegKeyValue node
  820. //
  821. // Return:
  822. // int - detection result: -1=none, 0=FALSE, 1=TRUE
  823. //
  824. // Assumption:
  825. // input parameter not NULL
  826. //
  827. //----------------------------------------------------------------------
  828. HRESULT
  829. DetectFileVersion(
  830. IXMLDOMNode* pFileVersionNode,
  831. BOOL *pfResult
  832. )
  833. {
  834. BOOL fRet = FALSE;
  835. BOOL fFileExists = FALSE;
  836. HRESULT hr = E_INVALIDARG;
  837. IXMLDOMNode* pFilePathNode = NULL;
  838. TCHAR szFilePath[MAX_PATH];
  839. int iFileVerComp;
  840. LPTSTR lpszTimeStamp = NULL,
  841. lpszVersion = NULL;
  842. BSTR bstrTime = NULL,
  843. bstrVersion = NULL,
  844. bstrVerState= NULL;
  845. FILE_VERSION fileVer;
  846. _VER_STATUS verStatus;
  847. LOG_Block("DetectFileVersion()");
  848. USES_IU_CONVERSION;
  849. if (NULL == pfResult || NULL == pFileVersionNode)
  850. {
  851. LOG_ErrorMsg(hr);
  852. return hr;
  853. }
  854. *pfResult = FALSE;
  855. //
  856. // find the version value
  857. //
  858. if (!FindNodeValue(pFileVersionNode, KEY_VERSION, &bstrVersion))
  859. {
  860. LOG_ErrorMsg(hr);
  861. return hr;
  862. }
  863. if (NULL == (lpszVersion = OLE2T(bstrVersion)))
  864. {
  865. LOG_ErrorMsg(E_OUTOFMEMORY);
  866. goto CleanUp;
  867. }
  868. LOG_XML(_T("Version=%s"), lpszVersion);
  869. if (!ConvertStringVerToFileVer(T2A(lpszVersion), &fileVer))
  870. {
  871. LOG_ErrorMsg(hr);
  872. goto CleanUp; // bad version string
  873. }
  874. //
  875. // find the file path value
  876. //
  877. //if (!FindNodeValue(pFileVersionNode, KEY_FILEPATH, &bstrFile))
  878. if (!FindNode(pFileVersionNode, KEY_FILEPATH, &pFilePathNode) ||
  879. NULL == pFilePathNode ||
  880. FAILED(hr = GetFullFilePathFromFilePathNode(pFilePathNode, szFilePath)))
  881. {
  882. LOG_ErrorMsg(hr);
  883. goto CleanUp; // no file path found!
  884. }
  885. LOG_XML(_T("File=%s"), szFilePath);
  886. //
  887. // check if file exist
  888. //
  889. fFileExists = FileExists(szFilePath);
  890. //
  891. // get the attribute versionStatus, a version compare verb
  892. //
  893. if (S_OK != GetAttribute(pFileVersionNode, KEY_VERSIONSTATUS, &bstrVerState))
  894. {
  895. goto CleanUp; // no version status found
  896. }
  897. LOG_XML(_T("VersionStatus=%s"), OLE2T(bstrVerState));
  898. if (!ConvertBstrVersionToEnum(bstrVerState, &verStatus))
  899. {
  900. //
  901. // bad version enum, shouldn't happen since the manifest has
  902. // been loaded into XMLDOM
  903. //
  904. LOG_ErrorMsg(hr);
  905. goto CleanUp;
  906. }
  907. //
  908. // get optional timestamp
  909. //
  910. if (S_OK == GetAttribute(pFileVersionNode, KEY_TIMESTAMP, &bstrTime))
  911. {
  912. TCHAR szFileTimeStamp[20];
  913. LPTSTR lpXmlTimeStamp = OLE2T(bstrTime);
  914. CleanUpFailedAllocSetHrMsg(lpXmlTimeStamp);
  915. //
  916. // find out the file creation time stamp
  917. //
  918. int iCompare;
  919. if (!fFileExists || !GetFileTimeStamp(szFilePath, szFileTimeStamp, 20))
  920. {
  921. //szFileTimeStamp[0] = '\0'; // we don't have a timestamp to compare
  922. //
  923. // for timestamp compare, it's date/time ISO format compare, i.e.,
  924. // in alphabetical order, so empty timestamp always smaller.
  925. //
  926. iCompare = -1;
  927. }
  928. else
  929. {
  930. //
  931. // compare file timestamp, if szFileTimeStamp < lpXmlTimeStamp, -1
  932. //
  933. int iCompVal = CompareString(
  934. MAKELCID(0x0409, SORT_DEFAULT),
  935. NORM_IGNORECASE,
  936. szFileTimeStamp,
  937. -1,
  938. lpXmlTimeStamp,
  939. -1);
  940. iCompare = (CSTR_EQUAL == iCompVal) ? 0 : ((CSTR_LESS_THAN == iCompVal) ? -1 : +1);
  941. }
  942. switch (verStatus)
  943. {
  944. case DETX_LOWER:
  945. fRet = (iCompare < 0);
  946. break;
  947. case DETX_LOWER_OR_EQUAL:
  948. fRet = (iCompare <= 0);
  949. break;
  950. case DETX_SAME:
  951. fRet = (iCompare == 0);
  952. break;
  953. case DETX_HIGHER_OR_EQUAL:
  954. fRet = (iCompare >= 0);
  955. break;
  956. case DETX_HIGHER:
  957. fRet = (iCompare > 0);
  958. break;
  959. }
  960. *pfResult = fRet;
  961. if (!fRet)
  962. {
  963. //
  964. // false, not need to continue
  965. //
  966. hr = S_OK;
  967. goto CleanUp;
  968. }
  969. }
  970. //
  971. // compare file version: if a < b, -1; a > b, +1
  972. //
  973. if (!fFileExists || (FAILED(CompareFileVersion((LPCTSTR)szFilePath, fileVer, &iFileVerComp))))
  974. {
  975. //
  976. // failed to compare version - file may doesn't have a version data.
  977. // in this case, we assume the file need to compare have version 0,0,0,0, and force
  978. // the comparision oontinue.
  979. //
  980. FILE_VERSION verNoneExists = {0,0,0,0};
  981. iFileVerComp = CompareFileVersion(verNoneExists, fileVer);
  982. }
  983. switch (verStatus)
  984. {
  985. case DETX_LOWER:
  986. fRet = (iFileVerComp < 0);
  987. break;
  988. case DETX_LOWER_OR_EQUAL:
  989. fRet = (iFileVerComp <= 0);
  990. break;
  991. case DETX_SAME:
  992. fRet = (iFileVerComp == 0);
  993. break;
  994. case DETX_HIGHER_OR_EQUAL:
  995. fRet = (iFileVerComp >= 0);
  996. break;
  997. case DETX_HIGHER:
  998. fRet = (iFileVerComp > 0);
  999. break;
  1000. }
  1001. *pfResult = fRet;
  1002. hr = S_OK;
  1003. CleanUp:
  1004. SysFreeString(bstrTime);
  1005. SysFreeString(bstrVersion);
  1006. SysFreeString(bstrVerState);
  1007. SafeReleaseNULL(pFilePathNode);
  1008. return hr;
  1009. }
  1010. //----------------------------------------------------------------------
  1011. //
  1012. // Helper function DetectFileExists()
  1013. // retrieve the data from the node,
  1014. // and do actual detection work
  1015. //
  1016. // Input:
  1017. // RegKeyValue node
  1018. //
  1019. // Return:
  1020. // int - detection result: -1=none, 0=FALSE, 1=TRUE
  1021. //
  1022. // Assumption:
  1023. // input parameter not NULL
  1024. //
  1025. //----------------------------------------------------------------------
  1026. HRESULT
  1027. DetectFileExists(
  1028. IXMLDOMNode* pFileExistsNode,
  1029. BOOL *pfResult
  1030. )
  1031. {
  1032. BOOL fRet = FALSE;
  1033. HRESULT hr = E_INVALIDARG;
  1034. TCHAR szFilePath[MAX_PATH];
  1035. IXMLDOMNode* pFilePathNode = NULL;
  1036. _VER_STATUS verStatus;
  1037. USES_IU_CONVERSION;
  1038. LOG_Block("DetectFileExists()");
  1039. if (NULL == pFileExistsNode || NULL == pfResult)
  1040. {
  1041. return E_INVALIDARG;
  1042. }
  1043. //
  1044. // find the version value
  1045. //
  1046. if (!FindNode(pFileExistsNode, KEY_FILEPATH, &pFilePathNode) ||
  1047. NULL == pFilePathNode ||
  1048. FAILED(hr = GetFullFilePathFromFilePathNode(pFilePathNode, szFilePath)))
  1049. {
  1050. LOG_ErrorMsg(hr);
  1051. }
  1052. else
  1053. {
  1054. *pfResult = FileExists((LPCTSTR)szFilePath);
  1055. hr = S_OK;
  1056. }
  1057. SafeReleaseNULL(pFilePathNode);
  1058. return hr;
  1059. }
  1060. //----------------------------------------------------------------------
  1061. //
  1062. // Helper function DetectComputerSystem()
  1063. // retrieve the data from the node,
  1064. // and do actual detection work
  1065. //
  1066. // Input:
  1067. // computerSystem node
  1068. //
  1069. // Return:
  1070. // detection result TRUE/FALSE
  1071. //
  1072. // Assumption:
  1073. // input parameter not NULL
  1074. //
  1075. //----------------------------------------------------------------------
  1076. HRESULT
  1077. DetectComputerSystem(
  1078. IXMLDOMNode* pComputerSystemNode,
  1079. BOOL *pfResult
  1080. )
  1081. {
  1082. HRESULT hr = E_INVALIDARG;
  1083. LOG_Block("DetectComputerSystem()");
  1084. BSTR bstrManufacturer = NULL;
  1085. BSTR bstrModel = NULL;
  1086. BSTR bstrSupportURL = NULL;
  1087. BSTR bstrXmlManufacturer = NULL;
  1088. BSTR bstrXmlModel = NULL;
  1089. if (NULL == pComputerSystemNode || NULL == pfResult)
  1090. {
  1091. LOG_ErrorMsg(hr);
  1092. return hr;
  1093. }
  1094. *pfResult = FALSE; // anything wrong, result should be FALSE and return error
  1095. //
  1096. // get manufecturer and model from XML node
  1097. //
  1098. hr = GetAttribute(pComputerSystemNode, KEY_MANUFACTURER, &bstrXmlManufacturer);
  1099. CleanUpIfFailedAndMsg(hr);
  1100. //
  1101. // optional model
  1102. //
  1103. GetAttribute(pComputerSystemNode, KEY_MODEL, &bstrXmlModel);
  1104. //
  1105. // find out real manufectuer and model of this machine
  1106. //
  1107. hr = GetOemBstrs(bstrManufacturer, bstrModel, bstrSupportURL);
  1108. CleanUpIfFailedAndMsg(hr);
  1109. //
  1110. // compare to see if manufacturer and model match.
  1111. // mafufacturer match required. If no model provided in xml
  1112. // then no check on model performed.
  1113. //
  1114. // definition of match: both empty or bstr compare equal
  1115. // definition of empty: bstr NULL or string length zero
  1116. //
  1117. *pfResult = (
  1118. (((NULL == bstrXmlManufacturer || SysStringLen(bstrXmlManufacturer) == 0) && // xml data empty and
  1119. (NULL == bstrManufacturer || SysStringLen(bstrManufacturer) == 0)) || // machine manufecturer empty, or
  1120. CompareBSTRsEqual(bstrManufacturer, bstrXmlManufacturer)) && // manufacturer same as xml data, also,
  1121. ((NULL == bstrXmlModel) || // xml data empty or
  1122. CompareBSTRsEqual(bstrModel, bstrXmlModel))); // model matches xml data
  1123. LOG_Out(_T("XML: %ls (%ls), Machine: %ls (%ls), Return: %hs"),
  1124. (LPCWSTR)bstrManufacturer,
  1125. (LPCWSTR)bstrModel,
  1126. (LPCWSTR)bstrXmlManufacturer,
  1127. (LPCWSTR)bstrXmlModel,
  1128. ((*pfResult) ? "True" : "False"));
  1129. CleanUp:
  1130. SysFreeString(bstrManufacturer);
  1131. SysFreeString(bstrModel);
  1132. SysFreeString(bstrSupportURL);
  1133. SysFreeString(bstrXmlManufacturer);
  1134. SysFreeString(bstrXmlModel);
  1135. return hr;
  1136. }