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.

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