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.

2818 lines
64 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  5. //
  6. // File: cprops.cxx
  7. //
  8. // Contents: Property Cache functionality for LDAP
  9. //
  10. // Functions:
  11. // CPropertyCache::addproperty
  12. // CPropertyCache::updateproperty
  13. // CPropertyCache::findproperty
  14. // CPropertyCache::getproperty
  15. // CPropertyCache::putproperty
  16. // CProperyCache::CPropertyCache
  17. // CPropertyCache::~CPropertyCache
  18. // CPropertyCache::createpropertycache
  19. //
  20. // History: 15-Jun-96 yihsins Created.
  21. //
  22. //----------------------------------------------------------------------------
  23. #include "ldap.hxx"
  24. //+------------------------------------------------------------------------
  25. //
  26. // Function: CPropertyCache::addproperty
  27. //
  28. // Synopsis:
  29. //
  30. //
  31. //
  32. // Arguments: [szPropertyName] --
  33. // [vt] --
  34. // [vaData] --
  35. //
  36. //
  37. //-------------------------------------------------------------------------
  38. HRESULT
  39. CPropertyCache::
  40. addproperty(
  41. LPWSTR szPropertyName
  42. )
  43. {
  44. HRESULT hr = S_OK;
  45. PPROPERTY pNewProperty = NULL;
  46. LPWSTR tempString1 = NULL;
  47. LPWSTR tempString2 = NULL;
  48. PPROPERTY pNewProperties = NULL;
  49. PDISPPROPERTY pDispNewProperty = NULL;
  50. PDISPPROPERTY pDispNewProperties = NULL;
  51. DWORD dwDispLoc = 0;
  52. //
  53. // Allocate the string first
  54. //
  55. tempString1 = AllocADsStr(szPropertyName);
  56. if (!tempString1)
  57. BAIL_ON_FAILURE(hr=E_OUTOFMEMORY);
  58. //
  59. // Make a copy for the Dispatch Mgr Table.
  60. //
  61. tempString2 = AllocADsStr(szPropertyName);
  62. if (!tempString2)
  63. BAIL_ON_FAILURE(hr=E_OUTOFMEMORY);
  64. //
  65. // extend the property cache by adding a new property entry
  66. //
  67. pNewProperties = (PPROPERTY)ReallocADsMem(
  68. _pProperties,
  69. _cb,
  70. _cb + sizeof(PROPERTY)
  71. );
  72. if (!pNewProperties) {
  73. hr = E_OUTOFMEMORY;
  74. BAIL_ON_FAILURE(hr);
  75. }
  76. _pProperties = pNewProperties;
  77. pNewProperty = (PPROPERTY)((LPBYTE)_pProperties + _cb);
  78. //
  79. // Since the memory has already been allocated in tempString
  80. // just set the value/pointer now.
  81. //
  82. pNewProperty->szPropertyName = tempString1;
  83. //
  84. // Update the index
  85. //
  86. _dwMaxProperties++;
  87. _cb += sizeof(PROPERTY);
  88. //
  89. // extend the property cache by adding a new property entry
  90. //
  91. //
  92. // Need to check if this property is already there in the
  93. // dispatch table - otherwise we are going to keep on growing
  94. // forever - AjayR 7-31-98.
  95. //
  96. hr = DispatchFindProperty(szPropertyName, &dwDispLoc);
  97. if (hr == S_OK) {
  98. // we do not need this string in this case
  99. if (tempString2) {
  100. FreeADsStr(tempString2);
  101. tempString2 = NULL;
  102. }
  103. } else {
  104. //
  105. // reset the hr otherwise we will return an
  106. // error incorrectly when there was none.
  107. //
  108. hr = S_OK;
  109. pDispNewProperties = (PDISPPROPERTY)ReallocADsMem(
  110. _pDispProperties,
  111. _cbDisp,
  112. _cbDisp + sizeof(DISPPROPERTY)
  113. );
  114. if (!pDispNewProperties) {
  115. hr = E_OUTOFMEMORY;
  116. BAIL_ON_FAILURE(hr);
  117. }
  118. _pDispProperties = pDispNewProperties;
  119. pDispNewProperty = (PDISPPROPERTY)((LPBYTE)_pDispProperties + _cbDisp);
  120. //
  121. // Since the memory has already been allocated in tempString
  122. // just set the value/pointer now.
  123. //
  124. pDispNewProperty->szPropertyName = tempString2;
  125. //
  126. // Update the index
  127. //
  128. _dwDispMaxProperties++;
  129. _cbDisp += sizeof(DISPPROPERTY);
  130. } // else clause - that is property not found in disp
  131. RRETURN(hr);
  132. error:
  133. if (tempString1){
  134. FreeADsStr(tempString1);
  135. }
  136. if (tempString2) {
  137. FreeADsStr(tempString2);
  138. }
  139. RRETURN(hr);
  140. }
  141. //+------------------------------------------------------------------------
  142. //
  143. // Function: CPropertyCache::putpropertyext
  144. //
  145. // Synopsis: Similar to put property only unlike update it will add
  146. // the property to the cahce if it is not already there !
  147. //
  148. //
  149. // Arguments: [szPropertyName] --
  150. // [vaData] --
  151. //
  152. // History
  153. //-------------------------------------------------------------------------
  154. HRESULT
  155. CPropertyCache::
  156. putpropertyext(
  157. LPWSTR szPropertyName,
  158. DWORD dwFlags,
  159. DWORD dwSyntaxId,
  160. LDAPOBJECTARRAY ldapObjectArray
  161. )
  162. {
  163. HRESULT hr;
  164. DWORD dwIndex;
  165. BOOL fFound = FALSE;
  166. PPROPERTY pThisProperty = NULL;
  167. hr = findproperty(
  168. szPropertyName,
  169. &dwIndex
  170. );
  171. //
  172. // If the property is not in the cache we need to add it
  173. // as updateproperty expects it to be in the cache.
  174. //
  175. if (hr == E_ADS_PROPERTY_NOT_FOUND) {
  176. hr = addproperty(
  177. szPropertyName
  178. );
  179. }
  180. else {
  181. fFound = TRUE;
  182. }
  183. BAIL_ON_FAILURE(hr);
  184. //
  185. // at this time we can call putproperty
  186. //
  187. if (fFound) {
  188. hr = putproperty(
  189. dwIndex,
  190. dwFlags,
  191. dwSyntaxId,
  192. ldapObjectArray
  193. );
  194. }
  195. else {
  196. hr = putproperty(
  197. szPropertyName,
  198. dwFlags,
  199. dwSyntaxId,
  200. ldapObjectArray
  201. );
  202. }
  203. error:
  204. RRETURN(hr);
  205. }
  206. //+------------------------------------------------------------------------
  207. //
  208. // Function: CPropertyCache::updateproperty
  209. //
  210. // Synopsis:
  211. //
  212. //
  213. //
  214. // Arguments: [szPropertyName] --
  215. // [vaData] --
  216. //
  217. //-------------------------------------------------------------------------
  218. HRESULT
  219. CPropertyCache::
  220. updateproperty(
  221. LPWSTR szPropertyName,
  222. DWORD dwSyntaxId,
  223. LDAPOBJECTARRAY ldapObjectArray,
  224. BOOL fExplicit
  225. )
  226. {
  227. HRESULT hr;
  228. DWORD dwIndex;
  229. PPROPERTY pThisProperty = NULL;
  230. hr = findproperty(
  231. szPropertyName,
  232. &dwIndex
  233. );
  234. BAIL_ON_FAILURE(hr);
  235. pThisProperty = _pProperties + dwIndex;
  236. if (!fExplicit) {
  237. if ( PROPERTY_FLAGS(pThisProperty) == PROPERTY_UPDATE ) {
  238. hr = S_OK;
  239. goto error;
  240. }
  241. }
  242. // Free the old values first
  243. LdapTypeFreeLdapObjects( &(PROPERTY_LDAPOBJECTARRAY(pThisProperty)));
  244. PROPERTY_SYNTAX(pThisProperty) = dwSyntaxId;
  245. PROPERTY_FLAGS(pThisProperty) = PROPERTY_INIT;
  246. hr = LdapTypeCopyConstruct(
  247. ldapObjectArray,
  248. &(PROPERTY_LDAPOBJECTARRAY(pThisProperty))
  249. );
  250. BAIL_ON_FAILURE(hr);
  251. error:
  252. RRETURN(hr);
  253. }
  254. //+------------------------------------------------------------------------
  255. //
  256. // Function: CPropertyCache::findproperty
  257. //
  258. // Synopsis:
  259. //
  260. //
  261. //
  262. // Arguments: [szPropertyName] --
  263. // [pdwIndex] --
  264. //
  265. //-------------------------------------------------------------------------
  266. HRESULT
  267. CPropertyCache::
  268. findproperty(
  269. LPWSTR szPropertyName,
  270. PDWORD pdwIndex
  271. )
  272. {
  273. DWORD i = 0;
  274. PPROPERTY pThisProperty = NULL;
  275. for (i = 0; i < _dwMaxProperties; i++) {
  276. pThisProperty = _pProperties + i;
  277. if (!_wcsicmp(pThisProperty->szPropertyName, szPropertyName)) {
  278. *pdwIndex = i;
  279. RRETURN(S_OK);
  280. }
  281. }
  282. *pdwIndex = 0;
  283. RRETURN(E_ADS_PROPERTY_NOT_FOUND);
  284. }
  285. //+------------------------------------------------------------------------
  286. //
  287. // Function: CPropertyCache::getproperty
  288. //
  289. // Synopsis:
  290. //
  291. //
  292. //
  293. // Arguments: [szPropertyName] -- Property to retrieve from the cache
  294. // [pvaData] -- Data returned in a variant
  295. //
  296. //-------------------------------------------------------------------------
  297. HRESULT
  298. CPropertyCache::
  299. getproperty(
  300. LPWSTR szPropertyName,
  301. PDWORD pdwSyntaxId,
  302. PDWORD pdwStatusFlag,
  303. LDAPOBJECTARRAY *pLdapObjectArray
  304. )
  305. {
  306. HRESULT hr;
  307. DWORD dwIndex = 0L;
  308. //
  309. // retrieve index of property in cache
  310. //
  311. hr = findproperty(
  312. szPropertyName,
  313. &dwIndex
  314. );
  315. //
  316. // if property not already in cache, try get properties from svr
  317. //
  318. //
  319. // INDEX_EMPTY(???) ???
  320. //
  321. if ((hr == E_ADS_PROPERTY_NOT_FOUND ||
  322. (INDEX_EMPTY(dwIndex) && !PROP_DELETED(dwIndex))
  323. ) &&
  324. !_fGetInfoDone)
  325. {
  326. BOOL fResult = FindSavingEntry(szPropertyName);
  327. if(!fResult) {
  328. hr = _pCoreADsObject->GetInfo(FALSE);
  329. // workaround to avoid confusing callers of getproperty.
  330. if (hr == E_NOTIMPL) {
  331. hr = E_ADS_PROPERTY_NOT_FOUND;
  332. }
  333. BAIL_ON_FAILURE(hr);
  334. hr = findproperty(szPropertyName, &dwIndex);
  335. }
  336. else {
  337. hr = E_ADS_PROPERTY_NOT_FOUND;
  338. }
  339. }
  340. BAIL_ON_FAILURE(hr);
  341. //
  342. // get property based on index in cache
  343. //
  344. hr = unboundgetproperty(
  345. dwIndex,
  346. pdwSyntaxId,
  347. pdwStatusFlag,
  348. pLdapObjectArray
  349. );
  350. error:
  351. RRETURN(hr);
  352. }
  353. //+------------------------------------------------------------------------
  354. //
  355. // Function: CPropertyCache::putproperty
  356. //
  357. //-------------------------------------------------------------------------
  358. HRESULT
  359. CPropertyCache::
  360. putproperty(
  361. LPWSTR szPropertyName,
  362. DWORD dwFlags,
  363. DWORD dwSyntaxId,
  364. LDAPOBJECTARRAY ldapObjectArray
  365. )
  366. {
  367. HRESULT hr = S_OK;
  368. DWORD dwIndex = 0L;
  369. hr = findproperty(szPropertyName, &dwIndex);
  370. if (SUCCEEDED(hr))
  371. hr = putproperty(dwIndex, dwFlags, dwSyntaxId, ldapObjectArray);
  372. RRETURN(hr);
  373. }
  374. //+------------------------------------------------------------------------
  375. //
  376. // Function: CPropertyCache::putproperty
  377. //
  378. //-------------------------------------------------------------------------
  379. HRESULT
  380. CPropertyCache::
  381. putproperty(
  382. DWORD dwIndex,
  383. DWORD dwFlags,
  384. DWORD dwSyntaxId,
  385. LDAPOBJECTARRAY ldapObjectArray
  386. )
  387. {
  388. HRESULT hr = S_OK;
  389. PPROPERTY pThisProperty = NULL;
  390. pThisProperty = _pProperties + dwIndex;
  391. // Free the old values first
  392. LdapTypeFreeLdapObjects( &(PROPERTY_LDAPOBJECTARRAY(pThisProperty)) );
  393. PROPERTY_SYNTAX(pThisProperty) = dwSyntaxId;
  394. switch ( dwFlags ) {
  395. case PROPERTY_INIT:
  396. if ( ldapObjectArray.dwCount > 0 )
  397. {
  398. hr = LdapTypeCopyConstruct(
  399. ldapObjectArray,
  400. &(PROPERTY_LDAPOBJECTARRAY(pThisProperty))
  401. );
  402. BAIL_ON_FAILURE(hr);
  403. }
  404. PROPERTY_FLAGS(pThisProperty) = PROPERTY_INIT;
  405. break;
  406. case PROPERTY_DELETE:
  407. PROPERTY_FLAGS(pThisProperty) = PROPERTY_DELETE;
  408. break;
  409. case PROPERTY_UPDATE:
  410. if ( ldapObjectArray.dwCount > 0 )
  411. {
  412. hr = LdapTypeCopyConstruct(
  413. ldapObjectArray,
  414. &(PROPERTY_LDAPOBJECTARRAY(pThisProperty))
  415. );
  416. BAIL_ON_FAILURE(hr);
  417. }
  418. PROPERTY_FLAGS(pThisProperty) = ldapObjectArray.dwCount?
  419. PROPERTY_UPDATE : PROPERTY_DELETE;
  420. break;
  421. case PROPERTY_DELETE_VALUE:
  422. if ( ldapObjectArray.dwCount > 0 )
  423. {
  424. hr = LdapTypeCopyConstruct(
  425. ldapObjectArray,
  426. &(PROPERTY_LDAPOBJECTARRAY(pThisProperty))
  427. );
  428. BAIL_ON_FAILURE(hr);
  429. }
  430. PROPERTY_FLAGS(pThisProperty) = PROPERTY_DELETE_VALUE;
  431. break;
  432. case PROPERTY_ADD:
  433. hr = LdapTypeCopyConstruct(
  434. ldapObjectArray,
  435. &(PROPERTY_LDAPOBJECTARRAY(pThisProperty))
  436. );
  437. BAIL_ON_FAILURE(hr);
  438. PROPERTY_FLAGS(pThisProperty) = PROPERTY_ADD;
  439. break;
  440. }
  441. error:
  442. RRETURN(hr);
  443. }
  444. //+------------------------------------------------------------------------
  445. //
  446. // Function: CPropertyCache::CPropertyCache
  447. //
  448. // Synopsis:
  449. //
  450. //
  451. //
  452. // Arguments:
  453. //
  454. //
  455. //-------------------------------------------------------------------------
  456. CPropertyCache::
  457. CPropertyCache():
  458. _dwMaxProperties(0),
  459. _pProperties(NULL),
  460. _cb(0),
  461. _dwCurrentIndex(0),
  462. _pCoreADsObject(NULL),
  463. _pGetAttributeSyntax(NULL),
  464. _fGetInfoDone(FALSE),
  465. _pDispProperties(NULL),
  466. _dwDispMaxProperties(0),
  467. _cbDisp(0),
  468. _pCredentials(NULL),
  469. _pszServerName(NULL),
  470. _dwPort(0)
  471. {
  472. InitializeListHead(&_ListSavingEntries);
  473. }
  474. //+------------------------------------------------------------------------
  475. //
  476. // Function: CPropertyCache::~CPropertyCache
  477. //
  478. // Synopsis:
  479. //
  480. //
  481. //
  482. // Arguments:
  483. //
  484. //
  485. //-------------------------------------------------------------------------
  486. CPropertyCache::
  487. ~CPropertyCache()
  488. {
  489. PPROPERTY pThisProperty = NULL;
  490. PDISPPROPERTY pThisDispProperty = NULL;
  491. if (_pProperties) {
  492. for ( DWORD i = 0; i < _dwMaxProperties; i++ ) {
  493. pThisProperty = _pProperties + i;
  494. if (pThisProperty->szPropertyName) {
  495. FreeADsStr(pThisProperty->szPropertyName);
  496. pThisProperty->szPropertyName = NULL;
  497. }
  498. LdapTypeFreeLdapObjects(&(PROPERTY_LDAPOBJECTARRAY(pThisProperty)));
  499. }
  500. FreeADsMem(_pProperties);
  501. }
  502. if (_pDispProperties) {
  503. for ( DWORD i = 0; i < _dwDispMaxProperties; i++ ) {
  504. pThisDispProperty = _pDispProperties + i;
  505. if (pThisDispProperty->szPropertyName) {
  506. FreeADsStr(pThisDispProperty->szPropertyName);
  507. pThisDispProperty->szPropertyName = NULL;
  508. }
  509. }
  510. FreeADsMem(_pDispProperties);
  511. }
  512. if (_pszServerName) {
  513. FreeADsStr(_pszServerName);
  514. _pszServerName = NULL;
  515. }
  516. DeleteSavingEntry();
  517. //
  518. // The property cache is deleted before the object is
  519. // so the object will handle freeing the credentials.
  520. // We just keep a pointer to the credentials.
  521. //
  522. if (_pCredentials) {
  523. _pCredentials = NULL;
  524. }
  525. }
  526. //+------------------------------------------------------------------------
  527. //
  528. // Function: CPropertyCache::ClearAllPropertyFlags
  529. //
  530. // Synopsis:
  531. //
  532. //
  533. //
  534. // Arguments:
  535. //
  536. //
  537. //-------------------------------------------------------------------------
  538. HRESULT CPropertyCache::ClearAllPropertyFlags(VOID)
  539. {
  540. PPROPERTY pThisProperty = NULL;
  541. if (_pProperties) {
  542. for ( DWORD i = 0; i < _dwMaxProperties; i++ ) {
  543. pThisProperty = _pProperties + i;
  544. PROPERTY_FLAGS(pThisProperty) = PROPERTY_INIT;
  545. }
  546. }
  547. RRETURN(S_OK);
  548. }
  549. //+------------------------------------------------------------------------
  550. //
  551. // Function: CPropertyCache::ClearPropertyFlag
  552. //
  553. // Synopsis:
  554. //
  555. //
  556. //
  557. // Arguments:
  558. //
  559. //
  560. //-------------------------------------------------------------------------
  561. HRESULT CPropertyCache::ClearPropertyFlag( LPWSTR szPropertyName )
  562. {
  563. PPROPERTY pThisProperty = NULL;
  564. HRESULT hr = S_OK;
  565. DWORD dwIndex;
  566. hr = findproperty(
  567. szPropertyName,
  568. &dwIndex
  569. );
  570. BAIL_ON_FAILURE(hr);
  571. pThisProperty = _pProperties + dwIndex;
  572. if (PROPERTY_LDAPOBJECTARRAY(pThisProperty).pLdapObjects) {
  573. PROPERTY_FLAGS(pThisProperty) = PROPERTY_INIT;
  574. }
  575. error:
  576. RRETURN(hr);
  577. }
  578. //+------------------------------------------------------------------------
  579. //
  580. // Function: CPropertyCache::ClearMarshalledProperties
  581. //
  582. // Synopsis: Once the properties have been marshalled and
  583. // the set has been done, the properties on the cache are no
  584. // longer valid. This method must be called to keep the property
  585. // cache in a coherrent state.
  586. // The method frees the 'dirty' entries, sets implicit get
  587. // flag. If the dirty entries cannot be cleared, then the
  588. // entire contents are flushed and they will be picked up at the
  589. // next GetInfo call -- AjayR
  590. //
  591. // Arguments: None.
  592. //
  593. //
  594. //-------------------------------------------------------------------------
  595. HRESULT CPropertyCache::ClearMarshalledProperties()
  596. {
  597. HRESULT hr = S_OK;
  598. DWORD dwIndx = 0;
  599. DWORD dwCtr = 0;
  600. DWORD dwChng = 0;
  601. PPROPERTY pNewProperties = NULL;
  602. PPROPERTY pThisProperty = NULL;
  603. PPROPERTY pNewCurProperty = NULL;
  604. DWORD dwNewProps = 0;
  605. //
  606. // Go through properties to see how many have changed
  607. //
  608. for (dwCtr = 0; dwCtr < _dwMaxProperties; dwCtr++ ) {
  609. pThisProperty = _pProperties + dwCtr;
  610. if (PROPERTY_FLAGS(pThisProperty) != PROPERTY_INIT)
  611. dwChng++;
  612. }
  613. if (dwChng == 0) {
  614. RRETURN(S_OK);
  615. }
  616. //
  617. // Need to remove those entries which were changed
  618. //
  619. dwNewProps = _dwMaxProperties - dwChng;
  620. if (dwNewProps != 0) {
  621. pNewProperties = (PPROPERTY) AllocADsMem(
  622. dwNewProps * sizeof(PROPERTY)
  623. );
  624. if (!pNewProperties) {
  625. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  626. // if this fails, then we cannot recover
  627. // effectively. What alternative is there ?
  628. // We do not want to flush the cache.
  629. }
  630. }
  631. for (dwCtr = 0, dwIndx = 0; dwCtr < _dwMaxProperties; dwCtr++ ) {
  632. pThisProperty = _pProperties + dwCtr;
  633. if (PROPERTY_FLAGS(pThisProperty) != PROPERTY_INIT) {
  634. //
  635. // delete the property
  636. //
  637. if (pThisProperty->szPropertyName) {
  638. FreeADsStr(pThisProperty->szPropertyName);
  639. pThisProperty->szPropertyName = NULL;
  640. }
  641. LdapTypeFreeLdapObjects(&(PROPERTY_LDAPOBJECTARRAY(pThisProperty)));
  642. } else {
  643. //
  644. // Sanity Check, should not hit this if Assert preferable
  645. //
  646. if (dwIndx > dwNewProps || dwIndx == dwNewProps) {
  647. BAIL_ON_FAILURE(hr = E_FAIL);
  648. }
  649. pNewCurProperty = pNewProperties + dwIndx;
  650. pNewCurProperty->szPropertyName = pThisProperty->szPropertyName;
  651. pNewCurProperty->ldapObjectArray =
  652. PROPERTY_LDAPOBJECTARRAY(pThisProperty);
  653. pNewCurProperty->dwFlags = pThisProperty->dwFlags;
  654. pNewCurProperty->dwSyntaxId = pThisProperty->dwSyntaxId;
  655. dwIndx++;
  656. }
  657. } // for, copying the old elements to new buffer
  658. _dwMaxProperties -= dwChng;
  659. _cb = dwNewProps * sizeof(PROPERTY);
  660. if (_pProperties)
  661. FreeADsMem(_pProperties);
  662. _pProperties = pNewProperties;
  663. // Need to set this flag to implicitly fetch properties
  664. // the next time somebody asks for a poperty not in the cache.
  665. _fGetInfoDone = FALSE;
  666. RRETURN(S_OK);
  667. error:
  668. if (pNewProperties) {
  669. FreeADsMem(pNewProperties);
  670. }
  671. RRETURN(hr);
  672. }
  673. //+------------------------------------------------------------------------
  674. //
  675. // Function: CPropertyCache::SetPropertyFlag
  676. //
  677. // Synopsis:
  678. //
  679. //
  680. //
  681. // Arguments:
  682. //
  683. //
  684. //-------------------------------------------------------------------------
  685. HRESULT CPropertyCache::SetPropertyFlag( LPWSTR szPropertyName, DWORD dwFlag )
  686. {
  687. PPROPERTY pThisProperty = NULL;
  688. HRESULT hr = S_OK;
  689. DWORD dwIndex;
  690. hr = findproperty(
  691. szPropertyName,
  692. &dwIndex
  693. );
  694. BAIL_ON_FAILURE(hr);
  695. pThisProperty = _pProperties + dwIndex;
  696. if (PROPERTY_LDAPOBJECTARRAY(pThisProperty).pLdapObjects) {
  697. PROPERTY_FLAGS(pThisProperty) = dwFlag;
  698. }
  699. error:
  700. RRETURN(hr);
  701. }
  702. //+------------------------------------------------------------------------
  703. //
  704. // Function: CPropertyCache::IsPropertyUpdated
  705. //
  706. // Synopsis:
  707. //
  708. //
  709. //
  710. // Arguments: [szPropertyName] --
  711. // [pdwIndex] --
  712. //
  713. //-------------------------------------------------------------------------
  714. HRESULT
  715. CPropertyCache::
  716. IsPropertyUpdated(
  717. LPWSTR szPropertyName,
  718. BOOL *pfUpdated
  719. )
  720. {
  721. PPROPERTY pThisProperty = NULL;
  722. HRESULT hr = S_OK;
  723. DWORD dwIndex;
  724. *pfUpdated = FALSE;
  725. hr = findproperty(
  726. szPropertyName,
  727. &dwIndex
  728. );
  729. BAIL_ON_FAILURE(hr);
  730. pThisProperty = _pProperties + dwIndex;
  731. if (PROPERTY_LDAPOBJECTARRAY(pThisProperty).pLdapObjects) {
  732. if ( PROPERTY_FLAGS(pThisProperty) == PROPERTY_UPDATE )
  733. *pfUpdated = TRUE;
  734. }
  735. error:
  736. RRETURN(hr);
  737. }
  738. //+------------------------------------------------------------------------
  739. //
  740. // Function: CPropertyCache::createpropertycache
  741. //
  742. // Synopsis:
  743. //
  744. //
  745. //
  746. // Arguments:
  747. //
  748. //
  749. //-------------------------------------------------------------------------
  750. HRESULT
  751. CPropertyCache::
  752. createpropertycache(
  753. CCoreADsObject *pCoreADsObject,
  754. IGetAttributeSyntax *pGetAttributeSyntax,
  755. CPropertyCache **ppPropertyCache
  756. )
  757. {
  758. CPropertyCache FAR * pPropertyCache = NULL;
  759. pPropertyCache = new CPropertyCache();
  760. if (!pPropertyCache) {
  761. RRETURN_EXP_IF_ERR(E_FAIL);
  762. }
  763. pPropertyCache->_pCoreADsObject = pCoreADsObject;
  764. pPropertyCache->_pGetAttributeSyntax = pGetAttributeSyntax;
  765. pPropertyCache->_fGetInfoDone = FALSE;
  766. *ppPropertyCache = pPropertyCache;
  767. RRETURN(S_OK);
  768. }
  769. HRESULT
  770. CPropertyCache::SetObjInformation(
  771. CCredentials* pCredentials,
  772. LPWSTR pszServerName,
  773. DWORD dwPortNo
  774. )
  775. {
  776. //
  777. // We need the credentials to be valid
  778. //
  779. if (!pCredentials) {
  780. ADsAssert(!"InvalidCredentials to prop cache");
  781. } else {
  782. _pCredentials = pCredentials;
  783. }
  784. //
  785. // This can be NULL, so it is better to allocate and dealloc
  786. // in destructor
  787. //
  788. if (_pszServerName) {
  789. FreeADsStr(_pszServerName);
  790. _pszServerName = NULL;
  791. }
  792. if (pszServerName) {
  793. _pszServerName = AllocADsStr(pszServerName);
  794. if (_pszServerName == NULL) {
  795. RRETURN(E_OUTOFMEMORY);
  796. }
  797. }
  798. _dwPort = dwPortNo;
  799. RRETURN(S_OK);
  800. }
  801. //+------------------------------------------------------------------------
  802. //
  803. // Function: CPropertyCache::flushpropertycache
  804. //
  805. // Synopsis: Flushes the property cache of all data.
  806. //
  807. // The name <-> index mappings need to stay until the property cache is
  808. // destructed, because the indexes are also used as the DISPIDs of the
  809. // properties. So this neither deallocates the names nor the array itself.
  810. //
  811. //-------------------------------------------------------------------------
  812. void
  813. CPropertyCache::
  814. flushpropertycache()
  815. {
  816. DWORD i = 0;
  817. PPROPERTY pThisProperty = NULL;
  818. if (_pProperties) {
  819. for (i = 0; i < _dwMaxProperties; i++) {
  820. pThisProperty = _pProperties + i;
  821. if (pThisProperty->szPropertyName) {
  822. FreeADsStr(pThisProperty->szPropertyName);
  823. pThisProperty->szPropertyName = NULL;
  824. }
  825. LdapTypeFreeLdapObjects(&(PROPERTY_LDAPOBJECTARRAY(pThisProperty)));
  826. PROPERTY_FLAGS(pThisProperty) = PROPERTY_INIT;
  827. }
  828. FreeADsMem(_pProperties);
  829. _pProperties = NULL;
  830. _dwMaxProperties = 0;
  831. _cb = 0;
  832. }
  833. //
  834. // Reset the property cache
  835. //
  836. _dwCurrentIndex = 0;
  837. _fGetInfoDone = FALSE;
  838. }
  839. //+------------------------------------------------------------------------
  840. //
  841. // Function: CPropertyCache::unmarshallproperty
  842. //
  843. // Synopsis:
  844. //
  845. //
  846. //
  847. // Arguments:
  848. //
  849. //
  850. //-------------------------------------------------------------------------
  851. HRESULT
  852. CPropertyCache::
  853. unmarshallproperty(
  854. LPWSTR szPropertyName,
  855. PADSLDP pLdapHandle,
  856. LDAPMessage *entry,
  857. DWORD dwSyntaxId,
  858. BOOL fExplicit,
  859. BOOL * pfRangeRetrieval // defaulted to NULL
  860. )
  861. {
  862. DWORD dwIndex = 0;
  863. HRESULT hr = S_OK;
  864. LDAPOBJECTARRAY ldapObjectArray;
  865. LPWSTR pszTemp = NULL;
  866. LDAPOBJECTARRAY_INIT(ldapObjectArray);
  867. //
  868. // If arg is valid default value to false.
  869. //
  870. if (pfRangeRetrieval) {
  871. *pfRangeRetrieval = FALSE;
  872. }
  873. hr = UnMarshallLDAPToLDAPSynID(
  874. szPropertyName,
  875. pLdapHandle,
  876. entry,
  877. dwSyntaxId,
  878. &ldapObjectArray
  879. );
  880. //
  881. // Need to look for ; as in members;range or value;binary
  882. // and strip the ; out before adding to cache.
  883. //
  884. if ((pszTemp = wcschr(szPropertyName, L';')) != NULL ) {
  885. *pszTemp = L'\0';
  886. }
  887. //
  888. // Find this property in the cache
  889. //
  890. hr = findproperty(
  891. szPropertyName,
  892. &dwIndex
  893. );
  894. //
  895. // If this property does not exist in the
  896. // cache, add this property into the cache.
  897. //
  898. if (FAILED(hr)) {
  899. hr = addproperty(
  900. szPropertyName
  901. );
  902. //
  903. // If the operation fails for some reason
  904. // move on to the next property
  905. //
  906. BAIL_ON_FAILURE(hr);
  907. }
  908. //
  909. // Now update the property in the cache
  910. //
  911. hr = updateproperty(
  912. szPropertyName,
  913. dwSyntaxId,
  914. ldapObjectArray,
  915. fExplicit
  916. );
  917. BAIL_ON_FAILURE(hr);
  918. //
  919. // Put the ; back if we replaced it.
  920. //
  921. if (pszTemp) {
  922. //
  923. // Do we need to update the flag ?
  924. //
  925. if (pfRangeRetrieval) {
  926. //
  927. // See if this was members and update flag.
  928. //
  929. if (!_wcsicmp(L"member", szPropertyName)) {
  930. *pfRangeRetrieval = TRUE;
  931. }
  932. }
  933. *pszTemp = L';';
  934. }
  935. if ( ldapObjectArray.fIsString )
  936. LdapValueFree( (TCHAR **) ldapObjectArray.pLdapObjects );
  937. else
  938. LdapValueFreeLen( (struct berval **) ldapObjectArray.pLdapObjects );
  939. error:
  940. RRETURN_EXP_IF_ERR(hr);
  941. }
  942. HRESULT
  943. CPropertyCache::
  944. LDAPUnMarshallProperties(
  945. LPWSTR pszServerPath,
  946. PADSLDP pLdapHandle,
  947. LDAPMessage *ldapmsg,
  948. BOOL fExplicit,
  949. CCredentials& Credentials
  950. )
  951. {
  952. int nNumberOfEntries = 0L;
  953. int nNumberOfValues = 0L;
  954. HRESULT hr = S_OK;
  955. DWORD i = 0;
  956. LDAPMessage *entry;
  957. LPWSTR pszAttrName = NULL;
  958. void *ptr;
  959. OBJECTINFO ObjectInfo;
  960. POBJECTINFO pObjectInfo = &ObjectInfo;
  961. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  962. //
  963. // Compute the number of attributes in the
  964. // read buffer.
  965. nNumberOfEntries = LdapCountEntries( pLdapHandle, ldapmsg );
  966. if ( nNumberOfEntries == 0 )
  967. RRETURN(S_OK);
  968. hr = LdapFirstEntry( pLdapHandle, ldapmsg, &entry );
  969. BAIL_ON_FAILURE(hr);
  970. hr = LdapFirstAttribute( pLdapHandle, entry, &ptr, &pszAttrName );
  971. BAIL_ON_FAILURE(hr);
  972. while ( pszAttrName != NULL )
  973. {
  974. DWORD dwSyntax = LDAPTYPE_UNKNOWN;
  975. LPWSTR pszADsPath;
  976. hr = _pCoreADsObject->get_CoreADsPath(&pszADsPath);
  977. BAIL_ON_FAILURE(hr);
  978. hr = ADsObject(pszADsPath, pObjectInfo);
  979. BAIL_ON_FAILURE(hr);
  980. //
  981. // unmarshall this property into the
  982. // property cache.
  983. // LdapGetSyntax takes care of ; while looking up
  984. // the schema no need to handle at this level.
  985. //
  986. hr = LdapGetSyntaxOfAttributeOnServer(
  987. pszServerPath,
  988. pszAttrName,
  989. &dwSyntax,
  990. Credentials,
  991. pObjectInfo->PortNumber,
  992. TRUE // fForce
  993. );
  994. ADsFreeString(pszADsPath);
  995. if ( SUCCEEDED(hr) && (dwSyntax != LDAPTYPE_UNKNOWN))
  996. {
  997. if ( (!_wcsicmp(pszAttrName, L"ntSecurityDescriptor")) &&
  998. (dwSyntax == LDAPTYPE_OCTETSTRING) )
  999. {
  1000. dwSyntax = LDAPTYPE_SECURITY_DESCRIPTOR;
  1001. }
  1002. (VOID) unmarshallproperty(
  1003. pszAttrName,
  1004. pLdapHandle,
  1005. entry,
  1006. dwSyntax,
  1007. fExplicit
  1008. );
  1009. }
  1010. LdapAttributeFree( pszAttrName );
  1011. pszAttrName = NULL;
  1012. //
  1013. // If we cannot find the syntax, ignore the property and
  1014. // continue with the next property
  1015. //
  1016. hr = S_OK;
  1017. hr = LdapNextAttribute( pLdapHandle, entry, ptr, &pszAttrName );
  1018. BAIL_ON_FAILURE(hr);
  1019. FreeObjectInfo(pObjectInfo);
  1020. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  1021. }
  1022. error:
  1023. FreeObjectInfo(pObjectInfo);
  1024. RRETURN_EXP_IF_ERR(hr);
  1025. }
  1026. ////////////////////////////////////////////////////////////////////////
  1027. //
  1028. // Unmarshall attributes (& their values) in [ldapmsg] into cache.
  1029. // Syntaxes of attributes are read from schema on server [pszServerPath].
  1030. // If an attribute not in the schema (e.g. not in our default schema used
  1031. // in case of schemaless server), the attribute is unmarshalled as ldap
  1032. // binary data with type = LDAPTYPE_UNKWNON.
  1033. //
  1034. // [Credentials]
  1035. // - used to access pszServerPath
  1036. //
  1037. // [pLdapHandle]
  1038. // - handle assoc with [ldapmsg]
  1039. // - used to retrive attributes and their values from [ldapmsg]
  1040. //
  1041. // [fExplicit]
  1042. // - overwrite value of exiting attributes in cache iff = TRUE
  1043. //
  1044. // NOTE: This function modified LDAPUnMarshallProperties to allow
  1045. // unmarshalling of attributes not in the schema.
  1046. //
  1047. ////////////////////////////////////////////////////////////////////////
  1048. HRESULT
  1049. CPropertyCache::
  1050. LDAPUnMarshallProperties2(
  1051. IN LPWSTR pszServerPath,
  1052. IN PADSLDP pLdapHandle,
  1053. IN LDAPMessage *ldapmsg,
  1054. IN BOOL fExplicit,
  1055. IN CCredentials& Credentials,
  1056. OUT BOOL * pfRangeRetrieval
  1057. )
  1058. {
  1059. HRESULT hr = S_OK;
  1060. int nNumberOfEntries = 0L;
  1061. LDAPMessage *entry = NULL;
  1062. void *ptr = NULL;
  1063. LPWSTR pszAttrName = NULL;
  1064. DWORD dwSyntax = LDAPTYPE_UNKNOWN;
  1065. LPWSTR pszADsPath = NULL;
  1066. OBJECTINFO ObjectInfo;
  1067. BOOL fRange = FALSE;
  1068. memset(&ObjectInfo, 0, sizeof(OBJECTINFO));
  1069. ADsAssert(pfRangeRetrieval);
  1070. *pfRangeRetrieval = FALSE;
  1071. if (!pLdapHandle || !ldapmsg)
  1072. RRETURN(E_ADS_BAD_PARAMETER);
  1073. //
  1074. // Compute the number of attributes in the read buffer.
  1075. //
  1076. nNumberOfEntries = LdapCountEntries(pLdapHandle, ldapmsg);
  1077. if ( nNumberOfEntries == 0 )
  1078. RRETURN(S_OK);
  1079. //
  1080. // get port number to talk to server on which schema locate ???
  1081. //
  1082. hr = _pCoreADsObject->get_CoreADsPath(&pszADsPath);
  1083. BAIL_ON_FAILURE(hr);
  1084. hr = ADsObject(pszADsPath, &ObjectInfo);
  1085. BAIL_ON_FAILURE(hr);
  1086. //
  1087. // Get first entry from ldapmsg first. Should be only one entry.
  1088. //
  1089. hr = LdapFirstEntry( pLdapHandle, ldapmsg, &entry );
  1090. BAIL_ON_FAILURE(hr);
  1091. //
  1092. // get first attribute's name
  1093. //
  1094. hr = LdapFirstAttribute( pLdapHandle, entry, &ptr, &pszAttrName );
  1095. BAIL_ON_FAILURE(hr);
  1096. while ( pszAttrName != NULL )
  1097. {
  1098. //
  1099. // get syntax of attribute from schema on sever (may be cached);
  1100. // continue to unmarshall the attribute even if it isn't in the
  1101. // schema.
  1102. //
  1103. dwSyntax = LDAPTYPE_UNKNOWN;
  1104. (VOID) LdapGetSyntaxOfAttributeOnServer(
  1105. pszServerPath,
  1106. pszAttrName,
  1107. &dwSyntax,
  1108. Credentials,
  1109. ObjectInfo.PortNumber,
  1110. TRUE // fForce
  1111. );
  1112. //
  1113. // There is currently no such syntax as "SecurityDescriptor" on
  1114. // server, ADSI will unmarshall "OctetString" security descriptor
  1115. // as as ntSecurityDescriptor
  1116. //
  1117. if ( (!_wcsicmp(pszAttrName, L"ntSecurityDescriptor"))
  1118. && (dwSyntax == LDAPTYPE_OCTETSTRING)
  1119. )
  1120. {
  1121. dwSyntax = LDAPTYPE_SECURITY_DESCRIPTOR;
  1122. }
  1123. //
  1124. // unmarshall the property into cache, LDAPTYPE_UNWKNOWN
  1125. // (dwSyntax) will be unmarshalled as binary data.
  1126. //
  1127. (VOID) unmarshallproperty(
  1128. pszAttrName,
  1129. pLdapHandle,
  1130. entry,
  1131. dwSyntax,
  1132. fExplicit,
  1133. fRange ? NULL : pfRangeRetrieval
  1134. );
  1135. //
  1136. // Small trick to make sure we do not loose the range
  1137. // retrieval information for members attribute.
  1138. //
  1139. fRange = *pfRangeRetrieval;
  1140. //
  1141. // get next attribute
  1142. //
  1143. LdapAttributeFree( pszAttrName );
  1144. pszAttrName = NULL;
  1145. hr = LdapNextAttribute( pLdapHandle, entry, ptr, &pszAttrName );
  1146. BAIL_ON_FAILURE(hr);
  1147. }
  1148. error:
  1149. if (pszADsPath)
  1150. ADsFreeString(pszADsPath);
  1151. FreeObjectInfo(&ObjectInfo);
  1152. RRETURN_EXP_IF_ERR(hr);
  1153. }
  1154. HRESULT
  1155. CPropertyCache::
  1156. LDAPMarshallProperties(
  1157. LDAPModW ***aMods,
  1158. PBOOL pfNTSecDes,
  1159. SECURITY_INFORMATION *pSeInfo
  1160. )
  1161. {
  1162. HRESULT hr = S_OK;
  1163. DWORD i = 0;
  1164. DWORD j = 0;
  1165. PPROPERTY pThisProperty = NULL;
  1166. int dwCount = 0;
  1167. LDAPModW *aModsBuffer = NULL;
  1168. LDAPOBJECTARRAY ldapObjectArray;
  1169. PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
  1170. BOOL fDaclDefaulted = FALSE;
  1171. BOOL fSaclDefaulted = FALSE;
  1172. BOOL fOwnerDefaulted = FALSE;
  1173. BOOL fGroupDefaulted = FALSE;
  1174. PSID pOwnerSid = NULL;
  1175. PSID pGroupSid = NULL;
  1176. PACL pDacl = NULL;
  1177. PACL pSacl = NULL;
  1178. BOOL DaclPresent = FALSE;
  1179. BOOL SaclPresent = FALSE;
  1180. BOOL fSecDesProp = FALSE;
  1181. *pSeInfo = INVALID_SE_VALUE;
  1182. *pfNTSecDes = FALSE;
  1183. for (i = 0; i < _dwMaxProperties ; i++) {
  1184. pThisProperty = _pProperties + i;
  1185. //
  1186. // Bypass any property that has not been
  1187. // modified
  1188. //
  1189. if (PROPERTY_FLAGS(pThisProperty) != PROPERTY_INIT)
  1190. dwCount++;
  1191. }
  1192. if ( dwCount == 0 ) // Nothing to change
  1193. {
  1194. *aMods = NULL;
  1195. RRETURN(S_OK);
  1196. }
  1197. *aMods = (LDAPModW **) AllocADsMem((dwCount+1) * sizeof(LDAPModW *));
  1198. if ( *aMods == NULL )
  1199. {
  1200. hr = E_OUTOFMEMORY;
  1201. BAIL_ON_FAILURE(hr);
  1202. }
  1203. aModsBuffer = (LDAPModW *) AllocADsMem( dwCount * sizeof(LDAPModW));
  1204. if ( aModsBuffer == NULL )
  1205. {
  1206. hr = E_OUTOFMEMORY;
  1207. BAIL_ON_FAILURE(hr);
  1208. }
  1209. for (i = 0, j = 0; i < _dwMaxProperties; i++) {
  1210. pThisProperty = _pProperties + i;
  1211. //
  1212. // Bypass any property that has not been
  1213. // modified
  1214. //
  1215. if (PROPERTY_FLAGS(pThisProperty) == PROPERTY_INIT ) {
  1216. continue;
  1217. }
  1218. if (!_wcsicmp(PROPERTY_NAME(pThisProperty),L"ntSecurityDescriptor")) {
  1219. *pfNTSecDes = TRUE;
  1220. fSecDesProp = TRUE;
  1221. } else {
  1222. fSecDesProp = FALSE;
  1223. }
  1224. ldapObjectArray = PROPERTY_LDAPOBJECTARRAY(pThisProperty);
  1225. (*aMods)[j] = &aModsBuffer[j];
  1226. aModsBuffer[j].mod_type = PROPERTY_NAME(pThisProperty);
  1227. if ( ldapObjectArray.fIsString )
  1228. {
  1229. aModsBuffer[j].mod_values = (TCHAR **) ldapObjectArray.pLdapObjects;
  1230. }
  1231. else
  1232. {
  1233. aModsBuffer[j].mod_bvalues = (struct berval **) ldapObjectArray.pLdapObjects;
  1234. aModsBuffer[j].mod_op = LDAP_MOD_BVALUES;
  1235. if (fSecDesProp) {
  1236. pSecurityDescriptor = LDAPOBJECT_BERVAL_VAL(ldapObjectArray.pLdapObjects);
  1237. if ( GetSecurityDescriptorOwner(
  1238. pSecurityDescriptor,
  1239. &pOwnerSid,
  1240. &fOwnerDefaulted
  1241. )
  1242. &&
  1243. GetSecurityDescriptorGroup(
  1244. pSecurityDescriptor,
  1245. &pGroupSid,
  1246. &fGroupDefaulted
  1247. )
  1248. &&
  1249. GetSecurityDescriptorDacl(
  1250. pSecurityDescriptor,
  1251. &DaclPresent,
  1252. &pDacl,
  1253. &fDaclDefaulted
  1254. )
  1255. &&
  1256. GetSecurityDescriptorSacl(
  1257. pSecurityDescriptor,
  1258. &SaclPresent,
  1259. &pSacl,
  1260. &fSaclDefaulted
  1261. )
  1262. ) {
  1263. //
  1264. // All the calls succeeded, so we should reset to 0
  1265. // instead of the invalid value.
  1266. //
  1267. *pSeInfo = 0;
  1268. if (!fOwnerDefaulted) {
  1269. *pSeInfo = *pSeInfo | OWNER_SECURITY_INFORMATION;
  1270. }
  1271. if (!fGroupDefaulted) {
  1272. *pSeInfo = *pSeInfo | GROUP_SECURITY_INFORMATION;
  1273. }
  1274. //
  1275. // If the DACL is present we need to send DACL bit.
  1276. //
  1277. if (DaclPresent) {
  1278. *pSeInfo = *pSeInfo | DACL_SECURITY_INFORMATION;
  1279. }
  1280. //
  1281. // If SACL present then we set the SACL bit.
  1282. if (SaclPresent) {
  1283. *pSeInfo = *pSeInfo | SACL_SECURITY_INFORMATION;
  1284. }
  1285. }
  1286. }
  1287. }
  1288. switch( PROPERTY_FLAGS(pThisProperty))
  1289. {
  1290. case PROPERTY_UPDATE:
  1291. aModsBuffer[j].mod_op |= LDAP_MOD_REPLACE;
  1292. break;
  1293. case PROPERTY_ADD:
  1294. aModsBuffer[j].mod_op |= LDAP_MOD_ADD;
  1295. break;
  1296. case PROPERTY_DELETE:
  1297. aModsBuffer[j].mod_op |= LDAP_MOD_DELETE;
  1298. break;
  1299. case PROPERTY_DELETE_VALUE:
  1300. aModsBuffer[j].mod_op |= LDAP_MOD_DELETE;
  1301. break;
  1302. }
  1303. j++;
  1304. }
  1305. RRETURN(hr);
  1306. error:
  1307. FreeADsMem( aModsBuffer );
  1308. FreeADsMem( *aMods );
  1309. RRETURN_EXP_IF_ERR(hr);
  1310. }
  1311. HRESULT
  1312. CPropertyCache::
  1313. LDAPMarshallProperties2(
  1314. LDAPModW ***aMods,
  1315. DWORD *pdwNumOfMods
  1316. )
  1317. {
  1318. HRESULT hr = S_OK;
  1319. DWORD i = 0;
  1320. DWORD j = 0;
  1321. PPROPERTY pThisProperty = NULL;
  1322. int dwCount = 0;
  1323. LDAPModW *aModsBuffer = NULL;
  1324. LDAPOBJECTARRAY ldapObjectArray;
  1325. for (i = 0; i < _dwMaxProperties ; i++) {
  1326. pThisProperty = _pProperties + i;
  1327. //
  1328. // Bypass any property that has not been
  1329. // modified
  1330. //
  1331. if (PROPERTY_FLAGS(pThisProperty) != PROPERTY_INIT)
  1332. dwCount++;
  1333. }
  1334. if ( dwCount == 0 ) // Nothing to change
  1335. RRETURN(S_OK);
  1336. if ( *aMods == NULL )
  1337. {
  1338. *aMods = (LDAPModW **) AllocADsMem((dwCount+1) * sizeof(LDAPModW *));
  1339. if ( *aMods == NULL )
  1340. {
  1341. hr = E_OUTOFMEMORY;
  1342. BAIL_ON_FAILURE(hr);
  1343. }
  1344. aModsBuffer = (LDAPModW *) AllocADsMem( dwCount * sizeof(LDAPModW));
  1345. if ( aModsBuffer == NULL )
  1346. {
  1347. FreeADsMem( *aMods );
  1348. *aMods = NULL;
  1349. hr = E_OUTOFMEMORY;
  1350. BAIL_ON_FAILURE(hr);
  1351. }
  1352. }
  1353. else
  1354. {
  1355. LDAPModW **aModsTemp = NULL;
  1356. aModsTemp = (LDAPModW **) AllocADsMem(
  1357. (*pdwNumOfMods+ dwCount + 1) * sizeof(LDAPModW *));
  1358. if ( aModsTemp == NULL )
  1359. {
  1360. hr = E_OUTOFMEMORY;
  1361. BAIL_ON_FAILURE(hr);
  1362. }
  1363. aModsBuffer = (LDAPModW *) AllocADsMem(
  1364. (*pdwNumOfMods + dwCount) * sizeof(LDAPModW));
  1365. if ( aModsBuffer == NULL )
  1366. {
  1367. FreeADsMem( aModsTemp );
  1368. hr = E_OUTOFMEMORY;
  1369. BAIL_ON_FAILURE(hr);
  1370. }
  1371. memcpy( aModsBuffer, **aMods, *pdwNumOfMods * sizeof(LDAPModW));
  1372. FreeADsMem( **aMods );
  1373. FreeADsMem( *aMods );
  1374. *aMods = aModsTemp;
  1375. for ( j = 0; j < *pdwNumOfMods; j++ )
  1376. {
  1377. (*aMods)[j] = &aModsBuffer[j];
  1378. }
  1379. }
  1380. for (i = 0; i < _dwMaxProperties; i++) {
  1381. pThisProperty = _pProperties + i;
  1382. //
  1383. // Bypass any property that has not been
  1384. // modified
  1385. //
  1386. if (PROPERTY_FLAGS(pThisProperty) == PROPERTY_INIT ) {
  1387. continue;
  1388. }
  1389. ldapObjectArray = PROPERTY_LDAPOBJECTARRAY(pThisProperty);
  1390. (*aMods)[j] = &aModsBuffer[j];
  1391. aModsBuffer[j].mod_type = PROPERTY_NAME(pThisProperty);
  1392. if ( ldapObjectArray.fIsString )
  1393. {
  1394. aModsBuffer[j].mod_values = (TCHAR **) ldapObjectArray.pLdapObjects;
  1395. }
  1396. else
  1397. {
  1398. aModsBuffer[j].mod_bvalues = (struct berval **) ldapObjectArray.pLdapObjects;
  1399. aModsBuffer[j].mod_op = LDAP_MOD_BVALUES;
  1400. }
  1401. switch( PROPERTY_FLAGS(pThisProperty))
  1402. {
  1403. case PROPERTY_UPDATE:
  1404. aModsBuffer[j].mod_op |= LDAP_MOD_REPLACE;
  1405. break;
  1406. case PROPERTY_ADD:
  1407. aModsBuffer[j].mod_op |= LDAP_MOD_ADD;
  1408. break;
  1409. case PROPERTY_DELETE:
  1410. aModsBuffer[j].mod_op |= LDAP_MOD_DELETE;
  1411. break;
  1412. }
  1413. j++;
  1414. }
  1415. *pdwNumOfMods += dwCount;
  1416. error:
  1417. RRETURN_EXP_IF_ERR(hr);
  1418. }
  1419. //+------------------------------------------------------------------------
  1420. //
  1421. // Function: CPropertyCache::unboundgetproperty
  1422. //
  1423. // Synopsis:
  1424. //
  1425. //
  1426. //
  1427. // Arguments: [szPropertyName] -- Property to retrieve from the cache
  1428. // [pvaData] -- Data returned in a variant
  1429. //
  1430. //-------------------------------------------------------------------------
  1431. HRESULT
  1432. CPropertyCache::
  1433. unboundgetproperty(
  1434. LPWSTR szPropertyName,
  1435. PDWORD pdwSyntaxId,
  1436. PDWORD pdwStatusFlag,
  1437. LDAPOBJECTARRAY *pLdapObjectArray
  1438. )
  1439. {
  1440. HRESULT hr;
  1441. DWORD dwIndex = 0L;
  1442. //
  1443. // get index of property in cache
  1444. //
  1445. hr = findproperty(
  1446. szPropertyName,
  1447. &dwIndex
  1448. );
  1449. BAIL_ON_FAILURE(hr);
  1450. //
  1451. // get property based on index in cache
  1452. //
  1453. hr = unboundgetproperty(
  1454. dwIndex,
  1455. pdwSyntaxId,
  1456. pdwStatusFlag,
  1457. pLdapObjectArray
  1458. );
  1459. error:
  1460. RRETURN_EXP_IF_ERR(hr);
  1461. }
  1462. //+------------------------------------------------------------------------
  1463. //
  1464. // Function: CPropertyCache::unboundgetproperty
  1465. //
  1466. // Synopsis: Note that this version takes the index of the element to
  1467. // fetch. It also returns the control code of the item in the cache.
  1468. //
  1469. //
  1470. // Arguments: [dwIndex] -- Index of the property to retrieve.
  1471. // [pdwSytnaxId] -- SyntaxId of the data.
  1472. // [pdwStatusFlag] -- Status of this property in cache.
  1473. // [pLdapObjectArray] -- Array of ldapObjects returned.
  1474. //
  1475. // NOTE: [dwIndex] is invalid -> E_ADS_PROPERTY_NOT_FOUND//E_FAIL ???
  1476. //
  1477. //-------------------------------------------------------------------------
  1478. HRESULT
  1479. CPropertyCache::
  1480. unboundgetproperty(
  1481. DWORD dwIndex,
  1482. PDWORD pdwSyntaxId,
  1483. PDWORD pdwStatusFlag,
  1484. LDAPOBJECTARRAY *pLdapObjectArray
  1485. )
  1486. {
  1487. HRESULT hr = S_OK;
  1488. PPROPERTY pThisProperty = NULL;
  1489. if (!index_valid(dwIndex))
  1490. RRETURN(E_ADS_PROPERTY_NOT_FOUND);
  1491. pThisProperty = _pProperties + dwIndex;
  1492. // Status flag has to be valid if we found the property
  1493. *pdwStatusFlag = PROPERTY_FLAGS(pThisProperty);
  1494. if (PROPERTY_LDAPOBJECTARRAY(pThisProperty).pLdapObjects) {
  1495. //
  1496. // property has non-empty values
  1497. //
  1498. *pdwSyntaxId = (DWORD)PROPERTY_SYNTAX(pThisProperty);
  1499. hr = LdapTypeCopyConstruct(
  1500. PROPERTY_LDAPOBJECTARRAY(pThisProperty),
  1501. pLdapObjectArray
  1502. );
  1503. BAIL_ON_FAILURE(hr);
  1504. }else {
  1505. //
  1506. // property has empty values: E.g. status flag indicate delete
  1507. // operation (or empty values allowed on non-ntds ldap server?)
  1508. //
  1509. pLdapObjectArray->pLdapObjects = NULL;
  1510. pLdapObjectArray->dwCount = 0;
  1511. *pdwSyntaxId = LDAPTYPE_UNKNOWN;
  1512. //hr = E_FAIL;
  1513. }
  1514. error:
  1515. RRETURN(hr);
  1516. }
  1517. void
  1518. CPropertyCache::
  1519. reset_propindex(
  1520. )
  1521. {
  1522. _dwCurrentIndex = 0;
  1523. }
  1524. HRESULT
  1525. CPropertyCache::
  1526. skip_propindex(
  1527. DWORD dwElements
  1528. )
  1529. {
  1530. DWORD newIndex = _dwCurrentIndex + dwElements;
  1531. if (!index_valid())
  1532. RRETURN_EXP_IF_ERR(E_FAIL);
  1533. //
  1534. // - allow current index to go from within range to out of range by 1
  1535. // - by 1 since initial state is out of range by 1
  1536. //
  1537. if ( newIndex > _dwMaxProperties )
  1538. RRETURN_EXP_IF_ERR(E_FAIL);
  1539. _dwCurrentIndex = newIndex;
  1540. RRETURN(S_OK);
  1541. }
  1542. HRESULT
  1543. CPropertyCache::
  1544. get_PropertyCount(
  1545. PDWORD pdwMaxProperties
  1546. )
  1547. {
  1548. ADsAssert(pdwMaxProperties); // function private -> use assertion
  1549. *pdwMaxProperties = _dwMaxProperties;
  1550. RRETURN(S_OK);
  1551. }
  1552. DWORD
  1553. CPropertyCache::
  1554. get_CurrentIndex(
  1555. )
  1556. {
  1557. return(_dwCurrentIndex);
  1558. }
  1559. LPWSTR
  1560. CPropertyCache::
  1561. get_CurrentPropName(
  1562. )
  1563. {
  1564. PPROPERTY pThisProperty = NULL;
  1565. if (!index_valid())
  1566. return(NULL);
  1567. pThisProperty = _pProperties + _dwCurrentIndex;
  1568. return(PROPERTY_NAME(pThisProperty));
  1569. }
  1570. LPWSTR
  1571. CPropertyCache::
  1572. get_PropName(
  1573. DWORD dwIndex
  1574. )
  1575. {
  1576. PPROPERTY pThisProperty = NULL;
  1577. if (!index_valid(dwIndex))
  1578. return(NULL);
  1579. pThisProperty = _pProperties + dwIndex;
  1580. return(PROPERTY_NAME(pThisProperty));
  1581. }
  1582. HRESULT
  1583. CPropertyCache::
  1584. LDAPUnMarshallPropertyAs(
  1585. LPWSTR pszServerPath,
  1586. PADSLDP pLdapHandle,
  1587. LDAPMessage *ldapmsg,
  1588. LPWSTR szPropertyName,
  1589. DWORD dwSyntaxId,
  1590. BOOL fExplicit,
  1591. CCredentials& Credentials
  1592. )
  1593. {
  1594. int nNumberOfEntries = 0L;
  1595. int nNumberOfValues = 0L;
  1596. HRESULT hr = S_OK;
  1597. DWORD i = 0;
  1598. LDAPMessage *entry;
  1599. LPWSTR pszAttrName = NULL;
  1600. void *ptr;
  1601. OBJECTINFO ObjectInfo;
  1602. POBJECTINFO pObjectInfo = &ObjectInfo;
  1603. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  1604. //
  1605. // Compute the number of attributes in the
  1606. // read buffer.
  1607. //
  1608. nNumberOfEntries = LdapCountEntries( pLdapHandle, ldapmsg );
  1609. if ( nNumberOfEntries == 0 )
  1610. RRETURN(S_OK);
  1611. hr = LdapFirstEntry( pLdapHandle, ldapmsg, &entry );
  1612. BAIL_ON_FAILURE(hr);
  1613. hr = LdapFirstAttribute( pLdapHandle, entry, &ptr, &pszAttrName );
  1614. BAIL_ON_FAILURE(hr);
  1615. while ( pszAttrName != NULL )
  1616. {
  1617. DWORD dwSyntax = LDAPTYPE_UNKNOWN;
  1618. LPWSTR pszADsPath;
  1619. hr = _pCoreADsObject->get_CoreADsPath(&pszADsPath);
  1620. BAIL_ON_FAILURE(hr);
  1621. hr = ADsObject(pszADsPath, pObjectInfo);
  1622. BAIL_ON_FAILURE(hr);
  1623. //
  1624. // unmarshall this property into the
  1625. // property cache
  1626. //
  1627. hr = LdapGetSyntaxOfAttributeOnServer(
  1628. pszServerPath,
  1629. pszAttrName,
  1630. &dwSyntax,
  1631. Credentials,
  1632. pObjectInfo->PortNumber
  1633. );
  1634. ADsFreeString(pszADsPath);
  1635. if ( SUCCEEDED(hr) && (dwSyntax != LDAPTYPE_UNKNOWN))
  1636. {
  1637. if ( (!_wcsicmp(pszAttrName, L"ntSecurityDescriptor")) &&
  1638. (dwSyntax == LDAPTYPE_OCTETSTRING) )
  1639. {
  1640. dwSyntax = LDAPTYPE_SECURITY_DESCRIPTOR;
  1641. }
  1642. (VOID) unmarshallproperty(
  1643. pszAttrName,
  1644. pLdapHandle,
  1645. entry,
  1646. dwSyntax,
  1647. fExplicit
  1648. );
  1649. }else {
  1650. if (!_wcsicmp(pszAttrName, szPropertyName)) {
  1651. (VOID) unmarshallproperty(
  1652. pszAttrName,
  1653. pLdapHandle,
  1654. entry,
  1655. dwSyntaxId,
  1656. fExplicit
  1657. );
  1658. }
  1659. }
  1660. LdapAttributeFree( pszAttrName );
  1661. pszAttrName = NULL;
  1662. //
  1663. // If we cannot find the syntax, ignore the property and
  1664. // continue with the next property
  1665. //
  1666. hr = S_OK;
  1667. hr = LdapNextAttribute( pLdapHandle, entry, ptr, &pszAttrName );
  1668. BAIL_ON_FAILURE(hr);
  1669. FreeObjectInfo(pObjectInfo);
  1670. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  1671. }
  1672. error:
  1673. FreeObjectInfo(pObjectInfo);
  1674. RRETURN_EXP_IF_ERR(hr);
  1675. }
  1676. HRESULT
  1677. CPropertyCache::
  1678. LDAPUnMarshallPropertiesAs(
  1679. LPWSTR pszServerPath,
  1680. PADSLDP pLdapHandle,
  1681. LDAPMessage *ldapmsg,
  1682. DWORD dwSyntaxId,
  1683. BOOL fExplicit,
  1684. CCredentials& Credentials
  1685. )
  1686. {
  1687. int nNumberOfEntries = 0L;
  1688. int nNumberOfValues = 0L;
  1689. HRESULT hr = S_OK;
  1690. DWORD i = 0;
  1691. LDAPMessage *entry;
  1692. LPWSTR pszAttrName = NULL;
  1693. void *ptr;
  1694. //
  1695. // Compute the number of attributes in the
  1696. // read buffer.
  1697. //
  1698. nNumberOfEntries = LdapCountEntries( pLdapHandle, ldapmsg );
  1699. if ( nNumberOfEntries == 0 )
  1700. RRETURN(S_OK);
  1701. hr = LdapFirstEntry( pLdapHandle, ldapmsg, &entry );
  1702. BAIL_ON_FAILURE(hr);
  1703. hr = LdapFirstAttribute( pLdapHandle, entry, &ptr, &pszAttrName );
  1704. BAIL_ON_FAILURE(hr);
  1705. while ( pszAttrName != NULL )
  1706. {
  1707. (VOID) unmarshallproperty(
  1708. pszAttrName,
  1709. pLdapHandle,
  1710. entry,
  1711. dwSyntaxId,
  1712. fExplicit
  1713. );
  1714. LdapAttributeFree( pszAttrName );
  1715. pszAttrName = NULL;
  1716. hr = LdapNextAttribute( pLdapHandle, entry, ptr, &pszAttrName );
  1717. BAIL_ON_FAILURE(hr);
  1718. }
  1719. error:
  1720. RRETURN_EXP_IF_ERR(hr);
  1721. }
  1722. HRESULT
  1723. CPropertyCache::
  1724. deleteproperty(
  1725. DWORD dwIndex
  1726. )
  1727. {
  1728. HRESULT hr = S_OK;
  1729. PPROPERTY pNewProperties = NULL;
  1730. PPROPERTY pThisProperty = _pProperties + dwIndex;
  1731. if (!index_valid(dwIndex)) {
  1732. hr = E_FAIL;
  1733. BAIL_ON_FAILURE(hr);
  1734. }
  1735. if (_dwMaxProperties == 1) {
  1736. //
  1737. // Deleting everything
  1738. //
  1739. FreeADsStr(pThisProperty->szPropertyName);
  1740. LdapTypeFreeLdapObjects( &(PROPERTY_LDAPOBJECTARRAY(pThisProperty)) );
  1741. FreeADsMem(_pProperties);
  1742. _pProperties = NULL;
  1743. _dwMaxProperties = 0;
  1744. _cb = 0;
  1745. //
  1746. // Need to reset the current index too just in case.
  1747. //
  1748. _dwCurrentIndex = 0;
  1749. RRETURN(hr);
  1750. }
  1751. pNewProperties = (PPROPERTY)AllocADsMem(
  1752. _cb - sizeof(PROPERTY)
  1753. );
  1754. if (!pNewProperties) {
  1755. hr = E_OUTOFMEMORY;
  1756. BAIL_ON_FAILURE(hr);
  1757. }
  1758. //
  1759. // Copying the memory before the deleted item
  1760. //
  1761. if (dwIndex != 0) {
  1762. memcpy( pNewProperties,
  1763. _pProperties,
  1764. dwIndex * sizeof(PROPERTY));
  1765. }
  1766. //
  1767. // Copying the memory following the deleted item
  1768. //
  1769. if (dwIndex != (_dwMaxProperties-1)) {
  1770. memcpy( pNewProperties + dwIndex,
  1771. _pProperties + dwIndex + 1,
  1772. (_dwMaxProperties - dwIndex - 1) * sizeof(PROPERTY));
  1773. }
  1774. FreeADsStr(pThisProperty->szPropertyName);
  1775. LdapTypeFreeLdapObjects( &(PROPERTY_LDAPOBJECTARRAY(pThisProperty)) );
  1776. FreeADsMem(_pProperties);
  1777. _pProperties = pNewProperties;
  1778. _dwMaxProperties--;
  1779. _cb -= sizeof(PROPERTY);
  1780. //
  1781. // Reset the current index if necesary so we do not skip a property.
  1782. //
  1783. if (_dwCurrentIndex > dwIndex) {
  1784. _dwCurrentIndex--;
  1785. }
  1786. error:
  1787. RRETURN_EXP_IF_ERR(hr);
  1788. }
  1789. //
  1790. // For dynamic dispid's.
  1791. //
  1792. //+------------------------------------------------------------------------
  1793. //
  1794. // Function: CPropertyCache::locateproperty
  1795. //
  1796. // Synopsis: Finds a property in the cache by name.
  1797. //
  1798. // This differs from findproperty() in return code; this returns no ADSI
  1799. // errors, since it's going to a VB interface.
  1800. //
  1801. // If the property is not found in the cache, this uses the IDirectoryObject
  1802. // interface of the containing object to get the attributes of the object.
  1803. // If GetObjectAttributes doesn't return any information about the property,
  1804. // this method returns DISP_E_UNKNOWNNAME.
  1805. //
  1806. // Arguments: [szPropertyName] -- Name of the property.
  1807. // [pdwIndex] -- Index in the array of properties.
  1808. //
  1809. //-------------------------------------------------------------------------
  1810. HRESULT
  1811. CPropertyCache::locateproperty(
  1812. LPWSTR szPropertyName,
  1813. PDWORD pdwIndex
  1814. )
  1815. {
  1816. HRESULT hr = findproperty(szPropertyName, pdwIndex);
  1817. if (hr == E_ADS_PROPERTY_NOT_FOUND)
  1818. {
  1819. DWORD dwLdapSyntaxId = 0;
  1820. PPROPERTY pProperty = NULL;
  1821. hr = _pGetAttributeSyntax->GetAttributeSyntax(
  1822. szPropertyName,
  1823. &dwLdapSyntaxId
  1824. );
  1825. BAIL_ON_FAILURE(hr);
  1826. hr = addproperty(szPropertyName);
  1827. BAIL_ON_FAILURE(hr);
  1828. hr = findproperty(szPropertyName, pdwIndex);
  1829. BAIL_ON_FAILURE(hr);
  1830. pProperty = _pProperties + *pdwIndex;
  1831. PROPERTY_SYNTAX(pProperty) = dwLdapSyntaxId;
  1832. PROPERTY_FLAGS(pProperty) = PROPERTY_INIT;
  1833. PROPERTY_LDAPOBJECTARRAY(pProperty).dwCount = 0;
  1834. PROPERTY_LDAPOBJECTARRAY(pProperty).pLdapObjects = NULL;
  1835. }
  1836. error:
  1837. //
  1838. // Automation return code would be DISP_E_UNKNOWNNAME.
  1839. // ADSI return code would be E_ADS_PROPERTY_NOT_FOUND (like findproperty.)
  1840. //
  1841. if (FAILED(hr))
  1842. hr = E_ADS_PROPERTY_NOT_FOUND;
  1843. RRETURN(hr);
  1844. }
  1845. //+------------------------------------------------------------------------
  1846. //
  1847. // Function: CPropertyCache::getproperty
  1848. //
  1849. // Synopsis: Get the values of a property from the cache.
  1850. // The values are returned as a VARIANT.
  1851. //
  1852. // Arguments: [dwIndex] -- Index of property to retrieve
  1853. // [pVarResult] -- Data returned as a VARIANT
  1854. //
  1855. //-------------------------------------------------------------------------
  1856. HRESULT
  1857. CPropertyCache::getproperty(
  1858. DWORD dwIndex,
  1859. PDWORD dwStatusFlag,
  1860. VARIANT *pVarResult,
  1861. CCredentials &Credentials
  1862. )
  1863. {
  1864. HRESULT hr = S_OK;
  1865. DWORD dwSyntaxId;
  1866. LDAPOBJECTARRAY LdapObjectArray;
  1867. LDAPOBJECTARRAY_INIT(LdapObjectArray);
  1868. //
  1869. // This should not return E_ADS_PROPERTY_NOT_FOUND in this case.
  1870. // We have an index, which should indicate that we have an array entry.
  1871. // If we weren't dealing with VB, I'd be tempted to make this an Assert.
  1872. //
  1873. if (!index_valid(dwIndex))
  1874. BAIL_ON_FAILURE(hr = DISP_E_MEMBERNOTFOUND);
  1875. if (INDEX_EMPTY(dwIndex) &&
  1876. !PROP_DELETED(dwIndex) &&
  1877. !_fGetInfoDone)
  1878. {
  1879. hr = _pCoreADsObject->GetInfo(FALSE);
  1880. // workaround to avoid confusing callers of getproperty.
  1881. if (hr == E_NOTIMPL)
  1882. hr = DISP_E_MEMBERNOTFOUND;
  1883. BAIL_ON_FAILURE(hr);
  1884. }
  1885. hr = unboundgetproperty(
  1886. dwIndex,
  1887. &dwSyntaxId,
  1888. dwStatusFlag,
  1889. &LdapObjectArray
  1890. );
  1891. // For backward compatibility
  1892. if (!LdapObjectArray.pLdapObjects && SUCCEEDED(hr)) {
  1893. hr = E_FAIL;
  1894. }
  1895. if (SUCCEEDED(hr))
  1896. {
  1897. if (LdapObjectArray.dwCount == 1) {
  1898. hr = LdapTypeToVarTypeCopy(
  1899. NULL,
  1900. Credentials,
  1901. LdapObjectArray.pLdapObjects,
  1902. dwSyntaxId,
  1903. pVarResult);
  1904. }
  1905. else {
  1906. hr = LdapTypeToVarTypeCopyConstruct(
  1907. NULL,
  1908. Credentials,
  1909. LdapObjectArray,
  1910. dwSyntaxId,
  1911. pVarResult);
  1912. }
  1913. }
  1914. else
  1915. {
  1916. //
  1917. // unboundgetproperty() returns E_FAIL on failure.
  1918. // But getproperty() should return E_ADS_PROPERTY_NOT_FOUND.
  1919. //
  1920. if (hr == E_FAIL)
  1921. hr = E_ADS_PROPERTY_NOT_FOUND;
  1922. //
  1923. // A proper Automation return value would be
  1924. // hr = DISP_E_MEMBERNOTFOUND;
  1925. //
  1926. ADsAssert(pVarResult);
  1927. V_VT(pVarResult) = VT_ERROR;
  1928. }
  1929. error:
  1930. LdapTypeFreeLdapObjects(&LdapObjectArray);
  1931. RRETURN(hr);
  1932. }
  1933. //
  1934. //
  1935. // This is here just so that we can compile, no one should be
  1936. // calling this
  1937. //
  1938. // - The comment above and within the function is INCORRECT.
  1939. // - At present, this function is called and works with known bug.
  1940. // This function should NOT be a wrap around of getproperty with
  1941. // 3 param. The [dwIndex] in this function should have a DIFFERENT
  1942. // meaning than the index in the cache.
  1943. // - Please LEAVE this for irenef to fix before beta2.
  1944. //
  1945. HRESULT
  1946. CPropertyCache::getproperty(
  1947. DWORD dwIndex,
  1948. VARIANT *pVarResult,
  1949. CCredentials &Credentials
  1950. )
  1951. {
  1952. HRESULT hr = S_OK;
  1953. DWORD dwStatus = 0;
  1954. // Ideally we need to get rid of this but this would mean that
  1955. // we need to change the cdispmgr code and the IPropertyCache
  1956. // interface.
  1957. hr = getproperty(
  1958. dwIndex,
  1959. &dwStatus,
  1960. pVarResult,
  1961. Credentials
  1962. );
  1963. if (hr == E_ADS_PROPERTY_NOT_FOUND)
  1964. {
  1965. hr = DISP_E_MEMBERNOTFOUND;
  1966. }
  1967. RRETURN(hr);
  1968. }
  1969. //+------------------------------------------------------------------------
  1970. //
  1971. // Function: CPropertyCache::putproperty
  1972. //
  1973. // Synopsis: Updates a property in the property cache.
  1974. // The property is specified by its index in the array of
  1975. // properties (which is also its DISPID), and the new value
  1976. // is given by a VARIANT.
  1977. //
  1978. // Arguments: [dwIndex] -- Index of the property.
  1979. // [varValue] -- Value of the property.
  1980. //
  1981. //-------------------------------------------------------------------------
  1982. HRESULT
  1983. CPropertyCache::putproperty(
  1984. DWORD dwIndex,
  1985. VARIANT vValue
  1986. )
  1987. {
  1988. HRESULT hr;
  1989. LDAPOBJECTARRAY LdapObjectArray;
  1990. DWORD dwLdapType;
  1991. LDAPOBJECTARRAY_INIT(LdapObjectArray);
  1992. VARIANT *pvValue = &vValue, *pvArray = NULL;
  1993. DWORD dwNumValues = 1;
  1994. //
  1995. // This should not return E_ADS_PROPERTY_NOT_FOUND in this case.
  1996. // We have an index, which should indicate that we have an array entry.
  1997. // If we weren't dealing with VB, I'd be tempted to make this an Assert.
  1998. //
  1999. if (!index_valid(dwIndex))
  2000. BAIL_ON_FAILURE(hr = DISP_E_MEMBERNOTFOUND);
  2001. //
  2002. // If we get a safe array of variants, convert it to a regular array
  2003. // of variants, so we can pass the first one to GetLdapSyntaxFromVariant.
  2004. // We assume that all the elements of the array are of the same type
  2005. //
  2006. if (V_VT(pvValue) == (VT_VARIANT|VT_ARRAY))
  2007. {
  2008. hr = ConvertSafeArrayToVariantArray(vValue, &pvArray, &dwNumValues);
  2009. BAIL_ON_FAILURE(hr);
  2010. pvValue = pvArray;
  2011. }
  2012. //
  2013. // - dwLdapType in cache can be LDAPTYPE_UNKNOWN.
  2014. // - for consistency btw this function and Put/PutEx, will
  2015. // get type from input VARIANT and overwrite existing type in
  2016. // cache if any
  2017. //
  2018. ADsAssert(_pCredentials);
  2019. hr = GetLdapSyntaxFromVariant(
  2020. pvValue,
  2021. &dwLdapType,
  2022. _pszServerName,
  2023. (_pProperties+dwIndex)->szPropertyName,
  2024. *_pCredentials,
  2025. _dwPort
  2026. );
  2027. BAIL_ON_FAILURE(hr);
  2028. hr = VarTypeToLdapTypeCopyConstruct(
  2029. _pszServerName,
  2030. *_pCredentials,
  2031. dwLdapType,
  2032. pvValue,
  2033. dwNumValues,
  2034. &LdapObjectArray
  2035. );
  2036. BAIL_ON_FAILURE(hr);
  2037. hr = putproperty(dwIndex, PROPERTY_UPDATE, dwLdapType, LdapObjectArray);
  2038. BAIL_ON_FAILURE(hr);
  2039. error:
  2040. // if (hr == E_ADS_CANT_CONVERT_DATATYPE)
  2041. // hr = DISP_E_TYPEMISMATCH;
  2042. LdapTypeFreeLdapObjects(&LdapObjectArray);
  2043. if (pvArray) {
  2044. for (DWORD i=0; i < dwNumValues; i++) {
  2045. VariantClear(pvArray + i);
  2046. }
  2047. FreeADsMem(pvArray);
  2048. }
  2049. RRETURN(hr);
  2050. }
  2051. //
  2052. // This method is called by _pCoreADsObject->GetInfo(). It signifies
  2053. // exactly that the property cache has been filled with all the data
  2054. // the server has, i.e. that a GetInfo() has been done. When this is
  2055. // set, further implicit calls to GetInfo are skipped. This flag is
  2056. // cleared only by "flushpropertycache".
  2057. //
  2058. void
  2059. CPropertyCache::setGetInfoFlag()
  2060. {
  2061. _fGetInfoDone = TRUE;
  2062. }
  2063. //+------------------------------------------------------------------------
  2064. //
  2065. // Function: CPropertyCache::findproperty
  2066. //
  2067. // Synopsis:
  2068. //
  2069. //
  2070. //
  2071. // Arguments: [szPropertyName] --
  2072. // [pdwIndex] --
  2073. //
  2074. //-------------------------------------------------------------------------
  2075. HRESULT
  2076. CPropertyCache::
  2077. DispatchFindProperty(
  2078. LPWSTR szPropertyName,
  2079. PDWORD pdwIndex
  2080. )
  2081. {
  2082. DWORD i = 0;
  2083. PDISPPROPERTY pThisDispProperty = NULL;
  2084. for (i = 0; i < _dwDispMaxProperties; i++) {
  2085. pThisDispProperty = _pDispProperties + i;
  2086. if (!_wcsicmp(pThisDispProperty->szPropertyName, szPropertyName)) {
  2087. *pdwIndex = i;
  2088. RRETURN(S_OK);
  2089. }
  2090. }
  2091. *pdwIndex = 0;
  2092. RRETURN(E_ADS_PROPERTY_NOT_FOUND);
  2093. }
  2094. //+---------------------------------------------------------------------------
  2095. // Function: CPropertyCache::GetPropertyNames.
  2096. //
  2097. // Synopsis: Gets a list of the names of the properties in this object.
  2098. //
  2099. // Arguments: ppUmiPropVals - Contains the return value.
  2100. //
  2101. // Returns: S_OK, or any appropriate error code.
  2102. //
  2103. // Modifies: N/A.
  2104. //
  2105. //----------------------------------------------------------------------------
  2106. HRESULT
  2107. CPropertyCache::GetPropertyNames(
  2108. UMI_PROPERTY_VALUES **ppUmiPropVals
  2109. )
  2110. {
  2111. HRESULT hr = S_OK;
  2112. PUMI_PROPERTY_VALUES pUmiPropVals = NULL;
  2113. PUMI_PROPERTY pUmiProps = NULL;
  2114. PPROPERTY pNextProperty = NULL;
  2115. DWORD dwCtr = 0;
  2116. ADsAssert(ppUmiPropVals);
  2117. //
  2118. // Always have only 1 value.
  2119. //
  2120. pUmiPropVals = (PUMI_PROPERTY_VALUES)
  2121. AllocADsMem(sizeof(UMI_PROPERTY_VALUES));
  2122. if (!pUmiPropVals) {
  2123. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2124. }
  2125. if (!_dwMaxProperties) {
  2126. //
  2127. // No properties, we need to special case this.
  2128. //
  2129. *ppUmiPropVals = pUmiPropVals;
  2130. RRETURN(S_OK);
  2131. }
  2132. pUmiProps = (PUMI_PROPERTY) AllocADsMem(
  2133. _dwMaxProperties * sizeof(UMI_PROPERTY)
  2134. );
  2135. if (!pUmiProps) {
  2136. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2137. }
  2138. for(dwCtr = 0; dwCtr < _dwMaxProperties; dwCtr++) {
  2139. pNextProperty = _pProperties + dwCtr;
  2140. pUmiProps[dwCtr].pszPropertyName =
  2141. (LPWSTR) AllocADsStr(pNextProperty->szPropertyName);
  2142. if(pUmiProps[dwCtr].pszPropertyName == NULL) {
  2143. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2144. }
  2145. pUmiProps[dwCtr].uCount = 0;
  2146. //
  2147. // Put correct operation type
  2148. //
  2149. hr = ConvertLdapCodeToUmiPropCode(
  2150. pNextProperty->dwFlags,
  2151. pUmiProps[dwCtr].uOperationType
  2152. );
  2153. //
  2154. // Verify that this is the right thing to do.
  2155. //
  2156. pUmiProps[dwCtr].uType = UMI_TYPE_NULL;
  2157. }
  2158. pUmiPropVals->uCount = _dwMaxProperties;
  2159. pUmiPropVals->pPropArray = pUmiProps;
  2160. *ppUmiPropVals = pUmiPropVals;
  2161. RRETURN(S_OK);
  2162. error:
  2163. if(pUmiProps != NULL) {
  2164. for(dwCtr = 0; dwCtr < _dwMaxProperties; dwCtr++) {
  2165. if(pUmiProps[dwCtr].pszPropertyName != NULL) {
  2166. FreeADsStr(pUmiProps[dwCtr].pszPropertyName);
  2167. }
  2168. }
  2169. FreeADsMem(pUmiProps);
  2170. }
  2171. if (pUmiProps) {
  2172. FreeADsMem(pUmiPropVals);
  2173. }
  2174. RRETURN(hr);
  2175. }
  2176. HRESULT
  2177. CPropertyCache::
  2178. AddSavingEntry(
  2179. LPWSTR propertyName
  2180. )
  2181. {
  2182. HRESULT hr = S_OK;
  2183. PSAVINGENTRY tempEntry = NULL;
  2184. BOOL fResult = FALSE;
  2185. fResult = FindSavingEntry(propertyName);
  2186. if(!fResult) {
  2187. tempEntry = new SAVINGENTRY;
  2188. if(!tempEntry) {
  2189. hr = E_OUTOFMEMORY;
  2190. BAIL_ON_FAILURE(hr);
  2191. }
  2192. tempEntry->entryData = AllocADsStr(propertyName);
  2193. if(!(tempEntry->entryData)) {
  2194. hr = E_OUTOFMEMORY;
  2195. delete tempEntry;
  2196. BAIL_ON_FAILURE(hr);
  2197. }
  2198. InsertTailList( &_ListSavingEntries, &tempEntry->ListEntry );
  2199. }
  2200. error:
  2201. return hr;
  2202. }
  2203. BOOL
  2204. CPropertyCache::
  2205. FindSavingEntry(
  2206. LPWSTR propertyName
  2207. )
  2208. {
  2209. PLIST_ENTRY listEntry = NULL;
  2210. PSAVINGENTRY EntryInfo = NULL;
  2211. BOOL fResult = FALSE;
  2212. listEntry = _ListSavingEntries.Flink;
  2213. while (listEntry != &_ListSavingEntries) {
  2214. EntryInfo = CONTAINING_RECORD( listEntry, SAVINGENTRY, ListEntry );
  2215. if (!_wcsicmp(EntryInfo->entryData, propertyName)) {
  2216. fResult = TRUE;
  2217. break;
  2218. }
  2219. listEntry = listEntry->Flink;
  2220. }
  2221. return fResult;
  2222. }
  2223. HRESULT
  2224. CPropertyCache::
  2225. DeleteSavingEntry()
  2226. {
  2227. PLIST_ENTRY pEntry;
  2228. PSAVINGENTRY EntryInfo;
  2229. while (!IsListEmpty (&_ListSavingEntries)) {
  2230. pEntry = RemoveHeadList (&_ListSavingEntries);
  2231. EntryInfo = CONTAINING_RECORD (pEntry, SAVINGENTRY, ListEntry);
  2232. if(EntryInfo->entryData) {
  2233. FreeADsStr(EntryInfo->entryData);
  2234. EntryInfo->entryData = NULL;
  2235. }
  2236. delete EntryInfo;
  2237. }
  2238. RRETURN(S_OK);
  2239. }