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.

2183 lines
57 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000.
  5. //
  6. // File: umisrch.cxx
  7. //
  8. // Contents: This object wraps an IDirectorySearch and returns Umi objects
  9. // as a result of the search. The Umi objects returned are
  10. // pre-populated with the attributes received from the search.
  11. // This object is used by the cursor object to support the
  12. // IUmiCursor interface.
  13. // This file also contains the CQueryStack helper class that is
  14. // used by the SearcHelper to parse SQL queries.
  15. //
  16. // History: 03-20-00 AjayR Created.
  17. //
  18. //----------------------------------------------------------------------------
  19. #include "ldap.hxx"
  20. //
  21. // Helper functions.
  22. //
  23. //+---------------------------------------------------------------------------
  24. // Function: HelperGetAttributeList - helper routine.
  25. //
  26. // Synopsis: Gets a list of attributes that can be used in an execute
  27. // search call from the wbem query information.
  28. //
  29. // Arguments: pdwAttribCount - Returns the number of attributes.
  30. // -1 means all attributes.
  31. // pppszAttribArray - Return value for string array.
  32. // ulListSize - Size of list of wbem names.
  33. // pWbemNames - The list of parsed tokens.
  34. //
  35. // Returns: S_OK or any appropriate error code.
  36. //
  37. // Modifies: pdwAttribCount to correct value and pppszAttribArray to
  38. // array of strings containing the attribute list.
  39. //
  40. //----------------------------------------------------------------------------
  41. HRESULT
  42. HelperGetAttributeList(
  43. PDWORD pdwAttribCount,
  44. LPWSTR ** pppszAttribArray,
  45. ULONG ulListSize,
  46. SWbemQueryQualifiedName **pWbemNames
  47. )
  48. {
  49. HRESULT hr = S_OK;
  50. DWORD dwCtr = 0;
  51. SWbemQueryQualifiedName *pName = NULL;
  52. LPWSTR pszTmpString = NULL;
  53. //
  54. // There should at least be a * in the list.
  55. //
  56. ADsAssert(pWbemNames);
  57. *pppszAttribArray = NULL;
  58. *pdwAttribCount = (DWORD) -1;
  59. //
  60. // If the count is just one we need to see if this is just *.
  61. //
  62. if (ulListSize == 1) {
  63. pName = pWbemNames[0];
  64. if (pName->m_ppszNameList
  65. && pName->m_ppszNameList[0]
  66. ) {
  67. if (_wcsicmp(pName->m_ppszNameList[0], L"*")) {
  68. //
  69. // We need to retun NULL and -1 for count.
  70. //
  71. RRETURN(hr);
  72. }
  73. }
  74. else {
  75. //
  76. // This has to be a bad query cause either
  77. // 1) the name list was empty - cannot have empty from clause,
  78. // 2) the name list had an empty string in it, or
  79. //
  80. BAIL_ON_FAILURE(hr = E_FAIL); // UMI_E_UNSUPPORTED_QUERY ???
  81. }
  82. }
  83. //
  84. // At this point we have a valid attribute list.
  85. //
  86. *pppszAttribArray = (LPWSTR *) AllocADsMem(sizeof(LPWSTR) * ulListSize);
  87. if (!*pppszAttribArray) {
  88. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  89. }
  90. for (dwCtr = 0; dwCtr < ulListSize; dwCtr++) {
  91. pszTmpString = NULL;
  92. pName = pWbemNames[dwCtr];
  93. if (!pName || !pName->m_ppszNameList) {
  94. BAIL_ON_FAILURE(hr = E_FAIL); // UMI_E_BAD_QUERY ???
  95. }
  96. //
  97. // ADSI does not expect more than one entry in each of the pName's.
  98. // so if some did user.Description then we just treat this as
  99. // as description by using the last value always.
  100. //
  101. pszTmpString = AllocADsStr(
  102. pName->m_ppszNameList[pName->m_uNameListSize-1]
  103. );
  104. if (!pszTmpString) {
  105. BAIL_ON_FAILURE(hr = E_FAIL);
  106. }
  107. (*pppszAttribArray)[dwCtr] = pszTmpString;
  108. }
  109. *pdwAttribCount = ulListSize;
  110. error:
  111. if (FAILED(hr)) {
  112. if (*pppszAttribArray) {
  113. for (dwCtr = 0; dwCtr < ulListSize; dwCtr++) {
  114. pszTmpString = (*pppszAttribArray)[dwCtr];
  115. if (pszTmpString) {
  116. FreeADsStr(pszTmpString);
  117. }
  118. }
  119. FreeADsMem(*pppszAttribArray);
  120. *pppszAttribArray = NULL;
  121. }
  122. }
  123. RRETURN(hr);
  124. }
  125. //+---------------------------------------------------------------------------
  126. // Function: HelperGetFromList - helper routine.
  127. //
  128. // Synopsis: Get a filter that represents the from list. For now this
  129. // will only return NULL. However we will need to spruce this fn
  130. // if we need to support a list of classes in here.
  131. //
  132. // Arguments: ppszFromFilter - Return value for a filter corresponding
  133. // to the From list.
  134. // pQuery - Wbem query object.
  135. //
  136. // Returns: S_OK or any appropriate error code.
  137. //
  138. // Modifies: *ppszFromFilter if From list is valid.
  139. //
  140. //----------------------------------------------------------------------------
  141. HRESULT
  142. HelperGetFromList(
  143. LPWSTR *ppszFromFilter,
  144. SWbemRpnEncodedQuery *pQuery
  145. )
  146. {
  147. HRESULT hr = E_FAIL;
  148. LPWSTR pszFilter = NULL;
  149. *ppszFromFilter = NULL;
  150. if (pQuery->m_uFromTargetType & WMIQ_RPN_FROM_PATH) {
  151. //
  152. // This can only be . for now.
  153. //
  154. if (!_wcsicmp(L".", pQuery->m_pszOptionalFromPath)) {
  155. //
  156. // We are ok as long as there are no other pieces.
  157. //
  158. RRETURN(S_OK);
  159. }
  160. else {
  161. RRETURN(E_FAIL); // UMI_E_NOT_SUPPORTED ???
  162. }
  163. }
  164. //
  165. // For now we are going to ignore pieces if there are any other
  166. // pieces in the from clause.
  167. //
  168. if (pQuery->m_uFromTargetType & WMIQ_RPN_FROM_UNARY) {
  169. // hr = E_FAIL; UMI_E_NOT_SUPPORTED.
  170. hr = S_OK;
  171. }
  172. else if (pQuery->m_uFromTargetType & WMIQ_RPN_FROM_CLASS_LIST) {
  173. // hr = E_FAIL; UMI_E_NOT_SUPPORTED.
  174. //for (unsigned u = 0; u < pQuery->m_uFromListSize; u++)
  175. //{
  176. // printf(" Selected class = %S\n", pQuery->m_ppszFromList[u]);
  177. //}
  178. hr = S_OK;
  179. }
  180. else {
  181. //
  182. // The query does not have anything in the from clause.
  183. // This is an invalid query.
  184. //
  185. hr = E_FAIL; // UMI_E_NOT_SUPPORTED ???
  186. }
  187. RRETURN(hr);
  188. }
  189. //+---------------------------------------------------------------------------
  190. // Function: HelperGetSubExpressionFromOperands - helper routine.
  191. //
  192. // Synopsis: Updates the result with the operands and the operator. This
  193. // routine munges the operators/operands around so that we can
  194. // support operands not supported by ldap directly.
  195. //
  196. // Arguments: pszResult - Return value, allocated by caller.
  197. // pszOperand1 - The attribute being tested.
  198. // pszOperand2 - The value being tested against.
  199. // ulOperator - Inidcates the comparision type.
  200. //
  201. // Returns: S_OK or any appropriate error code.
  202. //
  203. // Modifies: pStack contents.
  204. //
  205. //----------------------------------------------------------------------------
  206. HRESULT
  207. HelperGetSubExpressionFromOperands(
  208. LPWSTR pszResult,
  209. LPWSTR pszOperand1,
  210. LPWSTR pszOperand2,
  211. ULONG ulOperator
  212. )
  213. {
  214. HRESULT hr = S_OK;
  215. //
  216. // In all cases we will need to begin with "(".
  217. //
  218. wsprintf(pszResult, L"(");
  219. //
  220. // All these are easy to handle.
  221. //
  222. if ((ulOperator == WMIQ_RPN_OP_EQ)
  223. || (ulOperator == WMIQ_RPN_OP_LT)
  224. || (ulOperator == WMIQ_RPN_OP_GT)
  225. ) {
  226. wcscat(pszResult, pszOperand1);
  227. }
  228. switch (ulOperator) {
  229. case WMIQ_RPN_OP_EQ :
  230. wcscat(pszResult, L"=");
  231. wcscat(pszResult, pszOperand2);
  232. wcscat(pszResult, L")");
  233. break;
  234. case WMIQ_RPN_OP_LT :
  235. wcscat(pszResult, L"<");
  236. wcscat(pszResult, pszOperand2);
  237. wcscat(pszResult, L")");
  238. break;
  239. case WMIQ_RPN_OP_GT :
  240. wcscat(pszResult, L">");
  241. wcscat(pszResult, pszOperand2);
  242. wcscat(pszResult, L")");
  243. break;
  244. //
  245. // All these need some processing as ldap does not
  246. // handle these directly.
  247. //
  248. case WMIQ_RPN_OP_NE :
  249. //
  250. // This needs to be (!(operand1=operand2)) so a != b becomes
  251. // (!(a=b))
  252. //
  253. wcscat(pszResult, L"!");
  254. wcscat(pszResult, L"(");
  255. wcscat(pszResult, pszOperand1);
  256. wcscat(pszResult, L"=");
  257. wcscat(pszResult, pszOperand2);
  258. wcscat(pszResult, L"))");
  259. break;
  260. case WMIQ_RPN_OP_GE :
  261. //
  262. // a >= b becomes (!(a<b))
  263. //
  264. wcscat(pszResult, L"!(");
  265. wcscat(pszResult, pszOperand1);
  266. wcscat(pszResult, L"<");
  267. wcscat(pszResult, pszOperand2);
  268. wcscat(pszResult, L"))");
  269. break;
  270. case WMIQ_RPN_OP_LE :
  271. //
  272. // a <= b becomes (!(a>b))
  273. //
  274. wcscat(pszResult, L"!(");
  275. wcscat(pszResult, pszOperand1);
  276. wcscat(pszResult, L">");
  277. wcscat(pszResult, pszOperand2);
  278. wcscat(pszResult, L"))");
  279. break;
  280. default:
  281. hr = E_FAIL; // UMI_E_UNSUPPORTED_QUERY.
  282. break;
  283. }
  284. RRETURN(hr);
  285. }
  286. //+---------------------------------------------------------------------------
  287. // Function: HelperProcessOperator - helper routine.
  288. //
  289. // Synopsis: Pops 2 elements from the stack, applies the operator on them
  290. // and pushes the effective expression on to the stack.
  291. //
  292. // Arguments: pStack - Valid stack which should have at least 2
  293. // elements in the stack.
  294. // ulOperatorType- Operator type corresponding to wbem enum.
  295. //
  296. // Returns: S_OK or any appropriate error code.
  297. //
  298. // Modifies: pStack contents.
  299. //
  300. //----------------------------------------------------------------------------
  301. HRESULT
  302. HelperProcessSubExpression(
  303. CQueryStack *pStack,
  304. SWbemRpnQueryToken *pExpression
  305. )
  306. {
  307. HRESULT hr = S_OK;
  308. LPWSTR pszOperand1 = NULL;
  309. LPWSTR pszOperand2 = NULL;
  310. LPWSTR pszResult = NULL;
  311. ULONG ulShape = pExpression->m_uSubexpressionShape;
  312. DWORD dwTotalLen = 0;
  313. ADsAssert(pStack);
  314. //
  315. // As per what is supported we should not have a function.
  316. // However the query parses seems to always report functions so we
  317. // will ignore.
  318. //
  319. if (ulShape & WMIQ_RPN_LEFT_PROPERTY_NAME) {
  320. SWbemQueryQualifiedName *pName = pExpression->m_pLeftIdent;
  321. //
  322. // The identifier could be x.y.z in which case ADSI is only
  323. // interested in z
  324. //
  325. if (pName->m_ppszNameList[pName->m_uNameListSize-1]) {
  326. //
  327. // Alloc the name itself if the operand1 is not __CLASS.
  328. // If it is __CLASS we need to substitute with objectClass.
  329. //
  330. if (!_wcsicmp(
  331. pName->m_ppszNameList[pName->m_uNameListSize-1],
  332. L"__CLASS"
  333. )
  334. ) {
  335. pszOperand1 = AllocADsStr(L"objectClass");
  336. }
  337. else {
  338. //
  339. // Alloc whatever was passed in.
  340. //
  341. pszOperand1 = AllocADsStr(
  342. pName->m_ppszNameList[pName->m_uNameListSize-1]
  343. );
  344. }
  345. if (!pszOperand1) {
  346. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  347. }
  348. }
  349. else {
  350. //
  351. // Something really wrong.
  352. //
  353. BAIL_ON_FAILURE(hr = E_FAIL);
  354. }
  355. }
  356. else {
  357. //
  358. // We cannot handle this as there is no identifier on LHS.
  359. //
  360. BAIL_ON_FAILURE(hr = E_FAIL);
  361. }
  362. //
  363. // We should have the operand by now, need the value
  364. //
  365. switch (pExpression->m_uConstApparentType) {
  366. case VT_I4:
  367. case VT_UI4:
  368. //
  369. // We cannot possibly have more than 20 chars.
  370. //
  371. pszOperand2 = (LPWSTR) AllocADsMem(20 * sizeof(WCHAR));
  372. if (!pszOperand2) {
  373. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  374. }
  375. if (pExpression->m_uConstApparentType == VT_I4) {
  376. _ltot(pExpression->m_Const.m_lLongVal, pszOperand2, 10 );
  377. }
  378. else {
  379. _ltot(pExpression->m_Const.m_uLongVal, pszOperand2, 10);
  380. }
  381. break;
  382. case VT_BOOL:
  383. //
  384. // Again 20 sounds good !
  385. //
  386. pszOperand2 = (LPWSTR) AllocADsMem(20 * sizeof(WCHAR));
  387. if (!pszOperand2) {
  388. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  389. }
  390. if (pExpression->m_Const.m_bBoolVal )
  391. wcscpy(pszOperand2, L"TRUE");
  392. else
  393. wcscpy(pszOperand2, L"FALSE");
  394. break;
  395. case VT_LPWSTR:
  396. pszOperand2 = AllocADsStr(pExpression->m_Const.m_pszStrVal);
  397. if (!pszOperand2) {
  398. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  399. }
  400. break;
  401. default:
  402. BAIL_ON_FAILURE(hr = E_FAIL); // UMI_E_UNSUPPORTED.
  403. break;
  404. }
  405. //
  406. // At this point we can combine the 2 operands and operator.
  407. // Total size is size of strings + () + 2 for operator + 1 for \0.
  408. // Total additions = 5. This is for most cases.
  409. //
  410. dwTotalLen = wcslen(pszOperand1) + wcslen(pszOperand2) + 5;
  411. //
  412. // Operators <= >= and != need to be processed to be usable in ldap.
  413. // In these cases, we assume that twice the length is needed.
  414. //
  415. dwTotalLen *= 2;
  416. pszResult = (LPWSTR) AllocADsMem(dwTotalLen * sizeof(WCHAR));
  417. if (!pszResult) {
  418. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  419. }
  420. hr = HelperGetSubExpressionFromOperands(
  421. pszResult,
  422. pszOperand1,
  423. pszOperand2,
  424. pExpression->m_uOperator
  425. );
  426. /*
  427. wsprintf(pszResult, L"(");
  428. wcscat(pszResult, pszOperand1);
  429. //
  430. // Need to add the opearator now.
  431. //
  432. switch (pExpression->m_uOperator) {
  433. case WMIQ_RPN_OP_EQ :
  434. wcscat(pszResult,L"=");
  435. break;
  436. case WMIQ_RPN_OP_NE :
  437. wcscat(pszResult, L"!=");
  438. break;
  439. case WMIQ_RPN_OP_GE :
  440. wcscat(pszResult, L">=");
  441. break;
  442. case WMIQ_RPN_OP_LE :
  443. wcscat(pszResult, L"<=");
  444. break;
  445. case WMIQ_RPN_OP_LT :
  446. wcscat(pszResult, L"<");
  447. break;
  448. case WMIQ_RPN_OP_GT :
  449. wcscat(pszResult, L">");
  450. break;
  451. case WMIQ_RPN_OP_UNDEFINED:
  452. case WMIQ_RPN_OP_LIKE :
  453. case WMIQ_RPN_OP_ISA :
  454. case WMIQ_RPN_OP_ISNOTA :
  455. default :
  456. //
  457. // All these mean we have a bad query.
  458. //
  459. BAIL_ON_FAILURE(hr = E_FAIL);
  460. break;
  461. }
  462. //
  463. // Now tag on operand2 and the closing ), and push result onto stack.
  464. //
  465. wcscat(pszResult, pszOperand2);
  466. wcscat(pszResult, L")");
  467. */
  468. hr = pStack->Push(pszResult, QUERY_STACK_ITEM_LITERAL);
  469. BAIL_ON_FAILURE(hr);
  470. error:
  471. if (pszOperand1) {
  472. FreeADsStr(pszOperand1);
  473. }
  474. if (pszOperand2) {
  475. FreeADsStr(pszOperand2);
  476. }
  477. if (pszResult) {
  478. FreeADsStr(pszResult);
  479. }
  480. RRETURN(hr);
  481. }
  482. //+---------------------------------------------------------------------------
  483. // Function: HelperProcessOperator - helper routine.
  484. //
  485. // Synopsis: Pops 2 elements from the stack, applies the operator on them
  486. // and pushes the effective expression on to the stack.
  487. //
  488. // Arguments: pStack - Valid stack which should have at least 2
  489. // elements in the stack.
  490. // ulOperatorType- Operator type corresponding to wbem enum.
  491. //
  492. // Returns: S_OK or any appropriate error code.
  493. //
  494. // Modifies: pStack contents.
  495. //
  496. //----------------------------------------------------------------------------
  497. HRESULT
  498. HelperProcessOperator(
  499. CQueryStack *pStack,
  500. ULONG ulOperatorType
  501. )
  502. {
  503. HRESULT hr;
  504. LPWSTR pszStr1 = NULL;
  505. LPWSTR pszStr2 = NULL;
  506. LPWSTR pszResult = NULL;
  507. DWORD dwNodeType;
  508. DWORD dwTotalLen = 0;
  509. ADsAssert(pStack);
  510. hr = pStack->Pop(
  511. &pszStr1,
  512. &dwNodeType
  513. );
  514. BAIL_ON_FAILURE(hr);
  515. //
  516. // String has to be valid and the node cannot be an operator.
  517. //
  518. if (!pszStr1 || !*pszStr1
  519. || (dwNodeType != QUERY_STACK_ITEM_LITERAL)
  520. ) {
  521. BAIL_ON_FAILURE(hr = E_FAIL); // UMI_E_UNSUPPORTED_QUERY
  522. }
  523. dwTotalLen += wcslen(pszStr1);
  524. //
  525. // Not has only one operand.
  526. //
  527. if (ulOperatorType != WMIQ_RPN_TOKEN_NOT) {
  528. hr = pStack->Pop(
  529. &pszStr2,
  530. &dwNodeType
  531. );
  532. BAIL_ON_FAILURE(hr);
  533. //
  534. // Sanity check.
  535. //
  536. if (!pszStr2 || !*pszStr2
  537. || (dwNodeType != QUERY_STACK_ITEM_LITERAL)
  538. ) {
  539. BAIL_ON_FAILURE(hr = E_FAIL); // UMI_E_UNSUPPORTED_QUERY
  540. }
  541. //
  542. // Need to add string2's length.
  543. //
  544. dwTotalLen += wcslen(pszStr2);
  545. }
  546. //
  547. // The resultant node needs to hold both strings and the operator
  548. // and the additional set of parentheses.
  549. // 4 = operator + () and one for \0.
  550. //
  551. dwTotalLen += 4;
  552. pszResult = (LPWSTR) AllocADsMem(dwTotalLen * sizeof(WCHAR));
  553. if (!pszResult) {
  554. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  555. }
  556. wsprintf(pszResult, L"(");
  557. switch (ulOperatorType) {
  558. case WMIQ_RPN_TOKEN_AND :
  559. wcscat(pszResult, L"&");
  560. break;
  561. case WMIQ_RPN_TOKEN_OR :
  562. wcscat(pszResult, L"|");
  563. break;
  564. case WMIQ_RPN_TOKEN_NOT :
  565. wcscat(pszResult, L"!");
  566. break;
  567. default:
  568. BAIL_ON_FAILURE(hr = E_FAIL); // UMI_E_UNSUPPORTED.
  569. }
  570. //
  571. // At this point we need to tag on both the pre composed pieces
  572. // and the final closing parentheses.
  573. //
  574. wcscat(pszResult, pszStr1);
  575. //
  576. // Do not Tag on the second string only if operator is NOT.
  577. //
  578. if (ulOperatorType != WMIQ_RPN_TOKEN_NOT) {
  579. wcscat(pszResult, pszStr2);
  580. }
  581. wcscat(pszResult, L")");
  582. //
  583. // Need to push the result on to the stack as a literal.
  584. //
  585. hr = pStack->Push(
  586. pszResult,
  587. QUERY_STACK_ITEM_LITERAL
  588. );
  589. BAIL_ON_FAILURE(hr);
  590. error:
  591. if (pszStr1) {
  592. FreeADsStr(pszStr1);
  593. }
  594. if (pszStr2) {
  595. FreeADsStr(pszStr2);
  596. }
  597. if (pszResult) {
  598. FreeADsStr(pszResult);
  599. }
  600. RRETURN(hr);
  601. }
  602. //+---------------------------------------------------------------------------
  603. // Function: HelperGetFilterFromWhereClause - helper routine.
  604. //
  605. // Synopsis: Returns a filter corresponding to the elements specified in
  606. // the where clause.
  607. //
  608. // Arguments: ppszFilter - Return value for a filter corresponding
  609. // to the Where clause.
  610. // ulCount - Number of elements in the where clause.
  611. // pWhere - Pointer to the Wbem where clause.
  612. //
  613. // Returns: S_OK or any appropriate error code.
  614. //
  615. // Modifies: *ppszFilter if Where clause is valid.
  616. //
  617. //----------------------------------------------------------------------------
  618. HRESULT
  619. HelperGetFilterFromWhereClause(
  620. LPWSTR *ppszFilter,
  621. ULONG ulCount,
  622. SWbemRpnQueryToken **pWhere
  623. )
  624. {
  625. HRESULT hr = S_OK;
  626. DWORD dwCtr;
  627. CQueryStack *pStack = NULL;
  628. LPWSTR pszFilter = NULL;
  629. DWORD dwType;
  630. *ppszFilter = NULL;
  631. if (!ulCount) {
  632. //
  633. // In this case we will default to NULL.
  634. //
  635. RRETURN(hr);
  636. }
  637. pStack = new CQueryStack();
  638. if (!pStack) {
  639. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  640. }
  641. //
  642. // Process the tokens in the where clause.
  643. //
  644. for (dwCtr = 0; dwCtr < ulCount; dwCtr++) {
  645. SWbemRpnQueryToken *pToken = pWhere[dwCtr];
  646. switch (pToken->m_uTokenType) {
  647. //
  648. // All these are operations.
  649. //
  650. case WMIQ_RPN_TOKEN_AND :
  651. case WMIQ_RPN_TOKEN_OR :
  652. case WMIQ_RPN_TOKEN_NOT :
  653. HelperProcessOperator(pStack, pToken->m_uTokenType);
  654. break;
  655. case WMIQ_RPN_TOKEN_EXPRESSION :
  656. HelperProcessSubExpression(pStack, pToken);
  657. break;
  658. default:
  659. //
  660. // We cannot handle the query.
  661. //
  662. hr = E_FAIL; // UMI_E_UNSUPPORTED_QUERY.
  663. break;
  664. }
  665. BAIL_ON_FAILURE(hr);
  666. }
  667. //
  668. // At this stack should have one element and that should be
  669. // the filter we use if things went right.
  670. //
  671. hr = pStack->Pop(
  672. &pszFilter,
  673. &dwType
  674. );
  675. BAIL_ON_FAILURE(hr);
  676. if (!pStack->IsEmpty()) {
  677. BAIL_ON_FAILURE(hr = E_FAIL); // UMI_E_UNSUPPORTED_QUERY
  678. }
  679. *ppszFilter = pszFilter;
  680. error:
  681. if (pStack) {
  682. delete pStack;
  683. }
  684. if (FAILED(hr) && pszFilter) {
  685. FreeADsStr(pszFilter);
  686. }
  687. RRETURN(hr);
  688. }
  689. HRESULT
  690. HelperGetSortKey(
  691. SWbemRpnEncodedQuery *pRpn,
  692. PADS_SORTKEY * ppADsSortKey
  693. )
  694. {
  695. HRESULT hr = S_OK;
  696. PADS_SORTKEY pSortKey = NULL;
  697. if (!pRpn->m_uOrderByListSize) {
  698. RRETURN(S_OK);
  699. }
  700. //
  701. // Allocate the sort key.
  702. //
  703. pSortKey = (PADS_SORTKEY) AllocADsMem(sizeof(ADS_SORTKEY));
  704. if (!pSortKey) {
  705. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  706. }
  707. pSortKey->pszAttrType = AllocADsStr(pRpn->m_ppszOrderByList[0]);
  708. if (!pSortKey->pszAttrType) {
  709. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  710. }
  711. if (pRpn->m_uOrderDirectionEl[0]) {
  712. pSortKey->fReverseorder = TRUE;
  713. }
  714. RRETURN(S_OK);
  715. error:
  716. if (pSortKey) {
  717. if (pSortKey->pszAttrType) {
  718. FreeADsStr(pSortKey->pszAttrType);
  719. }
  720. FreeADsMem(pSortKey);
  721. }
  722. RRETURN(hr);
  723. }
  724. //+---------------------------------------------------------------------------
  725. // Function: CUmiSearchHelper::CUmiSearchHelper --- Constructor.
  726. //
  727. // Synopsis: Standard constructor.
  728. //
  729. // Arguments: N/A.
  730. //
  731. // Returns: N/A.
  732. //
  733. // Modifies: N/A.
  734. //
  735. //----------------------------------------------------------------------------
  736. CUmiSearchHelper::CUmiSearchHelper():
  737. _hSearchHandle(NULL),
  738. _pConnection(NULL),
  739. _pContainer(NULL),
  740. _pszADsPath(NULL),
  741. _pszLdapServer(NULL),
  742. _pszLdapDn(NULL),
  743. _pIID(NULL),
  744. _fSearchExecuted(FALSE),
  745. _fResetAllowed(TRUE)
  746. {
  747. //
  748. // This is global scope helper routine that will not fail.
  749. // The boolean is the value for cache results.
  750. //
  751. LdapInitializeSearchPreferences(&_searchPrefs, FALSE);
  752. }
  753. //+---------------------------------------------------------------------------
  754. // Function: CUmiSearchHelper::~CUmiSearchHelper --- Destructor.
  755. //
  756. // Synopsis: Standard destructor.
  757. //
  758. // Arguments: N/A.
  759. //
  760. // Returns: N/A.
  761. //
  762. // Modifies: N/A.
  763. //
  764. //----------------------------------------------------------------------------
  765. CUmiSearchHelper::~CUmiSearchHelper()
  766. {
  767. if (_hSearchHandle) {
  768. ADsCloseSearchHandle(_hSearchHandle);
  769. }
  770. if (_pConnection) {
  771. _pConnection->Release();
  772. }
  773. if (_pContainer) {
  774. _pContainer->Release();
  775. }
  776. if (_pQuery) {
  777. _pQuery->Release();
  778. }
  779. if (_pszADsPath) {
  780. FreeADsStr(_pszADsPath);
  781. }
  782. if (_pszLdapServer) {
  783. FreeADsStr(_pszLdapServer);
  784. }
  785. if (_pszLdapDn) {
  786. FreeADsStr(_pszLdapDn);
  787. }
  788. if (_pCreds) {
  789. delete _pCreds;
  790. }
  791. }
  792. //+---------------------------------------------------------------------------
  793. // Function: CUmiSearchHelper::CreateSearchHelper --- STATIC constructor.
  794. //
  795. // Synopsis: Static constructor.
  796. //
  797. // Arguments: pUmiQuery - Pointer to query object that.
  798. // pConnection - Connection to execute query on.
  799. // pUnk - Container on which the query is executed.
  800. // pSrchObj - New object is returned in this param.
  801. //
  802. // Returns: N/A.
  803. //
  804. // Modifies: N/A.
  805. //
  806. //----------------------------------------------------------------------------
  807. HRESULT
  808. CUmiSearchHelper::CreateSearchHelper(
  809. IUmiQuery *pUmiQuery,
  810. IUmiConnection *pConnection,
  811. IUnknown *pUnk,
  812. LPCWSTR pszADsPath,
  813. LPCWSTR pszLdapServer,
  814. LPCWSTR pszLdapDn,
  815. CCredentials cCredentials,
  816. DWORD dwPort,
  817. CUmiSearchHelper FAR* FAR * ppSrchObj
  818. )
  819. {
  820. HRESULT hr = S_OK;
  821. CUmiSearchHelper FAR * pSearchHelper = NULL;
  822. //
  823. // Asserts are good enough as this is an internal routine.
  824. //
  825. ADsAssert(ppSrchObj);
  826. ADsAssert(pUmiQuery && pConnection && pUnk);
  827. pSearchHelper = new CUmiSearchHelper();
  828. if (!pSearchHelper) {
  829. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  830. }
  831. pSearchHelper->_pszADsPath = AllocADsStr(pszADsPath);
  832. if (!pSearchHelper->_pszADsPath) {
  833. BAIL_ON_FAILURE(hr);
  834. }
  835. //
  836. // pszLdapDn can be null
  837. //
  838. if (pszLdapDn) {
  839. pSearchHelper->_pszLdapDn = AllocADsStr(pszLdapDn);
  840. if (!pSearchHelper->_pszLdapDn) {
  841. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  842. }
  843. }
  844. //
  845. // the server can also be null.
  846. //
  847. if (pszLdapServer) {
  848. pSearchHelper->_pszLdapServer = AllocADsStr(pszLdapServer);
  849. if (!pSearchHelper->_pszLdapServer) {
  850. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  851. }
  852. }
  853. pSearchHelper->_pCreds = new CCredentials(cCredentials);
  854. if (!pSearchHelper->_pCreds) {
  855. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  856. }
  857. pSearchHelper->_pConnection = pConnection;
  858. pConnection->AddRef();
  859. pSearchHelper->_pQuery = pUmiQuery;
  860. pUmiQuery->AddRef();
  861. pSearchHelper->_pContainer = pUnk;
  862. pUnk->AddRef();
  863. pSearchHelper->_dwPort = dwPort;
  864. *ppSrchObj = (CUmiSearchHelper FAR *)pSearchHelper;
  865. RRETURN(hr);
  866. error :
  867. delete pSearchHelper;
  868. RRETURN(hr);
  869. }
  870. //+---------------------------------------------------------------------------
  871. // Function: CUmiSearchHelper::SetIID
  872. //
  873. // Synopsis: Sets the IID requested on the returned objects.
  874. //
  875. // Arguments: riid - The iid requested.
  876. //
  877. // Returns: S_OK or any appropriate error code.
  878. //
  879. // Modifies: _pIID the internal IID pointer.
  880. //
  881. //----------------------------------------------------------------------------
  882. HRESULT
  883. CUmiSearchHelper::SetIID(REFIID riid)
  884. {
  885. if (_pIID) {
  886. FreeADsMem(_pIID);
  887. }
  888. _pIID = (IID *) AllocADsMem(sizeof(IID));
  889. if (!_pIID) {
  890. RRETURN(E_OUTOFMEMORY);
  891. }
  892. memcpy(_pIID, &riid, sizeof(IID));
  893. RRETURN(S_OK);
  894. }
  895. //+---------------------------------------------------------------------------
  896. // Function: CUmiSearchHelper::Reset
  897. //
  898. // Synopsis: Not implemented.
  899. //
  900. // Arguments: None.
  901. //
  902. // Returns: E_NOTIMPL.
  903. //
  904. // Modifies: N/A.
  905. //
  906. //----------------------------------------------------------------------------
  907. HRESULT
  908. CUmiSearchHelper::Reset()
  909. {
  910. //
  911. // We can potentially add support for this down the road.
  912. //
  913. RRETURN(E_NOTIMPL);
  914. }
  915. //+---------------------------------------------------------------------------
  916. // Function: CUmiSearchHelper::Next
  917. //
  918. // Synopsis: Return the next uNumRequested elements from the search.
  919. //
  920. // Arguments: uNumRequested - number of objects/rows to fetch.
  921. // pNumReturned - number of objects/rows returned.
  922. // pObject - array of returned objects.
  923. //
  924. // Returns: S_OK, S_FALSE or any appropriate error code.
  925. //
  926. // Modifies: pNumReturned, pObjects and internal search handle state.
  927. //
  928. //----------------------------------------------------------------------------
  929. HRESULT
  930. CUmiSearchHelper::Next(
  931. ULONG uNumRequested,
  932. ULONG *puNumReturned,
  933. LPVOID *ppObjects
  934. )
  935. {
  936. HRESULT hr = S_OK;
  937. IUnknown **pTempUnks = NULL;
  938. DWORD dwCtr = 0, dwIndex = 0;
  939. if (!puNumReturned || !ppObjects || (uNumRequested < 1)) {
  940. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  941. }
  942. if (!_fSearchExecuted) {
  943. hr = InitializeSearchContext();
  944. BAIL_ON_FAILURE(hr);
  945. }
  946. pTempUnks = (IUnknown **) AllocADsMem(sizeof(IUnknown*) * uNumRequested);
  947. if (!pTempUnks) {
  948. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  949. }
  950. //
  951. // Get the requested number of objects one at a time until
  952. // we hit S_FALSE or an error and then repackage to suitable
  953. // array as needed.
  954. //
  955. while ((dwCtr < uNumRequested)
  956. && (hr != S_FALSE) ) {
  957. IUnknown *pUnk = NULL;
  958. hr = GetNextObject(&pUnk);
  959. //
  960. // This wont catch S_FALSE.
  961. //
  962. BAIL_ON_FAILURE(hr);
  963. //
  964. // Needed as if he get S_FALSE we will set the ptr and
  965. // increase the count incorrectly.
  966. //
  967. if (hr != S_FALSE) {
  968. pTempUnks[dwCtr] = pUnk;
  969. dwCtr++;
  970. }
  971. }
  972. //
  973. // At this point we have all the results we need or can get.
  974. //
  975. if (uNumRequested == dwCtr) {
  976. //
  977. // We can return tempObjects in this case.
  978. //
  979. *ppObjects = (void *)pTempUnks;
  980. }
  981. else {
  982. //
  983. // Less than what had been requested.
  984. //
  985. IUnknown **pUnkCopy;
  986. pUnkCopy = (IUnknown **) AllocADsMem(sizeof(IUnknown *) * dwCtr);
  987. if (!pUnkCopy) {
  988. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  989. }
  990. for (dwIndex = 0; dwIndex < dwCtr; dwIndex++) {
  991. //
  992. // Just need to copy the ptrs over.
  993. //
  994. pUnkCopy[dwIndex] = pTempUnks[dwIndex];
  995. }
  996. //
  997. // Only return the number of entries we got back.
  998. //
  999. *ppObjects = (void *) pUnkCopy;
  1000. FreeADsMem((void *)pTempUnks);
  1001. }
  1002. //
  1003. // We are error free over here.
  1004. //
  1005. *puNumReturned = dwCtr;
  1006. RRETURN(hr);
  1007. error:
  1008. if (pTempUnks) {
  1009. //
  1010. // For will be executed only if we have valid count.
  1011. //
  1012. for (dwIndex = 0; dwIndex < dwCtr; dwIndex++) {
  1013. pTempUnks[dwIndex]->Release();
  1014. }
  1015. FreeADsMem(pTempUnks);
  1016. }
  1017. *puNumReturned = 0;
  1018. RRETURN(hr);
  1019. }
  1020. //+---------------------------------------------------------------------------
  1021. // Function: CUmiSearchHelper::Previous (E_NOTIMPL)
  1022. //
  1023. // Synopsis: Return the previous object in the result set - Not implemented.
  1024. //
  1025. // Arguments: uFlags - only flag supported is 0.
  1026. // pObj - object is returned in this param.
  1027. //
  1028. // Returns: S_OK, or any appropriate error code.
  1029. //
  1030. // Modifies: Internal search handle state and pObject.
  1031. //
  1032. //----------------------------------------------------------------------------
  1033. HRESULT
  1034. CUmiSearchHelper::Previous(
  1035. ULONG uFlags,
  1036. LPVOID *pObj
  1037. )
  1038. {
  1039. RRETURN(E_NOTIMPL);
  1040. }
  1041. //
  1042. // Internal/protected routines
  1043. //
  1044. //+---------------------------------------------------------------------------
  1045. // Function: CUmiSearchHelper::InitializeSearchContext.
  1046. //
  1047. // Synopsis: Prepares the internal state of the object. This initializes
  1048. // the search preferences from the query object, leaveing the search
  1049. // helper ready to retrieve results.
  1050. //
  1051. // Arguments: None.
  1052. //
  1053. // Returns: S_OK, or any appropriate error code.
  1054. //
  1055. // Modifies: Internal search preferences and also state search handle.
  1056. //
  1057. //----------------------------------------------------------------------------
  1058. HRESULT
  1059. CUmiSearchHelper::InitializeSearchContext()
  1060. {
  1061. HRESULT hr = S_OK;
  1062. PUMI_PROPERTY_VALUES pPropVals = NULL;
  1063. IUmiPropList *pPropList = NULL;
  1064. LPWSTR pszFilter = NULL;
  1065. LPWSTR *pszAttrNames = NULL;
  1066. DWORD dwAttrCount = (DWORD) -1;
  1067. ULONG ulLangBufSize = 100 * sizeof(WCHAR);
  1068. ULONG ulQueryBufSize = 1024 * sizeof(WCHAR);
  1069. LPWSTR pszLangBuf = NULL;
  1070. LPWSTR pszQueryText = NULL;
  1071. PADS_SORTKEY pSortKey = NULL;
  1072. //
  1073. // We need to walk through the properties in the query and update
  1074. // our local copy of preferences accordingly.
  1075. //
  1076. if (!_pQuery) {
  1077. BAIL_ON_FAILURE(hr = E_FAIL);
  1078. }
  1079. hr = _pQuery->GetInterfacePropList(0, &pPropList);
  1080. BAIL_ON_FAILURE(hr);
  1081. //
  1082. // Need to allocate memory for the buffers.
  1083. //
  1084. pszLangBuf = (LPWSTR) AllocADsMem(ulLangBufSize);
  1085. pszQueryText = (LPWSTR) AllocADsMem(ulQueryBufSize);
  1086. if (!pszLangBuf || !pszQueryText) {
  1087. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1088. }
  1089. //
  1090. // We need to look at the query language if the language is SQL,
  1091. // then we need to go through and convert the SQL settings to
  1092. // properties on the intfPropList of the query.
  1093. //
  1094. hr = _pQuery->GetQuery(
  1095. &ulLangBufSize,
  1096. pszLangBuf,
  1097. &ulQueryBufSize, // Change this before checking in.
  1098. pszQueryText
  1099. );
  1100. if (hr == E_OUTOFMEMORY ) {
  1101. //
  1102. // Means there was insufficient length in the buffers.
  1103. //
  1104. if (ulLangBufSize > (100 * sizeof(WCHAR))) {
  1105. FreeADsStr(pszLangBuf);
  1106. pszLangBuf = (LPWSTR) AllocADsMem(ulLangBufSize + sizeof(WCHAR));
  1107. if (!pszLangBuf) {
  1108. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1109. }
  1110. }
  1111. if (ulQueryBufSize > (1024 * sizeof(WCHAR))) {
  1112. FreeADsStr(pszQueryText);
  1113. pszQueryText = (LPWSTR) AllocADsMem(
  1114. ulQueryBufSize + sizeof(WCHAR)
  1115. );
  1116. if (pszQueryText) {
  1117. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1118. }
  1119. }
  1120. hr = _pQuery->GetQuery(
  1121. &ulLangBufSize,
  1122. pszLangBuf,
  1123. &ulQueryBufSize, // Change this before checking in.
  1124. pszQueryText
  1125. );
  1126. }
  1127. BAIL_ON_FAILURE(hr);
  1128. if (*pszLangBuf) {
  1129. if (!_wcsicmp(L"SQL", pszLangBuf)
  1130. || !_wcsicmp(L"WQL", pszLangBuf)
  1131. ) {
  1132. //
  1133. // This is a sql query and we need to process the query before
  1134. // pulling the options out of the query object.
  1135. //
  1136. hr = ProcessSQLQuery(
  1137. pszQueryText,
  1138. &pszFilter,
  1139. &pSortKey
  1140. );
  1141. BAIL_ON_FAILURE(hr);
  1142. }
  1143. else if (!_wcsicmp(L"LDAP", pszLangBuf)) {
  1144. //
  1145. // Neither SQL nor LDAP but the language is set which means
  1146. // we cannot handle this query.
  1147. //
  1148. pszFilter = AllocADsStr(pszQueryText);
  1149. if (!pszFilter) {
  1150. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1151. }
  1152. }
  1153. }
  1154. //
  1155. // At this point we need to go through and pick up all the properties.
  1156. // we know about and update our search preferences accordingly. Each of
  1157. // these properties has to be set and has to have some valid data.
  1158. //
  1159. //
  1160. // Start with the search scope.
  1161. //
  1162. hr = pPropList->Get(L"__SEARCH_SCOPE", 0, &pPropVals);
  1163. BAIL_ON_FAILURE(hr);
  1164. BAIL_ON_FAILURE(hr = VerifyValidLongProperty(pPropVals));
  1165. _searchPrefs._dwSearchScope =
  1166. pPropVals->pPropArray[0].pUmiValue->uValue[0];
  1167. pPropList->FreeMemory(0, (void *) pPropVals);
  1168. pPropVals = NULL;
  1169. //
  1170. // Get the synchronous/asynchronous pref.
  1171. //
  1172. hr = pPropList->Get(L"__PADS_SEARCHPREF_ASYNCHRONOUS", 0, &pPropVals);
  1173. BAIL_ON_FAILURE(hr);
  1174. BAIL_ON_FAILURE(hr = VerifyValidBoolProperty(pPropVals));
  1175. _searchPrefs._fAsynchronous =
  1176. pPropVals->pPropArray[0].pUmiValue->bValue[0];
  1177. pPropList->FreeMemory(0, (void *) pPropVals);
  1178. pPropVals = NULL;
  1179. //
  1180. // Get the deref aliases search pref.
  1181. //
  1182. hr = pPropList->Get(L"__PADS_SEARCHPREF_DEREF_ALIASES", 0, &pPropVals);
  1183. BAIL_ON_FAILURE(hr);
  1184. BAIL_ON_FAILURE(hr = VerifyValidBoolProperty(pPropVals));
  1185. _searchPrefs._dwDerefAliases =
  1186. pPropVals->pPropArray[0].pUmiValue->bValue[0];
  1187. pPropList->FreeMemory(0, (void *) pPropVals);
  1188. pPropVals = NULL;
  1189. //
  1190. // Get the size limit.
  1191. //
  1192. hr = pPropList->Get(L"__PADS_SEARCHPREF_SIZE_LIMIT", 0, &pPropVals);
  1193. BAIL_ON_FAILURE(hr);
  1194. BAIL_ON_FAILURE(hr = VerifyValidLongProperty(pPropVals));
  1195. _searchPrefs._dwSizeLimit = pPropVals->pPropArray[0].pUmiValue->uValue[0];
  1196. pPropList->FreeMemory(0, (void *) pPropVals);
  1197. pPropVals = NULL;
  1198. //
  1199. // Get the time limit.
  1200. //
  1201. hr = pPropList->Get(L"__PADS_SEARCHPREF_TIME_LIMIT", 0, &pPropVals);
  1202. BAIL_ON_FAILURE(hr);
  1203. BAIL_ON_FAILURE(hr = VerifyValidLongProperty(pPropVals));
  1204. _searchPrefs._dwTimeLimit = pPropVals->pPropArray[0].pUmiValue->uValue[0];
  1205. pPropList->FreeMemory(0, (void *) pPropVals);
  1206. pPropVals = NULL;
  1207. //
  1208. // Get the attributes only preference.
  1209. //
  1210. hr = pPropList->Get(L"__PADS_SEARCHPREF_ATTRIBTYPES_ONLY", 0, &pPropVals);
  1211. BAIL_ON_FAILURE(hr);
  1212. BAIL_ON_FAILURE(hr = VerifyValidBoolProperty(pPropVals));
  1213. _searchPrefs._fAttrsOnly = pPropVals->pPropArray[0].pUmiValue->bValue[0];
  1214. pPropList->FreeMemory(0, (void *) pPropVals);
  1215. pPropVals = NULL;
  1216. //
  1217. // Get the search scope again ???
  1218. //
  1219. // __PADS_SEARCHPREF_SEARCH_SCOPE (duplicate for consistency cause it should be for all ideally).
  1220. //
  1221. hr = pPropList->Get(L"__PADS_SEARCHPREF_TIMEOUT", 0, &pPropVals);
  1222. BAIL_ON_FAILURE(hr);
  1223. BAIL_ON_FAILURE(hr = VerifyValidLongProperty(pPropVals));
  1224. _searchPrefs._dwTimeLimit = pPropVals->pPropArray[0].pUmiValue->uValue[0];
  1225. pPropList->FreeMemory(0, (void *) pPropVals);
  1226. pPropVals = NULL;
  1227. //
  1228. // The page size is next.
  1229. //
  1230. hr = pPropList->Get(L"__PADS_SEARCHPREF_PAGESIZE", 0, &pPropVals);
  1231. BAIL_ON_FAILURE(hr);
  1232. BAIL_ON_FAILURE(hr = VerifyValidLongProperty(pPropVals));
  1233. _searchPrefs._dwPageSize = pPropVals->pPropArray[0].pUmiValue->uValue[0];
  1234. pPropList->FreeMemory(0, (void *) pPropVals);
  1235. pPropVals = NULL;
  1236. //
  1237. // Get the paged time limit.
  1238. //
  1239. hr = pPropList->Get(L"__PADS_SEARCHPREF_PAGED_TIME_LIMIT", 0, &pPropVals);
  1240. BAIL_ON_FAILURE(hr);
  1241. BAIL_ON_FAILURE(hr = VerifyValidLongProperty(pPropVals));
  1242. _searchPrefs._dwPagedTimeLimit =
  1243. pPropVals->pPropArray[0].pUmiValue->uValue[0];
  1244. pPropList->FreeMemory(0, (void *) pPropVals);
  1245. pPropVals = NULL;
  1246. //
  1247. // Chase referrals comes next.
  1248. //
  1249. hr = pPropList->Get(L"__PADS_SEARCHPREF_CHASE_REFERRALS", 0, &pPropVals);
  1250. BAIL_ON_FAILURE(hr);
  1251. BAIL_ON_FAILURE(hr = VerifyValidLongProperty(pPropVals));
  1252. _searchPrefs._dwChaseReferrals =
  1253. pPropVals->pPropArray[0].pUmiValue->uValue[0];
  1254. pPropList->FreeMemory(0, (void *) pPropVals);
  1255. pPropVals = NULL;
  1256. //
  1257. // Get the sort preferences ---> more complex do later.
  1258. //
  1259. // __PADS_SEARCHPREF_SORT_ON ---> potential candidate for all providers.
  1260. //
  1261. //
  1262. // Cache results.
  1263. //
  1264. pPropList->Get(L"__PADS_SEARCHPREF_CACHE_RESULTS", 0, &pPropVals);
  1265. BAIL_ON_FAILURE(hr);
  1266. BAIL_ON_FAILURE(hr = VerifyValidBoolProperty(pPropVals));
  1267. _searchPrefs._fCacheResults =
  1268. pPropVals->pPropArray[0].pUmiValue->bValue[0];
  1269. pPropList->FreeMemory(0, (void *) pPropVals);
  1270. pPropVals = NULL;
  1271. //
  1272. // DirSync control --- do later.
  1273. // __PADS_SEARCHPREF_DIRSYNC
  1274. //
  1275. //
  1276. // Tombstone preferences.
  1277. //
  1278. hr = pPropList->Get(L"__PADS_SEARCHPREF_TOMBSTONE", 0, &pPropVals);
  1279. BAIL_ON_FAILURE(hr);
  1280. BAIL_ON_FAILURE(hr = VerifyValidBoolProperty(pPropVals));
  1281. _searchPrefs._fTombStone = pPropVals->pPropArray[0].pUmiValue->bValue[0];
  1282. pPropList->FreeMemory(0, (void *) pPropVals);
  1283. pPropVals = NULL;
  1284. //
  1285. // Need to get the list of attributes.
  1286. //
  1287. //
  1288. hr = pPropList->Get(L"__PADS_SEARCHPREF_ATTRIBUTES", 0, &pPropVals);
  1289. BAIL_ON_FAILURE(hr);
  1290. //
  1291. // Need to change to check for NULL then set count to -1.
  1292. //
  1293. pszAttrNames = pPropVals->pPropArray[0].pUmiValue->pszStrValue;
  1294. dwAttrCount = pPropVals->pPropArray[0].uCount;
  1295. //
  1296. // Special case to ask for NULL with 0 to get all attributes.
  1297. //
  1298. if (!dwAttrCount && !pszAttrNames) {
  1299. dwAttrCount = (DWORD) -1;
  1300. }
  1301. //
  1302. // Now that we have all the preferences, we can set the search prefs
  1303. // and also execute the search.
  1304. //
  1305. hr = ADsExecuteSearch(
  1306. _searchPrefs,
  1307. _pszADsPath,
  1308. _pszLdapServer,
  1309. _pszLdapDn,
  1310. pszFilter,
  1311. pszAttrNames,
  1312. dwAttrCount,
  1313. & _hSearchHandle
  1314. );
  1315. BAIL_ON_FAILURE(hr);
  1316. _fSearchExecuted = TRUE;
  1317. error:
  1318. if (pPropVals) {
  1319. //
  1320. // Guess we need to use the query to free this !
  1321. //
  1322. _pQuery->FreeMemory(0, (void *)pPropVals);
  1323. }
  1324. if (pPropList) {
  1325. pPropList->Release();
  1326. }
  1327. if (pszLangBuf) {
  1328. FreeADsStr(pszLangBuf);
  1329. }
  1330. if (pszQueryText) {
  1331. FreeADsStr(pszQueryText);
  1332. }
  1333. if (pSortKey) {
  1334. if (pSortKey->pszAttrType) {
  1335. FreeADsStr(pSortKey->pszAttrType);
  1336. }
  1337. if (pSortKey->pszReserved) {
  1338. FreeADsStr(pSortKey->pszReserved);
  1339. }
  1340. FreeADsMem(pSortKey);
  1341. }
  1342. if (FAILED(hr)) {
  1343. //
  1344. // Should we really be doing this ?
  1345. //
  1346. LdapInitializeSearchPreferences(&_searchPrefs, FALSE);
  1347. }
  1348. RRETURN(hr);
  1349. }
  1350. //+---------------------------------------------------------------------------
  1351. // Function: CUmiSearchHelper::GetNextObject.
  1352. //
  1353. // Synopsis: This routine gets the next object in the result set. It calls
  1354. // get next row to get the next row and creates the equivalent
  1355. // cgenobj (need to add code to prepopulate the attributes).
  1356. //
  1357. // Arguments: None.
  1358. //
  1359. // Returns: S_OK, or any appropriate error code.
  1360. //
  1361. // Modifies: Internal search preferences and also state search handle.
  1362. //
  1363. //----------------------------------------------------------------------------
  1364. HRESULT
  1365. CUmiSearchHelper::GetNextObject(IUnknown **pUnk)
  1366. {
  1367. HRESULT hr = S_OK;
  1368. ADS_SEARCH_COLUMN adsColumn;
  1369. BSTR ADsPath = NULL;
  1370. LPWSTR pszParent = NULL;
  1371. LPWSTR pszCN = NULL;
  1372. PADSLDP ldapHandle = NULL;
  1373. LDAPMessage *pldapMsg = NULL;
  1374. //
  1375. // Zero init the struct to make sure we can free in error path.
  1376. //
  1377. memset(&adsColumn, 0, sizeof(ADS_SEARCH_COLUMN));
  1378. ADsAssert(_fSearchExecuted);
  1379. if (!_hSearchHandle) {
  1380. BAIL_ON_FAILURE(hr = E_FAIL);
  1381. }
  1382. //
  1383. // Get the next row.
  1384. //
  1385. hr = ADsGetNextRow(
  1386. _hSearchHandle,
  1387. *_pCreds
  1388. );
  1389. if (hr == S_ADS_NOMORE_ROWS) {
  1390. //
  1391. // Hit end of enumeration.
  1392. //
  1393. *pUnk = NULL;
  1394. RRETURN(S_FALSE);
  1395. }
  1396. else if (FAILED(hr)) {
  1397. BAIL_ON_FAILURE(hr);
  1398. }
  1399. //
  1400. // Fetch the path and use it to create the object.
  1401. //
  1402. hr = ADsGetColumn(
  1403. _hSearchHandle,
  1404. L"ADsPath",
  1405. *_pCreds,
  1406. _dwPort,
  1407. &adsColumn
  1408. );
  1409. BAIL_ON_FAILURE(hr);
  1410. if (adsColumn.dwADsType != ADSTYPE_CASE_IGNORE_STRING
  1411. || adsColumn.dwNumValues != 1) {
  1412. //
  1413. // Bad type or number of return values, this should never happen.
  1414. //
  1415. BAIL_ON_FAILURE(hr = E_FAIL);
  1416. }
  1417. //
  1418. // Get the whole ldap message for the current row, that way we can
  1419. // prepopulate the object. Since we are picking up the actual message,
  1420. // we cannot rely on GetNextColumnName to work properly.
  1421. //
  1422. hr = ADsHelperGetCurrentRowMessage(
  1423. _hSearchHandle,
  1424. &ldapHandle, // need this when getting the actual attributes.
  1425. &pldapMsg
  1426. );
  1427. BAIL_ON_FAILURE(hr);
  1428. //
  1429. //
  1430. // For creating the object, the parent path and the rdn is needed.
  1431. //
  1432. hr = BuildADsParentPath(
  1433. adsColumn.pADsValues[0].CaseIgnoreString,
  1434. &pszParent,
  1435. &pszCN
  1436. );
  1437. BAIL_ON_FAILURE(hr);
  1438. //
  1439. // Maybe we should just get all the values for this row and
  1440. // send into a constructor for the cgenobj ???
  1441. //
  1442. hr = CLDAPGenObject::CreateGenericObject(
  1443. pszParent,
  1444. pszCN,
  1445. *_pCreds,
  1446. ADS_OBJECT_BOUND,
  1447. ldapHandle,
  1448. pldapMsg,
  1449. _pIID ? (*_pIID) : IID_IUmiObject,
  1450. (void **) pUnk
  1451. );
  1452. BAIL_ON_FAILURE(hr);
  1453. error:
  1454. if (pszParent) {
  1455. FreeADsStr(pszParent);
  1456. }
  1457. if (pszCN) {
  1458. FreeADsStr(pszCN);
  1459. }
  1460. //
  1461. // Calling this can not harm us.
  1462. //
  1463. ADsFreeColumn(&adsColumn);
  1464. if (FAILED(hr) && *pUnk) {
  1465. (*pUnk)->Release();
  1466. }
  1467. RRETURN(hr);
  1468. }
  1469. //+---------------------------------------------------------------------------
  1470. // Function: CUmiSearchHelper::ProcessSQLQuery (helper function).
  1471. //
  1472. // Synopsis: This routine takes the SQL Query text, parses it using the
  1473. // wmi query parser and converts the query to preferences on
  1474. // the underlying queryObjects interface proplist.
  1475. //
  1476. // Arguments: pszQueryText - SQL language query.
  1477. //
  1478. // Returns: S_OK, or any appropriate error code.
  1479. //
  1480. // Modifies: Search preferences on the underlying query object.
  1481. //
  1482. //----------------------------------------------------------------------------
  1483. HRESULT
  1484. CUmiSearchHelper::ProcessSQLQuery(
  1485. LPCWSTR pszQueryText,
  1486. LPWSTR * ppszFilter,
  1487. PADS_SORTKEY *ppADsSortKey
  1488. )
  1489. {
  1490. HRESULT hr = S_OK;
  1491. IWbemQuery *pQuery = NULL;
  1492. ULONG ulFeatures[] = {
  1493. WMIQ_LF1_BASIC_SELECT,
  1494. WMIQ_LF2_CLASS_NAME_IN_QUERY,
  1495. WMIQ_LF6_ORDER_BY,
  1496. WMIQ_LF24_UMI_EXTENSIONS
  1497. };
  1498. SWbemRpnEncodedQuery *pRpn = NULL;
  1499. LPWSTR *pszAttribArray = NULL;
  1500. DWORD dwAttribCount = 0;
  1501. LPWSTR pszFromListFilter = NULL;
  1502. LPWSTR pszFilter = NULL;
  1503. IUmiPropList *pIntfPropList = NULL;
  1504. UMI_PROPERTY umiPropAttribs = {
  1505. UMI_TYPE_LPWSTR,
  1506. 1,
  1507. UMI_OPERATION_UPDATE,
  1508. L"__PADS_SEARCHPREF_ATTRIBUTES",
  1509. NULL
  1510. };
  1511. //
  1512. // Will likely need to set the attribute list.
  1513. //
  1514. UMI_PROPERTY pOneUmiProp[1];
  1515. pOneUmiProp[0] = umiPropAttribs;
  1516. UMI_PROPERTY_VALUES propUmiVals[1];
  1517. propUmiVals[0].uCount = 1;
  1518. propUmiVals[0].pPropArray = pOneUmiProp;
  1519. ADsAssert(ppszFilter);
  1520. *ppszFilter = NULL;
  1521. //
  1522. // Create the WBEM parser object.
  1523. //
  1524. hr = CoCreateInstance(
  1525. CLSID_WbemQuery,
  1526. NULL,
  1527. CLSCTX_INPROC_SERVER,
  1528. IID_IWbemQuery,
  1529. (LPVOID *) &pQuery
  1530. );
  1531. BAIL_ON_FAILURE(hr);
  1532. //
  1533. // Set the query into the parser and try and parse the query.
  1534. //
  1535. hr = pQuery->SetLanguageFeatures(
  1536. 0,
  1537. sizeof(ulFeatures)/sizeof(ULONG),
  1538. ulFeatures
  1539. );
  1540. BAIL_ON_FAILURE(hr);
  1541. hr = pQuery->Parse(L"SQL", pszQueryText, 0);
  1542. BAIL_ON_FAILURE(hr);
  1543. hr = pQuery->GetAnalysis(
  1544. WMIQ_ANALYSIS_RPN_SEQUENCE,
  1545. 0,
  1546. (LPVOID *) &pRpn
  1547. );
  1548. BAIL_ON_FAILURE(hr);
  1549. if (!pRpn->m_uSelectListSize) {
  1550. //
  1551. // Sanity check to make sure we are selecting something.
  1552. //
  1553. BAIL_ON_FAILURE(hr = E_FAIL);
  1554. }
  1555. hr = HelperGetAttributeList(
  1556. &dwAttribCount,
  1557. &pszAttribArray,
  1558. pRpn->m_uSelectListSize,
  1559. pRpn->m_ppSelectList
  1560. );
  1561. BAIL_ON_FAILURE(hr);
  1562. //
  1563. // As of now the from list cannot have anything in other than *.
  1564. //
  1565. hr = HelperGetFromList(
  1566. &pszFromListFilter,
  1567. pRpn
  1568. );
  1569. BAIL_ON_FAILURE(hr);
  1570. hr = HelperGetFilterFromWhereClause(
  1571. &pszFilter,
  1572. pRpn->m_uWhereClauseSize,
  1573. pRpn->m_ppRpnWhereClause
  1574. );
  1575. BAIL_ON_FAILURE(hr);
  1576. //
  1577. // See if we have an order by list, in SQL we support only one
  1578. // order by clause.
  1579. //
  1580. if (pRpn->m_uOrderByListSize) {
  1581. hr = HelperGetSortKey(pRpn, ppADsSortKey);
  1582. BAIL_ON_FAILURE(hr);
  1583. }
  1584. //
  1585. // Need to set the attribute list if applicable.
  1586. //
  1587. if ((dwAttribCount != (DWORD) -1)
  1588. && dwAttribCount) {
  1589. //
  1590. // Need to set the property on the interface proplist.
  1591. //
  1592. hr = _pQuery->GetInterfacePropList(
  1593. 0,
  1594. &pIntfPropList
  1595. );
  1596. BAIL_ON_FAILURE(hr);
  1597. pOneUmiProp[0].uCount = dwAttribCount;
  1598. pOneUmiProp[0].pUmiValue = (PUMI_VALUE) (LPVOID) pszAttribArray;
  1599. hr = pIntfPropList->Put(
  1600. L"__PADS_SEARCHPREF_ATTRIBUTES",
  1601. 0,
  1602. propUmiVals
  1603. );
  1604. BAIL_ON_FAILURE(hr);
  1605. }
  1606. //
  1607. // Need to return the filter back.
  1608. //
  1609. *ppszFilter = pszFilter;
  1610. error:
  1611. if (pQuery) {
  1612. pQuery->Release();
  1613. }
  1614. if (pszFromListFilter) {
  1615. FreeADsStr(pszFromListFilter);
  1616. }
  1617. if (pIntfPropList) {
  1618. pIntfPropList->Release();
  1619. }
  1620. //
  1621. // We might need to return this as a param.
  1622. //
  1623. if (FAILED(hr) && pszFilter) {
  1624. FreeADsStr(pszFilter);
  1625. }
  1626. RRETURN(hr);
  1627. }
  1628. //****************************************************************************
  1629. // CQueryStack Implementation *
  1630. //****************************************************************************
  1631. //+---------------------------------------------------------------------------
  1632. // Function: CQueryStack::CQueryStack - Constructor.
  1633. //
  1634. // Synopsis: Initializes the underlying list to NULL and count to 0.
  1635. //
  1636. // Arguments: None.
  1637. //
  1638. // Returns: N/A.
  1639. //
  1640. // Modifies: All member variables.
  1641. //
  1642. //----------------------------------------------------------------------------
  1643. CQueryStack::CQueryStack():
  1644. _pStackList(NULL),
  1645. _dwElementCount(0)
  1646. {
  1647. }
  1648. //+---------------------------------------------------------------------------
  1649. // Function: CQueryStack::~CQueryStack - Destructor.
  1650. //
  1651. // Synopsis: Frees the underlying list contents if applicable.
  1652. //
  1653. // Arguments: None.
  1654. //
  1655. // Returns: N/A.
  1656. //
  1657. // Modifies: N/A.
  1658. //
  1659. //----------------------------------------------------------------------------
  1660. CQueryStack::~CQueryStack()
  1661. {
  1662. if (_pStackList) {
  1663. STACKLIST *pList = _pStackList;
  1664. STACKLIST *pPrev = NULL;
  1665. //
  1666. // Walk through and free the list.
  1667. //
  1668. while (pList) {
  1669. pPrev = pList;
  1670. pList = pList->pNext;
  1671. //
  1672. // Need to free prev node and its contents.
  1673. //
  1674. CQueryStack::FreeStackEntry(pPrev);
  1675. }
  1676. _pStackList = NULL;
  1677. }
  1678. }
  1679. //+---------------------------------------------------------------------------
  1680. // Function: CQueryStack::Push.
  1681. //
  1682. // Synopsis: Pushes the node onto the stack and increases the count. The
  1683. // node is added to the head of the underlying list.
  1684. //
  1685. // Arguments: pszString - The string value of the node.
  1686. // dwType - The type of the node can either be
  1687. // a literal or an operator.
  1688. //
  1689. // Returns: S_OK or E_OUTOFMEMORY.
  1690. //
  1691. // Modifies: The underlying list.
  1692. //
  1693. //----------------------------------------------------------------------------
  1694. HRESULT
  1695. CQueryStack::Push(
  1696. LPWSTR pszString,
  1697. DWORD dwType
  1698. )
  1699. {
  1700. HRESULT hr = S_OK;
  1701. PSTACKLIST pStackEntry = NULL;
  1702. //
  1703. // Allocate the new node.
  1704. //
  1705. hr = CQueryStack::AllocateStackEntry(
  1706. pszString,
  1707. dwType,
  1708. &pStackEntry
  1709. );
  1710. if (FAILED(hr)) {
  1711. BAIL_ON_FAILURE(hr);
  1712. }
  1713. //
  1714. // If the list is not already then it is added to the head.
  1715. //
  1716. if (!this->_pStackList) {
  1717. _pStackList = pStackEntry;
  1718. }
  1719. else {
  1720. //
  1721. // Add new entry to the head of the list.
  1722. //
  1723. pStackEntry->pNext = _pStackList;
  1724. _pStackList = pStackEntry;
  1725. }
  1726. //
  1727. // Increment count as the add to list was successful.
  1728. //
  1729. _dwElementCount++;
  1730. error:
  1731. RRETURN(hr);
  1732. }
  1733. //+---------------------------------------------------------------------------
  1734. // Function: CQueryStack::Pop.
  1735. //
  1736. // Synopsis: Removes node node from the stack and returns the contents.
  1737. // Node is removed from the head of the underlying list.
  1738. //
  1739. // Arguments: ppszString - Return ptr for string value of node.
  1740. // dwType - Return ptr for the type of the node.
  1741. //
  1742. // Returns: S_OK, E_OUTOFMEMORY or E_FAIL.
  1743. //
  1744. // Modifies: The underlying list.
  1745. //
  1746. //----------------------------------------------------------------------------
  1747. HRESULT
  1748. CQueryStack::Pop(
  1749. LPWSTR *ppszString,
  1750. DWORD *pdwType
  1751. )
  1752. {
  1753. HRESULT hr = S_OK;
  1754. PSTACKLIST pStackEntry = _pStackList;
  1755. if (!pStackEntry
  1756. || !ppszString
  1757. || !pdwType ) {
  1758. BAIL_ON_FAILURE(hr = E_FAIL);
  1759. }
  1760. //
  1761. // Initialize the return values.
  1762. //
  1763. *ppszString = NULL;
  1764. *pdwType = (DWORD) -1;
  1765. if (pStackEntry->pszElement) {
  1766. *ppszString = AllocADsStr(pStackEntry->pszElement);
  1767. if (!*ppszString) {
  1768. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1769. }
  1770. *pdwType = pStackEntry->dwElementType;
  1771. }
  1772. else {
  1773. //
  1774. // Should never get here.
  1775. //
  1776. BAIL_ON_FAILURE(hr = E_FAIL);
  1777. }
  1778. //
  1779. // Need to advance the list to the next node and free the
  1780. // contents of the current node.
  1781. //
  1782. _pStackList = _pStackList->pNext;
  1783. CQueryStack::FreeStackEntry(pStackEntry);
  1784. //
  1785. // Decrement count as the remove from list was successful.
  1786. //
  1787. _dwElementCount--;
  1788. error:
  1789. RRETURN(hr);
  1790. }
  1791. //+---------------------------------------------------------------------------
  1792. // Function: CQueryStack::IsEmpty.
  1793. //
  1794. // Synopsis: Returns TRUE or FALSE based on the contents of the stack.
  1795. //
  1796. // Arguments: N/A.
  1797. //
  1798. // Returns: TRUE or FALSE.
  1799. //
  1800. // Modifies: N/A
  1801. //
  1802. //----------------------------------------------------------------------------
  1803. BOOL
  1804. CQueryStack::IsEmpty()
  1805. {
  1806. return (_dwElementCount == 0);
  1807. }
  1808. //+---------------------------------------------------------------------------
  1809. // Function: CQueryStack::AllocateStackEntry - static helper routine.
  1810. //
  1811. // Synopsis: Allocates a stack node with the specified contents.
  1812. //
  1813. // Arguments: pszString - The string value of the node.
  1814. // dwType - The type of the node can either be
  1815. // a literal or an operator.
  1816. // ppStackEntry - Return value.
  1817. //
  1818. // Returns: S_OK, E_OUTOFMEMORY or E_FAIL.
  1819. //
  1820. // Modifies: ppStackEntry.
  1821. //
  1822. //----------------------------------------------------------------------------
  1823. HRESULT
  1824. CQueryStack::AllocateStackEntry(
  1825. LPWSTR pszString,
  1826. DWORD dwType,
  1827. STACKLIST **ppStackEntry
  1828. )
  1829. {
  1830. HRESULT hr = S_OK;
  1831. LPWSTR pszTmpString = NULL;
  1832. if (!pszString || !dwType) {
  1833. BAIL_ON_FAILURE(hr = E_FAIL);
  1834. }
  1835. *ppStackEntry = NULL;
  1836. pszTmpString = AllocADsStr(pszString);
  1837. if (!pszString) {
  1838. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1839. }
  1840. //
  1841. // Allocate the new stack node.
  1842. //
  1843. *ppStackEntry = (PSTACKLIST) AllocADsMem(sizeof(STACKLIST));
  1844. if (!*ppStackEntry) {
  1845. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1846. }
  1847. (*ppStackEntry)->pszElement = pszTmpString;
  1848. (*ppStackEntry)->dwElementType = dwType;
  1849. error:
  1850. if (FAILED(hr) && pszTmpString) {
  1851. FreeADsStr(pszTmpString);
  1852. }
  1853. RRETURN(hr);
  1854. }
  1855. //+---------------------------------------------------------------------------
  1856. // Function: CQueryStack::FreeStackEntry - static helper routine.
  1857. //
  1858. // Synopsis: Frees contents of the stack node and the node itself.
  1859. //
  1860. // Arguments: pStackEntry - Pointer to stack node to free.
  1861. //
  1862. // Returns: N/A.
  1863. //
  1864. // Modifies: pStackEntry and contents.
  1865. //
  1866. //----------------------------------------------------------------------------
  1867. void
  1868. CQueryStack::FreeStackEntry(
  1869. PSTACKLIST pStackEntry
  1870. )
  1871. {
  1872. if (!pStackEntry) {
  1873. return;
  1874. }
  1875. //
  1876. // Free the string if there is one and then the node.
  1877. //
  1878. if (pStackEntry->pszElement) {
  1879. FreeADsStr(pStackEntry->pszElement);
  1880. }
  1881. FreeADsMem(pStackEntry);
  1882. return;
  1883. }