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.

1655 lines
37 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. hr = 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. _pPropertyCache->DeleteSavingEntry();
  211. error:
  212. if (aMod) {
  213. if ( *aMod )
  214. FreeADsMem( *aMod );
  215. FreeADsMem( aMod );
  216. }
  217. RRETURN_EXP_IF_ERR(hr);
  218. }
  219. HRESULT
  220. CLDAPRootDSE::InterfaceSupportsErrorInfo(THIS_ REFIID riid)
  221. {
  222. if (IsEqualIID(riid, IID_IADs) ||
  223. IsEqualIID(riid, IID_IADsPropertyList)) {
  224. RRETURN(S_OK);
  225. } else {
  226. RRETURN(S_FALSE);
  227. }
  228. }
  229. HRESULT
  230. CLDAPRootDSE::GetInfo()
  231. {
  232. RRETURN(GetInfo(GETINFO_FLAG_EXPLICIT));
  233. }
  234. HRESULT
  235. CLDAPRootDSE::GetInfo(
  236. DWORD dwFlags
  237. )
  238. {
  239. HRESULT hr = S_OK;
  240. DWORD dwSyntaxId = ADSTYPE_CASE_IGNORE_STRING;
  241. LDAPMessage *res = NULL;
  242. if (dwFlags == GETINFO_FLAG_IMPLICIT_AS_NEEDED) {
  243. if (_pPropertyCache->getGetInfoFlag()) {
  244. //
  245. // Nothing to do in this case.
  246. //
  247. RRETURN(S_OK);
  248. }
  249. }
  250. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  251. hr = E_ADS_OBJECT_UNBOUND;
  252. BAIL_ON_FAILURE(hr);
  253. }
  254. hr = LdapSearchS(
  255. _pLdapHandle,
  256. NULL,
  257. LDAP_SCOPE_BASE,
  258. TEXT("(objectClass=*)"),
  259. NULL,
  260. 0,
  261. &res
  262. );
  263. BAIL_ON_FAILURE(hr);
  264. if ( dwFlags == GETINFO_FLAG_EXPLICIT )
  265. {
  266. // If this is an explicit GetInfo,
  267. // delete the old cache and start a new cache from scratch.
  268. _pPropertyCache->flushpropertycache();
  269. }
  270. hr = _pPropertyCache->LDAPUnMarshallPropertiesAs(
  271. _pszLDAPServer,
  272. _pLdapHandle,
  273. res,
  274. dwSyntaxId,
  275. (dwFlags == GETINFO_FLAG_EXPLICIT) ?
  276. TRUE :
  277. FALSE,
  278. _Credentials
  279. );
  280. BAIL_ON_FAILURE(hr);
  281. _pPropertyCache->setGetInfoFlag();
  282. error:
  283. if (res) {
  284. LdapMsgFree( res );
  285. }
  286. RRETURN_EXP_IF_ERR(hr);
  287. }
  288. STDMETHODIMP
  289. CLDAPRootDSE::GetInfoEx(THIS_ VARIANT vProperties, long lnReserved)
  290. {
  291. HRESULT hr = S_OK;
  292. LDAPMessage *res = NULL;
  293. VARIANT *vVarArray = NULL;
  294. DWORD dwNumVariants = 0;
  295. PWSTR *ppszStringArray = NULL;
  296. DWORD dwOptions = 0;
  297. DWORD dwCtr = 0;
  298. DWORD dwSyntaxId = ADSTYPE_CASE_IGNORE_STRING;
  299. //
  300. // Make sure that the last error is reset
  301. //
  302. Macro_ClearADsLastError(L"LDAP Provider");
  303. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  304. hr = E_ADS_OBJECT_UNBOUND;
  305. BAIL_ON_FAILURE(hr);
  306. }
  307. hr = ConvertSafeArrayToVariantArray(
  308. vProperties,
  309. &vVarArray,
  310. &dwNumVariants
  311. );
  312. // returns E_FAIL if vProperties is invalid
  313. if (hr == E_FAIL)
  314. hr = E_ADS_BAD_PARAMETER;
  315. BAIL_ON_FAILURE(hr);
  316. hr = ConvertVariantArrayToLDAPStringArray(
  317. vVarArray,
  318. &ppszStringArray,
  319. dwNumVariants
  320. );
  321. BAIL_ON_FAILURE(hr);
  322. hr = LdapSearchS(
  323. _pLdapHandle,
  324. NULL,
  325. LDAP_SCOPE_BASE,
  326. TEXT("(objectClass=*)"),
  327. ppszStringArray,
  328. 0,
  329. &res
  330. );
  331. BAIL_ON_FAILURE(hr);
  332. hr = _pPropertyCache->LDAPUnMarshallProperties3(
  333. _pszLDAPServer,
  334. _pLdapHandle,
  335. res,
  336. TRUE, // fExplicit
  337. dwSyntaxId,
  338. _Credentials
  339. );
  340. BAIL_ON_FAILURE(hr);
  341. for(DWORD i = 0; i < dwNumVariants; i++) {
  342. _pPropertyCache->AddSavingEntry(ppszStringArray[i]);
  343. }
  344. error:
  345. if (res)
  346. LdapMsgFree(res);
  347. if (ppszStringArray)
  348. {
  349. for (DWORD i = 0; i < dwNumVariants; i++)
  350. if (ppszStringArray[i])
  351. FreeADsStr(ppszStringArray[i]);
  352. FreeADsMem(ppszStringArray);
  353. }
  354. if (vVarArray)
  355. {
  356. for (dwCtr = 0; dwCtr < dwNumVariants; dwCtr++) {
  357. VariantClear(vVarArray + dwCtr);
  358. }
  359. FreeADsMem(vVarArray);
  360. }
  361. RRETURN_EXP_IF_ERR(hr);
  362. }
  363. HRESULT
  364. CLDAPRootDSE::AllocateGenObject(
  365. CCredentials& Credentials,
  366. CLDAPRootDSE ** ppGenObject
  367. )
  368. {
  369. CLDAPRootDSE FAR * pGenObject = NULL;
  370. CAggregatorDispMgr FAR * pDispMgr = NULL;
  371. CPropertyCache FAR * pPropertyCache = NULL;
  372. HRESULT hr = S_OK;
  373. pGenObject = new CLDAPRootDSE();
  374. if (pGenObject == NULL) {
  375. hr = E_OUTOFMEMORY;
  376. }
  377. BAIL_ON_FAILURE(hr);
  378. pDispMgr = new CAggregatorDispMgr(Credentials);
  379. if (pDispMgr == NULL) {
  380. hr = E_OUTOFMEMORY;
  381. }
  382. BAIL_ON_FAILURE(hr);
  383. hr = pDispMgr->LoadTypeInfoEntry(
  384. LIBID_ADs,
  385. IID_IADs,
  386. (IADs *)pGenObject,
  387. DISPID_REGULAR
  388. );
  389. BAIL_ON_FAILURE(hr);
  390. hr = pDispMgr->LoadTypeInfoEntry(
  391. LIBID_ADs,
  392. IID_IADsPropertyList,
  393. (IADsPropertyList *)pGenObject,
  394. DISPID_VALUE
  395. );
  396. BAIL_ON_FAILURE(hr);
  397. hr = pDispMgr->LoadTypeInfoEntry(
  398. LIBID_ADs,
  399. IID_IADsObjectOptions,
  400. (IADsObjectOptions *)pGenObject,
  401. DISPID_VALUE
  402. );
  403. BAIL_ON_FAILURE(hr);
  404. hr = CPropertyCache::createpropertycache(
  405. (CCoreADsObject FAR *) pGenObject,
  406. (IGetAttributeSyntax *) pGenObject,
  407. &pPropertyCache
  408. );
  409. BAIL_ON_FAILURE(hr);
  410. pDispMgr->RegisterPropertyCache(pPropertyCache);
  411. pGenObject->_Credentials = Credentials;
  412. pGenObject->_pPropertyCache = pPropertyCache;
  413. pGenObject->_pDispMgr = pDispMgr;
  414. *ppGenObject = pGenObject;
  415. RRETURN(hr);
  416. error:
  417. delete pDispMgr;
  418. delete pGenObject;
  419. RRETURN_EXP_IF_ERR(hr);
  420. }
  421. STDMETHODIMP
  422. CLDAPRootDSE::Get(
  423. THIS_ BSTR bstrName,
  424. VARIANT FAR* pvProp
  425. )
  426. {
  427. HRESULT hr = S_OK;
  428. DWORD dwSyntaxId;
  429. DWORD dwStatus = 0;
  430. LDAPOBJECTARRAY ldapSrcObjects;
  431. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  432. //
  433. // For some folks who have no clue what they are doing.
  434. //
  435. if (!pvProp) {
  436. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  437. }
  438. //
  439. // retrieve data object from cache; if one exists
  440. //
  441. if ( GetObjectState() == ADS_OBJECT_UNBOUND ) {
  442. hr = _pPropertyCache->unboundgetproperty(
  443. bstrName,
  444. &dwSyntaxId,
  445. &dwStatus,
  446. &ldapSrcObjects
  447. );
  448. // For backward compatibility
  449. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  450. hr = E_FAIL;
  451. }
  452. } else {
  453. hr = _pPropertyCache->getproperty(
  454. bstrName,
  455. &dwSyntaxId,
  456. &dwStatus,
  457. &ldapSrcObjects
  458. );
  459. // For backward compatibility
  460. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  461. hr = E_ADS_PROPERTY_NOT_FOUND;
  462. }
  463. }
  464. BAIL_ON_FAILURE(hr);
  465. //
  466. // translate the Ldap objects to variants
  467. //
  468. if ( ldapSrcObjects.dwCount == 1 ) {
  469. hr = LdapTypeToVarTypeCopy(
  470. _pszLDAPServer,
  471. _Credentials,
  472. ldapSrcObjects.pLdapObjects,
  473. dwSyntaxId,
  474. pvProp
  475. );
  476. } else {
  477. hr = LdapTypeToVarTypeCopyConstruct(
  478. _pszLDAPServer,
  479. _Credentials,
  480. ldapSrcObjects,
  481. dwSyntaxId,
  482. pvProp
  483. );
  484. }
  485. BAIL_ON_FAILURE(hr);
  486. error:
  487. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  488. RRETURN_EXP_IF_ERR(hr);
  489. }
  490. STDMETHODIMP
  491. CLDAPRootDSE::Put(
  492. THIS_ BSTR bstrName,
  493. VARIANT vProp
  494. )
  495. {
  496. HRESULT hr = S_OK;
  497. DWORD dwSyntaxId = 0;
  498. DWORD dwIndex = 0;
  499. LDAPOBJECTARRAY ldapDestObjects;
  500. DWORD dwNumValues = 0;
  501. VARIANT * pVarArray = NULL;
  502. VARIANT * pvProp = NULL;
  503. VARIANT vDefProp;
  504. VariantInit(&vDefProp);
  505. LDAPOBJECTARRAY_INIT(ldapDestObjects);
  506. //
  507. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  508. // We should dereference a VT_BYREF|VT_VARIANT once and see
  509. // what's inside.
  510. //
  511. pvProp = &vProp;
  512. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  513. pvProp = V_VARIANTREF(&vProp);
  514. }
  515. if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
  516. (V_VT(pvProp) == (VT_VARIANT|VT_ARRAY))) {
  517. hr = ConvertSafeArrayToVariantArray(
  518. vProp,
  519. &pVarArray,
  520. &dwNumValues
  521. );
  522. // returns E_FAIL if vProp is invalid
  523. if (hr == E_FAIL)
  524. hr = E_ADS_BAD_PARAMETER;
  525. BAIL_ON_FAILURE(hr);
  526. pvProp = pVarArray;
  527. }
  528. else {
  529. //
  530. // If this is a single VT_BYREF of a basic type, we dereference
  531. // it once.
  532. //
  533. if (V_ISBYREF(pvProp)) {
  534. hr = VariantCopyInd(&vDefProp, pvProp);
  535. BAIL_ON_FAILURE(hr);
  536. pvProp = &vDefProp;
  537. }
  538. dwNumValues = 1;
  539. }
  540. //
  541. // check if the variant maps to the syntax of this property
  542. //
  543. hr = GetLdapSyntaxFromVariant(
  544. pvProp,
  545. &dwSyntaxId,
  546. _pszLDAPServer,
  547. bstrName,
  548. _Credentials,
  549. _dwPort
  550. );
  551. BAIL_ON_FAILURE(hr);
  552. if ( dwNumValues > 0 )
  553. {
  554. hr = VarTypeToLdapTypeCopyConstruct(
  555. _pszLDAPServer,
  556. _Credentials,
  557. dwSyntaxId,
  558. pvProp,
  559. dwNumValues,
  560. &ldapDestObjects
  561. );
  562. BAIL_ON_FAILURE(hr);
  563. }
  564. //
  565. // Find this property in the cache
  566. //
  567. hr = _pPropertyCache->findproperty(
  568. bstrName,
  569. &dwIndex
  570. );
  571. //
  572. // If this property does not exist in the
  573. // cache, add this property into the cache.
  574. //
  575. if (FAILED(hr)) {
  576. hr = _pPropertyCache->addproperty( bstrName );
  577. //
  578. // If dwNumValues == 0 ( delete the property ) but couldn't find
  579. // the property, or if the add operation fails, return the error.
  580. //
  581. BAIL_ON_FAILURE(hr);
  582. }
  583. //
  584. // Now update the property in the cache
  585. //
  586. hr = _pPropertyCache->putproperty(
  587. bstrName,
  588. PROPERTY_UPDATE,
  589. dwSyntaxId,
  590. ldapDestObjects
  591. );
  592. BAIL_ON_FAILURE(hr);
  593. error:
  594. LdapTypeFreeLdapObjects( &ldapDestObjects );
  595. if (pVarArray) {
  596. DWORD i = 0;
  597. for (i = 0; i < dwNumValues; i++) {
  598. VariantClear(pVarArray + i);
  599. }
  600. FreeADsMem(pVarArray);
  601. }
  602. RRETURN_EXP_IF_ERR(hr);
  603. }
  604. STDMETHODIMP
  605. CLDAPRootDSE::GetEx(
  606. THIS_ BSTR bstrName,
  607. VARIANT FAR* pvProp
  608. )
  609. {
  610. HRESULT hr = S_OK;
  611. DWORD dwSyntaxId;
  612. DWORD dwStatus = 0;
  613. LDAPOBJECTARRAY ldapSrcObjects;
  614. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  615. //
  616. // For those who know no not what they do
  617. //
  618. if (!pvProp) {
  619. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  620. }
  621. //
  622. // retrieve data object from cache; if one exists
  623. //
  624. if ( GetObjectState() == ADS_OBJECT_UNBOUND ) {
  625. hr = _pPropertyCache->unboundgetproperty(
  626. bstrName,
  627. &dwSyntaxId,
  628. &dwStatus,
  629. &ldapSrcObjects
  630. );
  631. // For backward compatibility
  632. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  633. hr = E_FAIL;
  634. }
  635. } else {
  636. hr = _pPropertyCache->getproperty(
  637. bstrName,
  638. &dwSyntaxId,
  639. &dwStatus,
  640. &ldapSrcObjects
  641. );
  642. // For backward compatibility
  643. if (!ldapSrcObjects.pLdapObjects && SUCCEEDED(hr)) {
  644. hr = E_ADS_PROPERTY_NOT_FOUND;
  645. }
  646. }
  647. BAIL_ON_FAILURE(hr);
  648. //
  649. // translate the Ldap objects to variants
  650. //
  651. hr = LdapTypeToVarTypeCopyConstruct(
  652. _pszLDAPServer,
  653. _Credentials,
  654. ldapSrcObjects,
  655. dwSyntaxId,
  656. pvProp
  657. );
  658. BAIL_ON_FAILURE(hr);
  659. error:
  660. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  661. RRETURN_EXP_IF_ERR(hr);
  662. }
  663. STDMETHODIMP
  664. CLDAPRootDSE::PutEx(
  665. THIS_ long lnControlCode,
  666. BSTR bstrName,
  667. VARIANT vProp
  668. )
  669. {
  670. HRESULT hr = S_OK;
  671. DWORD dwSyntaxId = 0;
  672. DWORD dwFlags = 0;
  673. DWORD dwIndex = 0;
  674. LDAPOBJECTARRAY ldapDestObjects;
  675. DWORD dwNumValues = 0;
  676. VARIANT * pVarArray = NULL;
  677. VARIANT * pvProp = NULL;
  678. LDAPOBJECTARRAY_INIT(ldapDestObjects);
  679. switch ( lnControlCode ) {
  680. case ADS_PROPERTY_CLEAR:
  681. dwFlags = PROPERTY_DELETE;
  682. break;
  683. case ADS_PROPERTY_APPEND:
  684. dwFlags = PROPERTY_ADD;
  685. break;
  686. case ADS_PROPERTY_UPDATE:
  687. dwFlags = PROPERTY_UPDATE;
  688. break;
  689. default:
  690. RRETURN(hr = E_ADS_BAD_PARAMETER);
  691. }
  692. if ( dwFlags != PROPERTY_DELETE )
  693. {
  694. //
  695. // A VT_BYREF|VT_VARIANT may expand to a VT_VARIANT|VT_ARRAY.
  696. // We should dereference a VT_BYREF|VT_VARIANT once and see
  697. // what's inside.
  698. //
  699. pvProp = &vProp;
  700. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  701. pvProp = V_VARIANTREF(&vProp);
  702. }
  703. if ((V_VT(pvProp) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
  704. (V_VT(pvProp) == (VT_VARIANT|VT_ARRAY))) {
  705. hr = ConvertSafeArrayToVariantArray(
  706. *pvProp,
  707. &pVarArray,
  708. &dwNumValues
  709. );
  710. // returns E_FAIL if *pvProp is invalid
  711. if (hr == E_FAIL)
  712. hr = E_ADS_BAD_PARAMETER;
  713. BAIL_ON_FAILURE(hr);
  714. pvProp = pVarArray;
  715. } else {
  716. hr = E_FAIL;
  717. BAIL_ON_FAILURE(hr);
  718. }
  719. //
  720. // check if the variant maps to the syntax of this property
  721. //
  722. //
  723. // check if the variant maps to the syntax of this property
  724. //
  725. hr = GetLdapSyntaxFromVariant(
  726. pvProp,
  727. &dwSyntaxId,
  728. _pszLDAPServer,
  729. bstrName,
  730. _Credentials,
  731. _dwPort
  732. );
  733. BAIL_ON_FAILURE(hr);
  734. if ( dwNumValues > 0 )
  735. {
  736. hr = VarTypeToLdapTypeCopyConstruct(
  737. _pszLDAPServer,
  738. _Credentials,
  739. dwSyntaxId,
  740. pvProp,
  741. dwNumValues,
  742. &ldapDestObjects
  743. );
  744. BAIL_ON_FAILURE(hr);
  745. }
  746. }
  747. //
  748. // Find this property in the cache
  749. //
  750. hr = _pPropertyCache->findproperty(
  751. bstrName,
  752. &dwIndex
  753. );
  754. //
  755. // If this property does not exist in the
  756. // cache, add this property into the cache.
  757. //
  758. if (FAILED(hr)) {
  759. hr = _pPropertyCache->addproperty( bstrName );
  760. //
  761. // If dwNumValues == 0 ( delete the property ) but couldn't find
  762. // the property, or if the add operation fails, return the error.
  763. //
  764. BAIL_ON_FAILURE(hr);
  765. }
  766. //
  767. // Now update the property in the cache
  768. //
  769. hr = _pPropertyCache->putproperty(
  770. bstrName,
  771. dwFlags,
  772. dwSyntaxId,
  773. ldapDestObjects
  774. );
  775. BAIL_ON_FAILURE(hr);
  776. error:
  777. LdapTypeFreeLdapObjects( &ldapDestObjects );
  778. if (pVarArray) {
  779. DWORD i = 0;
  780. for (i = 0; i < dwNumValues; i++) {
  781. VariantClear(pVarArray + i);
  782. }
  783. FreeADsMem(pVarArray);
  784. }
  785. RRETURN_EXP_IF_ERR(hr);
  786. }
  787. STDMETHODIMP
  788. CLDAPRootDSE::get_PropertyCount(
  789. THIS_ long FAR *plCount
  790. )
  791. {
  792. HRESULT hr = E_FAIL;
  793. if (!plCount) {
  794. RRETURN(E_ADS_BAD_PARAMETER);
  795. }
  796. if (_pPropertyCache) {
  797. hr = _pPropertyCache->get_PropertyCount((PDWORD)plCount);
  798. }
  799. RRETURN_EXP_IF_ERR(hr);
  800. }
  801. STDMETHODIMP
  802. CLDAPRootDSE::Next(
  803. THIS_ VARIANT FAR *pVariant
  804. )
  805. {
  806. HRESULT hr = E_FAIL;
  807. DWORD dwSyntaxId = 0;
  808. DWORD dwNumValues = 0;
  809. LDAPOBJECTARRAY ldapSrcObjects;
  810. IDispatch * pDispatch = NULL;
  811. DWORD dwNumAdsValues = 0;
  812. DWORD dwAdsType = 0;
  813. DWORD dwPropStatus = 0;
  814. DWORD dwCtrlCode = 0;
  815. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  816. if (!pVariant) {
  817. RRETURN(E_ADS_BAD_PARAMETER);
  818. }
  819. if(!_pPropertyCache->index_valid())
  820. RRETURN_EXP_IF_ERR(E_FAIL);
  821. //
  822. // retreive the item with current idex; unboundgetproperty()
  823. // returns E_ADS_PROPERTY_NOT_FOUND if index out of bound
  824. //
  825. hr = _pPropertyCache->unboundgetproperty(
  826. _pPropertyCache->get_CurrentIndex(),
  827. &dwSyntaxId,
  828. &dwPropStatus,
  829. &ldapSrcObjects
  830. );
  831. BAIL_ON_FAILURE(hr);
  832. dwCtrlCode = MapPropCacheFlagToControlCode(dwPropStatus);
  833. //
  834. // translate the LDAP objects to variants
  835. //
  836. hr = ConvertLdapValuesToVariant(
  837. _pPropertyCache->get_CurrentPropName(),
  838. &ldapSrcObjects,
  839. dwSyntaxId,
  840. dwCtrlCode,
  841. pVariant,
  842. _pszLDAPServer,
  843. &_Credentials
  844. );
  845. BAIL_ON_FAILURE(hr);
  846. error:
  847. //
  848. // - goto next one even if error to avoid infinite looping at a property
  849. // which we cannot convert (e.g. schemaless server property.)
  850. // - do not return the result of Skip() as current operation does not
  851. // depend on the success of Skip().
  852. //
  853. Skip(1);
  854. LdapTypeFreeLdapObjects(&ldapSrcObjects);
  855. if (FAILED(hr)) {
  856. V_VT(pVariant) = VT_ERROR;
  857. }
  858. RRETURN_EXP_IF_ERR(hr);
  859. }
  860. STDMETHODIMP
  861. CLDAPRootDSE::Skip(
  862. THIS_ long cElements
  863. )
  864. {
  865. HRESULT hr = E_FAIL;
  866. hr = _pPropertyCache->skip_propindex(
  867. cElements
  868. );
  869. RRETURN(hr);
  870. }
  871. STDMETHODIMP
  872. CLDAPRootDSE::Reset(
  873. )
  874. {
  875. _pPropertyCache->reset_propindex();
  876. RRETURN(S_OK);
  877. }
  878. STDMETHODIMP
  879. CLDAPRootDSE::ResetPropertyItem(THIS_ VARIANT varEntry)
  880. {
  881. HRESULT hr = S_OK;
  882. DWORD dwIndex = 0;
  883. switch (V_VT(&varEntry)) {
  884. case VT_BSTR:
  885. hr = _pPropertyCache->findproperty(
  886. V_BSTR(&varEntry),
  887. &dwIndex
  888. );
  889. BAIL_ON_FAILURE(hr);
  890. break;
  891. case VT_I4:
  892. dwIndex = V_I4(&varEntry);
  893. break;
  894. case VT_I2:
  895. dwIndex = V_I2(&varEntry);
  896. break;
  897. default:
  898. hr = E_FAIL;
  899. BAIL_ON_FAILURE(hr);
  900. }
  901. hr = _pPropertyCache->deleteproperty(
  902. dwIndex
  903. );
  904. error:
  905. RRETURN_EXP_IF_ERR(hr);
  906. }
  907. STDMETHODIMP
  908. CLDAPRootDSE::GetPropertyItem(
  909. THIS_ BSTR bstrName,
  910. LONG lnType,
  911. VARIANT * pVariant
  912. )
  913. {
  914. HRESULT hr = S_OK;
  915. DWORD dwSyntaxId;
  916. LDAPOBJECTARRAY ldapSrcObjects;
  917. DWORD dwNumValues = 0;
  918. DWORD dwUserSyntaxId = 0;
  919. DWORD dwStatus = 0;
  920. DWORD dwCtrlCode = 0;
  921. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  922. //
  923. // retrieve data object from cache; do NOT retreive from server
  924. //
  925. hr = _pPropertyCache->unboundgetproperty(
  926. bstrName,
  927. &dwSyntaxId,
  928. &dwStatus,
  929. &ldapSrcObjects
  930. );
  931. BAIL_ON_FAILURE(hr);
  932. //
  933. // translate the Ldap objects to variants
  934. //
  935. dwCtrlCode = MapPropCacheFlagToControlCode(dwStatus);
  936. hr = ConvertLdapValuesToVariant(
  937. bstrName,
  938. &ldapSrcObjects,
  939. dwSyntaxId,
  940. dwCtrlCode,
  941. pVariant,
  942. _pszLDAPServer,
  943. &_Credentials
  944. );
  945. error:
  946. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  947. RRETURN_EXP_IF_ERR(hr);
  948. }
  949. STDMETHODIMP
  950. CLDAPRootDSE::PutPropertyItem(
  951. THIS_ VARIANT varData
  952. )
  953. {
  954. HRESULT hr = S_OK;
  955. DWORD dwFlags = 0;
  956. DWORD dwIndex = 0;
  957. DWORD dwControlCode = 0;
  958. LDAPOBJECTARRAY ldapDestObjects;
  959. WCHAR* pszPropertyName = NULL;
  960. DWORD dwSyntaxId = 0;
  961. LDAPOBJECTARRAY_INIT(ldapDestObjects);
  962. hr = ConvertVariantToLdapValues(
  963. varData,
  964. &pszPropertyName,
  965. &dwControlCode,
  966. &ldapDestObjects,
  967. &dwSyntaxId,
  968. _pszLDAPServer,
  969. &_Credentials,
  970. _dwPort
  971. );
  972. BAIL_ON_FAILURE(hr);
  973. switch ( dwControlCode ) {
  974. case ADS_PROPERTY_CLEAR:
  975. //
  976. // Clears an entire property
  977. //
  978. dwFlags = PROPERTY_DELETE;
  979. break;
  980. case ADS_PROPERTY_UPDATE:
  981. //
  982. // Updates the entire property
  983. //
  984. dwFlags = PROPERTY_UPDATE;
  985. break;
  986. case ADS_PROPERTY_APPEND:
  987. //
  988. // Appends a set of values to the property
  989. //
  990. break;
  991. case ADS_PROPERTY_DELETE:
  992. //
  993. // Delete a value(s) from the property
  994. break;
  995. default:
  996. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  997. }
  998. //
  999. // Find this property in the cache
  1000. //
  1001. hr = _pPropertyCache->findproperty(
  1002. pszPropertyName,
  1003. &dwIndex
  1004. );
  1005. //
  1006. // If this property does not exist in the
  1007. // cache, add this property into the cache.
  1008. //
  1009. if (FAILED(hr)) {
  1010. hr = _pPropertyCache->addproperty( pszPropertyName );
  1011. //
  1012. // If dwNumValues == 0 ( delete the property ) but couldn't find
  1013. // the property, or if the add operation fails, return the error.
  1014. //
  1015. BAIL_ON_FAILURE(hr);
  1016. }
  1017. //
  1018. // Now update the property in the cache
  1019. //
  1020. hr = _pPropertyCache->putproperty(
  1021. pszPropertyName,
  1022. dwFlags,
  1023. dwSyntaxId,
  1024. ldapDestObjects
  1025. );
  1026. BAIL_ON_FAILURE(hr);
  1027. error:
  1028. LdapTypeFreeLdapObjects( &ldapDestObjects );
  1029. if(pszPropertyName)
  1030. {
  1031. FreeADsStr(pszPropertyName);
  1032. }
  1033. RRETURN_EXP_IF_ERR(hr);
  1034. }
  1035. STDMETHODIMP
  1036. CLDAPRootDSE::Item(THIS_ VARIANT varIndex, VARIANT * pVariant)
  1037. {
  1038. HRESULT hr = S_OK;
  1039. DWORD dwSyntaxId;
  1040. LDAPOBJECTARRAY ldapSrcObjects;
  1041. PADSVALUE pAdsValues = NULL;
  1042. DWORD dwNumValues = 0;
  1043. DWORD dwNumAdsValues = 0;
  1044. DWORD dwAdsType = 0;
  1045. DWORD dwStatus = 0;
  1046. DWORD dwCtrlCode = 0;
  1047. VARIANT *pvVar = &varIndex;
  1048. LPWSTR szPropName = NULL;
  1049. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  1050. //
  1051. // retrieve data object from cache; if one exis
  1052. //
  1053. if (V_VT(pvVar) == (VT_BYREF|VT_VARIANT)) {
  1054. //
  1055. // The value is being passed in byref so we need to
  1056. // deref it for vbs stuff to work
  1057. //
  1058. pvVar = V_VARIANTREF(&varIndex);
  1059. }
  1060. switch (V_VT(pvVar)) {
  1061. case VT_BSTR:
  1062. //
  1063. // retrieve data object from cache; if one exists
  1064. //
  1065. if ( GetObjectState() == ADS_OBJECT_UNBOUND ) {
  1066. hr = _pPropertyCache->unboundgetproperty(
  1067. V_BSTR(pvVar),
  1068. &dwSyntaxId,
  1069. &dwStatus,
  1070. &ldapSrcObjects
  1071. );
  1072. // For backward compatibility -- nothing done, you
  1073. // should be able to get an item marked as delete.
  1074. } else {
  1075. hr = _pPropertyCache->getproperty(
  1076. V_BSTR(pvVar),
  1077. &dwSyntaxId,
  1078. &dwStatus,
  1079. &ldapSrcObjects
  1080. );
  1081. // For backward compatibility -- nothing done,
  1082. // you should be able to get an item marked as delete.
  1083. }
  1084. BAIL_ON_FAILURE(hr);
  1085. szPropName = V_BSTR(pvVar);
  1086. dwCtrlCode = MapPropCacheFlagToControlCode(dwStatus);
  1087. break;
  1088. case VT_I4:
  1089. hr = _pPropertyCache->unboundgetproperty(
  1090. (DWORD)V_I4(pvVar),
  1091. &dwSyntaxId,
  1092. &dwStatus,
  1093. &ldapSrcObjects
  1094. );
  1095. // For backward compatibility -- nothing done, you
  1096. // should be able to get an item marked as delte.
  1097. BAIL_ON_FAILURE(hr);
  1098. szPropName = _pPropertyCache->get_PropName(
  1099. (DWORD)V_I4(pvVar)
  1100. );
  1101. dwCtrlCode = MapPropCacheFlagToControlCode(dwStatus);
  1102. break;
  1103. case VT_I2:
  1104. hr = _pPropertyCache->unboundgetproperty(
  1105. (DWORD)V_I2(pvVar),
  1106. &dwSyntaxId,
  1107. &dwStatus,
  1108. &ldapSrcObjects
  1109. );
  1110. // For backward compatibility -- nothing done, you
  1111. // should be able to get an item marked as delete.
  1112. BAIL_ON_FAILURE(hr);
  1113. szPropName = _pPropertyCache->get_PropName(
  1114. (DWORD)V_I2(pvVar)
  1115. );
  1116. dwCtrlCode = MapPropCacheFlagToControlCode(dwStatus);
  1117. break;
  1118. default:
  1119. hr = E_FAIL;
  1120. BAIL_ON_FAILURE(hr);
  1121. }
  1122. //
  1123. // translate the Ldap objects to variants
  1124. //
  1125. dwCtrlCode = MapPropCacheFlagToControlCode(dwStatus);
  1126. hr = ConvertLdapValuesToVariant(
  1127. szPropName,
  1128. &ldapSrcObjects,
  1129. dwSyntaxId,
  1130. dwCtrlCode,
  1131. pVariant,
  1132. _pszLDAPServer,
  1133. &_Credentials
  1134. );
  1135. error:
  1136. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  1137. RRETURN_EXP_IF_ERR(hr);
  1138. }
  1139. STDMETHODIMP
  1140. CLDAPRootDSE::PurgePropertyList()
  1141. {
  1142. _pPropertyCache->flushpropertycache();
  1143. RRETURN(S_OK);
  1144. }
  1145. STDMETHODIMP
  1146. CLDAPRootDSE::GetInfo(
  1147. LPWSTR szPropertyName,
  1148. DWORD dwSyntaxId,
  1149. BOOL fExplicit
  1150. )
  1151. {
  1152. HRESULT hr = S_OK;
  1153. LDAPMessage *res = NULL;
  1154. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  1155. hr = E_ADS_OBJECT_UNBOUND;
  1156. BAIL_ON_FAILURE(hr);
  1157. }
  1158. hr = LdapSearchS(
  1159. _pLdapHandle,
  1160. _pszLDAPDn,
  1161. LDAP_SCOPE_BASE,
  1162. TEXT("(objectClass=*)"),
  1163. NULL,
  1164. 0,
  1165. &res
  1166. );
  1167. BAIL_ON_FAILURE(hr);
  1168. if ( fExplicit )
  1169. {
  1170. // If this is an explicit GetInfo,
  1171. // delete the old cache and start a new cache from scratch.
  1172. _pPropertyCache->flushpropertycache();
  1173. }
  1174. hr = _pPropertyCache->LDAPUnMarshallPropertiesAs(
  1175. _pszLDAPServer,
  1176. _pLdapHandle,
  1177. res,
  1178. ADSTYPE_CASE_IGNORE_STRING,
  1179. fExplicit,
  1180. _Credentials
  1181. );
  1182. BAIL_ON_FAILURE(hr);
  1183. _pPropertyCache->setGetInfoFlag();
  1184. error:
  1185. if (res) {
  1186. LdapMsgFree( res );
  1187. }
  1188. RRETURN_EXP_IF_ERR(hr);
  1189. }
  1190. //
  1191. // Needed for dynamic dispid's in the property cache.
  1192. //
  1193. HRESULT
  1194. CLDAPRootDSE::GetAttributeSyntax(
  1195. LPWSTR szPropertyName,
  1196. PDWORD pdwSyntaxId
  1197. )
  1198. {
  1199. HRESULT hr;
  1200. hr = LdapGetSyntaxOfAttributeOnServer(
  1201. _pszLDAPServer,
  1202. szPropertyName,
  1203. pdwSyntaxId,
  1204. _Credentials,
  1205. _dwPort
  1206. );
  1207. RRETURN_EXP_IF_ERR(hr);
  1208. }
  1209. //
  1210. // IADsObjecOptions methods
  1211. //
  1212. //
  1213. // Unlike the cgenobj GetOption implementation, this will support
  1214. // only a subset of the flags - mutual auth status being the only one.
  1215. //
  1216. STDMETHODIMP
  1217. CLDAPRootDSE::GetOption(
  1218. THIS_ long lnControlCode,
  1219. VARIANT FAR* pvProp
  1220. )
  1221. {
  1222. HRESULT hr = S_OK;
  1223. ULONG ulFlags = 0;
  1224. CtxtHandle hCtxtHandle;
  1225. DWORD dwErr = 0;
  1226. VariantInit(pvProp);
  1227. switch (lnControlCode) {
  1228. case ADS_OPTION_MUTUAL_AUTH_STATUS :
  1229. dwErr = ldap_get_option(
  1230. _pLdapHandle->LdapHandle,
  1231. LDAP_OPT_SECURITY_CONTEXT,
  1232. (void *) &hCtxtHandle
  1233. );
  1234. if (dwErr) {
  1235. BAIL_ON_FAILURE(hr = E_FAIL);
  1236. }
  1237. //DSCLIENT
  1238. #if (!defined(WIN95))
  1239. dwErr = QueryContextAttributesWrapper(
  1240. &hCtxtHandle,
  1241. SECPKG_ATTR_FLAGS,
  1242. (void *) &ulFlags
  1243. );
  1244. if (dwErr) {
  1245. BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(dwErr));
  1246. }
  1247. #else
  1248. ulFlags = 0;
  1249. #endif
  1250. pvProp->vt = VT_I4;
  1251. pvProp->lVal = ulFlags;
  1252. break;
  1253. default:
  1254. hr = E_NOTIMPL;
  1255. }
  1256. error:
  1257. RRETURN(hr);
  1258. }
  1259. STDMETHODIMP
  1260. CLDAPRootDSE::SetOption(
  1261. THIS_ long lnControlCode,
  1262. VARIANT vProp
  1263. )
  1264. {
  1265. HRESULT hr = S_OK;
  1266. DWORD dwOptVal = 0;
  1267. VARIANT *pvProp = NULL;
  1268. //
  1269. // To make sure we handle variant by refs correctly.
  1270. //
  1271. pvProp = &vProp;
  1272. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  1273. pvProp = V_VARIANTREF(&vProp);
  1274. }
  1275. switch (lnControlCode) {
  1276. case ADS_PRIVATE_OPTION_KEEP_HANDLES :
  1277. hr = LdapcKeepHandleAround(_pLdapHandle);
  1278. break;
  1279. default:
  1280. hr = E_NOTIMPL;
  1281. }
  1282. RRETURN(hr);
  1283. }