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.

1524 lines
32 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995.
  5. //
  6. // File: cprops.cxx
  7. //
  8. // Contents: Property Cache functionality for NW
  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: 17-June-1996 KrishnaG Created.
  21. // cloned off NDS property cache code
  22. //
  23. //
  24. //----------------------------------------------------------------------------
  25. #include "nwcompat.hxx"
  26. #pragma hdrstop
  27. //+------------------------------------------------------------------------
  28. //
  29. // Function: CPropertyCache::addproperty
  30. //
  31. // Synopsis: adds a new empty property to the cache
  32. //
  33. //
  34. //
  35. // Arguments: [szPropertyName] --
  36. // [vt] --
  37. // [vaData] --
  38. //
  39. //
  40. //-------------------------------------------------------------------------
  41. HRESULT
  42. CPropertyCache::
  43. addproperty(
  44. LPWSTR szPropertyName,
  45. DWORD dwSyntaxId
  46. )
  47. {
  48. HRESULT hr = S_OK;
  49. PPROPERTY pNewProperty = NULL;
  50. LPWSTR tempString = NULL;
  51. //
  52. // Allocate the string first
  53. //
  54. tempString = AllocADsStr(szPropertyName);
  55. if (!tempString)
  56. BAIL_ON_FAILURE(hr=E_OUTOFMEMORY);
  57. //
  58. // extend the property cache by adding a new property entry
  59. //
  60. _pProperties = (PPROPERTY)ReallocADsMem(
  61. _pProperties,
  62. _cb,
  63. _cb + sizeof(PROPERTY)
  64. );
  65. if (!_pProperties) {
  66. hr = E_OUTOFMEMORY;
  67. BAIL_ON_FAILURE(hr);
  68. }
  69. pNewProperty = (PPROPERTY)((LPBYTE)_pProperties + _cb);
  70. if (pNewProperty->szPropertyName) {
  71. FreeADsStr(pNewProperty->szPropertyName);
  72. pNewProperty->szPropertyName = NULL;
  73. }
  74. //
  75. // Since the memory has already been allocated in tempString
  76. // just set the value/pointer now.
  77. //
  78. pNewProperty->szPropertyName = tempString;
  79. //
  80. // Update the index
  81. //
  82. _dwMaxProperties++;
  83. _cb += sizeof(PROPERTY);
  84. RRETURN(hr);
  85. error:
  86. if (tempString)
  87. FreeADsStr(tempString);
  88. RRETURN_EXP_IF_ERR(hr);
  89. }
  90. //+------------------------------------------------------------------------
  91. //
  92. // Function: CPropertyCache::updateproperty
  93. //
  94. // Synopsis:
  95. //
  96. //
  97. //
  98. // Arguments: [szPropertyName] --
  99. // [vaData] --
  100. //
  101. //-------------------------------------------------------------------------
  102. HRESULT
  103. CPropertyCache::updateproperty(
  104. LPWSTR szPropertyName,
  105. DWORD dwSyntaxId,
  106. DWORD dwNumValues,
  107. PNTOBJECT pNtObject,
  108. BOOL fExplicit
  109. )
  110. {
  111. HRESULT hr;
  112. DWORD dwIndex;
  113. PNTOBJECT pNtTempObject = NULL;
  114. PPROPERTY pThisProperty = NULL;
  115. hr = findproperty(
  116. szPropertyName,
  117. &dwIndex
  118. );
  119. BAIL_ON_FAILURE(hr);
  120. pThisProperty = _pProperties + dwIndex;
  121. if (!fExplicit) {
  122. if (PROPERTY_IS_MODIFIED(pThisProperty)) {
  123. hr = S_OK;
  124. goto error;
  125. }
  126. }
  127. //
  128. // Factor in cases where object state is necessary to
  129. // decide on update.
  130. //
  131. if (PROPERTY_NTOBJECT(pThisProperty)) {
  132. NTTypeFreeNTObjects(
  133. PROPERTY_NTOBJECT(pThisProperty),
  134. PROPERTY_NUMVALUES(pThisProperty)
  135. );
  136. PROPERTY_NTOBJECT(pThisProperty) = NULL;
  137. }
  138. PROPERTY_SYNTAX(pThisProperty) = dwSyntaxId;
  139. PROPERTY_NUMVALUES(pThisProperty) = dwNumValues;
  140. hr = NtTypeCopyConstruct(
  141. pNtObject,
  142. dwNumValues,
  143. &pNtTempObject
  144. );
  145. BAIL_ON_FAILURE(hr);
  146. PROPERTY_NTOBJECT(pThisProperty) = pNtTempObject;
  147. PROPERTY_FLAGS(pThisProperty) &= ~CACHE_PROPERTY_MODIFIED;
  148. error:
  149. RRETURN_EXP_IF_ERR(hr);
  150. }
  151. //+------------------------------------------------------------------------
  152. //
  153. // Function: CPropertyCache::findproperty
  154. //
  155. // Synopsis:
  156. //
  157. //
  158. //
  159. // Arguments: [szPropertyName] --
  160. // [pdwIndex] --
  161. //
  162. //-------------------------------------------------------------------------
  163. HRESULT
  164. CPropertyCache::findproperty(
  165. LPWSTR szPropertyName,
  166. PDWORD pdwIndex
  167. )
  168. {
  169. DWORD i = 0;
  170. PPROPERTY pThisProperty = NULL;
  171. for (i = 0; i < _dwMaxProperties; i++) {
  172. pThisProperty = _pProperties + i;
  173. if (!_wcsicmp(pThisProperty->szPropertyName, szPropertyName)) {
  174. *pdwIndex = i;
  175. RRETURN(S_OK);
  176. }
  177. }
  178. *pdwIndex = 0;
  179. RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_FOUND);
  180. }
  181. //+------------------------------------------------------------------------
  182. //
  183. // Function: CPropertyCache::getproperty
  184. //
  185. // Synopsis:
  186. //
  187. //
  188. //
  189. // Arguments: [szPropertyName] -- Property to retrieve from the cache
  190. // [pvaData] -- Data returned in a variant
  191. //
  192. //-------------------------------------------------------------------------
  193. HRESULT
  194. CPropertyCache::
  195. getproperty(
  196. LPWSTR szPropertyName,
  197. PDWORD pdwSyntaxId,
  198. PDWORD pdwNumValues,
  199. PNTOBJECT * ppNtObject
  200. )
  201. {
  202. HRESULT hr;
  203. DWORD dwIndex = 0L;
  204. PPROPERTY pThisProperty = NULL;
  205. DWORD dwResult;
  206. DWORD dwInfoLevel = 0;
  207. hr = findproperty(
  208. szPropertyName,
  209. &dwIndex
  210. );
  211. if (hr == E_ADS_PROPERTY_NOT_FOUND) {
  212. hr = GetPropertyInfoLevel(
  213. szPropertyName,
  214. _pSchemaClassProps,
  215. _dwNumProperties,
  216. &dwInfoLevel
  217. );
  218. BAIL_ON_FAILURE(hr);
  219. //
  220. // Now call the GetInfo function
  221. //
  222. hr = _pCoreADsObject->GetInfo(
  223. FALSE,
  224. dwInfoLevel
  225. );
  226. BAIL_ON_FAILURE(hr);
  227. hr = findproperty(
  228. szPropertyName,
  229. &dwIndex
  230. );
  231. }
  232. BAIL_ON_FAILURE(hr);
  233. pThisProperty = _pProperties + dwIndex;
  234. if (PROPERTY_NTOBJECT(pThisProperty)) {
  235. *pdwSyntaxId = (DWORD)PROPERTY_SYNTAX(pThisProperty);
  236. *pdwNumValues = (DWORD)PROPERTY_NUMVALUES(pThisProperty);
  237. hr = NtTypeCopyConstruct(PROPERTY_NTOBJECT(pThisProperty),
  238. PROPERTY_NUMVALUES(pThisProperty),
  239. ppNtObject );
  240. BAIL_ON_FAILURE(hr);
  241. }else {
  242. *ppNtObject = NULL;
  243. *pdwNumValues = 0;
  244. *pdwSyntaxId = 0;
  245. hr = E_FAIL;
  246. }
  247. error:
  248. RRETURN_EXP_IF_ERR(hr);
  249. }
  250. //+------------------------------------------------------------------------
  251. //
  252. // Function: CPropertyCache::marshallgetproperty
  253. //
  254. // Synopsis:
  255. //
  256. //
  257. //
  258. // Arguments: [szPropertyName] -- Property to retrieve from the cache
  259. // [pvaData] -- Data returned in a variant
  260. //
  261. //-------------------------------------------------------------------------
  262. HRESULT
  263. CPropertyCache::
  264. marshallgetproperty(
  265. LPWSTR szPropertyName,
  266. PDWORD pdwSyntaxId,
  267. PDWORD pdwNumValues,
  268. PNTOBJECT * ppNtObject
  269. )
  270. {
  271. HRESULT hr;
  272. DWORD dwIndex = 0L;
  273. PPROPERTY pThisProperty = NULL;
  274. DWORD dwResult;
  275. DWORD dwInfoLevel = 0;
  276. hr = findproperty(
  277. szPropertyName,
  278. &dwIndex
  279. );
  280. BAIL_ON_FAILURE(hr);
  281. pThisProperty = _pProperties + dwIndex;
  282. if (PROPERTY_NTOBJECT(pThisProperty)) {
  283. *pdwSyntaxId = (DWORD)PROPERTY_SYNTAX(pThisProperty);
  284. *pdwNumValues = (DWORD)PROPERTY_NUMVALUES(pThisProperty);
  285. hr = NtTypeCopyConstruct(PROPERTY_NTOBJECT(pThisProperty),
  286. PROPERTY_NUMVALUES(pThisProperty),
  287. ppNtObject );
  288. BAIL_ON_FAILURE(hr);
  289. }else {
  290. *ppNtObject = NULL;
  291. *pdwNumValues = 0;
  292. *pdwSyntaxId = 0;
  293. hr = E_FAIL;
  294. }
  295. error:
  296. RRETURN_EXP_IF_ERR(hr);
  297. }
  298. //+------------------------------------------------------------------------
  299. //
  300. // Function: CPropertyCache::putproperty
  301. //
  302. // Synopsis:
  303. //
  304. //
  305. //
  306. // Arguments: [szPropertyName] -- Clsid index
  307. // [vaData] -- Matching clsid returned in *pclsid
  308. //
  309. //-------------------------------------------------------------------------
  310. HRESULT
  311. CPropertyCache::putproperty(
  312. LPWSTR szPropertyName,
  313. DWORD dwSyntaxId,
  314. DWORD dwNumValues,
  315. PNTOBJECT pNtObject
  316. )
  317. {
  318. HRESULT hr;
  319. DWORD dwIndex = 0L;
  320. PNTOBJECT pNtTempObject = NULL;
  321. PPROPERTY pThisProperty = NULL;
  322. hr = findproperty(
  323. szPropertyName,
  324. &dwIndex
  325. );
  326. BAIL_ON_FAILURE(hr);
  327. pThisProperty = _pProperties + dwIndex;
  328. //
  329. // AccountLocked is "half writable" -> need special care
  330. //
  331. if (_wcsicmp(szPropertyName, TEXT("IsAccountLocked"))==0 ) {
  332. if (pNtObject->NTType != NT_SYNTAX_ID_BOOL) {
  333. hr = E_ADS_BAD_PARAMETER;
  334. BAIL_ON_FAILURE(hr);
  335. }
  336. //
  337. // canNOT just disallow user to set cache to TRUE since
  338. // user may have accidentally set cache to FALSE (unlock) and
  339. // want to set the cache back to TRUE (do not unlock) without
  340. // GetInfo to affect other changes in cache. It will be a major
  341. // mistake if cuser cannot set the cache back to TRUE after
  342. // changing it to FALSE accidentally and thus unlocking the
  343. // account even if the user does not want to.
  344. //
  345. // If cache value on IsAccountLocked is changed from FALSE to TRUE,
  346. // cached value will be automatically changed back to FALSE upon
  347. // SetInfo since user cannot lock an account thru' ADSI. (NW server
  348. // wont' allow. Ref: SysCon)
  349. //
  350. // Should: If new value == value already in cache, do nothing.
  351. // That is, do not try to set the cache_property_modified flag.
  352. // This is to prevent
  353. // 1) the side effect of setting BadLogins to 0 when a
  354. // user set the cached property IsAccountLocked
  355. // from FALSE to FALSE (no change really) and call SetInfo.
  356. // 2) the side effect of changing the cache value to 0 (not
  357. // consistent with server or original cached value) when
  358. // a user set the cache property IsAccontLocked
  359. // from TRUE to TRUE (no change really) and call SetInfo.
  360. //
  361. // If user set IsAccountLocked from FALSE to TRUE and then
  362. // back to FALSE, or from TRUE to FALSE and then back to TURE,
  363. // side effect 1) or 2) will happen.
  364. // Both side effect not critical.
  365. //
  366. // We first check whether the object has been set previously, if not,
  367. // NTOBJECT will be NULL
  368. //
  369. if (PROPERTY_NTOBJECT(pThisProperty) &&
  370. (pNtObject->NTValue.fValue ==
  371. PROPERTY_NTOBJECT(pThisProperty)->NTValue.fValue)) {
  372. RRETURN(S_OK);
  373. }
  374. }
  375. if (PROPERTY_NTOBJECT(pThisProperty)) {
  376. NTTypeFreeNTObjects(
  377. PROPERTY_NTOBJECT(pThisProperty),
  378. PROPERTY_NUMVALUES(pThisProperty)
  379. );
  380. PROPERTY_NTOBJECT(pThisProperty) = NULL;
  381. }
  382. PROPERTY_SYNTAX(pThisProperty) = dwSyntaxId;
  383. PROPERTY_NUMVALUES(pThisProperty) = dwNumValues;
  384. hr = NtTypeCopyConstruct(
  385. pNtObject,
  386. dwNumValues,
  387. &pNtTempObject
  388. );
  389. BAIL_ON_FAILURE(hr);
  390. PROPERTY_NTOBJECT(pThisProperty) = pNtTempObject;
  391. PROPERTY_FLAGS(pThisProperty) |= CACHE_PROPERTY_MODIFIED;
  392. error:
  393. RRETURN_EXP_IF_ERR(hr);
  394. }
  395. //+------------------------------------------------------------------------
  396. //
  397. // Function: CPropertyCache
  398. //
  399. // Synopsis:
  400. //
  401. //
  402. //
  403. // Arguments:
  404. //
  405. //
  406. //-------------------------------------------------------------------------
  407. CPropertyCache::CPropertyCache():
  408. _pCoreADsObject(NULL),
  409. _pSchemaClassProps(NULL),
  410. _dwMaxProperties(0),
  411. _pProperties(NULL),
  412. _dwCurrentIndex(0),
  413. _cb(0)
  414. {
  415. }
  416. //+------------------------------------------------------------------------
  417. //
  418. // Function: ~CPropertyCache
  419. //
  420. // Synopsis:
  421. //
  422. //
  423. //
  424. // Arguments:
  425. //
  426. //
  427. //-------------------------------------------------------------------------
  428. CPropertyCache::
  429. ~CPropertyCache()
  430. {
  431. DWORD i = 0;
  432. PPROPERTY pThisProperty = NULL;
  433. if (_pProperties) {
  434. for (i = 0; i < _dwMaxProperties; i++) {
  435. pThisProperty = _pProperties + i;
  436. if (pThisProperty->szPropertyName) {
  437. FreeADsStr(pThisProperty->szPropertyName);
  438. pThisProperty->szPropertyName = NULL;
  439. }
  440. if (PROPERTY_NTOBJECT(pThisProperty)) {
  441. NTTypeFreeNTObjects(
  442. PROPERTY_NTOBJECT(pThisProperty),
  443. PROPERTY_NUMVALUES(pThisProperty)
  444. );
  445. PROPERTY_NTOBJECT(pThisProperty) = NULL;
  446. }
  447. }
  448. FreeADsMem(_pProperties);
  449. }
  450. }
  451. //+------------------------------------------------------------------------
  452. //
  453. // Function:
  454. //
  455. // Synopsis:
  456. //
  457. //
  458. //
  459. // Arguments:
  460. //
  461. //
  462. //-------------------------------------------------------------------------
  463. HRESULT
  464. CPropertyCache::
  465. createpropertycache(
  466. PPROPERTYINFO pSchemaClassProps,
  467. DWORD dwNumProperties,
  468. CCoreADsObject FAR * pCoreADsObject,
  469. CPropertyCache FAR *FAR * ppPropertyCache
  470. )
  471. {
  472. CPropertyCache FAR * pPropertyCache = NULL;
  473. pPropertyCache = new CPropertyCache();
  474. if (!pPropertyCache) {
  475. RRETURN_EXP_IF_ERR(E_OUTOFMEMORY);
  476. }
  477. pPropertyCache->_pCoreADsObject = pCoreADsObject;
  478. pPropertyCache->_pSchemaClassProps = pSchemaClassProps;
  479. pPropertyCache->_dwNumProperties = dwNumProperties;
  480. *ppPropertyCache = pPropertyCache;
  481. RRETURN(S_OK);
  482. }
  483. //+------------------------------------------------------------------------
  484. //
  485. // Function:
  486. //
  487. // Synopsis:
  488. //
  489. //
  490. //
  491. // Arguments:
  492. //
  493. //
  494. //-------------------------------------------------------------------------
  495. HRESULT
  496. CPropertyCache::
  497. unmarshallproperty(
  498. LPWSTR szPropertyName,
  499. LPBYTE lpValue,
  500. DWORD dwNumValues,
  501. DWORD dwSyntaxId,
  502. BOOL fExplicit
  503. )
  504. {
  505. DWORD dwIndex = 0;
  506. HRESULT hr = S_OK;
  507. PNTOBJECT pNTObject = NULL;
  508. hr = UnMarshallNTToNTSynId(
  509. dwSyntaxId,
  510. dwNumValues,
  511. lpValue,
  512. &pNTObject
  513. );
  514. BAIL_ON_FAILURE(hr);
  515. //
  516. // Find this property in the cache
  517. //
  518. hr = findproperty(
  519. szPropertyName,
  520. &dwIndex
  521. );
  522. //
  523. // If this property does not exist in the
  524. // cache, add this property into the cache.
  525. //
  526. if (FAILED(hr)) {
  527. hr = addproperty(
  528. szPropertyName,
  529. dwSyntaxId
  530. );
  531. //
  532. // If the operation fails for some reason
  533. // move on to the next property
  534. //
  535. BAIL_ON_FAILURE(hr);
  536. }
  537. //
  538. // Now update the property in the cache
  539. //
  540. hr = updateproperty(
  541. szPropertyName,
  542. dwSyntaxId,
  543. dwNumValues,
  544. pNTObject,
  545. fExplicit
  546. );
  547. BAIL_ON_FAILURE(hr);
  548. if (pNTObject) {
  549. NTTypeFreeNTObjects(
  550. pNTObject,
  551. dwNumValues
  552. );
  553. }
  554. error:
  555. RRETURN_EXP_IF_ERR(hr);
  556. }
  557. HRESULT
  558. ValidatePropertyinSchemaClass(
  559. PPROPERTYINFO pSchemaClassProps,
  560. DWORD dwNumProperties,
  561. LPWSTR pszPropName,
  562. PDWORD pdwSyntaxId
  563. )
  564. {
  565. DWORD i = 0;
  566. PPROPERTYINFO pThisSchProperty = NULL;
  567. for (i = 0; i < dwNumProperties; i++) {
  568. pThisSchProperty = (pSchemaClassProps + i);
  569. if (!_wcsicmp(pszPropName, pThisSchProperty->szPropertyName)) {
  570. *pdwSyntaxId = pThisSchProperty->dwSyntaxId;
  571. RRETURN (S_OK);
  572. }
  573. }
  574. RRETURN(E_ADS_SCHEMA_VIOLATION);
  575. }
  576. HRESULT
  577. ValidateIfWriteableProperty(
  578. PPROPERTYINFO pSchemaClassProps,
  579. DWORD dwNumProperties,
  580. LPWSTR pszPropName
  581. )
  582. {
  583. DWORD i = 0;
  584. PPROPERTYINFO pThisSchProperty = NULL;
  585. for (i = 0; i < dwNumProperties; i++) {
  586. pThisSchProperty = (pSchemaClassProps + i);
  587. if (!_wcsicmp(pszPropName, pThisSchProperty->szPropertyName)) {
  588. RRETURN((pThisSchProperty->dwFlags & PROPERTY_WRITEABLE)
  589. ? S_OK : E_ADS_SCHEMA_VIOLATION);
  590. }
  591. }
  592. RRETURN(E_ADS_SCHEMA_VIOLATION);
  593. // for winnt & nw312, return E_ADS_SCHEMA_VIOLATION if not ok even
  594. // attempt to write to cache only
  595. }
  596. HRESULT
  597. GetPropertyInfoLevel(
  598. LPWSTR pszPropName,
  599. PPROPERTYINFO pSchemaClassProps,
  600. DWORD dwNumProperties,
  601. PDWORD pdwInfoLevel
  602. )
  603. {
  604. DWORD i = 0;
  605. PPROPERTYINFO pThisSchProperty = NULL;
  606. for (i = 0; i < dwNumProperties; i++) {
  607. pThisSchProperty = (pSchemaClassProps + i);
  608. if (!_wcsicmp(pszPropName, pThisSchProperty->szPropertyName)) {
  609. *pdwInfoLevel = pThisSchProperty->dwInfoLevel;
  610. RRETURN(S_OK);
  611. }
  612. }
  613. //
  614. // Returning E_ADS_PROPERTY_NOT_FOUND so that implicit
  615. // GetInfo fails gracefully
  616. //
  617. RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_FOUND);
  618. }
  619. //+------------------------------------------------------------------------
  620. //
  621. // Function: ~CPropertyCache
  622. //
  623. // Synopsis:
  624. //
  625. //
  626. //
  627. // Arguments:
  628. //
  629. //
  630. //-------------------------------------------------------------------------
  631. void
  632. CPropertyCache::
  633. flushpropcache()
  634. {
  635. DWORD i = 0;
  636. PPROPERTY pThisProperty = NULL;
  637. if (_pProperties) {
  638. for (i = 0; i < _dwMaxProperties; i++) {
  639. pThisProperty = _pProperties + i;
  640. if (pThisProperty->szPropertyName) {
  641. FreeADsStr(pThisProperty->szPropertyName);
  642. pThisProperty->szPropertyName = NULL;
  643. }
  644. if (PROPERTY_NTOBJECT(pThisProperty)) {
  645. NTTypeFreeNTObjects(
  646. PROPERTY_NTOBJECT(pThisProperty),
  647. PROPERTY_NUMVALUES(pThisProperty)
  648. );
  649. PROPERTY_NTOBJECT(pThisProperty) = NULL;
  650. }
  651. }
  652. FreeADsMem(_pProperties);
  653. }
  654. //
  655. // Reset the property cache
  656. //
  657. _pProperties = NULL;
  658. _dwMaxProperties = 0;
  659. _cb = 0;
  660. }
  661. //+------------------------------------------------------------------------
  662. //
  663. // Function: CPropertyCache::getproperty
  664. //
  665. // Synopsis:
  666. //
  667. //
  668. //
  669. // Arguments: [szPropertyName] -- Property to retrieve from the cache
  670. // [pvaData] -- Data returned in a variant
  671. //
  672. //-------------------------------------------------------------------------
  673. HRESULT
  674. CPropertyCache::
  675. unboundgetproperty(
  676. LPWSTR szPropertyName,
  677. PDWORD pdwSyntaxId,
  678. PDWORD pdwNumValues,
  679. PNTOBJECT * ppNtObject
  680. )
  681. {
  682. HRESULT hr;
  683. DWORD dwIndex = 0L;
  684. PPROPERTY pThisProperty = NULL;
  685. hr = findproperty(
  686. szPropertyName,
  687. &dwIndex
  688. );
  689. BAIL_ON_FAILURE(hr);
  690. pThisProperty = _pProperties + dwIndex;
  691. if (PROPERTY_NTOBJECT(pThisProperty)) {
  692. *pdwSyntaxId = (DWORD)PROPERTY_SYNTAX(pThisProperty);
  693. *pdwNumValues = (DWORD)PROPERTY_NUMVALUES(pThisProperty);
  694. hr = NtTypeCopyConstruct(
  695. PROPERTY_NTOBJECT(pThisProperty),
  696. PROPERTY_NUMVALUES(pThisProperty),
  697. ppNtObject
  698. );
  699. BAIL_ON_FAILURE(hr);
  700. }else {
  701. *ppNtObject = NULL;
  702. *pdwNumValues = 0;
  703. *pdwSyntaxId = 0;
  704. hr = E_FAIL;
  705. }
  706. error:
  707. RRETURN_EXP_IF_ERR(hr);
  708. }
  709. //+------------------------------------------------------------------------
  710. //
  711. // Function: CPropertyCache::getproperty
  712. //
  713. // Synopsis:
  714. //
  715. //
  716. //
  717. // Arguments: [szPropertyName] -- Property to retrieve from the cache
  718. // [pvaData] -- Data returned in a variant
  719. //
  720. //-------------------------------------------------------------------------
  721. HRESULT
  722. CPropertyCache::
  723. unboundgetproperty(
  724. DWORD dwIndex,
  725. PDWORD pdwSyntaxId,
  726. PDWORD pdwNumValues,
  727. PNTOBJECT * ppNtObject
  728. )
  729. {
  730. HRESULT hr;
  731. PPROPERTY pThisProperty = NULL;
  732. if (!index_valid(dwIndex)) {
  733. RRETURN(E_ADS_BAD_PARAMETER); // better if E_ADS_INDEX or sth
  734. }
  735. pThisProperty = _pProperties + dwIndex;
  736. if (PROPERTY_NTOBJECT(pThisProperty)) {
  737. *pdwSyntaxId = (DWORD)PROPERTY_SYNTAX(pThisProperty);
  738. *pdwNumValues = (DWORD)PROPERTY_NUMVALUES(pThisProperty);
  739. hr = NtTypeCopyConstruct(
  740. PROPERTY_NTOBJECT(pThisProperty),
  741. PROPERTY_NUMVALUES(pThisProperty),
  742. ppNtObject
  743. );
  744. BAIL_ON_FAILURE(hr);
  745. }else {
  746. *ppNtObject = NULL;
  747. *pdwNumValues = 0;
  748. *pdwSyntaxId = 0;
  749. hr = E_FAIL;
  750. }
  751. error:
  752. RRETURN_EXP_IF_ERR(hr);
  753. }
  754. BOOL
  755. CPropertyCache::
  756. index_valid(
  757. )
  758. {
  759. //
  760. // need to check _dwMaxProperties==0 separately since a negative
  761. // DWORD is equal to +ve large #
  762. //
  763. if (_dwMaxProperties==0 || (_dwCurrentIndex>_dwMaxProperties-1) )
  764. return(FALSE);
  765. else
  766. return(TRUE);
  767. }
  768. BOOL
  769. CPropertyCache::
  770. index_valid(
  771. DWORD dwIndex
  772. )
  773. {
  774. //
  775. // need to check _dwMaxProperties==0 separately since a negative
  776. // DWORD is equal to +ve large #
  777. //
  778. if (_dwMaxProperties==0 || (dwIndex>_dwMaxProperties-1) )
  779. return(FALSE);
  780. else
  781. return(TRUE);
  782. }
  783. void
  784. CPropertyCache::
  785. reset_propindex(
  786. )
  787. {
  788. _dwCurrentIndex = 0;
  789. }
  790. HRESULT
  791. CPropertyCache::
  792. skip_propindex(
  793. DWORD dwElements
  794. )
  795. {
  796. DWORD newIndex = _dwCurrentIndex + dwElements;
  797. if (!index_valid())
  798. RRETURN_EXP_IF_ERR(E_FAIL);
  799. //
  800. // - allow current index to go from within range to out of range by 1
  801. // - by 1 since initial state is out of range by 1
  802. //
  803. if (newIndex>_dwMaxProperties) {
  804. RRETURN_EXP_IF_ERR(E_FAIL);
  805. }
  806. _dwCurrentIndex = newIndex;
  807. RRETURN(S_OK);
  808. }
  809. HRESULT
  810. CPropertyCache::
  811. get_PropertyCount(
  812. PDWORD pdwMaxProperties
  813. )
  814. {
  815. *pdwMaxProperties = _dwMaxProperties;
  816. RRETURN(S_OK);
  817. }
  818. DWORD
  819. CPropertyCache::
  820. get_CurrentIndex(
  821. )
  822. {
  823. return(_dwCurrentIndex);
  824. }
  825. LPWSTR
  826. CPropertyCache::
  827. get_CurrentPropName(
  828. )
  829. {
  830. PPROPERTY pThisProperty = NULL;
  831. if (!index_valid())
  832. return(NULL);
  833. pThisProperty = _pProperties + _dwCurrentIndex;
  834. return(PROPERTY_NAME(pThisProperty));
  835. }
  836. LPWSTR
  837. CPropertyCache::
  838. get_PropName(
  839. DWORD dwIndex
  840. )
  841. {
  842. PPROPERTY pThisProperty = NULL;
  843. if (!index_valid(dwIndex))
  844. return(NULL);
  845. pThisProperty = _pProperties + dwIndex;
  846. return(PROPERTY_NAME(pThisProperty));
  847. }
  848. HRESULT
  849. CPropertyCache::
  850. deleteproperty(
  851. DWORD dwIndex
  852. )
  853. {
  854. HRESULT hr = S_OK;
  855. PPROPERTY pNewProperties = NULL;
  856. PPROPERTY pThisProperty = _pProperties + dwIndex;
  857. if (!index_valid(dwIndex)) {
  858. RRETURN(E_ADS_BAD_PARAMETER);
  859. }
  860. if (_dwMaxProperties == 1) {
  861. //
  862. // Deleting everything
  863. //
  864. if (PROPERTY_NTOBJECT(pThisProperty)) {
  865. NTTypeFreeNTObjects(
  866. PROPERTY_NTOBJECT(pThisProperty),
  867. PROPERTY_NUMVALUES(pThisProperty)
  868. );
  869. PROPERTY_NTOBJECT(pThisProperty) = NULL;
  870. }
  871. FreeADsMem(_pProperties);
  872. _pProperties = NULL;
  873. _dwMaxProperties = 0;
  874. _cb = 0;
  875. //
  876. // Reset the current index just in case
  877. //
  878. _dwCurrentIndex = 0;
  879. RRETURN(hr);
  880. }
  881. pNewProperties = (PPROPERTY)AllocADsMem(
  882. _cb - sizeof(PROPERTY)
  883. );
  884. if (!pNewProperties) {
  885. hr = E_OUTOFMEMORY;
  886. BAIL_ON_FAILURE(hr);
  887. }
  888. //
  889. // Copying the memory before the deleted item
  890. //
  891. if (dwIndex != 0) {
  892. memcpy( pNewProperties,
  893. _pProperties,
  894. dwIndex * sizeof(PROPERTY));
  895. }
  896. //
  897. // Copying the memory following the deleted item
  898. //
  899. if (dwIndex != (_dwMaxProperties-1)) {
  900. memcpy( pNewProperties + dwIndex,
  901. _pProperties + dwIndex + 1,
  902. (_dwMaxProperties - dwIndex - 1) * sizeof(PROPERTY));
  903. }
  904. if (PROPERTY_NTOBJECT(pThisProperty)) {
  905. NTTypeFreeNTObjects(
  906. PROPERTY_NTOBJECT(pThisProperty),
  907. PROPERTY_NUMVALUES(pThisProperty)
  908. );
  909. PROPERTY_NTOBJECT(pThisProperty) = NULL;
  910. }
  911. FreeADsMem(_pProperties);
  912. _pProperties = pNewProperties;
  913. _dwMaxProperties--;
  914. _cb -= sizeof(PROPERTY);
  915. //
  916. // Reset the current index if necesary so we do not skip a property.
  917. //
  918. if (_dwCurrentIndex > dwIndex) {
  919. _dwCurrentIndex--;
  920. }
  921. error:
  922. RRETURN_EXP_IF_ERR(hr);
  923. }
  924. HRESULT
  925. CPropertyCache::
  926. propertyismodified(
  927. LPWSTR szPropertyName,
  928. BOOL * pfModified
  929. )
  930. {
  931. HRESULT hr;
  932. DWORD dwIndex = 0L;
  933. PPROPERTY pThisProperty = NULL;
  934. if (!szPropertyName || !pfModified) {
  935. RRETURN(E_ADS_BAD_PARAMETER);
  936. }
  937. hr = findproperty(
  938. szPropertyName,
  939. &dwIndex
  940. );
  941. BAIL_ON_FAILURE(hr);
  942. pThisProperty = _pProperties + dwIndex;
  943. *pfModified=PROPERTY_IS_MODIFIED(pThisProperty);
  944. error:
  945. RRETURN(hr);
  946. }
  947. ////////////////////////////////////////////////////////////////////////
  948. //
  949. // IPropertyCache
  950. //
  951. HRESULT
  952. CPropertyCache::
  953. locateproperty(
  954. LPWSTR szPropertyName,
  955. PDWORD pdwDispid
  956. )
  957. {
  958. HRESULT hr;
  959. DWORD dwSyntaxId; // (dummy)
  960. if (!pdwDispid || !szPropertyName)
  961. RRETURN(DISP_E_PARAMNOTOPTIONAL);
  962. //
  963. // return dispid of property if already in table;
  964. //
  965. hr = findproperty(
  966. szPropertyName,
  967. pdwDispid
  968. );
  969. if (hr==E_ADS_PROPERTY_NOT_FOUND) {
  970. //
  971. // check if property in schema
  972. // - this is necessary; otherwise, property not in schema will
  973. // be allowed to be added to cache and will not be given the
  974. // chance to be handled by 3rd party extension.
  975. // - note that property not in schema but added to the cache
  976. // thru' IADsProperty list will not be handled by 3rd
  977. // party extension either.
  978. //
  979. hr = ValidatePropertyinSchemaClass(
  980. _pSchemaClassProps,
  981. _dwNumProperties,
  982. szPropertyName,
  983. &dwSyntaxId
  984. );
  985. //
  986. // Add property that is in the schema but not in the cache
  987. // That is, property which is in the
  988. // schema will always be handled by the cache/server thur ADSI but
  989. // will NOT be handled by 3rd party extension.
  990. //
  991. if (SUCCEEDED(hr)) {
  992. hr = addproperty(
  993. szPropertyName,
  994. dwSyntaxId
  995. );
  996. BAIL_ON_FAILURE(hr);
  997. }
  998. //
  999. // Property Not in the schema will nto be added to the dynamic
  1000. // dispid table and could be handled by 3rd party extension.
  1001. //
  1002. else {
  1003. hr = DISP_E_MEMBERNOTFOUND;
  1004. BAIL_ON_FAILURE(hr);
  1005. }
  1006. }
  1007. RRETURN(hr);
  1008. error:
  1009. //
  1010. // translate E_ADS_ error codes to DISP_E if appropriate, see above
  1011. //
  1012. ADsECodesToDispECodes(&hr);
  1013. *pdwDispid = (DWORD) DISPID_UNKNOWN;
  1014. RRETURN(hr);
  1015. }
  1016. HRESULT
  1017. CPropertyCache::
  1018. getproperty(
  1019. DWORD dwDispid,
  1020. VARIANT * pvarVal
  1021. )
  1022. {
  1023. HRESULT hr;
  1024. LPWSTR szPropName = NULL;
  1025. DWORD dwSyntaxId = (DWORD) -1;
  1026. DWORD dwNumValues = 0;
  1027. PNTOBJECT pNtObjs = NULL;
  1028. //
  1029. // Use DISP_E_ERROR codes since this function directly called by
  1030. // the dispatch manager
  1031. //
  1032. if (!pvarVal)
  1033. RRETURN(DISP_E_PARAMNOTOPTIONAL);
  1034. if (!index_valid(dwDispid))
  1035. RRETURN(DISP_E_MEMBERNOTFOUND);
  1036. szPropName = PROPERTY_NAME((_pProperties + dwDispid));
  1037. //
  1038. // return value in cache for szPropName; retrieve value from server
  1039. // if not already in cache; fail if none on sever
  1040. //
  1041. hr = getproperty(
  1042. szPropName,
  1043. &dwSyntaxId,
  1044. &dwNumValues,
  1045. &pNtObjs
  1046. );
  1047. BAIL_ON_FAILURE(hr);
  1048. //
  1049. // translate NT objects into variants
  1050. //
  1051. if (dwNumValues == 1) {
  1052. hr = NtTypeToVarTypeCopy(
  1053. pNtObjs,
  1054. pvarVal
  1055. );
  1056. } else {
  1057. hr = NtTypeToVarTypeCopyConstruct(
  1058. pNtObjs,
  1059. dwNumValues,
  1060. pvarVal
  1061. );
  1062. }
  1063. BAIL_ON_FAILURE(hr);
  1064. error:
  1065. if (pNtObjs) {
  1066. NTTypeFreeNTObjects(
  1067. pNtObjs,
  1068. dwNumValues
  1069. );
  1070. }
  1071. if (FAILED(hr)) {
  1072. //
  1073. // return DISP_E errors instead E_ADS_ errors , see above
  1074. //
  1075. ADsECodesToDispECodes(&hr);
  1076. V_VT(pvarVal) = VT_ERROR;
  1077. }
  1078. RRETURN(hr);
  1079. }
  1080. HRESULT
  1081. CPropertyCache::
  1082. putproperty(
  1083. DWORD dwDispid,
  1084. VARIANT varVal
  1085. )
  1086. {
  1087. HRESULT hr;
  1088. LPWSTR szPropName = NULL;
  1089. VARIANT * pvProp = NULL; // do not free
  1090. DWORD dwNumValues = 0;
  1091. VARIANT * pTempVarArray = NULL; // to be freed
  1092. DWORD dwSyntaxId = (DWORD) -1;
  1093. LPNTOBJECT pNtObjs = NULL;
  1094. DWORD dwIndex = (DWORD) -1;
  1095. //
  1096. // Use DISP_E_ERROR codes since this function directly called by
  1097. // the dispatch manager
  1098. //
  1099. if (!index_valid(dwDispid))
  1100. RRETURN(DISP_E_MEMBERNOTFOUND);
  1101. //
  1102. // retreive property name from Dynamic Dispatch Table
  1103. //
  1104. szPropName = PROPERTY_NAME((_pProperties + dwDispid));
  1105. dwSyntaxId = PROPERTY_SYNTAX((_pProperties + dwDispid));
  1106. //
  1107. // translate variant to NT Objects
  1108. //
  1109. //
  1110. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  1111. // We should dereference a VT_BYREF|VT_VARIANT once and see
  1112. // what's inside. ??
  1113. //
  1114. pvProp = &varVal;
  1115. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  1116. pvProp = V_VARIANTREF(pvProp);
  1117. }
  1118. if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY)) ||
  1119. (V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF))) {
  1120. hr = ConvertByRefSafeArrayToVariantArray(
  1121. varVal,
  1122. &pTempVarArray,
  1123. &dwNumValues
  1124. );
  1125. BAIL_ON_FAILURE(hr);
  1126. pvProp = pTempVarArray;
  1127. }else {
  1128. //
  1129. // Single value NOT stored in array MUST BE ALLOWED since clients
  1130. // would expect Put() to behave the same whether the dipatch
  1131. // manager is invoked or not. (This funct'n has to be consitent
  1132. // GenericPutPropertyManager(), but NOT GenericPutExProperty...)
  1133. dwNumValues = 1;
  1134. }
  1135. //
  1136. // check if this is a writeable property in schema
  1137. //
  1138. hr = ValidateIfWriteableProperty(
  1139. _pSchemaClassProps,
  1140. _dwNumProperties,
  1141. szPropName
  1142. );
  1143. BAIL_ON_FAILURE(hr);
  1144. //
  1145. // Variant Array to Nt Objects
  1146. //
  1147. hr = VarTypeToNtTypeCopyConstruct(
  1148. dwSyntaxId,
  1149. pvProp,
  1150. dwNumValues,
  1151. &pNtObjs
  1152. );
  1153. BAIL_ON_FAILURE(hr);
  1154. //
  1155. // update property value in cache
  1156. //
  1157. hr = putproperty(
  1158. szPropName,
  1159. dwSyntaxId,
  1160. dwNumValues,
  1161. pNtObjs
  1162. );
  1163. BAIL_ON_FAILURE(hr);
  1164. error:
  1165. if (pNtObjs) {
  1166. NTTypeFreeNTObjects(
  1167. pNtObjs,
  1168. dwNumValues
  1169. );
  1170. }
  1171. if (pTempVarArray) {
  1172. DWORD i = 0;
  1173. for (i = 0; i < dwNumValues; i++) {
  1174. VariantClear(pTempVarArray + i);
  1175. }
  1176. FreeADsMem(pTempVarArray);
  1177. }
  1178. if (FAILED(hr)) {
  1179. //
  1180. // return DISP_E errors instead E_ADS_ errors , see above
  1181. //
  1182. ADsECodesToDispECodes(&hr);
  1183. }
  1184. RRETURN(hr);
  1185. }
  1186. void
  1187. ADsECodesToDispECodes(
  1188. HRESULT *pHr
  1189. )
  1190. {
  1191. DWORD dwADsErr = *pHr;
  1192. switch (dwADsErr) {
  1193. case E_ADS_UNKNOWN_OBJECT:
  1194. case E_ADS_PROPERTY_NOT_SUPPORTED:
  1195. case E_ADS_PROPERTY_INVALID:
  1196. case E_ADS_PROPERTY_NOT_FOUND:
  1197. *pHr = DISP_E_MEMBERNOTFOUND;
  1198. break;
  1199. case E_ADS_BAD_PARAMETER:
  1200. //*pHr = DISP_E_PARAMNOTOPTIONAL;
  1201. break;
  1202. case E_ADS_CANT_CONVERT_DATATYPE:
  1203. *pHr = DISP_E_TYPEMISMATCH;
  1204. //*pHr = DISP_E_BADVARTYPE;
  1205. break;
  1206. case E_ADS_SCHEMA_VIOLATION:
  1207. // depends
  1208. break;
  1209. default:
  1210. break;
  1211. // should make it s.t. E_ADS_xxx -> E_FAIL and no changes on others
  1212. // LATER
  1213. };
  1214. }