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.

1561 lines
33 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996
  5. //
  6. // File: cgenobj.cxx
  7. //
  8. // Contents: Microsoft ADs LDAP Provider Generic Object
  9. //
  10. //
  11. // History: 08-30-96 yihsins Created.
  12. //
  13. //----------------------------------------------------------------------------
  14. #include "ldap.hxx"
  15. #pragma hdrstop
  16. // Class CLDAPRootDSE
  17. DEFINE_IDispatch_Implementation(CLDAPRootDSE)
  18. DEFINE_IADs_Implementation(CLDAPRootDSE)
  19. CLDAPRootDSE::CLDAPRootDSE():
  20. _pPropertyCache( NULL ),
  21. _pDispMgr( NULL ),
  22. _pszLDAPServer(NULL),
  23. _pszLDAPDn(NULL),
  24. _pLdapHandle( NULL )
  25. {
  26. VariantInit(&_vFilter);
  27. VariantInit(&_vHints);
  28. ENLIST_TRACKING(CLDAPRootDSE);
  29. }
  30. HRESULT
  31. CLDAPRootDSE::CreateRootDSE(
  32. BSTR Parent,
  33. BSTR CommonName,
  34. BSTR LdapClassName,
  35. CCredentials& Credentials,
  36. DWORD dwObjectState,
  37. REFIID riid,
  38. void **ppvObj
  39. )
  40. {
  41. CLDAPRootDSE FAR * pGenObject = NULL;
  42. HRESULT hr = S_OK;
  43. hr = AllocateGenObject(Credentials, &pGenObject);
  44. BAIL_ON_FAILURE(hr);
  45. hr = pGenObject->InitializeCoreObject(
  46. Parent,
  47. CommonName,
  48. LdapClassName,
  49. CLSID_LDAPGenObject,
  50. dwObjectState
  51. );
  52. BAIL_ON_FAILURE(hr);
  53. hr = BuildLDAPPathFromADsPath2(
  54. pGenObject->_ADsPath,
  55. &pGenObject->_pszLDAPServer,
  56. &pGenObject->_pszLDAPDn,
  57. &pGenObject->_dwPort
  58. );
  59. BAIL_ON_FAILURE(hr);
  60. //
  61. // At this point update the info in the property cache
  62. //
  63. pGenObject->_pPropertyCache->SetObjInformation(
  64. &(pGenObject->_Credentials),
  65. pGenObject->_pszLDAPServer,
  66. pGenObject->_dwPort
  67. );
  68. BAIL_ON_FAILURE(hr);
  69. hr = LdapOpenObject(
  70. pGenObject->_pszLDAPServer,
  71. NULL,
  72. &(pGenObject->_pLdapHandle),
  73. pGenObject->_Credentials,
  74. pGenObject->_dwPort
  75. );
  76. BAIL_ON_FAILURE(hr);
  77. if (Credentials.GetAuthFlags() & ADS_AUTH_RESERVED) {
  78. //
  79. // From Umi so we need to return UMI Object not RootDSE.
  80. //
  81. hr = ((CCoreADsObject*)pGenObject)->InitUmiObject(
  82. IntfPropsGeneric,
  83. pGenObject->_pPropertyCache,
  84. (IADs*) pGenObject,
  85. (IADs*) pGenObject,
  86. riid,
  87. ppvObj,
  88. &(pGenObject->_Credentials),
  89. pGenObject->_dwPort,
  90. pGenObject->_pszLDAPServer,
  91. NULL,
  92. pGenObject->_pLdapHandle
  93. );
  94. BAIL_ON_FAILURE(hr);
  95. RRETURN(S_OK);
  96. }
  97. hr = pGenObject->QueryInterface(riid, ppvObj);
  98. BAIL_ON_FAILURE(hr);
  99. pGenObject->Release();
  100. RRETURN(hr);
  101. error:
  102. *ppvObj = NULL;
  103. delete pGenObject;
  104. RRETURN_EXP_IF_ERR(hr);
  105. }
  106. CLDAPRootDSE::~CLDAPRootDSE( )
  107. {
  108. VariantClear(&_vFilter);
  109. VariantClear(&_vHints);
  110. if ( _pLdapHandle )
  111. {
  112. LdapCloseObject(_pLdapHandle);
  113. _pLdapHandle = NULL;
  114. }
  115. if (_pszLDAPServer) {
  116. FreeADsStr(_pszLDAPServer);
  117. _pszLDAPServer = NULL;
  118. }
  119. if (_pszLDAPDn) {
  120. FreeADsStr(_pszLDAPDn);
  121. _pszLDAPDn = NULL;
  122. }
  123. delete _pDispMgr;
  124. delete _pPropertyCache;
  125. }
  126. STDMETHODIMP
  127. CLDAPRootDSE::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  128. {
  129. if (ppv == NULL) {
  130. RRETURN(E_POINTER);
  131. }
  132. if (IsEqualIID(iid, IID_IUnknown))
  133. {
  134. *ppv = (IADs FAR *) this;
  135. }
  136. else if (IsEqualIID(iid, IID_IADs))
  137. {
  138. *ppv = (IADs FAR *) this;
  139. }
  140. else if (IsEqualIID(iid, IID_IDispatch))
  141. {
  142. *ppv = (IADs FAR *) this;
  143. }
  144. else if (IsEqualIID(iid, IID_IADsPropertyList))
  145. {
  146. *ppv = (IADsPropertyList FAR *) this;
  147. }
  148. else if (IsEqualIID(iid, IID_IADsObjectOptions)) {
  149. *ppv = (IADsObjectOptions FAR *) this;
  150. }
  151. else if (IsEqualIID(iid, IID_ISupportErrorInfo))
  152. {
  153. *ppv = (ISupportErrorInfo FAR *) this;
  154. }
  155. else
  156. {
  157. *ppv = NULL;
  158. return E_NOINTERFACE;
  159. }
  160. AddRef();
  161. return NOERROR;
  162. }
  163. HRESULT
  164. CLDAPRootDSE::SetInfo()
  165. {
  166. HRESULT hr = S_OK;
  167. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  168. //
  169. // No concept of creating RootDSE objects
  170. // Any DS must have a RootDSE object
  171. //
  172. hr = E_FAIL;
  173. BAIL_ON_FAILURE(hr);
  174. //
  175. // If the create succeded, set the object type to bound
  176. //
  177. SetObjectState(ADS_OBJECT_BOUND);
  178. }else {
  179. hr = LDAPSetObject();
  180. BAIL_ON_FAILURE(hr);
  181. }
  182. error:
  183. RRETURN_EXP_IF_ERR(hr);
  184. }
  185. HRESULT
  186. CLDAPRootDSE::LDAPSetObject()
  187. {
  188. HRESULT hr = S_OK;
  189. LDAPModW **aMod = NULL;
  190. BOOL fNTSecDes = FALSE;
  191. SECURITY_INFORMATION NewSeInfo;
  192. hr = _pPropertyCache->LDAPMarshallProperties(
  193. &aMod,
  194. &fNTSecDes,
  195. &NewSeInfo
  196. );
  197. BAIL_ON_FAILURE(hr);
  198. if ( aMod == NULL ) // There are no changes that needs to be modified
  199. RRETURN(S_OK);
  200. hr = LdapModifyS(
  201. _pLdapHandle,
  202. NULL,
  203. aMod
  204. );
  205. BAIL_ON_FAILURE(hr);
  206. // We are successful at this point,
  207. // So, clean up the flags in the cache so the same operation
  208. // won't be repeated on the next SetInfo()
  209. _pPropertyCache->ClearAllPropertyFlags();
  210. error:
  211. if (aMod) {
  212. if ( *aMod )
  213. FreeADsMem( *aMod );
  214. FreeADsMem( aMod );
  215. }
  216. RRETURN_EXP_IF_ERR(hr);
  217. }
  218. HRESULT
  219. CLDAPRootDSE::InterfaceSupportsErrorInfo(THIS_ REFIID riid)
  220. {
  221. if (IsEqualIID(riid, IID_IADs) ||
  222. IsEqualIID(riid, IID_IADsPropertyList)) {
  223. RRETURN(S_OK);
  224. } else {
  225. RRETURN(S_FALSE);
  226. }
  227. }
  228. HRESULT
  229. CLDAPRootDSE::GetInfo()
  230. {
  231. RRETURN(GetInfo(GETINFO_FLAG_EXPLICIT));
  232. }
  233. HRESULT
  234. CLDAPRootDSE::GetInfo(
  235. DWORD dwFlags
  236. )
  237. {
  238. HRESULT hr = S_OK;
  239. DWORD dwSyntaxId = ADSTYPE_CASE_IGNORE_STRING;
  240. LDAPMessage *res = NULL;
  241. if (dwFlags == GETINFO_FLAG_IMPLICIT_AS_NEEDED) {
  242. if (_pPropertyCache->getGetInfoFlag()) {
  243. //
  244. // Nothing to do in this case.
  245. //
  246. RRETURN(S_OK);
  247. }
  248. }
  249. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  250. hr = E_ADS_OBJECT_UNBOUND;
  251. BAIL_ON_FAILURE(hr);
  252. }
  253. hr = LdapSearchS(
  254. _pLdapHandle,
  255. NULL,
  256. LDAP_SCOPE_BASE,
  257. TEXT("(objectClass=*)"),
  258. NULL,
  259. 0,
  260. &res
  261. );
  262. BAIL_ON_FAILURE(hr);
  263. if ( dwFlags == GETINFO_FLAG_EXPLICIT )
  264. {
  265. // If this is an explicit GetInfo,
  266. // delete the old cache and start a new cache from scratch.
  267. _pPropertyCache->flushpropertycache();
  268. }
  269. hr = _pPropertyCache->LDAPUnMarshallPropertiesAs(
  270. _pszLDAPServer,
  271. _pLdapHandle,
  272. res,
  273. dwSyntaxId,
  274. (dwFlags == GETINFO_FLAG_EXPLICIT) ?
  275. TRUE :
  276. FALSE,
  277. _Credentials
  278. );
  279. BAIL_ON_FAILURE(hr);
  280. _pPropertyCache->setGetInfoFlag();
  281. error:
  282. if (res) {
  283. LdapMsgFree( res );
  284. }
  285. RRETURN_EXP_IF_ERR(hr);
  286. }
  287. STDMETHODIMP
  288. CLDAPRootDSE::GetInfoEx(THIS_ VARIANT vProperties, long lnReserved)
  289. {
  290. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  291. }
  292. HRESULT
  293. CLDAPRootDSE::AllocateGenObject(
  294. CCredentials& Credentials,
  295. CLDAPRootDSE ** ppGenObject
  296. )
  297. {
  298. CLDAPRootDSE FAR * pGenObject = NULL;
  299. CAggregatorDispMgr FAR * pDispMgr = NULL;
  300. CPropertyCache FAR * pPropertyCache = NULL;
  301. HRESULT hr = S_OK;
  302. pGenObject = new CLDAPRootDSE();
  303. if (pGenObject == NULL) {
  304. hr = E_OUTOFMEMORY;
  305. }
  306. BAIL_ON_FAILURE(hr);
  307. pDispMgr = new CAggregatorDispMgr(Credentials);
  308. if (pDispMgr == NULL) {
  309. hr = E_OUTOFMEMORY;
  310. }
  311. BAIL_ON_FAILURE(hr);
  312. hr = pDispMgr->LoadTypeInfoEntry(
  313. LIBID_ADs,
  314. IID_IADs,
  315. (IADs *)pGenObject,
  316. DISPID_REGULAR
  317. );
  318. BAIL_ON_FAILURE(hr);
  319. hr = pDispMgr->LoadTypeInfoEntry(
  320. LIBID_ADs,
  321. IID_IADsPropertyList,
  322. (IADsPropertyList *)pGenObject,
  323. DISPID_VALUE
  324. );
  325. BAIL_ON_FAILURE(hr);
  326. hr = pDispMgr->LoadTypeInfoEntry(
  327. LIBID_ADs,
  328. IID_IADsObjectOptions,
  329. (IADsObjectOptions *)pGenObject,
  330. DISPID_VALUE
  331. );
  332. BAIL_ON_FAILURE(hr);
  333. hr = CPropertyCache::createpropertycache(
  334. (CCoreADsObject FAR *) pGenObject,
  335. (IGetAttributeSyntax *) pGenObject,
  336. &pPropertyCache
  337. );
  338. BAIL_ON_FAILURE(hr);
  339. pDispMgr->RegisterPropertyCache(pPropertyCache);
  340. pGenObject->_Credentials = Credentials;
  341. pGenObject->_pPropertyCache = pPropertyCache;
  342. pGenObject->_pDispMgr = pDispMgr;
  343. *ppGenObject = pGenObject;
  344. RRETURN(hr);
  345. error:
  346. delete pDispMgr;
  347. delete pGenObject;
  348. RRETURN_EXP_IF_ERR(hr);
  349. }
  350. STDMETHODIMP
  351. CLDAPRootDSE::Get(
  352. THIS_ BSTR bstrName,
  353. VARIANT FAR* pvProp
  354. )
  355. {
  356. HRESULT hr = S_OK;
  357. DWORD dwSyntaxId;
  358. DWORD dwStatus = 0;
  359. LDAPOBJECTARRAY ldapSrcObjects;
  360. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  361. //
  362. // For some folks who have no clue what they are doing.
  363. //
  364. if (!pvProp) {
  365. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  366. }
  367. //
  368. // retrieve data object from cache; if one exists
  369. //
  370. if ( GetObjectState() == ADS_OBJECT_UNBOUND ) {
  371. hr = _pPropertyCache->unboundgetproperty(
  372. bstrName,
  373. &dwSyntaxId,
  374. &dwStatus,
  375. &ldapSrcObjects
  376. );
  377. // For backward compatibility
  378. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  379. hr = E_FAIL;
  380. }
  381. } else {
  382. hr = _pPropertyCache->getproperty(
  383. bstrName,
  384. &dwSyntaxId,
  385. &dwStatus,
  386. &ldapSrcObjects
  387. );
  388. // For backward compatibility
  389. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  390. hr = E_ADS_PROPERTY_NOT_FOUND;
  391. }
  392. }
  393. BAIL_ON_FAILURE(hr);
  394. //
  395. // translate the Ldap objects to variants
  396. //
  397. if ( ldapSrcObjects.dwCount == 1 ) {
  398. hr = LdapTypeToVarTypeCopy(
  399. _pszLDAPServer,
  400. _Credentials,
  401. ldapSrcObjects.pLdapObjects,
  402. dwSyntaxId,
  403. pvProp
  404. );
  405. } else {
  406. hr = LdapTypeToVarTypeCopyConstruct(
  407. _pszLDAPServer,
  408. _Credentials,
  409. ldapSrcObjects,
  410. dwSyntaxId,
  411. pvProp
  412. );
  413. }
  414. BAIL_ON_FAILURE(hr);
  415. error:
  416. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  417. RRETURN_EXP_IF_ERR(hr);
  418. }
  419. STDMETHODIMP
  420. CLDAPRootDSE::Put(
  421. THIS_ BSTR bstrName,
  422. VARIANT vProp
  423. )
  424. {
  425. HRESULT hr = S_OK;
  426. DWORD dwSyntaxId = 0;
  427. DWORD dwIndex = 0;
  428. LDAPOBJECTARRAY ldapDestObjects;
  429. DWORD dwNumValues = 0;
  430. VARIANT * pVarArray = NULL;
  431. VARIANT * pvProp = NULL;
  432. VARIANT vDefProp;
  433. VariantInit(&vDefProp);
  434. LDAPOBJECTARRAY_INIT(ldapDestObjects);
  435. //
  436. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  437. // We should dereference a VT_BYREF|VT_VARIANT once and see
  438. // what's inside.
  439. //
  440. pvProp = &vProp;
  441. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  442. pvProp = V_VARIANTREF(&vProp);
  443. }
  444. if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
  445. (V_VT(pvProp) == (VT_VARIANT|VT_ARRAY))) {
  446. hr = ConvertSafeArrayToVariantArray(
  447. vProp,
  448. &pVarArray,
  449. &dwNumValues
  450. );
  451. // returns E_FAIL if vProp is invalid
  452. if (hr == E_FAIL)
  453. hr = E_ADS_BAD_PARAMETER;
  454. BAIL_ON_FAILURE(hr);
  455. pvProp = pVarArray;
  456. }
  457. else {
  458. //
  459. // If this is a single VT_BYREF of a basic type, we dereference
  460. // it once.
  461. //
  462. if (V_ISBYREF(pvProp)) {
  463. hr = VariantCopyInd(&vDefProp, pvProp);
  464. BAIL_ON_FAILURE(hr);
  465. pvProp = &vDefProp;
  466. }
  467. dwNumValues = 1;
  468. }
  469. //
  470. // check if the variant maps to the syntax of this property
  471. //
  472. hr = GetLdapSyntaxFromVariant(
  473. pvProp,
  474. &dwSyntaxId,
  475. _pszLDAPServer,
  476. bstrName,
  477. _Credentials,
  478. _dwPort
  479. );
  480. BAIL_ON_FAILURE(hr);
  481. if ( dwNumValues > 0 )
  482. {
  483. hr = VarTypeToLdapTypeCopyConstruct(
  484. _pszLDAPServer,
  485. _Credentials,
  486. dwSyntaxId,
  487. pvProp,
  488. dwNumValues,
  489. &ldapDestObjects
  490. );
  491. BAIL_ON_FAILURE(hr);
  492. }
  493. //
  494. // Find this property in the cache
  495. //
  496. hr = _pPropertyCache->findproperty(
  497. bstrName,
  498. &dwIndex
  499. );
  500. //
  501. // If this property does not exist in the
  502. // cache, add this property into the cache.
  503. //
  504. if (FAILED(hr)) {
  505. hr = _pPropertyCache->addproperty( bstrName );
  506. //
  507. // If dwNumValues == 0 ( delete the property ) but couldn't find
  508. // the property, or if the add operation fails, return the error.
  509. //
  510. BAIL_ON_FAILURE(hr);
  511. }
  512. //
  513. // Now update the property in the cache
  514. //
  515. hr = _pPropertyCache->putproperty(
  516. bstrName,
  517. PROPERTY_UPDATE,
  518. dwSyntaxId,
  519. ldapDestObjects
  520. );
  521. BAIL_ON_FAILURE(hr);
  522. error:
  523. LdapTypeFreeLdapObjects( &ldapDestObjects );
  524. if (pVarArray) {
  525. DWORD i = 0;
  526. for (i = 0; i < dwNumValues; i++) {
  527. VariantClear(pVarArray + i);
  528. }
  529. FreeADsMem(pVarArray);
  530. }
  531. RRETURN_EXP_IF_ERR(hr);
  532. }
  533. STDMETHODIMP
  534. CLDAPRootDSE::GetEx(
  535. THIS_ BSTR bstrName,
  536. VARIANT FAR* pvProp
  537. )
  538. {
  539. HRESULT hr = S_OK;
  540. DWORD dwSyntaxId;
  541. DWORD dwStatus = 0;
  542. LDAPOBJECTARRAY ldapSrcObjects;
  543. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  544. //
  545. // For those who know no not what they do
  546. //
  547. if (!pvProp) {
  548. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  549. }
  550. //
  551. // retrieve data object from cache; if one exists
  552. //
  553. if ( GetObjectState() == ADS_OBJECT_UNBOUND ) {
  554. hr = _pPropertyCache->unboundgetproperty(
  555. bstrName,
  556. &dwSyntaxId,
  557. &dwStatus,
  558. &ldapSrcObjects
  559. );
  560. // For backward compatibility
  561. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  562. hr = E_FAIL;
  563. }
  564. } else {
  565. hr = _pPropertyCache->getproperty(
  566. bstrName,
  567. &dwSyntaxId,
  568. &dwStatus,
  569. &ldapSrcObjects
  570. );
  571. // For backward compatibility
  572. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  573. hr = E_ADS_PROPERTY_NOT_FOUND;
  574. }
  575. }
  576. BAIL_ON_FAILURE(hr);
  577. //
  578. // translate the Ldap objects to variants
  579. //
  580. hr = LdapTypeToVarTypeCopyConstruct(
  581. _pszLDAPServer,
  582. _Credentials,
  583. ldapSrcObjects,
  584. dwSyntaxId,
  585. pvProp
  586. );
  587. BAIL_ON_FAILURE(hr);
  588. error:
  589. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  590. RRETURN_EXP_IF_ERR(hr);
  591. }
  592. STDMETHODIMP
  593. CLDAPRootDSE::PutEx(
  594. THIS_ long lnControlCode,
  595. BSTR bstrName,
  596. VARIANT vProp
  597. )
  598. {
  599. HRESULT hr = S_OK;
  600. DWORD dwSyntaxId = 0;
  601. DWORD dwFlags = 0;
  602. DWORD dwIndex = 0;
  603. LDAPOBJECTARRAY ldapDestObjects;
  604. DWORD dwNumValues = 0;
  605. VARIANT * pVarArray = NULL;
  606. VARIANT * pvProp = NULL;
  607. LDAPOBJECTARRAY_INIT(ldapDestObjects);
  608. switch ( lnControlCode ) {
  609. case ADS_PROPERTY_CLEAR:
  610. dwFlags = PROPERTY_DELETE;
  611. break;
  612. case ADS_PROPERTY_APPEND:
  613. dwFlags = PROPERTY_ADD;
  614. break;
  615. case ADS_PROPERTY_UPDATE:
  616. dwFlags = PROPERTY_UPDATE;
  617. break;
  618. default:
  619. RRETURN(hr = E_ADS_BAD_PARAMETER);
  620. }
  621. if ( dwFlags != PROPERTY_DELETE )
  622. {
  623. //
  624. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  625. // We should dereference a VT_BYREF|VT_VARIANT once and see
  626. // what's inside.
  627. //
  628. pvProp = &vProp;
  629. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  630. pvProp = V_VARIANTREF(&vProp);
  631. }
  632. if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
  633. (V_VT(pvProp) == (VT_VARIANT|VT_ARRAY))) {
  634. hr = ConvertSafeArrayToVariantArray(
  635. *pvProp,
  636. &pVarArray,
  637. &dwNumValues
  638. );
  639. // returns E_FAIL if *pvProp is invalid
  640. if (hr == E_FAIL)
  641. hr = E_ADS_BAD_PARAMETER;
  642. BAIL_ON_FAILURE(hr);
  643. pvProp = pVarArray;
  644. } else {
  645. hr = E_FAIL;
  646. BAIL_ON_FAILURE(hr);
  647. }
  648. //
  649. // check if the variant maps to the syntax of this property
  650. //
  651. //
  652. // check if the variant maps to the syntax of this property
  653. //
  654. hr = GetLdapSyntaxFromVariant(
  655. pvProp,
  656. &dwSyntaxId,
  657. _pszLDAPServer,
  658. bstrName,
  659. _Credentials,
  660. _dwPort
  661. );
  662. BAIL_ON_FAILURE(hr);
  663. if ( dwNumValues > 0 )
  664. {
  665. hr = VarTypeToLdapTypeCopyConstruct(
  666. _pszLDAPServer,
  667. _Credentials,
  668. dwSyntaxId,
  669. pvProp,
  670. dwNumValues,
  671. &ldapDestObjects
  672. );
  673. BAIL_ON_FAILURE(hr);
  674. }
  675. }
  676. //
  677. // Find this property in the cache
  678. //
  679. hr = _pPropertyCache->findproperty(
  680. bstrName,
  681. &dwIndex
  682. );
  683. //
  684. // If this property does not exist in the
  685. // cache, add this property into the cache.
  686. //
  687. if (FAILED(hr)) {
  688. hr = _pPropertyCache->addproperty( bstrName );
  689. //
  690. // If dwNumValues == 0 ( delete the property ) but couldn't find
  691. // the property, or if the add operation fails, return the error.
  692. //
  693. BAIL_ON_FAILURE(hr);
  694. }
  695. //
  696. // Now update the property in the cache
  697. //
  698. hr = _pPropertyCache->putproperty(
  699. bstrName,
  700. dwFlags,
  701. dwSyntaxId,
  702. ldapDestObjects
  703. );
  704. BAIL_ON_FAILURE(hr);
  705. error:
  706. LdapTypeFreeLdapObjects( &ldapDestObjects );
  707. if (pVarArray) {
  708. DWORD i = 0;
  709. for (i = 0; i < dwNumValues; i++) {
  710. VariantClear(pVarArray + i);
  711. }
  712. FreeADsMem(pVarArray);
  713. }
  714. RRETURN_EXP_IF_ERR(hr);
  715. }
  716. STDMETHODIMP
  717. CLDAPRootDSE::get_PropertyCount(
  718. THIS_ long FAR *plCount
  719. )
  720. {
  721. HRESULT hr = E_FAIL;
  722. if (!plCount) {
  723. RRETURN(E_ADS_BAD_PARAMETER);
  724. }
  725. if (_pPropertyCache) {
  726. hr = _pPropertyCache->get_PropertyCount((PDWORD)plCount);
  727. }
  728. RRETURN_EXP_IF_ERR(hr);
  729. }
  730. STDMETHODIMP
  731. CLDAPRootDSE::Next(
  732. THIS_ VARIANT FAR *pVariant
  733. )
  734. {
  735. HRESULT hr = E_FAIL;
  736. DWORD dwSyntaxId = 0;
  737. DWORD dwNumValues = 0;
  738. LDAPOBJECTARRAY ldapSrcObjects;
  739. IDispatch * pDispatch = NULL;
  740. DWORD dwNumAdsValues = 0;
  741. DWORD dwAdsType = 0;
  742. DWORD dwPropStatus = 0;
  743. DWORD dwCtrlCode = 0;
  744. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  745. if (!pVariant) {
  746. RRETURN(E_ADS_BAD_PARAMETER);
  747. }
  748. if(!_pPropertyCache->index_valid())
  749. RRETURN_EXP_IF_ERR(E_FAIL);
  750. //
  751. // retreive the item with current idex; unboundgetproperty()
  752. // returns E_ADS_PROPERTY_NOT_FOUND if index out of bound
  753. //
  754. hr = _pPropertyCache->unboundgetproperty(
  755. _pPropertyCache->get_CurrentIndex(),
  756. &dwSyntaxId,
  757. &dwPropStatus,
  758. &ldapSrcObjects
  759. );
  760. BAIL_ON_FAILURE(hr);
  761. dwCtrlCode = MapPropCacheFlagToControlCode(dwPropStatus);
  762. //
  763. // translate the LDAP objects to variants
  764. //
  765. hr = ConvertLdapValuesToVariant(
  766. _pPropertyCache->get_CurrentPropName(),
  767. &ldapSrcObjects,
  768. dwSyntaxId,
  769. dwCtrlCode,
  770. pVariant,
  771. _pszLDAPServer,
  772. &_Credentials
  773. );
  774. BAIL_ON_FAILURE(hr);
  775. error:
  776. //
  777. // - goto next one even if error to avoid infinite looping at a property
  778. // which we cannot convert (e.g. schemaless server property.)
  779. // - do not return the result of Skip() as current operation does not
  780. // depend on the success of Skip().
  781. //
  782. Skip(1);
  783. LdapTypeFreeLdapObjects(&ldapSrcObjects);
  784. if (FAILED(hr)) {
  785. V_VT(pVariant) = VT_ERROR;
  786. }
  787. RRETURN_EXP_IF_ERR(hr);
  788. }
  789. STDMETHODIMP
  790. CLDAPRootDSE::Skip(
  791. THIS_ long cElements
  792. )
  793. {
  794. HRESULT hr = E_FAIL;
  795. hr = _pPropertyCache->skip_propindex(
  796. cElements
  797. );
  798. RRETURN(hr);
  799. }
  800. STDMETHODIMP
  801. CLDAPRootDSE::Reset(
  802. )
  803. {
  804. _pPropertyCache->reset_propindex();
  805. RRETURN(S_OK);
  806. }
  807. STDMETHODIMP
  808. CLDAPRootDSE::ResetPropertyItem(THIS_ VARIANT varEntry)
  809. {
  810. HRESULT hr = S_OK;
  811. DWORD dwIndex = 0;
  812. switch (V_VT(&varEntry)) {
  813. case VT_BSTR:
  814. hr = _pPropertyCache->findproperty(
  815. V_BSTR(&varEntry),
  816. &dwIndex
  817. );
  818. BAIL_ON_FAILURE(hr);
  819. break;
  820. case VT_I4:
  821. dwIndex = V_I4(&varEntry);
  822. break;
  823. case VT_I2:
  824. dwIndex = V_I2(&varEntry);
  825. break;
  826. default:
  827. hr = E_FAIL;
  828. BAIL_ON_FAILURE(hr);
  829. }
  830. hr = _pPropertyCache->deleteproperty(
  831. dwIndex
  832. );
  833. error:
  834. RRETURN_EXP_IF_ERR(hr);
  835. }
  836. STDMETHODIMP
  837. CLDAPRootDSE::GetPropertyItem(
  838. THIS_ BSTR bstrName,
  839. LONG lnType,
  840. VARIANT * pVariant
  841. )
  842. {
  843. HRESULT hr = S_OK;
  844. DWORD dwSyntaxId;
  845. LDAPOBJECTARRAY ldapSrcObjects;
  846. DWORD dwNumValues = 0;
  847. DWORD dwUserSyntaxId = 0;
  848. DWORD dwStatus = 0;
  849. DWORD dwCtrlCode = 0;
  850. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  851. //
  852. // retrieve data object from cache; do NOT retreive from server
  853. //
  854. hr = _pPropertyCache->unboundgetproperty(
  855. bstrName,
  856. &dwSyntaxId,
  857. &dwStatus,
  858. &ldapSrcObjects
  859. );
  860. BAIL_ON_FAILURE(hr);
  861. //
  862. // translate the Ldap objects to variants
  863. //
  864. dwCtrlCode = MapPropCacheFlagToControlCode(dwStatus);
  865. hr = ConvertLdapValuesToVariant(
  866. bstrName,
  867. &ldapSrcObjects,
  868. dwSyntaxId,
  869. dwCtrlCode,
  870. pVariant,
  871. _pszLDAPServer,
  872. &_Credentials
  873. );
  874. error:
  875. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  876. RRETURN_EXP_IF_ERR(hr);
  877. }
  878. STDMETHODIMP
  879. CLDAPRootDSE::PutPropertyItem(
  880. THIS_ VARIANT varData
  881. )
  882. {
  883. HRESULT hr = S_OK;
  884. DWORD dwFlags = 0;
  885. DWORD dwIndex = 0;
  886. DWORD dwControlCode = 0;
  887. LDAPOBJECTARRAY ldapDestObjects;
  888. WCHAR szPropertyName[MAX_PATH];
  889. DWORD dwSyntaxId = 0;
  890. LDAPOBJECTARRAY_INIT(ldapDestObjects);
  891. hr = ConvertVariantToLdapValues(
  892. varData,
  893. szPropertyName,
  894. &dwControlCode,
  895. &ldapDestObjects,
  896. &dwSyntaxId,
  897. _pszLDAPServer,
  898. &_Credentials,
  899. _dwPort
  900. );
  901. BAIL_ON_FAILURE(hr);
  902. switch ( dwControlCode ) {
  903. case ADS_PROPERTY_CLEAR:
  904. //
  905. // Clears an entire property
  906. //
  907. dwFlags = PROPERTY_DELETE;
  908. break;
  909. case ADS_PROPERTY_UPDATE:
  910. //
  911. // Updates the entire property
  912. //
  913. dwFlags = PROPERTY_UPDATE;
  914. break;
  915. case ADS_PROPERTY_APPEND:
  916. //
  917. // Appends a set of values to the property
  918. //
  919. break;
  920. case ADS_PROPERTY_DELETE:
  921. //
  922. // Delete a value(s) from the property
  923. break;
  924. default:
  925. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  926. }
  927. //
  928. // Find this property in the cache
  929. //
  930. hr = _pPropertyCache->findproperty(
  931. szPropertyName,
  932. &dwIndex
  933. );
  934. //
  935. // If this property does not exist in the
  936. // cache, add this property into the cache.
  937. //
  938. if (FAILED(hr)) {
  939. hr = _pPropertyCache->addproperty( szPropertyName );
  940. //
  941. // If dwNumValues == 0 ( delete the property ) but couldn't find
  942. // the property, or if the add operation fails, return the error.
  943. //
  944. BAIL_ON_FAILURE(hr);
  945. }
  946. //
  947. // Now update the property in the cache
  948. //
  949. hr = _pPropertyCache->putproperty(
  950. szPropertyName,
  951. dwFlags,
  952. dwSyntaxId,
  953. ldapDestObjects
  954. );
  955. BAIL_ON_FAILURE(hr);
  956. error:
  957. LdapTypeFreeLdapObjects( &ldapDestObjects );
  958. RRETURN_EXP_IF_ERR(hr);
  959. }
  960. STDMETHODIMP
  961. CLDAPRootDSE::Item(THIS_ VARIANT varIndex, VARIANT * pVariant)
  962. {
  963. HRESULT hr = S_OK;
  964. DWORD dwSyntaxId;
  965. LDAPOBJECTARRAY ldapSrcObjects;
  966. PADSVALUE pAdsValues = NULL;
  967. DWORD dwNumValues = 0;
  968. DWORD dwNumAdsValues = 0;
  969. DWORD dwAdsType = 0;
  970. DWORD dwStatus = 0;
  971. DWORD dwCtrlCode = 0;
  972. VARIANT *pvVar = &varIndex;
  973. LPWSTR szPropName = NULL;
  974. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  975. //
  976. // retrieve data object from cache; if one exis
  977. //
  978. if (V_VT(pvVar) == (VT_BYREF|VT_VARIANT)) {
  979. //
  980. // The value is being passed in byref so we need to
  981. // deref it for vbs stuff to work
  982. //
  983. pvVar = V_VARIANTREF(&varIndex);
  984. }
  985. switch (V_VT(pvVar)) {
  986. case VT_BSTR:
  987. //
  988. // retrieve data object from cache; if one exists
  989. //
  990. if ( GetObjectState() == ADS_OBJECT_UNBOUND ) {
  991. hr = _pPropertyCache->unboundgetproperty(
  992. V_BSTR(pvVar),
  993. &dwSyntaxId,
  994. &dwStatus,
  995. &ldapSrcObjects
  996. );
  997. // For backward compatibility -- nothing done, you
  998. // should be able to get an item marked as delete.
  999. } else {
  1000. hr = _pPropertyCache->getproperty(
  1001. V_BSTR(pvVar),
  1002. &dwSyntaxId,
  1003. &dwStatus,
  1004. &ldapSrcObjects
  1005. );
  1006. // For backward compatibility -- nothing done,
  1007. // you should be able to get an item marked as delete.
  1008. }
  1009. BAIL_ON_FAILURE(hr);
  1010. szPropName = V_BSTR(pvVar);
  1011. dwCtrlCode = MapPropCacheFlagToControlCode(dwStatus);
  1012. break;
  1013. case VT_I4:
  1014. hr = _pPropertyCache->unboundgetproperty(
  1015. (DWORD)V_I4(pvVar),
  1016. &dwSyntaxId,
  1017. &dwStatus,
  1018. &ldapSrcObjects
  1019. );
  1020. // For backward compatibility -- nothing done, you
  1021. // should be able to get an item marked as delte.
  1022. BAIL_ON_FAILURE(hr);
  1023. szPropName = _pPropertyCache->get_PropName(
  1024. (DWORD)V_I4(pvVar)
  1025. );
  1026. dwCtrlCode = MapPropCacheFlagToControlCode(dwStatus);
  1027. break;
  1028. case VT_I2:
  1029. hr = _pPropertyCache->unboundgetproperty(
  1030. (DWORD)V_I2(pvVar),
  1031. &dwSyntaxId,
  1032. &dwStatus,
  1033. &ldapSrcObjects
  1034. );
  1035. // For backward compatibility -- nothing done, you
  1036. // should be able to get an item marked as delete.
  1037. BAIL_ON_FAILURE(hr);
  1038. szPropName = _pPropertyCache->get_PropName(
  1039. (DWORD)V_I2(pvVar)
  1040. );
  1041. dwCtrlCode = MapPropCacheFlagToControlCode(dwStatus);
  1042. break;
  1043. default:
  1044. hr = E_FAIL;
  1045. BAIL_ON_FAILURE(hr);
  1046. }
  1047. //
  1048. // translate the Ldap objects to variants
  1049. //
  1050. dwCtrlCode = MapPropCacheFlagToControlCode(dwStatus);
  1051. hr = ConvertLdapValuesToVariant(
  1052. szPropName,
  1053. &ldapSrcObjects,
  1054. dwSyntaxId,
  1055. dwCtrlCode,
  1056. pVariant,
  1057. _pszLDAPServer,
  1058. &_Credentials
  1059. );
  1060. error:
  1061. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  1062. RRETURN_EXP_IF_ERR(hr);
  1063. }
  1064. STDMETHODIMP
  1065. CLDAPRootDSE::PurgePropertyList()
  1066. {
  1067. _pPropertyCache->flushpropertycache();
  1068. RRETURN(S_OK);
  1069. }
  1070. STDMETHODIMP
  1071. CLDAPRootDSE::GetInfo(
  1072. LPWSTR szPropertyName,
  1073. DWORD dwSyntaxId,
  1074. BOOL fExplicit
  1075. )
  1076. {
  1077. HRESULT hr = S_OK;
  1078. LDAPMessage *res = NULL;
  1079. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  1080. hr = E_ADS_OBJECT_UNBOUND;
  1081. BAIL_ON_FAILURE(hr);
  1082. }
  1083. hr = LdapSearchS(
  1084. _pLdapHandle,
  1085. _pszLDAPDn,
  1086. LDAP_SCOPE_BASE,
  1087. TEXT("(objectClass=*)"),
  1088. NULL,
  1089. 0,
  1090. &res
  1091. );
  1092. BAIL_ON_FAILURE(hr);
  1093. if ( fExplicit )
  1094. {
  1095. // If this is an explicit GetInfo,
  1096. // delete the old cache and start a new cache from scratch.
  1097. _pPropertyCache->flushpropertycache();
  1098. }
  1099. hr = _pPropertyCache->LDAPUnMarshallPropertiesAs(
  1100. _pszLDAPServer,
  1101. _pLdapHandle,
  1102. res,
  1103. ADSTYPE_CASE_IGNORE_STRING,
  1104. fExplicit,
  1105. _Credentials
  1106. );
  1107. BAIL_ON_FAILURE(hr);
  1108. _pPropertyCache->setGetInfoFlag();
  1109. error:
  1110. if (res) {
  1111. LdapMsgFree( res );
  1112. }
  1113. RRETURN_EXP_IF_ERR(hr);
  1114. }
  1115. //
  1116. // Needed for dynamic dispid's in the property cache.
  1117. //
  1118. HRESULT
  1119. CLDAPRootDSE::GetAttributeSyntax(
  1120. LPWSTR szPropertyName,
  1121. PDWORD pdwSyntaxId
  1122. )
  1123. {
  1124. HRESULT hr;
  1125. hr = LdapGetSyntaxOfAttributeOnServer(
  1126. _pszLDAPServer,
  1127. szPropertyName,
  1128. pdwSyntaxId,
  1129. _Credentials,
  1130. _dwPort
  1131. );
  1132. RRETURN_EXP_IF_ERR(hr);
  1133. }
  1134. //
  1135. // IADsObjecOptions methods
  1136. //
  1137. //
  1138. // Unlike the cgenobj GetOption implementation, this will support
  1139. // only a subset of the flags - mutual auth status being the only one.
  1140. //
  1141. STDMETHODIMP
  1142. CLDAPRootDSE::GetOption(
  1143. THIS_ long lnControlCode,
  1144. VARIANT FAR* pvProp
  1145. )
  1146. {
  1147. HRESULT hr = S_OK;
  1148. ULONG ulFlags = 0;
  1149. CtxtHandle hCtxtHandle;
  1150. DWORD dwErr = 0;
  1151. VariantInit(pvProp);
  1152. switch (lnControlCode) {
  1153. case ADS_OPTION_MUTUAL_AUTH_STATUS :
  1154. dwErr = ldap_get_option(
  1155. _pLdapHandle->LdapHandle,
  1156. LDAP_OPT_SECURITY_CONTEXT,
  1157. (void *) &hCtxtHandle
  1158. );
  1159. if (dwErr) {
  1160. BAIL_ON_FAILURE(hr = E_FAIL);
  1161. }
  1162. //DSCLIENT
  1163. #if (!defined(WIN95))
  1164. dwErr = QueryContextAttributesWrapper(
  1165. &hCtxtHandle,
  1166. SECPKG_ATTR_FLAGS,
  1167. (void *) &ulFlags
  1168. );
  1169. if (dwErr) {
  1170. BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(dwErr));
  1171. }
  1172. #else
  1173. ulFlags = 0;
  1174. #endif
  1175. pvProp->vt = VT_I4;
  1176. pvProp->lVal = ulFlags;
  1177. break;
  1178. default:
  1179. hr = E_NOTIMPL;
  1180. }
  1181. error:
  1182. RRETURN(hr);
  1183. }
  1184. STDMETHODIMP
  1185. CLDAPRootDSE::SetOption(
  1186. THIS_ long lnControlCode,
  1187. VARIANT vProp
  1188. )
  1189. {
  1190. HRESULT hr = S_OK;
  1191. DWORD dwOptVal = 0;
  1192. VARIANT *pvProp = NULL;
  1193. //
  1194. // To make sure we handle variant by refs correctly.
  1195. //
  1196. pvProp = &vProp;
  1197. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  1198. pvProp = V_VARIANTREF(&vProp);
  1199. }
  1200. switch (lnControlCode) {
  1201. case ADS_PRIVATE_OPTION_KEEP_HANDLES :
  1202. hr = LdapcKeepHandleAround(_pLdapHandle);
  1203. break;
  1204. default:
  1205. hr = E_NOTIMPL;
  1206. }
  1207. RRETURN(hr);
  1208. }