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.

801 lines
20 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. pDispatch = NULL;
  269. pIADs->Release();
  270. pIADs = NULL;
  271. if (pszClass) {
  272. ADsFreeString(pszClass);
  273. pszClass = NULL;
  274. }
  275. continue;
  276. }
  277. if (pszClass) {
  278. ADsFreeString(pszClass);
  279. pszClass = NULL;
  280. }
  281. }
  282. if(pIADs)
  283. {
  284. pIADs->Release();
  285. pIADs = NULL;
  286. }
  287. //
  288. // Return it.
  289. //
  290. VariantInit(&pvar[i]);
  291. pvar[i].vt = VT_DISPATCH;
  292. pvar[i].pdispVal = pDispatch;
  293. (*pcElementFetched)++;
  294. i++;
  295. }
  296. RRETURN_EXP_IF_ERR(hr);
  297. error:
  298. if (pDispatch) {
  299. pDispatch->Release();
  300. }
  301. if (pIADs) {
  302. pIADs->Release();
  303. }
  304. if (pszClass) {
  305. ADsFreeString(pszClass);
  306. }
  307. RRETURN_EXP_IF_ERR(hr);
  308. }
  309. //----------------------------------------------------------------------------
  310. //
  311. // Function:
  312. //
  313. // Synopsis:
  314. //
  315. //----------------------------------------------------------------------------
  316. HRESULT
  317. CLDAPGroupCollectionEnum::GetUserMemberObject(
  318. IDispatch ** ppDispatch
  319. )
  320. {
  321. HRESULT hr = S_OK;
  322. VARIANT v;
  323. IUnknown *pObject = NULL;
  324. TCHAR *pszADsPath = NULL;
  325. LPWSTR pszUserName = NULL;
  326. LPWSTR pszPassword = NULL;
  327. DWORD dwAuthFlags = 0;
  328. BOOL fRangeUsed = FALSE;
  329. *ppDispatch = NULL;
  330. VariantInit(&v);
  331. hr = _Credentials.GetUserName(&pszUserName);
  332. BAIL_ON_FAILURE(hr);
  333. hr = _Credentials.GetPassword(&pszPassword);
  334. BAIL_ON_FAILURE(hr);
  335. dwAuthFlags = _Credentials.GetAuthFlags();
  336. while ( TRUE )
  337. {
  338. VariantInit(&v);
  339. if ( _lCurrentIndex >= _lMembersCount ) {
  340. hr = S_FALSE;
  341. //
  342. // See if we need to fetch members using Rangeretrieval.
  343. //
  344. if (_fRangeRetrieval && !_fAllRetrieved) {
  345. hr = GetNextMemberRange(&v);
  346. BAIL_ON_FAILURE(hr);
  347. if (hr == S_FALSE) {
  348. goto error;
  349. }
  350. fRangeUsed = TRUE;
  351. }
  352. else
  353. goto error;
  354. }
  355. //
  356. // Variant v will have correct value already if range
  357. // retrieval was used.
  358. //
  359. if (!fRangeUsed) {
  360. if ( _vMembers.vt == VT_BSTR )
  361. {
  362. hr = VariantCopy( &v, &_vMembers );
  363. }
  364. else
  365. {
  366. hr = SafeArrayGetElement( V_ARRAY(&_vMembers), &_lCurrentIndex, &v);
  367. }
  368. BAIL_ON_FAILURE(hr);
  369. }
  370. _lCurrentIndex++;
  371. LPTSTR pszMember = V_BSTR(&v);
  372. LPTSTR pszTemp = NULL;
  373. hr = BuildADsPathFromLDAPPath( _Parent, pszMember, &pszADsPath );
  374. BAIL_ON_FAILURE(hr);
  375. hr = ADsOpenObject(
  376. pszADsPath,
  377. pszUserName,
  378. pszPassword,
  379. dwAuthFlags,
  380. IID_IUnknown,
  381. (LPVOID *)&pObject
  382. );
  383. if ( pszADsPath )
  384. {
  385. FreeADsStr( pszADsPath );
  386. pszADsPath = 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. hr = S_OK;
  399. goto error;
  400. }
  401. error:
  402. if ( pObject )
  403. pObject->Release();
  404. if ( pszADsPath )
  405. FreeADsStr( pszADsPath );
  406. if (pszPassword) {
  407. SecureZeroMemory(pszPassword, wcslen(pszPassword)*sizeof(WCHAR));
  408. FreeADsStr(pszPassword);
  409. }
  410. if (pszUserName) {
  411. FreeADsStr(pszUserName);
  412. }
  413. VariantClear(&v);
  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. }