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.

495 lines
12 KiB

  1. //
  2. // Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
  3. //
  4. #include "precomp.h"
  5. const WCHAR QueryConvertor::wchAND = L'&';
  6. const WCHAR QueryConvertor::wchOR = L'|';
  7. const WCHAR QueryConvertor::wchNOT = L'!';
  8. const WCHAR QueryConvertor::wchSTAR = L'*';
  9. const WCHAR QueryConvertor::wchEQUAL = L'=';
  10. const WCHAR QueryConvertor::wchLEFT_BRACKET = L'(';
  11. const WCHAR QueryConvertor::wchRIGHT_BRACKET = L')';
  12. const WCHAR QueryConvertor::wchBACK_SLASH = L'\\';
  13. LPCWSTR QueryConvertor::pszGE = L">=";
  14. LPCWSTR QueryConvertor::pszLE = L"<=";
  15. int Stack::s_iMax = 100;
  16. // This assumes that enough memory has been allocated to the resulting query
  17. BOOLEAN QueryConvertor::ConvertQueryToLDAP(SQL_LEVEL_1_RPN_EXPRESSION *pExp, LPWSTR pszLDAPQuery)
  18. {
  19. Stack t_stack;
  20. int iCurrentOperator = 0, idwNumOperandsLeft = 0;
  21. int iOutputIndex = 0;
  22. if(pExp->nNumTokens == 0)
  23. return TRUE;
  24. int iCurrentToken = pExp->nNumTokens -1;
  25. SQL_LEVEL_1_TOKEN *pNextToken = pExp->pArrayOfTokens + iCurrentToken;
  26. BOOLEAN retVal = FALSE, done = FALSE;
  27. // Write a '(' at the head of the LDAP Query
  28. pszLDAPQuery[iOutputIndex ++] = wchLEFT_BRACKET;
  29. while (!done && iCurrentToken >= 0)
  30. {
  31. switch(pNextToken->nTokenType)
  32. {
  33. case SQL_LEVEL_1_TOKEN::OP_EXPRESSION:
  34. {
  35. // Try to tranlsate expression to LDAP
  36. if(TranslateExpression(pszLDAPQuery, &iOutputIndex, pNextToken->nOperator, pNextToken->pPropertyName, &pNextToken->vConstValue))
  37. {
  38. // If we've finished all the operands for the current operator, get the next one
  39. idwNumOperandsLeft --;
  40. while(idwNumOperandsLeft == 0)
  41. {
  42. pszLDAPQuery[iOutputIndex ++] = wchRIGHT_BRACKET;
  43. if(!t_stack.Pop(&iCurrentOperator, &idwNumOperandsLeft))
  44. done = TRUE;
  45. idwNumOperandsLeft --;
  46. }
  47. iCurrentToken --;
  48. }
  49. else
  50. done = TRUE;
  51. pNextToken --;
  52. break;
  53. }
  54. case SQL_LEVEL_1_TOKEN::TOKEN_AND:
  55. {
  56. if(iCurrentOperator)
  57. {
  58. if(!t_stack.Push(iCurrentOperator, idwNumOperandsLeft))
  59. done = TRUE;
  60. iCurrentOperator = SQL_LEVEL_1_TOKEN::TOKEN_AND;
  61. idwNumOperandsLeft = 2;
  62. pszLDAPQuery[iOutputIndex ++] = wchLEFT_BRACKET;
  63. pszLDAPQuery[iOutputIndex ++] = wchAND;
  64. }
  65. else
  66. {
  67. pszLDAPQuery[iOutputIndex ++] = wchLEFT_BRACKET;
  68. pszLDAPQuery[iOutputIndex ++] = wchAND;
  69. iCurrentOperator = SQL_LEVEL_1_TOKEN::TOKEN_AND;
  70. idwNumOperandsLeft = 2;
  71. }
  72. iCurrentToken --;
  73. pNextToken --;
  74. break;
  75. }
  76. case SQL_LEVEL_1_TOKEN::TOKEN_OR:
  77. {
  78. if(iCurrentOperator)
  79. {
  80. if(!t_stack.Push(iCurrentOperator, idwNumOperandsLeft))
  81. done = TRUE;
  82. iCurrentOperator = SQL_LEVEL_1_TOKEN::TOKEN_OR;
  83. idwNumOperandsLeft = 2;
  84. pszLDAPQuery[iOutputIndex ++] = wchLEFT_BRACKET;
  85. pszLDAPQuery[iOutputIndex ++] = wchOR;
  86. }
  87. else
  88. {
  89. pszLDAPQuery[iOutputIndex ++] = wchLEFT_BRACKET;
  90. pszLDAPQuery[iOutputIndex ++] = wchOR;
  91. iCurrentOperator = SQL_LEVEL_1_TOKEN::TOKEN_OR;
  92. idwNumOperandsLeft = 2;
  93. }
  94. iCurrentToken --;
  95. pNextToken --;
  96. break;
  97. }
  98. case SQL_LEVEL_1_TOKEN::TOKEN_NOT:
  99. {
  100. if(iCurrentOperator)
  101. {
  102. if(!t_stack.Push(iCurrentOperator, idwNumOperandsLeft))
  103. done = TRUE;
  104. iCurrentOperator = SQL_LEVEL_1_TOKEN::TOKEN_NOT;
  105. idwNumOperandsLeft = 1;
  106. pszLDAPQuery[iOutputIndex ++] = wchLEFT_BRACKET;
  107. pszLDAPQuery[iOutputIndex ++] = wchNOT;
  108. }
  109. else
  110. {
  111. pszLDAPQuery[iOutputIndex ++] = wchLEFT_BRACKET;
  112. pszLDAPQuery[iOutputIndex ++] = wchNOT;
  113. iCurrentOperator = SQL_LEVEL_1_TOKEN::TOKEN_NOT;
  114. idwNumOperandsLeft = 1;
  115. }
  116. iCurrentToken --;
  117. pNextToken --;
  118. break;
  119. }
  120. default:
  121. done = TRUE;
  122. break;
  123. }
  124. }
  125. // Check if we used up all the tokens
  126. if(iCurrentToken == -1)
  127. retVal = TRUE;
  128. // Write a ')' at the end of the LDAP Query
  129. pszLDAPQuery[iOutputIndex ++] = wchRIGHT_BRACKET;
  130. pszLDAPQuery[iOutputIndex ++] = NULL;
  131. return retVal;
  132. }
  133. BOOLEAN QueryConvertor::TranslateExpression(LPWSTR pszLDAPQuery, int *piOutputIndex,
  134. int iOperator, LPCWSTR pszPropertyName, VARIANT *pValue)
  135. {
  136. // If it is a CIMOM System property, then dont attempt to map it to LDAP
  137. if(pszPropertyName[0] == L'_' &&
  138. pszPropertyName[1] == L'_' )
  139. return TRUE;
  140. // If it is ADSIPath, convert it to distinguishedName attribute
  141. if(_wcsicmp(pszPropertyName, ADSI_PATH_ATTR) == 0 )
  142. {
  143. if(pValue== NULL || pValue->vt == VT_NULL)
  144. {
  145. if(iOperator == SQL_LEVEL_1_TOKEN::OP_NOT_EQUAL)
  146. {
  147. // Put the property name as DistiguishedName
  148. wcscpy(pszLDAPQuery + *piOutputIndex, DISTINGUISHED_NAME_ATTR);
  149. *piOutputIndex += wcslen(DISTINGUISHED_NAME_ATTR);
  150. *(pszLDAPQuery + *piOutputIndex) = wchEQUAL;
  151. (*piOutputIndex) ++;
  152. *(pszLDAPQuery + *piOutputIndex) = wchSTAR;
  153. (*piOutputIndex) ++;
  154. return TRUE;
  155. }
  156. else
  157. {
  158. // The '!'
  159. *(pszLDAPQuery + *piOutputIndex) = wchNOT;
  160. (*piOutputIndex) ++;
  161. // The '('
  162. *(pszLDAPQuery + *piOutputIndex) = wchLEFT_BRACKET;
  163. (*piOutputIndex) ++;
  164. if(TranslateExpression(pszLDAPQuery, piOutputIndex, SQL_LEVEL_1_TOKEN::OP_NOT_EQUAL, pszPropertyName, NULL))
  165. {
  166. // The ')'
  167. *(pszLDAPQuery + *piOutputIndex) = wchRIGHT_BRACKET;
  168. (*piOutputIndex) ++;
  169. return TRUE;
  170. }
  171. else
  172. return FALSE;
  173. }
  174. }
  175. // TODO - WinMgmt should not allow this. It should check that the property type matches the property value
  176. // As soon as Winmgmt has fixed this bug, the next 2 lines may be deleted
  177. if(pValue->vt != VT_BSTR)
  178. return FALSE;
  179. // Get the parentADSI path and RDN from the ADSI Path
  180. IADsPathname *pADsPathName = NULL;
  181. BSTR strADSIPath = SysAllocString(pValue->bstrVal);
  182. BSTR strDN = NULL;
  183. BOOLEAN bRetVal = FALSE;
  184. HRESULT result = E_FAIL;
  185. if(SUCCEEDED(result = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_ALL, IID_IADsPathname, (LPVOID *)&pADsPathName)))
  186. {
  187. if(SUCCEEDED(result = pADsPathName->Set(strADSIPath, ADS_SETTYPE_FULL)))
  188. {
  189. // This gives the DN
  190. if(SUCCEEDED(result = pADsPathName->Retrieve(ADS_FORMAT_X500_DN, &strDN)))
  191. {
  192. // Put the property name as DistiguishedName
  193. wcscpy(pszLDAPQuery + *piOutputIndex, DISTINGUISHED_NAME_ATTR);
  194. *piOutputIndex += wcslen(DISTINGUISHED_NAME_ATTR);
  195. // Put the LDAP Operator
  196. if(iOperator == SQL_LEVEL_1_TOKEN::OP_EQUAL)
  197. {
  198. *(pszLDAPQuery + *piOutputIndex) = wchEQUAL;
  199. (*piOutputIndex) ++;
  200. }
  201. else
  202. {
  203. // The '!'
  204. *(pszLDAPQuery + *piOutputIndex) = wchNOT;
  205. (*piOutputIndex) ++;
  206. *(pszLDAPQuery + *piOutputIndex) = wchEQUAL;
  207. (*piOutputIndex) ++;
  208. }
  209. // Look for the special characters ( ) * and \ and escape them with a \
  210. LPWSTR pszEscapedValue = EscapeStringValue(strDN);
  211. wcscpy(pszLDAPQuery + *piOutputIndex, pszEscapedValue);
  212. (*piOutputIndex) += wcslen(pszEscapedValue);
  213. delete [] pszEscapedValue;
  214. SysFreeString(strDN);
  215. bRetVal = TRUE;
  216. }
  217. }
  218. pADsPathName->Release();
  219. }
  220. SysFreeString(strADSIPath);
  221. return bRetVal;
  222. }
  223. // Write a '('
  224. pszLDAPQuery[(*piOutputIndex) ++] = wchLEFT_BRACKET;
  225. switch(iOperator)
  226. {
  227. case SQL_LEVEL_1_TOKEN::OP_EQUAL:
  228. {
  229. // Special case where we use '*' LDAP operator
  230. // is NULL translates to !( x=*)
  231. if(pValue->vt == VT_NULL)
  232. {
  233. // The '!'
  234. *(pszLDAPQuery + *piOutputIndex) = wchNOT;
  235. (*piOutputIndex) ++;
  236. // The '('
  237. *(pszLDAPQuery + *piOutputIndex) = wchLEFT_BRACKET;
  238. (*piOutputIndex) ++;
  239. if(!TranslateExpression(pszLDAPQuery, piOutputIndex, SQL_LEVEL_1_TOKEN::OP_NOT_EQUAL, pszPropertyName, NULL))
  240. return FALSE;
  241. // The ')'
  242. *(pszLDAPQuery + *piOutputIndex) = wchRIGHT_BRACKET;
  243. (*piOutputIndex) ++;
  244. break;
  245. }
  246. else
  247. {
  248. // Followthru
  249. }
  250. }
  251. case SQL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN:
  252. case SQL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN:
  253. {
  254. // Get the LDAP name of the property
  255. LPWSTR pszLDAPName = CLDAPHelper::UnmangleWBEMNameToLDAP(pszPropertyName);
  256. wcscpy(pszLDAPQuery + *piOutputIndex, pszLDAPName);
  257. *piOutputIndex += wcslen(pszLDAPName);
  258. delete [] pszLDAPName;
  259. // Put the LDAP Operator
  260. if(iOperator == SQL_LEVEL_1_TOKEN::OP_EQUAL)
  261. {
  262. *(pszLDAPQuery + *piOutputIndex) = wchEQUAL;
  263. (*piOutputIndex) ++;
  264. }
  265. else if(iOperator == SQL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN)
  266. {
  267. wcscpy(pszLDAPQuery + *piOutputIndex, pszGE);
  268. *piOutputIndex += 2;
  269. }
  270. else
  271. {
  272. wcscpy(pszLDAPQuery + *piOutputIndex, pszLE);
  273. *piOutputIndex += 2;
  274. }
  275. // Put the value of the property
  276. if(!TranslateValueToLDAP(pszLDAPQuery, piOutputIndex, pValue))
  277. return FALSE;
  278. }
  279. break;
  280. case SQL_LEVEL_1_TOKEN::OP_NOT_EQUAL:
  281. {
  282. // Special case for use of '*'
  283. if(pValue == NULL || pValue->vt == VT_NULL)
  284. {
  285. // Get the LDAP name of the property
  286. LPWSTR pszLDAPName = CLDAPHelper::UnmangleWBEMNameToLDAP(pszPropertyName);
  287. wcscpy(pszLDAPQuery + *piOutputIndex, pszLDAPName);
  288. *piOutputIndex += wcslen(pszLDAPName);
  289. delete [] pszLDAPName;
  290. *(pszLDAPQuery + *piOutputIndex) = wchEQUAL;
  291. (*piOutputIndex) ++;
  292. *(pszLDAPQuery + *piOutputIndex) = wchSTAR;
  293. (*piOutputIndex) ++;
  294. }
  295. else
  296. {
  297. // The '!'
  298. *(pszLDAPQuery + *piOutputIndex) = wchNOT;
  299. (*piOutputIndex) ++;
  300. // The '('
  301. *(pszLDAPQuery + *piOutputIndex) = wchLEFT_BRACKET;
  302. (*piOutputIndex) ++;
  303. if(TranslateExpression(pszLDAPQuery, piOutputIndex, SQL_LEVEL_1_TOKEN::OP_EQUAL, pszPropertyName, pValue))
  304. {
  305. // The ')'
  306. *(pszLDAPQuery + *piOutputIndex) = wchRIGHT_BRACKET;
  307. (*piOutputIndex) ++;
  308. }
  309. else
  310. return FALSE;
  311. }
  312. }
  313. break;
  314. case SQL_LEVEL_1_TOKEN::OP_LESSTHAN:
  315. {
  316. // The '!'
  317. *(pszLDAPQuery + *piOutputIndex) = wchNOT;
  318. (*piOutputIndex) ++;
  319. // The '('
  320. *(pszLDAPQuery + *piOutputIndex) = wchLEFT_BRACKET;
  321. (*piOutputIndex) ++;
  322. if(TranslateExpression(pszLDAPQuery, piOutputIndex, SQL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN, pszPropertyName, pValue))
  323. {
  324. // The ')'
  325. *(pszLDAPQuery + *piOutputIndex) = wchRIGHT_BRACKET;
  326. (*piOutputIndex) ++;
  327. }
  328. else
  329. return FALSE;
  330. }
  331. break;
  332. case SQL_LEVEL_1_TOKEN::OP_GREATERTHAN:
  333. {
  334. // The '!'
  335. *(pszLDAPQuery + *piOutputIndex) = wchNOT;
  336. (*piOutputIndex) ++;
  337. // The '('
  338. *(pszLDAPQuery + *piOutputIndex) = wchLEFT_BRACKET;
  339. (*piOutputIndex) ++;
  340. if(TranslateExpression(pszLDAPQuery, piOutputIndex, SQL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN, pszPropertyName, pValue))
  341. {
  342. // The ')'
  343. *(pszLDAPQuery + *piOutputIndex) = wchRIGHT_BRACKET;
  344. (*piOutputIndex) ++;
  345. }
  346. else
  347. return FALSE;
  348. }
  349. break;
  350. default:
  351. return FALSE;
  352. }
  353. // Write a ')'
  354. pszLDAPQuery[(*piOutputIndex) ++] = wchRIGHT_BRACKET;
  355. return TRUE;
  356. }
  357. BOOLEAN QueryConvertor::TranslateValueToLDAP(LPWSTR pszLDAPQuery, int *piOutputIndex, VARIANT *pValue)
  358. {
  359. switch(pValue->vt)
  360. {
  361. case VT_BSTR:
  362. {
  363. // Look for the special characters ( ) * and \ and escape them with a \
  364. LPWSTR pszEscapedValue = EscapeStringValue(pValue->bstrVal);
  365. wcscpy(pszLDAPQuery + *piOutputIndex, pszEscapedValue);
  366. (*piOutputIndex) += wcslen(pszEscapedValue);
  367. delete [] pszEscapedValue;
  368. }
  369. break;
  370. case VT_I4:
  371. {
  372. WCHAR temp[18];
  373. swprintf(temp, L"%d", pValue->lVal);
  374. wcscpy(pszLDAPQuery + *piOutputIndex, temp);
  375. (*piOutputIndex) += wcslen(temp);
  376. }
  377. break;
  378. case VT_BOOL:
  379. {
  380. if(pValue->boolVal == VARIANT_TRUE)
  381. {
  382. wcscpy(pszLDAPQuery + *piOutputIndex, L"TRUE");
  383. (*piOutputIndex) += wcslen(L"TRUE");
  384. }
  385. else
  386. {
  387. wcscpy(pszLDAPQuery + *piOutputIndex, L"FALSE");
  388. (*piOutputIndex) += wcslen(L"FALSE");
  389. }
  390. }
  391. break;
  392. default:
  393. return FALSE;
  394. }
  395. return TRUE;
  396. }
  397. LPWSTR QueryConvertor::EscapeStringValue(LPCWSTR pszValue)
  398. {
  399. // Escape the special characters in a string value in a query
  400. LPWSTR pszRetValue = new WCHAR [wcslen(pszValue)*2 + 1];
  401. DWORD j=0;
  402. for(DWORD i=0; i<wcslen(pszValue); i++)
  403. {
  404. switch(pszValue[i])
  405. {
  406. case wchLEFT_BRACKET:
  407. pszRetValue[j++] = wchBACK_SLASH;
  408. pszRetValue[j++] = '2';
  409. pszRetValue[j++] = '8';
  410. break;
  411. case wchRIGHT_BRACKET:
  412. pszRetValue[j++] = wchBACK_SLASH;
  413. pszRetValue[j++] = '2';
  414. pszRetValue[j++] = '9';
  415. break;
  416. case wchSTAR:
  417. pszRetValue[j++] = wchBACK_SLASH;
  418. pszRetValue[j++] = '2';
  419. pszRetValue[j++] = 'a';
  420. break;
  421. case wchBACK_SLASH:
  422. pszRetValue[j++] = wchBACK_SLASH;
  423. pszRetValue[j++] = '5';
  424. pszRetValue[j++] = 'c';
  425. break;
  426. default:
  427. pszRetValue[j++] = pszValue[i];
  428. break;
  429. }
  430. }
  431. pszRetValue[j] = NULL;
  432. return pszRetValue;
  433. }