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.

801 lines
19 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996
  5. //
  6. // File: cenumgrp.cxx
  7. //
  8. // Contents: LDAP GroupCollection Enumeration Code
  9. //
  10. // CLDAPGroupCollectionEnum::
  11. // CLDAPGroupCollectionEnum::
  12. // CLDAPGroupCollectionEnum::
  13. // CLDAPGroupCollectionEnum::
  14. //
  15. // History:
  16. //----------------------------------------------------------------------------
  17. #include "ldap.hxx"
  18. #pragma hdrstop
  19. HRESULT
  20. BuildADsPathFromLDAPPath(
  21. LPWSTR szNamespace,
  22. LPWSTR szLdapDN,
  23. LPWSTR * ppszADsPathName
  24. );
  25. //+---------------------------------------------------------------------------
  26. //
  27. // Function: LDAPEnumVariant::Create
  28. //
  29. // Synopsis:
  30. //
  31. // Arguments: [pCollection]
  32. // [ppEnumVariant]
  33. //
  34. // Returns: HRESULT
  35. //
  36. // Modifies:
  37. //
  38. // History: 01-30-95 krishnag Created.
  39. //
  40. //----------------------------------------------------------------------------
  41. HRESULT
  42. CLDAPGroupCollectionEnum::Create(
  43. CLDAPGroupCollectionEnum FAR* FAR* ppenumvariant,
  44. BSTR Parent,
  45. BSTR ADsPath,
  46. BSTR GroupName,
  47. VARIANT vMembers,
  48. VARIANT vFilter,
  49. CCredentials& Credentials,
  50. IDirectoryObject * pIDirObj,
  51. BOOL fRangeRetrieval
  52. )
  53. {
  54. HRESULT hr = NOERROR;
  55. CLDAPGroupCollectionEnum FAR* penumvariant = NULL;
  56. long lLBound = 0;
  57. long lUBound = 0;
  58. *ppenumvariant = NULL;
  59. penumvariant = new CLDAPGroupCollectionEnum();
  60. if (!penumvariant) {
  61. hr = E_OUTOFMEMORY;
  62. BAIL_ON_FAILURE(hr);
  63. }
  64. penumvariant->_fRangeRetrieval = fRangeRetrieval;
  65. hr = ADsAllocString( Parent , &penumvariant->_Parent);
  66. BAIL_ON_FAILURE(hr);
  67. hr = ADsAllocString(GroupName, &penumvariant->_GroupName);
  68. BAIL_ON_FAILURE(hr);
  69. hr = ADsAllocString(ADsPath, &penumvariant->_ADsPath);
  70. BAIL_ON_FAILURE(hr);
  71. hr = VariantCopy( &penumvariant->_vMembers, &vMembers );
  72. BAIL_ON_FAILURE(hr);
  73. if ( vMembers.vt == VT_BSTR ) // 1 member only
  74. {
  75. penumvariant->_lMembersCount = 1;
  76. }
  77. else
  78. {
  79. hr = SafeArrayGetLBound(V_ARRAY(&penumvariant->_vMembers),
  80. 1,
  81. (long FAR *)&lLBound
  82. );
  83. BAIL_ON_FAILURE(hr);
  84. hr = SafeArrayGetUBound(V_ARRAY(&penumvariant->_vMembers),
  85. 1,
  86. (long FAR *)&lUBound
  87. );
  88. BAIL_ON_FAILURE(hr);
  89. penumvariant->_lMembersCount = lUBound - lLBound + 1;
  90. }
  91. hr = ObjectTypeList::CreateObjectTypeList(
  92. vFilter,
  93. &penumvariant->_pObjList
  94. );
  95. BAIL_ON_FAILURE(hr);
  96. penumvariant->_Credentials = Credentials;
  97. pIDirObj->QueryInterface(
  98. IID_IDirectoryObject,
  99. (void **) &(penumvariant->_pIDirObj)
  100. );
  101. BAIL_ON_FAILURE(hr);
  102. *ppenumvariant = penumvariant;
  103. RRETURN(hr);
  104. error:
  105. delete penumvariant;
  106. RRETURN_EXP_IF_ERR(hr);
  107. }
  108. //----------------------------------------------------------------------------
  109. //
  110. // Function:
  111. //
  112. // Synopsis:
  113. //
  114. //----------------------------------------------------------------------------
  115. CLDAPGroupCollectionEnum::CLDAPGroupCollectionEnum()
  116. : _Parent(NULL),
  117. _ADsPath(NULL),
  118. _GroupName(NULL),
  119. _lCurrentIndex(0),
  120. _lMembersCount(0),
  121. _pIDirObj(NULL),
  122. _fRangeRetrieval(FALSE),
  123. _fAllRetrieved(FALSE),
  124. _pszRangeToFetch(NULL),
  125. _pAttributeEntries(NULL),
  126. _pCurrentEntry(NULL),
  127. _dwCurRangeIndex(0),
  128. _dwCurRangeMax(0),
  129. _dwNumEntries(0),
  130. _fLastSet(FALSE)
  131. {
  132. VariantInit( &_vMembers );
  133. _pObjList = NULL;
  134. }
  135. //----------------------------------------------------------------------------
  136. //
  137. // Function:
  138. //
  139. // Synopsis:
  140. //
  141. //----------------------------------------------------------------------------
  142. CLDAPGroupCollectionEnum::CLDAPGroupCollectionEnum( ObjectTypeList ObjList )
  143. : _Parent(NULL),
  144. _ADsPath(NULL),
  145. _GroupName(NULL),
  146. _lCurrentIndex(0),
  147. _lMembersCount(0)
  148. {
  149. VariantInit( &_vMembers );
  150. _pObjList = NULL;
  151. }
  152. //----------------------------------------------------------------------------
  153. //
  154. // Function:
  155. //
  156. // Synopsis:
  157. //
  158. //----------------------------------------------------------------------------
  159. CLDAPGroupCollectionEnum::~CLDAPGroupCollectionEnum()
  160. {
  161. VariantClear( &_vMembers );
  162. delete _pObjList;
  163. if ( _Parent )
  164. ADsFreeString( _Parent );
  165. if ( _GroupName )
  166. ADsFreeString( _GroupName );
  167. if ( _ADsPath )
  168. ADsFreeString( _ADsPath );
  169. if (_pIDirObj) {
  170. _pIDirObj->Release();
  171. }
  172. if (_pszRangeToFetch) {
  173. FreeADsStr(_pszRangeToFetch);
  174. }
  175. if (_pAttributeEntries) {
  176. FreeADsMem(_pAttributeEntries);
  177. }
  178. }
  179. //----------------------------------------------------------------------------
  180. //
  181. // Function:
  182. //
  183. // Synopsis:
  184. //
  185. //----------------------------------------------------------------------------
  186. HRESULT
  187. CLDAPGroupCollectionEnum::EnumGroupMembers(
  188. ULONG cElements,
  189. VARIANT FAR* pvar,
  190. ULONG FAR* pcElementFetched
  191. )
  192. {
  193. HRESULT hr = S_FALSE;
  194. IDispatch *pDispatch = NULL;
  195. DWORD i = 0;
  196. IADs * pIADs = NULL;
  197. BSTR pszClass = NULL;
  198. DWORD dwClassID;
  199. BSTR pszFilterName = NULL;
  200. BOOL fFound = FALSE;
  201. BOOL fEmpty = TRUE;
  202. while (i < cElements) {
  203. hr = GetUserMemberObject(&pDispatch);
  204. if (FAILED(hr)) {
  205. //
  206. // Set hr to S_FALSE as all our enumerators are not
  207. // built to handle a failure hr but only S_OK and S_FALSE.
  208. //
  209. hr = S_FALSE;
  210. }
  211. if (hr == S_FALSE) {
  212. break;
  213. }
  214. //
  215. // Apply the IADsMembers::put_Filter filter.
  216. // If the enumerated object is not one of the types to be returned,
  217. // go on to the next member of the group.
  218. //
  219. hr = pDispatch->QueryInterface(IID_IADs, (void **)&pIADs);
  220. BAIL_ON_FAILURE(hr);
  221. //
  222. // To check whether use specifies filter
  223. //
  224. fEmpty = _pObjList->IsEmpty();
  225. //
  226. // User specifies the filter
  227. //
  228. if (!fEmpty) {
  229. //
  230. // Determine the object class of the enumerated object and the corresponding
  231. // object class ID number (as specified in the Filters global array).
  232. //
  233. hr = pIADs->get_Class(&pszClass);
  234. BAIL_ON_FAILURE(hr);
  235. //
  236. // Enumerate through the object classes listed in the user-specified filter
  237. // until we either find a match (fFound = TRUE) or we reach the end of the
  238. // list.
  239. //
  240. hr = _pObjList->Reset();
  241. //
  242. // compare with the user defined filter
  243. //
  244. while (SUCCEEDED(hr)) {
  245. hr = _pObjList->GetCurrentObject(&pszFilterName);
  246. if (SUCCEEDED(hr)
  247. && (!_wcsicmp(pszClass, pszFilterName))
  248. ) {
  249. fFound = TRUE;
  250. if(pszFilterName) {
  251. SysFreeString(pszFilterName);
  252. pszFilterName = NULL;
  253. }
  254. break;
  255. }
  256. if(pszFilterName) {
  257. SysFreeString(pszFilterName);
  258. pszFilterName = NULL;
  259. }
  260. hr = _pObjList->Next();
  261. }
  262. if (!fFound) {
  263. //
  264. // not on the list of objects to return, try again
  265. // with the next member of the group
  266. //
  267. pDispatch->Release();
  268. pIADs->Release();
  269. if (pszClass) {
  270. ADsFreeString(pszClass);
  271. pszClass = NULL;
  272. }
  273. continue;
  274. }
  275. pIADs->Release();
  276. if (pszClass) {
  277. ADsFreeString(pszClass);
  278. pszClass = NULL;
  279. }
  280. }
  281. //
  282. // Return it.
  283. //
  284. VariantInit(&pvar[i]);
  285. pvar[i].vt = VT_DISPATCH;
  286. pvar[i].pdispVal = pDispatch;
  287. (*pcElementFetched)++;
  288. i++;
  289. }
  290. RRETURN_EXP_IF_ERR(hr);
  291. error:
  292. if (pDispatch) {
  293. pDispatch->Release();
  294. }
  295. if (pIADs) {
  296. pIADs->Release();
  297. }
  298. if (pszClass) {
  299. ADsFreeString(pszClass);
  300. }
  301. RRETURN_EXP_IF_ERR(hr);
  302. }
  303. //----------------------------------------------------------------------------
  304. //
  305. // Function:
  306. //
  307. // Synopsis:
  308. //
  309. //----------------------------------------------------------------------------
  310. HRESULT
  311. CLDAPGroupCollectionEnum::GetUserMemberObject(
  312. IDispatch ** ppDispatch
  313. )
  314. {
  315. HRESULT hr = S_OK;
  316. VARIANT v;
  317. IUnknown *pObject = NULL;
  318. TCHAR *pszADsPath = NULL;
  319. LPWSTR pszUserName = NULL;
  320. LPWSTR pszPassword = NULL;
  321. DWORD dwAuthFlags = 0;
  322. BOOL fRangeUsed = FALSE;
  323. hr = _Credentials.GetUserName(&pszUserName);
  324. BAIL_ON_FAILURE(hr);
  325. hr = _Credentials.GetPassword(&pszPassword);
  326. BAIL_ON_FAILURE(hr);
  327. dwAuthFlags = _Credentials.GetAuthFlags();
  328. while ( TRUE )
  329. {
  330. VariantInit(&v);
  331. if ( _lCurrentIndex >= _lMembersCount ) {
  332. hr = S_FALSE;
  333. //
  334. // See if we need to fetch members using Rangeretrieval.
  335. //
  336. if (_fRangeRetrieval && !_fAllRetrieved) {
  337. hr = GetNextMemberRange(&v);
  338. BAIL_ON_FAILURE(hr);
  339. if (hr == S_FALSE) {
  340. goto error;
  341. }
  342. fRangeUsed = TRUE;
  343. }
  344. else
  345. goto error;
  346. }
  347. //
  348. // Variant v will have correct value already if range
  349. // retrieval was used.
  350. //
  351. if (!fRangeUsed) {
  352. if ( _vMembers.vt == VT_BSTR )
  353. {
  354. hr = VariantCopy( &v, &_vMembers );
  355. }
  356. else
  357. {
  358. hr = SafeArrayGetElement( V_ARRAY(&_vMembers), &_lCurrentIndex, &v);
  359. }
  360. BAIL_ON_FAILURE(hr);
  361. }
  362. _lCurrentIndex++;
  363. LPTSTR pszMember = V_BSTR(&v);
  364. LPTSTR pszTemp = NULL;
  365. hr = BuildADsPathFromLDAPPath( _Parent, pszMember, &pszADsPath );
  366. BAIL_ON_FAILURE(hr);
  367. hr = ADsOpenObject(
  368. pszADsPath,
  369. pszUserName,
  370. pszPassword,
  371. dwAuthFlags,
  372. IID_IUnknown,
  373. (LPVOID *)&pObject
  374. );
  375. if ( pszADsPath )
  376. {
  377. FreeADsStr( pszADsPath );
  378. pszADsPath = NULL;
  379. }
  380. if (pszPassword) {
  381. FreeADsStr(pszPassword);
  382. pszPassword = NULL;
  383. }
  384. if (pszUserName) {
  385. FreeADsStr(pszUserName);
  386. pszUserName = NULL;
  387. }
  388. VariantClear(&v);
  389. //
  390. // If we failed to get the current object, continue with the next one
  391. //
  392. if ( FAILED(hr))
  393. continue;
  394. hr = pObject->QueryInterface(
  395. IID_IDispatch,
  396. (LPVOID *) ppDispatch );
  397. BAIL_ON_FAILURE(hr);
  398. pObject->Release();
  399. RRETURN(S_OK);
  400. }
  401. error:
  402. if ( pObject )
  403. pObject->Release();
  404. if ( pszADsPath )
  405. FreeADsStr( pszADsPath );
  406. if (pszPassword) {
  407. FreeADsStr(pszPassword);
  408. }
  409. if (pszUserName) {
  410. FreeADsStr(pszUserName);
  411. }
  412. VariantClear(&v);
  413. *ppDispatch = NULL;
  414. RRETURN(hr);
  415. }
  416. //+---------------------------------------------------------------------------
  417. //
  418. // Function: CLDAPGroupCollectionEnum::Next
  419. //
  420. // Synopsis: Returns cElements number of requested NetOle objects in the
  421. // array supplied in pvar.
  422. //
  423. // Arguments: [cElements] -- The number of elements requested by client
  424. // [pvar] -- ptr to array of VARIANTs to for return objects
  425. // [pcElementFetched] -- if non-NULL, then number of elements
  426. // -- actually returned is placed here
  427. //
  428. // Returns: HRESULT -- S_OK if number of elements requested are returned
  429. // -- S_FALSE if number of elements is < requested
  430. //
  431. // Modifies:
  432. //
  433. // History: 11-3-95 krishnag Created.
  434. //
  435. //----------------------------------------------------------------------------
  436. STDMETHODIMP
  437. CLDAPGroupCollectionEnum::Next(
  438. ULONG cElements,
  439. VARIANT FAR* pvar,
  440. ULONG FAR* pcElementFetched
  441. )
  442. {
  443. ULONG cElementFetched = 0;
  444. HRESULT hr = S_OK;
  445. hr = EnumGroupMembers(
  446. cElements,
  447. pvar,
  448. &cElementFetched
  449. );
  450. if (pcElementFetched) {
  451. *pcElementFetched = cElementFetched;
  452. }
  453. RRETURN_EXP_IF_ERR(hr);
  454. }
  455. HRESULT
  456. CLDAPGroupCollectionEnum::UpdateRangeToFetch()
  457. {
  458. HRESULT hr = S_OK;
  459. WCHAR szPath[512];
  460. //
  461. // szPath should be big enough to handle any range we
  462. // can reasonably expect and will be used to build the
  463. // member string.
  464. //
  465. if (_pszRangeToFetch == NULL) {
  466. //
  467. // Rather than ask for the first n elements again,
  468. // we can use the count we have in the variant array
  469. // to decide where we need to start.
  470. //
  471. wsprintf(szPath, L"member;range=%d-*", _lMembersCount);
  472. _pszRangeToFetch = AllocADsStr(szPath);
  473. if (!_pszRangeToFetch) {
  474. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  475. }
  476. }
  477. else {
  478. //
  479. // In this case the call to GetObjectAttr has been made
  480. // and we need to get the info out of the name.
  481. //
  482. BOOL fUpdated = FALSE;
  483. for (DWORD i = 0; (i < _dwNumEntries) && !fUpdated; i++) {
  484. LPWSTR pszTemp = NULL;
  485. LPWSTR pszAttrName = _pAttributeEntries[i].pszAttrName;
  486. LPWSTR pszStar = NULL;
  487. if (wcslen(pszAttrName) > wcslen(L"member;range=")) {
  488. //
  489. // See if we have our string
  490. //
  491. if (!_wcsnicmp(
  492. pszAttrName,
  493. L"member;range=",
  494. wcslen(L"member;range")
  495. )
  496. ) {
  497. _pCurrentEntry = &(_pAttributeEntries[i]);
  498. _dwCurRangeMax = _pCurrentEntry->dwNumValues;
  499. _dwCurRangeIndex = 0;
  500. pszTemp = wcschr(pszAttrName, L'=');
  501. if (!pszTemp) {
  502. //
  503. // No chance of recovery from this.
  504. //
  505. BAIL_ON_FAILURE(hr = E_FAIL);
  506. }
  507. //
  508. // Move the lower part of range.
  509. //
  510. *pszTemp++;
  511. if (!*pszTemp) {
  512. BAIL_ON_FAILURE(hr = E_FAIL);
  513. }
  514. pszStar = wcschr(pszTemp, L'*');
  515. if (pszStar) {
  516. //
  517. // Do not bother with any udpate of the range,
  518. // we have all the entries.
  519. //
  520. _fLastSet = TRUE;
  521. goto error;
  522. }
  523. DWORD dwLower = 0;
  524. DWORD dwHigher = 0;
  525. if (!swscanf(pszTemp, L"%d-%d", &dwLower, &dwHigher)) {
  526. BAIL_ON_FAILURE(hr = E_FAIL);
  527. }
  528. dwHigher++;
  529. wsprintf(szPath, L"member;range=%d-*", dwHigher);
  530. FreeADsStr(_pszRangeToFetch);
  531. _pszRangeToFetch = AllocADsStr(szPath);
  532. if (!_pszRangeToFetch) {
  533. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  534. }
  535. //
  536. // Set flag so we can get out of the loop.
  537. //
  538. fUpdated = TRUE;
  539. } // this was not member;
  540. } // is the length greater than that of member;
  541. } // for each entry in attribute entries.
  542. if (!fUpdated) {
  543. //
  544. // Failed cause there was no members or a range.
  545. //
  546. BAIL_ON_FAILURE(hr = E_FAIL);
  547. }
  548. } // _pszRangeToFetch was non NULL
  549. error:
  550. RRETURN(hr);
  551. }
  552. //+---------------------------------------------------------------------------
  553. //
  554. // Function: CLDAPGroupCollectionEnum::GetNextMemberRange
  555. //
  556. // Synopsis: Returns a variant bstr with the dn of the next member in
  557. // the group or FALSE if there are no more. This routine will
  558. // will use IDirectoryObject to fetch more members if applicable.
  559. //
  560. //
  561. // Arguments: [pVarMemberBstr] -- ptr to VARIANT for return bstr.
  562. //
  563. // Returns: HRESULT -- S_OK if number of elements requested are returned
  564. // -- S_FALSE if number of elements is < requested
  565. // -- Other failure hr's.
  566. // Modifies:
  567. //
  568. // History: 9-12-99 AjayR Created.
  569. //
  570. //----------------------------------------------------------------------------
  571. HRESULT
  572. CLDAPGroupCollectionEnum::GetNextMemberRange(
  573. VARIANT FAR* pVarMemberBstr
  574. )
  575. {
  576. HRESULT hr = S_FALSE;
  577. if (_fAllRetrieved) {
  578. RRETURN(S_FALSE);
  579. }
  580. //
  581. // Initialize the range to fetch if applicable.
  582. //
  583. if (_pszRangeToFetch == NULL) {
  584. hr = UpdateRangeToFetch();
  585. BAIL_ON_FAILURE(hr);
  586. }
  587. if (_dwCurRangeIndex == _dwCurRangeMax) {
  588. //
  589. // Call into wrapper for GetObjectAttributes.
  590. //
  591. if (_fLastSet) {
  592. _fAllRetrieved = TRUE;
  593. hr = S_FALSE;
  594. }
  595. else {
  596. hr = UpdateAttributeEntries();
  597. BAIL_ON_FAILURE(hr);
  598. }
  599. if (hr == S_FALSE) {
  600. goto error;
  601. }
  602. }
  603. //
  604. // At this point we should have the entries in our current
  605. // return set.
  606. //
  607. if (!_pCurrentEntry) {
  608. BAIL_ON_FAILURE(hr = E_FAIL);
  609. }
  610. if (_dwCurRangeIndex < _dwCurRangeMax) {
  611. hr = ADsAllocString(
  612. _pCurrentEntry->pADsValues[_dwCurRangeIndex].DNString,
  613. &V_BSTR(pVarMemberBstr)
  614. );
  615. BAIL_ON_FAILURE(hr);
  616. }
  617. _dwCurRangeIndex++;
  618. error:
  619. RRETURN(hr);
  620. }
  621. HRESULT
  622. CLDAPGroupCollectionEnum::UpdateAttributeEntries()
  623. {
  624. HRESULT hr = S_OK;
  625. LPWSTR aStrings[2];
  626. ADsAssert(_pszRangeToFetch || !"Range is NULL internal error");
  627. if (_pAttributeEntries) {
  628. FreeADsMem(_pAttributeEntries);
  629. _pAttributeEntries = NULL;
  630. }
  631. aStrings[0] = _pszRangeToFetch;
  632. aStrings[1] = NULL;
  633. hr = _pIDirObj->GetObjectAttributes(
  634. aStrings,
  635. 1,
  636. &_pAttributeEntries,
  637. &_dwNumEntries
  638. );
  639. BAIL_ON_FAILURE(hr);
  640. if (_dwNumEntries == 0) {
  641. hr = S_FALSE;
  642. }
  643. else {
  644. //
  645. // Will return error if member was not there.
  646. //
  647. hr = UpdateRangeToFetch();
  648. BAIL_ON_FAILURE(hr);
  649. }
  650. error:
  651. RRETURN(hr);
  652. }