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.

4164 lines
96 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. #ifdef __cplusplus
  17. extern "C"
  18. #else
  19. extern
  20. #endif
  21. HRESULT
  22. AdsTypeToPropVariant2(
  23. PADSVALUE pAdsValues,
  24. DWORD dwNumValues,
  25. VARIANT * pVariant,
  26. LPWSTR pszServerName,
  27. CCredentials* pCredentials,
  28. BOOL fNTDSType
  29. );
  30. #ifdef __cplusplus
  31. extern "C"
  32. #else
  33. extern
  34. #endif
  35. HRESULT
  36. PropVariantToAdsType2(
  37. PVARIANT pVariant,
  38. DWORD dwNumVariant,
  39. PADSVALUE *ppAdsValues,
  40. PDWORD pdwNumValues,
  41. LPWSTR pszServerName,
  42. CCredentials* pCredentials,
  43. BOOL fNTDSType
  44. );
  45. //
  46. // Helper routine that handles setting the sticky server private
  47. // option when the input is an array.
  48. //
  49. HRESULT
  50. SetStickyServerWithDomain(
  51. PVARIANT pvProp
  52. );
  53. // Class CLDAPGenObject
  54. DEFINE_IDispatch_ExtMgr_Implementation(CLDAPGenObject)
  55. DEFINE_IADs_Shorter_Implementation(CLDAPGenObject)
  56. //
  57. // This is a useful function
  58. //
  59. HRESULT GetIntegerFromVariant(
  60. VARIANT* pvProp,
  61. DWORD* pdwValue
  62. );
  63. typedef struct _classeshierarchylist {
  64. LPWSTR pszClassName;
  65. struct _classeshierarchylist *pNext;
  66. } ClassesHierarchyList, *PClassesHierarchyList;
  67. //
  68. // Helper to Trace The Tree for a class
  69. //
  70. HRESULT
  71. TraceTreeForClass(
  72. BSTR Parent,
  73. BSTR CommonName,
  74. LPWSTR pszClassName,
  75. CCredentials& Credentials,
  76. PWCHAR **pppszNameArr,
  77. PLONG plnNumElements
  78. );
  79. HRESULT
  80. AddToClassesList(
  81. VARIANT vBstrVal,
  82. LPWSTR *ppszCurClass,
  83. PClassesHierarchyList *pClassListhead,
  84. PLONG plnNumItems
  85. );
  86. CLDAPGenObject::CLDAPGenObject():
  87. _pExtMgr(NULL),
  88. _pPropertyCache( NULL ),
  89. _pDispMgr( NULL ),
  90. _pszLDAPServer(NULL),
  91. _pszLDAPDn(NULL),
  92. _pLdapHandle( NULL ),
  93. _dwOptReferral((DWORD) LDAP_CHASE_EXTERNAL_REFERRALS),
  94. _dwPageSize(99),
  95. _dwCorePropStatus(0),
  96. _fRangeRetrieval(FALSE)
  97. {
  98. VariantInit(&_vFilter);
  99. VariantInit(&_vHints);
  100. _seInfo = OWNER_SECURITY_INFORMATION
  101. | GROUP_SECURITY_INFORMATION
  102. | DACL_SECURITY_INFORMATION;
  103. _fExplicitSecurityMask = FALSE;
  104. LdapInitializeSearchPreferences(&_SearchPref, TRUE);
  105. ENLIST_TRACKING(CLDAPGenObject);
  106. }
  107. //
  108. // fClassDefaulted indicates if the class has been defaulted
  109. // because of a fast bind flag or otherwise.
  110. //
  111. HRESULT
  112. CLDAPGenObject::CreateGenericObject(
  113. BSTR Parent,
  114. BSTR CommonName,
  115. BSTR LdapClassName,
  116. CCredentials& Credentials,
  117. DWORD dwObjectState,
  118. REFIID riid,
  119. void **ppvObj,
  120. BOOL fClassDefaulted,
  121. BOOL fNoQI // defaulted to FALSE
  122. )
  123. {
  124. //
  125. // Call into the fully featured Create
  126. //
  127. LPWSTR pszClassNames[2];
  128. HRESULT hr = S_OK;
  129. PWCHAR *ppListOfNames;
  130. LONG lnNumNames = 0;
  131. pszClassNames[0] = LdapClassName;
  132. pszClassNames[1] = NULL;
  133. hr = TraceTreeForClass(
  134. Parent,
  135. CommonName,
  136. LdapClassName,
  137. Credentials,
  138. &ppListOfNames,
  139. &lnNumNames
  140. );
  141. if (FAILED(hr)) {
  142. //
  143. // Default to just the class name given
  144. //
  145. RRETURN(CreateGenericObject(
  146. Parent,
  147. CommonName,
  148. pszClassNames,
  149. 1,
  150. Credentials,
  151. dwObjectState,
  152. riid,
  153. ppvObj,
  154. fClassDefaulted,
  155. fNoQI
  156. )
  157. );
  158. }
  159. else {
  160. //
  161. // Create with all the classes specified
  162. //
  163. hr = CreateGenericObject(
  164. Parent,
  165. CommonName,
  166. ppListOfNames,
  167. lnNumNames,
  168. Credentials,
  169. dwObjectState,
  170. riid,
  171. ppvObj,
  172. fClassDefaulted,
  173. fNoQI
  174. );
  175. for (long i = 0; i < lnNumNames; i++) {
  176. if (ppListOfNames[i]) {
  177. FreeADsStr(ppListOfNames[i]);
  178. }
  179. }
  180. if (ppListOfNames) {
  181. FreeADsMem(ppListOfNames);
  182. }
  183. RRETURN(hr);
  184. }
  185. }
  186. //+------------------------------------------------------------------------
  187. //
  188. // Function: CLDAPGenObject::CreateGenericObject
  189. //
  190. // Synopsis: Does all the work and actually creates the object.
  191. // Difference from the overlaoded member being that it accepts an
  192. // array of values for the class name so that it can load
  193. // extensions for all the classes in the inheritance hierarchy.
  194. //
  195. // Arguments:
  196. //
  197. //-------------------------------------------------------------------------
  198. HRESULT
  199. CLDAPGenObject::CreateGenericObject(
  200. BSTR Parent,
  201. BSTR CommonName,
  202. LPWSTR LdapClassNames[],
  203. long lnNumClasses,
  204. CCredentials& Credentials,
  205. DWORD dwObjectState,
  206. REFIID riid,
  207. void **ppvObj,
  208. BOOL fClassDefaulted,
  209. BOOL fNoQI // will return cgenobject if set to TRUE, defaulted FALSE
  210. )
  211. {
  212. CLDAPGenObject FAR * pGenObject = NULL;
  213. HRESULT hr = S_OK;
  214. DWORD dwCtr = 0;
  215. LPWSTR pszBaseClassName = GET_BASE_CLASS(LdapClassNames, lnNumClasses);
  216. hr = AllocateGenObject(pszBaseClassName, Credentials, &pGenObject);
  217. BAIL_ON_FAILURE(hr);
  218. ADsAssert(pGenObject->_pDispMgr);
  219. pGenObject->_Credentials = Credentials;
  220. hr = pGenObject->InitializeCoreObject(
  221. Parent,
  222. CommonName,
  223. pszBaseClassName,
  224. CLSID_LDAPGenObject,
  225. dwObjectState
  226. );
  227. BAIL_ON_FAILURE(hr);
  228. hr = BuildLDAPPathFromADsPath2(
  229. pGenObject->_ADsPath,
  230. &pGenObject->_pszLDAPServer,
  231. &pGenObject->_pszLDAPDn,
  232. &pGenObject->_dwPort
  233. );
  234. BAIL_ON_FAILURE(hr);
  235. //
  236. // At this point update the info in the property cache
  237. //
  238. hr = pGenObject->_pPropertyCache->SetObjInformation(
  239. &(pGenObject->_Credentials),
  240. pGenObject->_pszLDAPServer,
  241. pGenObject->_dwPort
  242. );
  243. BAIL_ON_FAILURE(hr);
  244. //
  245. // Create and Load 3rd party extensions and the extension mgr.
  246. // This should be done after initilaization of core and generic object s.t
  247. // 1) an extension writer can access info on IADs (e.g _Parent) etc
  248. // during extension creation, if he wants to.
  249. // 2) we shouldn't waste the effort to create and load extension
  250. // objects if fialure in the aggregator's creation
  251. //
  252. hr = CADsExtMgr::CreateExtMgr(
  253. (IADs *)pGenObject,
  254. pGenObject->_pDispMgr,
  255. LdapClassNames,
  256. lnNumClasses,
  257. &(pGenObject->_Credentials),
  258. &pGenObject->_pExtMgr
  259. );
  260. BAIL_ON_FAILURE(hr);
  261. ADsAssert(pGenObject->_pExtMgr);
  262. hr = LdapOpenObject(
  263. pGenObject->_pszLDAPServer,
  264. pGenObject->_pszLDAPDn,
  265. &(pGenObject->_pLdapHandle),
  266. pGenObject->_Credentials,
  267. pGenObject->_dwPort
  268. );
  269. BAIL_ON_FAILURE(hr);
  270. if (!fClassDefaulted) {
  271. //
  272. // Update the status to reflect we do not need to go
  273. // on the wire to get the class
  274. //
  275. pGenObject->_dwCorePropStatus |= LDAP_CLASS_VALID;
  276. }
  277. if (fNoQI) {
  278. *ppvObj = (void *) pGenObject;
  279. }
  280. else if (Credentials.GetAuthFlags() & ADS_AUTH_RESERVED) {
  281. //
  282. // Call is from umi so we need to create the umi object.
  283. //
  284. hr = ((CCoreADsObject*)pGenObject)->InitUmiObject(
  285. IntfPropsGeneric,
  286. pGenObject->_pPropertyCache,
  287. (IADs *) pGenObject,
  288. (IADs *) pGenObject,
  289. IID_IUnknown,
  290. ppvObj,
  291. &(pGenObject->_Credentials),
  292. pGenObject->_dwPort,
  293. pGenObject->_pszLDAPServer,
  294. pGenObject->_pszLDAPDn,
  295. pGenObject->_pLdapHandle,
  296. pGenObject->_pExtMgr
  297. );
  298. BAIL_ON_FAILURE(hr);
  299. RRETURN(S_OK);
  300. } else {
  301. //
  302. // Need the appropriate interface.
  303. //
  304. hr = pGenObject->QueryInterface(riid, ppvObj);
  305. BAIL_ON_FAILURE(hr);
  306. pGenObject->Release();
  307. }
  308. BAIL_ON_FAILURE(hr);
  309. RRETURN(hr);
  310. error:
  311. *ppvObj = NULL;
  312. delete pGenObject;
  313. RRETURN_EXP_IF_ERR(hr);
  314. }
  315. //+---------------------------------------------------------------------------
  316. // Function: CLDAPGenObject::CreateGenericObject (static constructor), this
  317. // constructor is used by Umi Searches only.
  318. //
  319. // Synopsis: This routine uses the other static constructor routines
  320. // depending on the objectClass information available in the passed
  321. // in ldapMsg. The state of the newly created object reflects this
  322. // information. The newly created object is then prepopulated with
  323. // the attributes in the ldapMsg. The return value from this routine
  324. // is the newly created object (interface asked on this object).
  325. //
  326. // Arguments: Parent - Path to the parent of the newly created object.
  327. // CommonName - Name of new object to create.
  328. // Credentials - Standard credentials object.
  329. // dwObjectState- Bound/unbound (always bound in this case).
  330. // ldapHandle - Handle used in the deciphering search info.
  331. // pldapMsg - The Ldao msg with the attributes.
  332. // riid - IID requested on newly created object.
  333. // ppvObj - Return value.
  334. //
  335. //
  336. // Returns: S_OK, or any appropriate error code.
  337. //
  338. // Modifies: ppvObj contains newly created object with attributes.
  339. //
  340. //----------------------------------------------------------------------------
  341. HRESULT
  342. CLDAPGenObject::CreateGenericObject(
  343. BSTR Parent,
  344. BSTR CommonName,
  345. CCredentials& Credentials,
  346. DWORD dwObjectState,
  347. PADSLDP ldapHandle,
  348. LDAPMessage *pldapMsg,
  349. REFIID riid,
  350. void **ppvObj
  351. )
  352. {
  353. HRESULT hr = S_OK;
  354. TCHAR **aValues = NULL;
  355. int nCount;
  356. CLDAPGenObject *pGenObject = NULL;
  357. hr = LdapGetValues(
  358. ldapHandle,
  359. pldapMsg,
  360. L"objectClass",
  361. &aValues,
  362. &nCount
  363. );
  364. if (FAILED(hr) || !aValues) {
  365. //
  366. // We do not have the objectClass
  367. //
  368. hr = CLDAPGenObject::CreateGenericObject(
  369. Parent,
  370. CommonName,
  371. L"Top",
  372. Credentials,
  373. dwObjectState,
  374. riid,
  375. (void **) &pGenObject,
  376. TRUE, // class is defaulted
  377. TRUE // No QI
  378. );
  379. }
  380. else {
  381. //
  382. // We have the info we need for the constructor with class name
  383. //
  384. hr = CLDAPGenObject::CreateGenericObject(
  385. Parent,
  386. CommonName,
  387. aValues,
  388. nCount,
  389. Credentials,
  390. dwObjectState,
  391. riid,
  392. (void **) &pGenObject,
  393. FALSE, // objectClass is not defaulted
  394. TRUE // No QI
  395. );
  396. }
  397. BAIL_ON_FAILURE(hr);
  398. //
  399. // Now we need to prepopulate the object.
  400. //
  401. hr = pGenObject->_pPropertyCache->
  402. LDAPUnMarshallProperties2(
  403. pGenObject->_pszLDAPServer,
  404. pGenObject->_pLdapHandle,
  405. pldapMsg,
  406. FALSE, // this is not an explicit getinfo.
  407. pGenObject->_Credentials,
  408. &pGenObject->_fRangeRetrieval
  409. );
  410. //
  411. // Should we really fail if we could not unmarshall properties ???
  412. ///
  413. BAIL_ON_FAILURE(hr);
  414. //
  415. // This call is always from UMI, so now we need to get the
  416. // outer umiObject and return that.
  417. //
  418. hr = ((CCoreADsObject*)pGenObject)->InitUmiObject(
  419. IntfPropsGeneric,
  420. pGenObject->_pPropertyCache,
  421. (IADs *) pGenObject,
  422. (IADs *) pGenObject,
  423. riid,
  424. ppvObj,
  425. &(pGenObject->_Credentials),
  426. pGenObject->_dwPort,
  427. pGenObject->_pszLDAPServer,
  428. pGenObject->_pszLDAPDn,
  429. pGenObject->_pLdapHandle,
  430. pGenObject->_pExtMgr
  431. );
  432. BAIL_ON_FAILURE(hr);
  433. //
  434. // Only thing remaining is to get a list of the attributes fetched
  435. // into this object. That way we wont go on the wire for them. This
  436. // can be done once the GetInfoEx related bug is fixed.
  437. //
  438. error :
  439. if (pGenObject && FAILED(hr)) {
  440. delete pGenObject;
  441. *ppvObj = NULL;
  442. }
  443. //
  444. // Need to free the Ldap values in all cases.
  445. //
  446. if (aValues) {
  447. LdapValueFree(aValues);
  448. aValues = NULL;
  449. }
  450. RRETURN(hr);
  451. }
  452. CLDAPGenObject::~CLDAPGenObject( )
  453. {
  454. //
  455. // last to be created - first to be unloaded
  456. //
  457. delete _pExtMgr;
  458. VariantClear(&_vFilter);
  459. VariantClear(&_vHints);
  460. if ( _pLdapHandle )
  461. {
  462. LdapCloseObject(_pLdapHandle);
  463. _pLdapHandle = NULL;
  464. }
  465. if (_pszLDAPServer) {
  466. FreeADsStr(_pszLDAPServer);
  467. _pszLDAPServer = NULL;
  468. }
  469. if (_pszLDAPDn) {
  470. FreeADsStr(_pszLDAPDn);
  471. _pszLDAPDn = NULL;
  472. }
  473. delete _pDispMgr;
  474. delete _pPropertyCache;
  475. //
  476. // Free the sort keys if applicable.
  477. //
  478. if (_SearchPref._pSortKeys) {
  479. for (DWORD dwCtr = 0; dwCtr < _SearchPref._nSortKeys; dwCtr++) {
  480. if (_SearchPref._pSortKeys[dwCtr].sk_attrtype)
  481. FreeADsStr(_SearchPref._pSortKeys[dwCtr].sk_attrtype);
  482. }
  483. FreeADsMem(_SearchPref._pSortKeys);
  484. }
  485. //
  486. // Free the VLV information if applicable
  487. //
  488. if (_SearchPref._pVLVInfo) {
  489. if (_SearchPref._pVLVInfo->ldvlv_attrvalue) {
  490. if (_SearchPref._pVLVInfo->ldvlv_attrvalue->bv_val) {
  491. FreeADsMem(_SearchPref._pVLVInfo->ldvlv_attrvalue->bv_val);
  492. }
  493. FreeADsMem(_SearchPref._pVLVInfo->ldvlv_attrvalue);
  494. }
  495. if (_SearchPref._pVLVInfo->ldvlv_context) {
  496. if (_SearchPref._pVLVInfo->ldvlv_context->bv_val) {
  497. FreeADsMem(_SearchPref._pVLVInfo->ldvlv_context->bv_val);
  498. }
  499. FreeADsMem(_SearchPref._pVLVInfo->ldvlv_context);
  500. }
  501. FreeADsMem(_SearchPref._pVLVInfo);
  502. }
  503. //
  504. // Free the attribute scoped query information if applicable
  505. //
  506. if (_SearchPref._pAttribScoped) {
  507. FreeADsStr(_SearchPref._pAttribScoped);
  508. }
  509. }
  510. STDMETHODIMP
  511. CLDAPGenObject::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  512. {
  513. HRESULT hr = S_OK;
  514. if (ppv == NULL) {
  515. RRETURN(E_POINTER);
  516. }
  517. if (IsEqualIID(iid, IID_IUnknown))
  518. {
  519. *ppv = (IADs FAR *) this;
  520. }
  521. else if (IsEqualIID(iid, IID_IADsContainer))
  522. {
  523. *ppv = (IADsContainer FAR *) this;
  524. }
  525. else if (IsEqualIID(iid, IID_IADs))
  526. {
  527. *ppv = (IADs FAR *) this;
  528. }
  529. else if (IsEqualIID(iid, IID_IDispatch))
  530. {
  531. *ppv = (IADs FAR *) this;
  532. }
  533. else if (IsEqualIID(iid, IID_IDirectoryObject))
  534. {
  535. *ppv = (IDirectoryObject FAR *) this;
  536. }
  537. else if (IsEqualIID(iid, IID_IDirectorySearch))
  538. {
  539. *ppv = (IDirectorySearch FAR *) this;
  540. }
  541. else if (IsEqualIID(iid, IID_IDirectorySchemaMgmt))
  542. {
  543. *ppv = (IDirectorySchemaMgmt FAR *) this;
  544. }
  545. else if (IsEqualIID(iid, IID_IADsPropertyList))
  546. {
  547. *ppv = (IADsPropertyList FAR *) this;
  548. }
  549. else if (IsEqualIID(iid, IID_IADsObjectOptions))
  550. {
  551. *ppv = (IADsObjectOptions FAR *) this;
  552. }
  553. else if (IsEqualIID(iid, IID_IADsDeleteOps))
  554. {
  555. *ppv = (IADsDeleteOps FAR *) this;
  556. }
  557. else if (IsEqualIID(iid, IID_ISupportErrorInfo))
  558. {
  559. *ppv = (ISupportErrorInfo FAR *) this;
  560. }
  561. else if (IsEqualIID(iid, IID_IADsObjOptPrivate))
  562. {
  563. *ppv = (IADsObjOptPrivate *) this;
  564. }
  565. else if (_pExtMgr)
  566. {
  567. RRETURN(hr = _pExtMgr->QueryInterface(iid, ppv));
  568. }else {
  569. *ppv = NULL;
  570. return E_NOINTERFACE;
  571. }
  572. AddRef();
  573. return NOERROR;
  574. }
  575. /* ISupportErrorInfo method */
  576. HRESULT
  577. CLDAPGenObject::InterfaceSupportsErrorInfo(THIS_ REFIID riid)
  578. {
  579. if (IsEqualIID(riid, IID_IADs) ||
  580. IsEqualIID(riid, IID_IADsPropertyList) ||
  581. IsEqualIID(riid, IID_IADsContainer) ||
  582. #if 0
  583. IsEqualIID(riid, IID_IDirectoryObject) ||
  584. IsEqualIID(riid, IID_IDirectorySearch) ||
  585. IsEqualIID(riid, IID_IDirectorySchemaMgmt) ||
  586. #endif
  587. IsEqualIID(riid, IID_IADsObjectOptions)) {
  588. RRETURN(S_OK);
  589. }
  590. else {
  591. RRETURN(S_FALSE);
  592. }
  593. }
  594. HRESULT
  595. CLDAPGenObject::SetInfo()
  596. {
  597. HRESULT hr = S_OK;
  598. //
  599. // Make sure that the last error is reset
  600. //
  601. Macro_ClearADsLastError(L"LDAP Provider");
  602. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  603. hr = LDAPCreateObject();
  604. BAIL_ON_FAILURE(hr);
  605. //
  606. // If the create succeded, set the object type to bound
  607. //
  608. SetObjectState(ADS_OBJECT_BOUND);
  609. }else {
  610. hr = LDAPSetObject();
  611. BAIL_ON_FAILURE(hr);
  612. }
  613. error:
  614. RRETURN_EXP_IF_ERR(hr);
  615. }
  616. HRESULT
  617. CLDAPGenObject::LDAPSetObject()
  618. {
  619. HRESULT hr = S_OK;
  620. LDAPModW **aMod = NULL;
  621. BOOL fNTSecDes=FALSE;
  622. DWORD dwSecDescType = ADSI_LDAPC_SECDESC_NONE;
  623. BOOL fModifyDone = FALSE;
  624. SECURITY_INFORMATION NewSeInfo=0;
  625. SECURITY_INFORMATION SeInfo = _seInfo;
  626. BYTE berValue[8];
  627. memset(berValue, 0, 8);
  628. berValue[0] = 0x30; // Start sequence tag
  629. berValue[1] = 0x03; // Length in bytes of following
  630. berValue[2] = 0x02; // Actual value this and next 2
  631. berValue[3] = 0x01;
  632. berValue[4] = (BYTE) ((ULONG)SeInfo);
  633. LDAPControl SeInfoControl =
  634. {
  635. LDAP_SERVER_SD_FLAGS_OID_W,
  636. {
  637. 5, (PCHAR) berValue
  638. },
  639. TRUE
  640. };
  641. LDAPControl ModifyControl =
  642. {
  643. LDAP_SERVER_PERMISSIVE_MODIFY_OID_W,
  644. {
  645. 0, NULL
  646. },
  647. FALSE
  648. };
  649. PLDAPControl ServerControls[2] =
  650. {
  651. &SeInfoControl,
  652. NULL
  653. };
  654. PLDAPControl ServerControlsOnlyModify[2] =
  655. {
  656. &ModifyControl,
  657. NULL
  658. };
  659. PLDAPControl ServerControlsAll[3] =
  660. {
  661. &SeInfoControl,
  662. &ModifyControl,
  663. NULL
  664. };
  665. BOOL fServerIsAD = FALSE;
  666. //
  667. // Make sure that the last error is reset
  668. //
  669. Macro_ClearADsLastError(L"LDAP Provider");
  670. hr = _pPropertyCache->LDAPMarshallProperties(
  671. &aMod,
  672. &fNTSecDes,
  673. &NewSeInfo
  674. );
  675. BAIL_ON_FAILURE(hr);
  676. if ( aMod == NULL ) // There are no changes that needs to be modified
  677. RRETURN(S_OK);
  678. //
  679. // Sometimes the call to Marshall might contain the SD but NewSeInfo
  680. // might not have been updated suitable because of failures not sever
  681. // enough to warrant failing the entire operation.
  682. //
  683. if (!_fExplicitSecurityMask
  684. && fNTSecDes
  685. && (NewSeInfo != INVALID_SE_VALUE)
  686. ) {
  687. berValue[4] = (BYTE) ((ULONG)NewSeInfo);
  688. }
  689. //
  690. // Find out if server is AD.
  691. //
  692. hr = ReadServerSupportsIsADControl(
  693. _pszLDAPServer,
  694. &fServerIsAD,
  695. _Credentials,
  696. _dwPort
  697. );
  698. if (FAILED(hr)) {
  699. //
  700. // Assume it is not AD and continue, there is no
  701. // good reason for this to fail on AD.
  702. //
  703. fServerIsAD = FALSE;
  704. }
  705. if (fNTSecDes) {
  706. hr = ReadSecurityDescriptorControlType(
  707. _pszLDAPServer,
  708. &dwSecDescType,
  709. _Credentials,
  710. _dwPort
  711. );
  712. if (SUCCEEDED(hr) && (dwSecDescType == ADSI_LDAPC_SECDESC_NT)) {
  713. hr = LdapModifyExtS(
  714. _pLdapHandle,
  715. _pszLDAPDn,
  716. aMod,
  717. fServerIsAD ?
  718. (PLDAPControl *) &ServerControlsAll :
  719. (PLDAPControl *) &ServerControls,
  720. NULL
  721. );
  722. fModifyDone = TRUE;
  723. } // SecDesc type == NT
  724. } // if modifySecDes
  725. if (!fModifyDone) {
  726. if (fServerIsAD) {
  727. //
  728. // Need to send the additional control that says it is
  729. // ok to clear the values on attributes that do not
  730. // have any values.
  731. //
  732. hr = LdapModifyExtS(
  733. _pLdapHandle,
  734. _pszLDAPDn,
  735. aMod,
  736. (PLDAPControl *) &ServerControlsOnlyModify,
  737. NULL
  738. );
  739. }
  740. else {
  741. hr = LdapModifyS(
  742. _pLdapHandle,
  743. _pszLDAPDn,
  744. aMod
  745. );
  746. }
  747. }
  748. BAIL_ON_FAILURE(hr);
  749. // We are successful at this point,
  750. // So, clean up the flags in the cache so the same operation
  751. // won't be repeated on the next SetInfo()
  752. _pPropertyCache->ClearMarshalledProperties();
  753. _pPropertyCache->ClearAllPropertyFlags();
  754. _pPropertyCache->DeleteSavingEntry();
  755. error:
  756. if (aMod) {
  757. if ( *aMod )
  758. FreeADsMem( *aMod );
  759. FreeADsMem( aMod );
  760. }
  761. RRETURN_EXP_IF_ERR(hr);
  762. }
  763. HRESULT
  764. CLDAPGenObject::LDAPCreateObject()
  765. {
  766. HRESULT hr = S_OK;
  767. LDAPModW **aMod = NULL;
  768. DWORD dwIndex = 0;
  769. BOOL fNTSecDes= FALSE;
  770. BOOL fAddDone = FALSE;
  771. DWORD dwSecDescType = ADSI_LDAPC_SECDESC_NONE;
  772. SECURITY_INFORMATION SeInfo = _seInfo;
  773. SECURITY_INFORMATION NewSeInfo=0;
  774. BYTE berValue[8];
  775. memset(berValue, 0, 8);
  776. berValue[0] = 0x30; // Start sequence tag
  777. berValue[1] = 0x03; // Length in bytes of following
  778. berValue[2] = 0x02; // Actual value this and next 2
  779. berValue[3] = 0x01;
  780. berValue[4] = (BYTE) ((ULONG)SeInfo);
  781. LDAPControl SeInfoControl =
  782. {
  783. LDAP_SERVER_SD_FLAGS_OID_W,
  784. {
  785. 5, (PCHAR) berValue
  786. },
  787. TRUE
  788. };
  789. PLDAPControl ServerControls[2] =
  790. {
  791. &SeInfoControl,
  792. NULL
  793. };
  794. if ( _pPropertyCache->findproperty( TEXT("objectClass"), &dwIndex )
  795. == E_ADS_PROPERTY_NOT_FOUND )
  796. {
  797. VARIANT v;
  798. VariantInit(&v);
  799. v.vt = VT_BSTR;
  800. V_BSTR(&v) = _SchemaClass;
  801. hr = Put( TEXT("objectClass"), v );
  802. BAIL_ON_FAILURE(hr);
  803. }
  804. hr = _pPropertyCache->LDAPMarshallProperties(
  805. &aMod,
  806. &fNTSecDes,
  807. &NewSeInfo
  808. );
  809. BAIL_ON_FAILURE(hr);
  810. if (!_fExplicitSecurityMask && NewSeInfo) {
  811. berValue[4] = (BYTE) ((ULONG)NewSeInfo);
  812. }
  813. if (fNTSecDes == TRUE) {
  814. //
  815. // If we support the SD control, then we use
  816. // the add ext method.
  817. //
  818. if (fNTSecDes) {
  819. hr = ReadSecurityDescriptorControlType(
  820. _pszLDAPServer,
  821. &dwSecDescType,
  822. _Credentials,
  823. _dwPort
  824. );
  825. if (SUCCEEDED(hr) && (dwSecDescType == ADSI_LDAPC_SECDESC_NT)) {
  826. hr = LdapAddExtS(
  827. _pLdapHandle,
  828. _pszLDAPDn,
  829. aMod,
  830. (PLDAPControl *)&ServerControls,
  831. NULL
  832. );
  833. fAddDone = TRUE;
  834. } // SecDesc type == NT
  835. }
  836. } // if SecDesc needs to be sent.
  837. if (!fAddDone) {
  838. //
  839. // Call add s
  840. //
  841. hr = LdapAddS(
  842. _pLdapHandle,
  843. _pszLDAPDn,
  844. aMod
  845. );
  846. }
  847. BAIL_ON_FAILURE(hr);
  848. // We are successful at this point,
  849. // So, clean up the flags in the cache so the same operation
  850. // won't be repeated on the next SetInfo()
  851. _pPropertyCache->ClearAllPropertyFlags();
  852. error:
  853. if (aMod) {
  854. if ( *aMod )
  855. FreeADsMem( *aMod );
  856. FreeADsMem( aMod );
  857. }
  858. RRETURN_EXP_IF_ERR(hr);
  859. }
  860. HRESULT
  861. CLDAPGenObject::GetInfoEx(
  862. THIS_ VARIANT vProperties,
  863. long lnReserved
  864. )
  865. {
  866. HRESULT hr = S_OK;
  867. LDAPMessage *res = NULL;
  868. VARIANT *vVarArray = NULL;
  869. DWORD dwNumVariants = 0;
  870. PWSTR *ppszStringArray = NULL;
  871. DWORD dwOptions = 0;
  872. int ldaperr = 0;
  873. DWORD dwCtr = 0;
  874. DWORD dwSecDescType = 0;
  875. BOOL fSearchDone = FALSE;
  876. SECURITY_INFORMATION SeInfo = _seInfo;
  877. BYTE berValue[8];
  878. memset(berValue, 0, 8);
  879. berValue[0] = 0x30; // Start sequence tag
  880. berValue[1] = 0x03; // Length in bytes of following
  881. berValue[2] = 0x02; // Actual value this and next 2
  882. berValue[3] = 0x01;
  883. berValue[4] = (BYTE)((ULONG)SeInfo);
  884. LDAPControl SeInfoControl =
  885. {
  886. LDAP_SERVER_SD_FLAGS_OID_W,
  887. {
  888. 5, (PCHAR) berValue
  889. },
  890. TRUE
  891. };
  892. PLDAPControl ServerControls[2] =
  893. {
  894. &SeInfoControl,
  895. NULL
  896. };
  897. UNREFERENCED_PARAMETER(lnReserved);
  898. //
  899. // Make sure that the last error is reset
  900. //
  901. Macro_ClearADsLastError(L"LDAP Provider");
  902. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  903. hr = E_ADS_OBJECT_UNBOUND;
  904. BAIL_ON_FAILURE(hr);
  905. }
  906. hr = ConvertSafeArrayToVariantArray(
  907. vProperties,
  908. &vVarArray,
  909. &dwNumVariants
  910. );
  911. // returns E_FAIL if vProperties is invalid
  912. if (hr == E_FAIL)
  913. hr = E_ADS_BAD_PARAMETER;
  914. BAIL_ON_FAILURE(hr);
  915. hr = ConvertVariantArrayToLDAPStringArray(
  916. vVarArray,
  917. &ppszStringArray,
  918. dwNumVariants
  919. );
  920. BAIL_ON_FAILURE(hr);
  921. while ((dwCtr < dwNumVariants) && (dwSecDescType == 0)) {
  922. if (_wcsicmp(ppszStringArray[dwCtr], L"ntSecurityDescriptor") == 0) {
  923. dwSecDescType = 1;
  924. }
  925. dwCtr++;
  926. }
  927. //
  928. // Do not bother doing this if secdesc has not been
  929. // explicitly requested.
  930. //
  931. if (dwSecDescType) {
  932. //
  933. // If the server is V3, we want to use controls in case
  934. // the security descriptor has to be retrieved
  935. //
  936. ldaperr = ldap_get_option(
  937. _pLdapHandle->LdapHandle,
  938. LDAP_OPT_VERSION,
  939. &dwOptions
  940. );
  941. if (dwOptions == LDAP_VERSION3) {
  942. hr = ReadSecurityDescriptorControlType(
  943. _pszLDAPServer,
  944. &dwSecDescType,
  945. _Credentials,
  946. _dwPort
  947. );
  948. BAIL_ON_FAILURE(hr);
  949. if (dwSecDescType == ADSI_LDAPC_SECDESC_NT) {
  950. hr = LdapSearchExtS(
  951. _pLdapHandle,
  952. _pszLDAPDn,
  953. LDAP_SCOPE_BASE,
  954. TEXT("(objectClass=*)"),
  955. ppszStringArray,
  956. 0,
  957. (PLDAPControl *)&ServerControls,
  958. NULL,
  959. NULL,
  960. 10000,
  961. &res
  962. );
  963. fSearchDone = TRUE;
  964. }
  965. }
  966. } // sec desc requested
  967. //
  968. // At this point even if it is a vesion 3 DS, we might still
  969. // need to call the normal search routine as all version 3
  970. // DS's need not necessarily support controls - Ex: Exchange.
  971. //
  972. if (!fSearchDone) {
  973. hr = LdapSearchS(
  974. _pLdapHandle,
  975. _pszLDAPDn,
  976. LDAP_SCOPE_BASE,
  977. TEXT("(objectClass=*)"),
  978. ppszStringArray,
  979. 0,
  980. &res
  981. );
  982. fSearchDone = TRUE;
  983. }
  984. BAIL_ON_FAILURE(hr);
  985. //
  986. // This is an explicit GetInfo[Ex], but we don't want to flush the
  987. // property cache. For example, if we have [A B C] in the cache, and
  988. // we request [C D E], we want to end up with [A B C D E] in the cache.
  989. //
  990. // But we do want to tell LDAPUnMarshallProperties that this is an
  991. // explicit call; using the same example, we want the server's value of
  992. // C in the cache after this call, not the old value.
  993. //
  994. hr = _pPropertyCache->LDAPUnMarshallProperties2(
  995. _pszLDAPServer,
  996. _pLdapHandle,
  997. res,
  998. TRUE, // fExplicit
  999. _Credentials,
  1000. &_fRangeRetrieval
  1001. );
  1002. BAIL_ON_FAILURE(hr);
  1003. for(DWORD i = 0; i < dwNumVariants; i++) {
  1004. _pPropertyCache->AddSavingEntry(ppszStringArray[i]);
  1005. }
  1006. error:
  1007. if (res)
  1008. LdapMsgFree(res);
  1009. if (ppszStringArray) {
  1010. for (DWORD i = 0; i < dwNumVariants; i++)
  1011. if (ppszStringArray[i])
  1012. FreeADsStr(ppszStringArray[i]);
  1013. FreeADsMem(ppszStringArray);
  1014. }
  1015. if (vVarArray) {
  1016. for (dwCtr = 0; dwCtr < dwNumVariants; dwCtr++) {
  1017. VariantClear(vVarArray + dwCtr);
  1018. }
  1019. FreeADsMem(vVarArray);
  1020. }
  1021. RRETURN_EXP_IF_ERR(hr);
  1022. }
  1023. HRESULT
  1024. CLDAPGenObject::GetInfo()
  1025. {
  1026. _fRangeRetrieval = FALSE;
  1027. RRETURN(GetInfo(GETINFO_FLAG_EXPLICIT));
  1028. }
  1029. HRESULT
  1030. CLDAPGenObject::GetInfo(
  1031. DWORD dwFlags
  1032. )
  1033. {
  1034. HRESULT hr = S_OK;
  1035. LDAPMessage *res = NULL;
  1036. int ldaperr = 0;
  1037. DWORD dwOptions = 0;
  1038. DWORD dwSecDescType = 0;
  1039. BOOL fSearchDone = FALSE;
  1040. SECURITY_INFORMATION SeInfo = _seInfo;
  1041. BYTE berValue[8];
  1042. memset(berValue, 0, 8);
  1043. berValue[0] = 0x30; // Start sequence tag
  1044. berValue[1] = 0x03; // Length in bytes of following
  1045. berValue[2] = 0x02; // Actual value this and next 2
  1046. berValue[3] = 0x01;
  1047. berValue[4] = (BYTE)((ULONG)SeInfo);
  1048. LDAPControl SeInfoControl =
  1049. {
  1050. LDAP_SERVER_SD_FLAGS_OID_W,
  1051. {
  1052. 5, (PCHAR) berValue
  1053. },
  1054. TRUE
  1055. };
  1056. PLDAPControl ServerControls[2] =
  1057. {
  1058. &SeInfoControl,
  1059. NULL
  1060. };
  1061. //
  1062. // Make sure that the last error is reset
  1063. //
  1064. Macro_ClearADsLastError(L"LDAP Provider");
  1065. if (dwFlags == GETINFO_FLAG_IMPLICIT_AS_NEEDED) {
  1066. if (_pPropertyCache->getGetInfoFlag()) {
  1067. //
  1068. // We are done there is nothing to do.
  1069. //
  1070. goto error;
  1071. }
  1072. }
  1073. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  1074. hr = E_ADS_OBJECT_UNBOUND;
  1075. BAIL_ON_FAILURE(hr);
  1076. }
  1077. if ( dwFlags == GETINFO_FLAG_EXPLICIT )
  1078. {
  1079. // If this is an explicit GetInfo,
  1080. // delete the old cache and start a new cache from scratch.
  1081. _pPropertyCache->flushpropertycache();
  1082. }
  1083. // modified from LdapSearchS to LdapSearchExtS to get all attributes
  1084. // including SecurityDescriptor by one call
  1085. ldaperr = ldap_get_option(
  1086. _pLdapHandle->LdapHandle,
  1087. LDAP_OPT_VERSION,
  1088. &dwOptions
  1089. );
  1090. if (dwOptions == LDAP_VERSION3) {
  1091. hr = ReadSecurityDescriptorControlType(
  1092. _pszLDAPServer,
  1093. &dwSecDescType,
  1094. _Credentials,
  1095. _dwPort
  1096. );
  1097. BAIL_ON_FAILURE(hr);
  1098. if (dwSecDescType == ADSI_LDAPC_SECDESC_NT) {
  1099. hr = LdapSearchExtS(
  1100. _pLdapHandle,
  1101. _pszLDAPDn,
  1102. LDAP_SCOPE_BASE,
  1103. TEXT("(objectClass=*)"),
  1104. NULL, // modified to NULL for all attributes
  1105. 0,
  1106. (PLDAPControl *)&ServerControls,
  1107. NULL,
  1108. NULL,
  1109. 10000,
  1110. &res
  1111. );
  1112. fSearchDone = TRUE;
  1113. }
  1114. }
  1115. //
  1116. // If the fSearchDone flags is not set, then the server
  1117. // probably did not support the SecDesc control and we need to
  1118. // just a search not extended.
  1119. //
  1120. if (!fSearchDone) {
  1121. hr = LdapSearchS(
  1122. _pLdapHandle,
  1123. _pszLDAPDn,
  1124. LDAP_SCOPE_BASE,
  1125. TEXT("(objectClass=*)"),
  1126. NULL,
  1127. 0,
  1128. &res
  1129. );
  1130. fSearchDone = TRUE;
  1131. }
  1132. BAIL_ON_FAILURE(hr);
  1133. hr = _pPropertyCache->LDAPUnMarshallProperties2(
  1134. _pszLDAPServer,
  1135. _pLdapHandle,
  1136. res,
  1137. (dwFlags == GETINFO_FLAG_EXPLICIT) ?
  1138. TRUE : FALSE,
  1139. _Credentials,
  1140. &_fRangeRetrieval
  1141. );
  1142. BAIL_ON_FAILURE(hr);
  1143. _pPropertyCache->setGetInfoFlag();
  1144. error:
  1145. if (res) {
  1146. LdapMsgFree( res );
  1147. }
  1148. if (_pPropertyCache) {
  1149. Reset();
  1150. }
  1151. RRETURN_EXP_IF_ERR(hr);
  1152. }
  1153. STDMETHODIMP
  1154. CLDAPGenObject::get_GUID(THIS_ BSTR FAR* retval)
  1155. {
  1156. HRESULT hr = S_OK;
  1157. DWORD dwSyntaxId;
  1158. DWORD dwStatus = 0;
  1159. ULONG ulLength = 0;
  1160. LDAPOBJECTARRAY ldapSrcObjects;
  1161. LPWSTR pszTempStr = NULL;
  1162. WCHAR pszSmallStr[5];
  1163. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  1164. //
  1165. // Make sure that the last error is reset
  1166. //
  1167. Macro_ClearADsLastError(L"LDAP Provider");
  1168. if (_dwObjectState == ADS_OBJECT_UNBOUND) {
  1169. RRETURN(E_ADS_OBJECT_UNBOUND);
  1170. }
  1171. if (!(_dwCorePropStatus & LDAP_GUID_VALID)) {
  1172. //
  1173. // Get the property from the server (implicit getinfo)
  1174. // and update the property in the
  1175. //
  1176. hr = _pPropertyCache->getproperty(
  1177. L"objectGUID",
  1178. &dwSyntaxId,
  1179. &dwStatus,
  1180. &ldapSrcObjects
  1181. );
  1182. BAIL_ON_FAILURE(hr);
  1183. if ((ldapSrcObjects.dwCount == 0)
  1184. || (ldapSrcObjects.dwCount > 1)) {
  1185. BAIL_ON_FAILURE(hr = E_ADS_PROPERTY_NOT_FOUND);
  1186. }
  1187. ulLength = LDAPOBJECT_BERVAL_LEN(ldapSrcObjects.pLdapObjects);
  1188. pszTempStr = (LPWSTR) AllocADsMem((ulLength * 2 + 1) * sizeof(WCHAR));
  1189. if (!pszTempStr) {
  1190. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1191. }
  1192. for (DWORD dwCtr = 0; dwCtr < ulLength; dwCtr++) {
  1193. wsprintf(pszSmallStr, L"%02x", (BYTE) LDAPOBJECT_BERVAL_VAL(ldapSrcObjects.pLdapObjects)[dwCtr]);
  1194. wcscat(pszTempStr, pszSmallStr);
  1195. }
  1196. wcscat(pszTempStr, L"\0");
  1197. if (_ADsGuid) {
  1198. ADsFreeString(_ADsGuid);
  1199. _ADsGuid = NULL;
  1200. }
  1201. hr = ADsAllocString(pszTempStr, &_ADsGuid);
  1202. if (SUCCEEDED(hr)) {
  1203. _dwCorePropStatus |= LDAP_GUID_VALID;
  1204. }
  1205. }
  1206. error:
  1207. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  1208. if (pszTempStr) {
  1209. FreeADsMem(pszTempStr);
  1210. }
  1211. if (SUCCEEDED(hr)) {
  1212. RRETURN(get_CoreGUID(retval));
  1213. }
  1214. RRETURN(hr);
  1215. }
  1216. HRESULT
  1217. CLDAPGenObject::get_Parent(BSTR * retval)
  1218. {
  1219. HRESULT hr;
  1220. DWORD dwSyntaxId;
  1221. DWORD dwStatus = 0;
  1222. LDAPOBJECTARRAY ldapSrcObjects;
  1223. LPWSTR pszTempStr = NULL;
  1224. LPWSTR pszADsPath = NULL;
  1225. LPWSTR pszADsParent = NULL;
  1226. LPWSTR pszADsCommon = NULL;
  1227. BOOL fGCNameSpace = FALSE;
  1228. //
  1229. // Make sure that the last error is reset
  1230. //
  1231. Macro_ClearADsLastError(L"LDAP Provider");
  1232. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  1233. if (FAILED(hr = ValidateOutParameter(retval))){
  1234. RRETURN_EXP_IF_ERR(hr);
  1235. }
  1236. if ( (wcslen(_Name) > wcslen(L"<GUID=")) &&
  1237. (_wcsnicmp(_Name, L"<GUID=", wcslen(L"<GUID=")) == 0)) {
  1238. //
  1239. // Replace the guid with the distinguishedName
  1240. //
  1241. //
  1242. // Get the property from the server (implicit getinfo)
  1243. //
  1244. hr = _pPropertyCache->getproperty(
  1245. L"distinguishedName",
  1246. &dwSyntaxId,
  1247. &dwStatus,
  1248. &ldapSrcObjects
  1249. );
  1250. BAIL_ON_FAILURE(hr);
  1251. if (ldapSrcObjects.dwCount == 0) {
  1252. BAIL_ON_FAILURE(hr = E_ADS_PROPERTY_NOT_FOUND);
  1253. }
  1254. pszTempStr = LDAPOBJECT_STRING(ldapSrcObjects.pLdapObjects);
  1255. //
  1256. // Break it down into parent name & common name portions
  1257. //
  1258. // _ADsPath could not be NULL
  1259. if(!_wcsnicmp(L"GC:", _ADsPath, wcslen(L"GC:")))
  1260. {
  1261. fGCNameSpace = TRUE;
  1262. }
  1263. hr = BuildADsPathFromLDAPPath2(
  1264. (_pszLDAPServer ? TRUE : FALSE),
  1265. fGCNameSpace ? L"GC:" : L"LDAP:",
  1266. _pszLDAPServer,
  1267. _dwPort,
  1268. pszTempStr,
  1269. &pszADsPath
  1270. );
  1271. BAIL_ON_FAILURE(hr);
  1272. hr = BuildADsParentPath(pszADsPath,
  1273. &pszADsParent,
  1274. &pszADsCommon);
  1275. BAIL_ON_FAILURE(hr);
  1276. hr = ADsAllocString(pszADsParent, retval);
  1277. }
  1278. else {
  1279. hr = get_CoreParent(retval);
  1280. }
  1281. error:
  1282. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  1283. if (pszADsPath)
  1284. FreeADsMem(pszADsPath);
  1285. if (pszADsParent)
  1286. FreeADsMem(pszADsParent);
  1287. if (pszADsCommon)
  1288. FreeADsMem(pszADsCommon);
  1289. RRETURN_EXP_IF_ERR(hr);
  1290. }
  1291. HRESULT
  1292. CLDAPGenObject::get_Name(BSTR * retval)
  1293. {
  1294. HRESULT hr;
  1295. DWORD dwSyntaxId;
  1296. DWORD dwStatus = 0;
  1297. LDAPOBJECTARRAY ldapSrcObjects;
  1298. LPWSTR pszTempStr = NULL;
  1299. LPWSTR pszADsPath = NULL;
  1300. LPWSTR pszADsParent = NULL;
  1301. LPWSTR pszADsCommon = NULL;
  1302. //
  1303. // Make sure that the last error is reset
  1304. //
  1305. Macro_ClearADsLastError(L"LDAP Provider");
  1306. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  1307. if (FAILED(hr = ValidateOutParameter(retval))){
  1308. RRETURN_EXP_IF_ERR(hr);
  1309. }
  1310. if ( (wcslen(_Name) > wcslen(L"<WKGUID=")) &&
  1311. (_wcsnicmp(_Name, L"<WKGUID=", wcslen(L"<WKGUID=")) == 0)) {
  1312. //
  1313. // Replace the name with the DN
  1314. //
  1315. hr = ADsAllocString(_pszLDAPDn, retval);
  1316. }
  1317. else if ( (wcslen(_Name) > wcslen(L"<GUID=")) &&
  1318. (_wcsnicmp(_Name, L"<GUID=", wcslen(L"<GUID=")) == 0)) {
  1319. //
  1320. // Replace the guid with the distinguishedName
  1321. //
  1322. //
  1323. // Get the property from the server (implicit getinfo)
  1324. //
  1325. hr = _pPropertyCache->getproperty(
  1326. L"distinguishedName",
  1327. &dwSyntaxId,
  1328. &dwStatus,
  1329. &ldapSrcObjects
  1330. );
  1331. BAIL_ON_FAILURE(hr);
  1332. if (ldapSrcObjects.dwCount == 0) {
  1333. BAIL_ON_FAILURE(hr = E_ADS_PROPERTY_NOT_FOUND);
  1334. }
  1335. pszTempStr = LDAPOBJECT_STRING(ldapSrcObjects.pLdapObjects);
  1336. //
  1337. // Break it down into parent name & common name portions
  1338. //
  1339. hr = BuildADsPathFromLDAPPath2(
  1340. (_pszLDAPServer ? TRUE : FALSE),
  1341. L"LDAP:", // does not matter, just a place holder
  1342. _pszLDAPServer,
  1343. _dwPort, // doesn't matter
  1344. pszTempStr,
  1345. &pszADsPath
  1346. );
  1347. BAIL_ON_FAILURE(hr);
  1348. hr = BuildADsParentPath(pszADsPath,
  1349. &pszADsParent,
  1350. &pszADsCommon);
  1351. BAIL_ON_FAILURE(hr);
  1352. hr = ADsAllocString(pszADsCommon, retval);
  1353. }
  1354. else {
  1355. hr = ADsAllocString(_Name, retval);
  1356. }
  1357. error:
  1358. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  1359. if (pszADsPath)
  1360. FreeADsMem(pszADsPath);
  1361. if (pszADsParent)
  1362. FreeADsMem(pszADsParent);
  1363. if (pszADsCommon)
  1364. FreeADsMem(pszADsCommon);
  1365. RRETURN_EXP_IF_ERR(hr);
  1366. }
  1367. STDMETHODIMP
  1368. CLDAPGenObject::get_Class(THIS_ BSTR FAR* retval)
  1369. {
  1370. HRESULT hr = S_OK;
  1371. DWORD dwSyntaxId;
  1372. DWORD dwStatus = 0;
  1373. ULONG ulNumVals = 0;
  1374. LDAPOBJECTARRAY ldapSrcObjects;
  1375. PLDAPOBJECT pLdapObject = NULL;
  1376. LPWSTR pszTempStr = NULL;
  1377. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  1378. //
  1379. // Make sure that the last error is reset
  1380. //
  1381. Macro_ClearADsLastError(L"LDAP Provider");
  1382. //
  1383. // Need to go on wire only if object is bound as in this
  1384. // object is not being create now
  1385. //
  1386. if (!(_dwCorePropStatus & LDAP_CLASS_VALID)
  1387. && _dwObjectState != ADS_OBJECT_UNBOUND) {
  1388. //
  1389. // Get the property from the server (implicit getinfo)
  1390. // and update the property in the
  1391. //
  1392. hr = _pPropertyCache->getproperty(
  1393. L"objectClass",
  1394. &dwSyntaxId,
  1395. &dwStatus,
  1396. &ldapSrcObjects
  1397. );
  1398. BAIL_ON_FAILURE(hr);
  1399. if (ldapSrcObjects.dwCount == 0) {
  1400. BAIL_ON_FAILURE(hr = E_ADS_PROPERTY_NOT_FOUND);
  1401. }
  1402. ulNumVals = ldapSrcObjects.dwCount;
  1403. pLdapObject = ldapSrcObjects.pLdapObjects;
  1404. //
  1405. // Try and see if we need the first or the last value
  1406. //
  1407. if (_wcsicmp(LDAPOBJECT_STRING(pLdapObject + (ulNumVals - 1)),
  1408. L"Top")== 0) {
  1409. pszTempStr = LDAPOBJECT_STRING(
  1410. pLdapObject + 0
  1411. );
  1412. } else {
  1413. pszTempStr = LDAPOBJECT_STRING(
  1414. pLdapObject + (ulNumVals - 1)
  1415. );
  1416. }
  1417. if (_SchemaClass) {
  1418. ADsFreeString(_SchemaClass);
  1419. _SchemaClass = NULL;
  1420. }
  1421. hr = ADsAllocString(pszTempStr, &_SchemaClass);
  1422. if (SUCCEEDED(hr)) {
  1423. _dwCorePropStatus |= LDAP_CLASS_VALID;
  1424. }
  1425. }
  1426. error:
  1427. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  1428. if (SUCCEEDED(hr)) {
  1429. RRETURN(get_CoreADsClass(retval));
  1430. }
  1431. RRETURN(hr);
  1432. }
  1433. STDMETHODIMP
  1434. CLDAPGenObject::get_Schema(THIS_ BSTR FAR* retval)
  1435. {
  1436. BSTR bstrTemp = NULL;
  1437. //
  1438. // We call the get_Class method because that will take care
  1439. // of all the work we need to do in the event that we need
  1440. // read the information from the server. It makes sense to do
  1441. // that rather than repeat the code here.
  1442. //
  1443. HRESULT hr = get_Class(&bstrTemp);
  1444. if (FAILED(hr)) {
  1445. RRETURN(hr);
  1446. }
  1447. if (bstrTemp) {
  1448. SysFreeString(bstrTemp);
  1449. }
  1450. RRETURN(get_CoreSchema(retval));
  1451. }
  1452. /* IADsContainer methods */
  1453. STDMETHODIMP
  1454. CLDAPGenObject::get_Count(long FAR* retval)
  1455. {
  1456. //
  1457. // Make sure that the last error is reset
  1458. //
  1459. Macro_ClearADsLastError(L"LDAP Provider");
  1460. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  1461. }
  1462. STDMETHODIMP
  1463. CLDAPGenObject::get_Filter(THIS_ VARIANT FAR* pVar)
  1464. {
  1465. HRESULT hr;
  1466. //
  1467. // Make sure that the last error is reset
  1468. //
  1469. Macro_ClearADsLastError(L"LDAP Provider");
  1470. VariantInit(pVar);
  1471. hr = VariantCopy(pVar, &_vFilter);
  1472. RRETURN_EXP_IF_ERR(hr);
  1473. }
  1474. STDMETHODIMP
  1475. CLDAPGenObject::put_Filter(THIS_ VARIANT Var)
  1476. {
  1477. HRESULT hr;
  1478. //
  1479. // Make sure that the last error is reset
  1480. //
  1481. Macro_ClearADsLastError(L"LDAP Provider");
  1482. VariantClear(&_vFilter);
  1483. hr = VariantCopy(&_vFilter, &Var);
  1484. RRETURN_EXP_IF_ERR(hr);
  1485. }
  1486. STDMETHODIMP
  1487. CLDAPGenObject::get_Hints(THIS_ VARIANT FAR* pVar)
  1488. {
  1489. HRESULT hr;
  1490. //
  1491. // Make sure that the last error is reset
  1492. //
  1493. Macro_ClearADsLastError(L"LDAP Provider");
  1494. VariantInit(pVar);
  1495. hr = VariantCopy(pVar, &_vHints);
  1496. RRETURN_EXP_IF_ERR(hr);
  1497. }
  1498. STDMETHODIMP
  1499. CLDAPGenObject::put_Hints(THIS_ VARIANT Var)
  1500. {
  1501. HRESULT hr;
  1502. //
  1503. // Make sure that the last error is reset
  1504. //
  1505. Macro_ClearADsLastError(L"LDAP Provider");
  1506. VariantClear(&_vHints);
  1507. hr = VariantCopy(&_vHints, &Var);
  1508. RRETURN_EXP_IF_ERR(hr);
  1509. }
  1510. STDMETHODIMP
  1511. CLDAPGenObject::GetObject(
  1512. THIS_ BSTR ClassName,
  1513. BSTR RelativeName,
  1514. IDispatch * FAR* ppObject
  1515. )
  1516. {
  1517. TCHAR *pszBuffer = NULL;
  1518. HRESULT hr = S_OK;
  1519. IADs *pADs = NULL;
  1520. BSTR bstrClass = NULL;
  1521. BSTR bstrParent = NULL;
  1522. BSTR bstrName = NULL;
  1523. LPWSTR pszADsPath = NULL;
  1524. //
  1525. // Make sure that the last error is reset
  1526. //
  1527. Macro_ClearADsLastError(L"LDAP Provider");
  1528. if (!RelativeName || !*RelativeName) {
  1529. RRETURN_EXP_IF_ERR(E_ADS_UNKNOWN_OBJECT);
  1530. }
  1531. //
  1532. // Build an ADsPath from get_Parent/get_Name
  1533. // (which always returns useful LDAP-style values)
  1534. // rather than using _ADsPath, which could be
  1535. // of the <GUID=....> form
  1536. //
  1537. hr = get_Parent(&bstrParent);
  1538. BAIL_ON_FAILURE(hr);
  1539. hr = get_Name(&bstrName);
  1540. BAIL_ON_FAILURE(hr);
  1541. hr = BuildADsPathFromParent(bstrParent,
  1542. bstrName,
  1543. &pszADsPath);
  1544. BAIL_ON_FAILURE(hr);
  1545. //
  1546. // Tack on the path component of the child
  1547. // object being retrieved
  1548. //
  1549. hr = BuildADsPathFromParent(
  1550. pszADsPath,
  1551. RelativeName,
  1552. &pszBuffer
  1553. );
  1554. BAIL_ON_FAILURE(hr);
  1555. hr = ::GetObject(
  1556. pszBuffer,
  1557. _Credentials,
  1558. (LPVOID *)ppObject
  1559. );
  1560. BAIL_ON_FAILURE(hr);
  1561. //
  1562. // Check the class name only if we are not in umi land. In umi
  1563. // land, we will fail the QI for the IID_IADs interface.
  1564. //
  1565. if(ClassName && !(_Credentials.GetAuthFlags() & ADS_AUTH_RESERVED)) {
  1566. hr = (*ppObject)->QueryInterface(
  1567. IID_IADs,
  1568. (void **)&pADs
  1569. );
  1570. BAIL_ON_FAILURE(hr);
  1571. hr = pADs->get_Class(&bstrClass);
  1572. BAIL_ON_FAILURE(hr);
  1573. #ifdef WIN95
  1574. if (_wcsicmp( bstrClass, ClassName )) {
  1575. #else
  1576. if (CompareStringW(
  1577. LOCALE_SYSTEM_DEFAULT,
  1578. NORM_IGNORECASE,
  1579. bstrClass,
  1580. -1,
  1581. ClassName,
  1582. -1
  1583. ) != CSTR_EQUAL) {
  1584. #endif
  1585. (*ppObject)->Release();
  1586. *ppObject = NULL;
  1587. BAIL_ON_FAILURE(hr=E_ADS_UNKNOWN_OBJECT);
  1588. }
  1589. }
  1590. error:
  1591. if (bstrParent) {
  1592. ADsFreeString(bstrParent);
  1593. }
  1594. if (bstrName) {
  1595. ADsFreeString(bstrName);
  1596. }
  1597. if (pszADsPath) {
  1598. FreeADsMem(pszADsPath);
  1599. }
  1600. if ( pADs ) {
  1601. pADs->Release();
  1602. }
  1603. if ( pszBuffer )
  1604. FreeADsMem( pszBuffer );
  1605. if ( bstrClass ) {
  1606. SysFreeString( bstrClass );
  1607. }
  1608. RRETURN_EXP_IF_ERR(hr);
  1609. }
  1610. STDMETHODIMP
  1611. CLDAPGenObject::get__NewEnum(
  1612. THIS_ IUnknown * FAR* retval
  1613. )
  1614. {
  1615. HRESULT hr = S_OK;
  1616. IUnknown FAR* punkEnum=NULL;
  1617. IEnumVARIANT * penum = NULL;
  1618. //
  1619. // Make sure that the last error is reset
  1620. //
  1621. Macro_ClearADsLastError(L"LDAP Provider");
  1622. *retval = NULL;
  1623. hr = CLDAPGenObjectEnum::Create(
  1624. (CLDAPGenObjectEnum **)&penum,
  1625. _ADsPath,
  1626. _pLdapHandle,
  1627. this,
  1628. _vFilter,
  1629. _Credentials,
  1630. _dwOptReferral,
  1631. _dwPageSize
  1632. );
  1633. BAIL_ON_FAILURE(hr);
  1634. hr = penum->QueryInterface(
  1635. IID_IUnknown,
  1636. (VOID FAR* FAR*)retval
  1637. );
  1638. BAIL_ON_FAILURE(hr);
  1639. if (penum) {
  1640. penum->Release();
  1641. }
  1642. RRETURN(NOERROR);
  1643. error:
  1644. if (penum) {
  1645. delete penum;
  1646. }
  1647. RRETURN_EXP_IF_ERR(hr);
  1648. }
  1649. STDMETHODIMP
  1650. CLDAPGenObject::Create(
  1651. THIS_ BSTR ClassName,
  1652. BSTR RelativeName,
  1653. IDispatch * FAR* ppObject
  1654. )
  1655. {
  1656. HRESULT hr = S_OK;
  1657. BOOL fValid = FALSE;
  1658. BSTR bstrParent = NULL;
  1659. BSTR bstrName = NULL;
  1660. LPWSTR pszADsPath = NULL;
  1661. //
  1662. // Make sure that the last error is reset
  1663. //
  1664. Macro_ClearADsLastError(L"LDAP Provider");
  1665. //
  1666. // No null or empty names for class or rdn.
  1667. //
  1668. if (!ClassName || !*ClassName
  1669. || !RelativeName || !*RelativeName) {
  1670. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  1671. }
  1672. //
  1673. // Build an ADsPath from get_Parent/get_Name
  1674. // (which always returns useful LDAP-style values)
  1675. // rather than using _ADsPath, which could be
  1676. // of the <GUID=....> form
  1677. //
  1678. hr = get_Parent(&bstrParent);
  1679. BAIL_ON_FAILURE(hr);
  1680. hr = get_Name(&bstrName);
  1681. BAIL_ON_FAILURE(hr);
  1682. hr = BuildADsPathFromParent(bstrParent,
  1683. bstrName,
  1684. &pszADsPath);
  1685. BAIL_ON_FAILURE(hr);
  1686. hr = CLDAPGenObject::CreateGenericObject(
  1687. pszADsPath,
  1688. RelativeName,
  1689. ClassName,
  1690. _Credentials,
  1691. ADS_OBJECT_UNBOUND,
  1692. IID_IADs,
  1693. (void **) ppObject
  1694. );
  1695. BAIL_ON_FAILURE(hr);
  1696. error:
  1697. if (bstrParent) {
  1698. ADsFreeString(bstrParent);
  1699. }
  1700. if (bstrName) {
  1701. ADsFreeString(bstrName);
  1702. }
  1703. if (pszADsPath) {
  1704. FreeADsMem(pszADsPath);
  1705. }
  1706. RRETURN_EXP_IF_ERR(hr);
  1707. }
  1708. STDMETHODIMP
  1709. CLDAPGenObject::Delete(
  1710. THIS_ BSTR bstrClassName,
  1711. BSTR bstrRelativeName
  1712. )
  1713. {
  1714. HRESULT hr = S_OK;
  1715. BSTR bstrParent = NULL;
  1716. BSTR bstrName = NULL;
  1717. LPWSTR pszADsPath = NULL;
  1718. BSTR bstrAbsoluteName = NULL;
  1719. TCHAR *pszLDAPServer = NULL;
  1720. TCHAR *pszLDAPDn = NULL;
  1721. LPTSTR *aValues = NULL;
  1722. int nCount = 0;
  1723. DWORD dwPort = 0;
  1724. //
  1725. // Make sure that the last error is reset
  1726. //
  1727. Macro_ClearADsLastError(L"LDAP Provider");
  1728. //
  1729. // Check to see if the RelativeName is non empty
  1730. //
  1731. if (bstrRelativeName == NULL) {
  1732. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  1733. }
  1734. //
  1735. // Build an ADsPath from get_Parent/get_Name
  1736. // (which always returns useful LDAP-style values)
  1737. // rather than using _ADsPath, which could be
  1738. // of the <GUID=....> form
  1739. //
  1740. hr = get_Parent(&bstrParent);
  1741. BAIL_ON_FAILURE(hr);
  1742. hr = get_Name(&bstrName);
  1743. BAIL_ON_FAILURE(hr);
  1744. hr = BuildADsPathFromParent(bstrParent,
  1745. bstrName,
  1746. &pszADsPath);
  1747. BAIL_ON_FAILURE(hr);
  1748. //
  1749. // Tack on the path component of the child object to be
  1750. // deleted
  1751. //
  1752. hr = BuildADsPath(
  1753. pszADsPath,
  1754. bstrRelativeName,
  1755. &bstrAbsoluteName
  1756. );
  1757. BAIL_ON_FAILURE(hr);
  1758. hr = BuildLDAPPathFromADsPath2(
  1759. bstrAbsoluteName,
  1760. &pszLDAPServer,
  1761. &pszLDAPDn,
  1762. &dwPort
  1763. );
  1764. BAIL_ON_FAILURE(hr);
  1765. //
  1766. // Compare the class names only if one is given. Null
  1767. // can be used to speed up the delete operation.
  1768. //
  1769. if (bstrClassName) {
  1770. //
  1771. // Validate the class name first
  1772. //
  1773. hr = LdapReadAttribute(
  1774. pszLDAPServer,
  1775. pszLDAPDn,
  1776. TEXT("objectClass"),
  1777. &aValues,
  1778. &nCount,
  1779. _Credentials,
  1780. _dwPort
  1781. );
  1782. BAIL_ON_FAILURE(hr);
  1783. if ( nCount > 0 )
  1784. {
  1785. if ( _tcsicmp( bstrClassName, GET_BASE_CLASS( aValues, nCount) ) != 0 )
  1786. {
  1787. hr = E_ADS_BAD_PARAMETER;
  1788. BAIL_ON_FAILURE(hr);
  1789. }
  1790. }
  1791. }
  1792. hr = LdapDeleteS(
  1793. _pLdapHandle,
  1794. pszLDAPDn
  1795. );
  1796. BAIL_ON_FAILURE(hr);
  1797. error:
  1798. if (bstrParent) {
  1799. ADsFreeString(bstrParent);
  1800. }
  1801. if (bstrName) {
  1802. ADsFreeString(bstrName);
  1803. }
  1804. if (pszADsPath) {
  1805. FreeADsMem(pszADsPath);
  1806. }
  1807. if ( bstrAbsoluteName ) {
  1808. ADsFreeString( bstrAbsoluteName );
  1809. }
  1810. if ( pszLDAPServer ) {
  1811. FreeADsStr( pszLDAPServer );
  1812. }
  1813. if (pszLDAPDn) {
  1814. FreeADsStr(pszLDAPDn);
  1815. }
  1816. if ( aValues ) {
  1817. LdapValueFree( aValues );
  1818. }
  1819. RRETURN_EXP_IF_ERR(hr);
  1820. }
  1821. STDMETHODIMP
  1822. CLDAPGenObject::CopyHere(
  1823. THIS_ BSTR SourceName,
  1824. BSTR NewName,
  1825. IDispatch * FAR* ppObject
  1826. )
  1827. {
  1828. //
  1829. // Make sure that the last error is reset
  1830. //
  1831. Macro_ClearADsLastError(L"LDAP Provider");
  1832. /*
  1833. RRETURN(CopyObject( SourceName,
  1834. _ADsPath,
  1835. _pLdapHandle,
  1836. _pSchemaInfo,
  1837. NewName,
  1838. ppObject ) );
  1839. */
  1840. RRETURN_EXP_IF_ERR(E_NOTIMPL);
  1841. }
  1842. STDMETHODIMP
  1843. CLDAPGenObject::MoveHere(
  1844. THIS_ BSTR SourceName,
  1845. BSTR NewName,
  1846. IDispatch * FAR* ppObject
  1847. )
  1848. {
  1849. LPWSTR pszLDAPServer= NULL;
  1850. LPWSTR pszLDAPDn = NULL;
  1851. BSTR bstrParent = NULL;
  1852. BSTR bstrName = NULL;
  1853. LPWSTR pszADsPath = NULL;
  1854. HRESULT hr = S_OK;
  1855. LPWSTR pszSrcParent= NULL;
  1856. LPWSTR pszCN = NULL;
  1857. LPWSTR pszRelativeName = NULL;
  1858. BSTR bstrDestADsPath = NULL;
  1859. LPWSTR pszDestLDAPServer = NULL;
  1860. LPWSTR pszDestLDAPDn = NULL;
  1861. LPWSTR pszLDAPServerTemp = NULL;
  1862. LPWSTR pszLDAPSourceDnParent = NULL;
  1863. DWORD dwPort = 0;
  1864. LPBOOL lpBoolVal = NULL;
  1865. // Variables need to conver wide char to ANSI format
  1866. DWORD dwOptions = 0;
  1867. int intErr = 0;
  1868. LPSTR pANSIServer = NULL;
  1869. DWORD dwDestLen = 0;
  1870. PADSLDP pSourceLD = NULL;
  1871. BOOL fTryXDom = FALSE;
  1872. LPWSTR pszDestLDAPRelativeName = NULL;
  1873. LDAPControl RenExtInfoControl =
  1874. {
  1875. LDAP_SERVER_CROSSDOM_MOVE_TARGET_OID_W,
  1876. {
  1877. 0, NULL
  1878. },
  1879. TRUE
  1880. };
  1881. PLDAPControl ServerControls[2] =
  1882. {
  1883. &RenExtInfoControl,
  1884. NULL
  1885. };
  1886. //
  1887. // Make sure that the last error is reset
  1888. //
  1889. Macro_ClearADsLastError(L"LDAP Provider");
  1890. //
  1891. // Build the source paths of the object
  1892. // being moved
  1893. //
  1894. hr = BuildADsParentPath(
  1895. SourceName,
  1896. &pszSrcParent,
  1897. &pszCN
  1898. );
  1899. BAIL_ON_FAILURE(hr);
  1900. hr = BuildLDAPPathFromADsPath2(
  1901. SourceName,
  1902. &pszLDAPServer,
  1903. &pszLDAPDn,
  1904. &dwPort
  1905. );
  1906. BAIL_ON_FAILURE(hr);
  1907. if (!pszSrcParent) {
  1908. //
  1909. // If we cannot get the parent, then we cannot move this object.
  1910. //
  1911. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  1912. }
  1913. //
  1914. // We need the dn to the parent of the object being moved.
  1915. //
  1916. hr = BuildLDAPPathFromADsPath2(
  1917. pszSrcParent,
  1918. &pszLDAPServerTemp,
  1919. &pszLDAPSourceDnParent,
  1920. &dwPort
  1921. );
  1922. BAIL_ON_FAILURE(hr);
  1923. //
  1924. // set the right value of relative distinguished name
  1925. // use the name given by the user if given at all
  1926. // otherwise use the name of the source
  1927. //
  1928. if (NewName != NULL) {
  1929. pszRelativeName = NewName;
  1930. } else {
  1931. pszRelativeName = pszCN;
  1932. }
  1933. //
  1934. // Build an ADsPath from get_Parent/get_Name
  1935. // (which always returns useful LDAP-style values)
  1936. // rather than using _ADsPath, which could be
  1937. // of the <GUID=....> form
  1938. //
  1939. hr = get_Parent(&bstrParent);
  1940. BAIL_ON_FAILURE(hr);
  1941. hr = get_Name(&bstrName);
  1942. BAIL_ON_FAILURE(hr);
  1943. hr = BuildADsPathFromParent(
  1944. bstrParent,
  1945. bstrName,
  1946. &pszADsPath
  1947. );
  1948. BAIL_ON_FAILURE(hr);
  1949. //
  1950. // Build the destination ADsPath of the object being moved.
  1951. //
  1952. hr = BuildADsPath(
  1953. pszADsPath,
  1954. pszRelativeName,
  1955. &bstrDestADsPath
  1956. );
  1957. BAIL_ON_FAILURE(hr);
  1958. hr = BuildLDAPPathFromADsPath2(
  1959. bstrDestADsPath,
  1960. &pszDestLDAPServer,
  1961. &pszDestLDAPDn,
  1962. &dwPort
  1963. );
  1964. BAIL_ON_FAILURE(hr);
  1965. //
  1966. // ADSI needs to escape /, but on server side, / is not a special character. So if someone passes
  1967. // in rdn but has ADSI type escaping, we need to convert it to ldap type path, otherwise server will
  1968. // reject this kind of rdn
  1969. //
  1970. hr = GetLDAPTypeName(
  1971. pszRelativeName,
  1972. &pszDestLDAPRelativeName
  1973. );
  1974. BAIL_ON_FAILURE(hr);
  1975. //
  1976. // LdapModDNS uses ldap_modrdn2_s. This function is used to
  1977. // rename the object not to really move it. If the path of this
  1978. // container and the parentDN of the object being moved here are
  1979. // not the same, we need to use ldapRenameExt instead.
  1980. //
  1981. #ifdef WIN95
  1982. if (!_wcsicmp(_pszLDAPDN, pszLDAPSourceDnParent)) {
  1983. #else
  1984. if (CompareStringW(
  1985. LOCALE_SYSTEM_DEFAULT,
  1986. NORM_IGNORECASE,
  1987. _pszLDAPDn,
  1988. -1,
  1989. pszLDAPSourceDnParent,
  1990. -1
  1991. ) == CSTR_EQUAL ) {
  1992. #endif
  1993. //
  1994. // They have the same parent, so we can use LdapModDnS.
  1995. //
  1996. hr = LdapModDnS(
  1997. _pLdapHandle,
  1998. pszLDAPDn,
  1999. pszDestLDAPRelativeName,
  2000. TRUE
  2001. );
  2002. }
  2003. else {
  2004. //
  2005. // Since the object is not in this container, we need to use
  2006. // the renameExt call.
  2007. //
  2008. hr = LdapRenameExtS(
  2009. _pLdapHandle,
  2010. pszLDAPDn,
  2011. pszDestLDAPRelativeName,
  2012. _pszLDAPDn,
  2013. TRUE,
  2014. NULL,
  2015. NULL
  2016. );
  2017. }
  2018. // if there was an error it maybe because the move should
  2019. // be across the domains.
  2020. if (FAILED(hr)) {
  2021. intErr = ldap_get_option(
  2022. _pLdapHandle->LdapHandle,
  2023. LDAP_OPT_VERSION,
  2024. &dwOptions
  2025. );
  2026. //
  2027. // Only if server is V3 and if the server names are not
  2028. // the same will we attempt the extended rename operation.
  2029. // is there are a better way to decide ?
  2030. //
  2031. if (!pszDestLDAPServer) {
  2032. //
  2033. // This object does not have a server, we should
  2034. // read it and then use that as the target server.
  2035. //
  2036. // If this call succeeds, it will copy the servername
  2037. // to the ptr, even if it fails, there should not be problem
  2038. // of memory leak
  2039. //
  2040. GetActualHostName(&pszDestLDAPServer);
  2041. } // if !pszDestLDAPServer
  2042. //
  2043. // Try the XDom move only if we have no match on the server
  2044. // names. Note that there is small chance that we will call
  2045. // crossdom when both are serverless but that should be rare
  2046. // as the ModDN call should have succeeded.
  2047. // If the source server is NULL, LDAPOpenObject will handle
  2048. // that case. The target can never be NULL for XDOm.
  2049. //
  2050. if (dwOptions == LDAP_VERSION3 && pszDestLDAPServer) {
  2051. if (!pszLDAPServer) {
  2052. //
  2053. // One server is set the other is not.
  2054. //
  2055. fTryXDom = TRUE;
  2056. }
  2057. #ifdef WIN95
  2058. else if (_wcsicmp(pszLDAPServer, pszDestLDAPServer)) {
  2059. #else
  2060. else if (CompareStringW(
  2061. LOCALE_SYSTEM_DEFAULT,
  2062. NORM_IGNORECASE,
  2063. pszLDAPServer,
  2064. -1,
  2065. pszDestLDAPServer,
  2066. -1
  2067. ) != CSTR_EQUAL ) {
  2068. #endif
  2069. //
  2070. // Only if both the servers are different.
  2071. //
  2072. fTryXDom = TRUE;
  2073. }
  2074. }
  2075. if (fTryXDom) {
  2076. //
  2077. // The move request has to go to the server that has
  2078. // the object not the target server.
  2079. //
  2080. dwDestLen = _tcslen(pszDestLDAPServer);
  2081. pANSIServer = (LPSTR)LocalAlloc(LPTR, dwDestLen * 2);
  2082. if (!pANSIServer) {
  2083. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2084. }
  2085. intErr = LdapUnicodeToUTF8(
  2086. pszDestLDAPServer,
  2087. dwDestLen,
  2088. pANSIServer,
  2089. dwDestLen * 2
  2090. );
  2091. /*
  2092. intErr = WideCharToMultiByte(
  2093. CP_OEMCP,
  2094. WC_DEFAULTCHAR,
  2095. pszDestLDAPServer,
  2096. dwDestLen,
  2097. pANSIDestServer,
  2098. dwDestLen * 2,
  2099. NULL,
  2100. lpBoolVal
  2101. );
  2102. */
  2103. if (!intErr) {
  2104. // note that there has to be a valid hr from the
  2105. // previous LdapModDN call to be here.
  2106. BAIL_ON_FAILURE(hr);
  2107. }
  2108. // Update the control information
  2109. RenExtInfoControl.ldctl_value.bv_len = strlen(pANSIServer);
  2110. RenExtInfoControl.ldctl_value.bv_val = pANSIServer;
  2111. CCredentials Credentials = _Credentials;
  2112. //
  2113. // Add request delegation flag
  2114. //
  2115. Credentials.SetAuthFlags(
  2116. _Credentials.GetAuthFlags()
  2117. | ADS_USE_DELEGATION
  2118. );
  2119. hr = LdapOpenObject(
  2120. pszLDAPServer,
  2121. pszLDAPDn,
  2122. &pSourceLD,
  2123. Credentials,
  2124. dwPort
  2125. );
  2126. BAIL_ON_FAILURE(hr);
  2127. hr = LdapRenameExtS(
  2128. pSourceLD,
  2129. pszLDAPDn,
  2130. pszDestLDAPRelativeName,
  2131. _pszLDAPDn,
  2132. TRUE,
  2133. ServerControls,
  2134. NULL
  2135. );
  2136. }
  2137. }
  2138. BAIL_ON_FAILURE(hr);
  2139. //
  2140. // We do not need to pass the class name - even if we do it
  2141. // is not used
  2142. //
  2143. hr = GetObject(
  2144. NULL,
  2145. pszDestLDAPRelativeName,
  2146. (IDispatch **)ppObject
  2147. );
  2148. error:
  2149. if (bstrParent) {
  2150. ADsFreeString(bstrParent);
  2151. }
  2152. if (bstrName) {
  2153. ADsFreeString(bstrName);
  2154. }
  2155. if (pszADsPath) {
  2156. FreeADsMem(pszADsPath);
  2157. }
  2158. if(pszSrcParent){
  2159. FreeADsStr(pszSrcParent);
  2160. }
  2161. if(pszCN){
  2162. FreeADsStr(pszCN);
  2163. }
  2164. if(bstrDestADsPath){
  2165. ADsFreeString(bstrDestADsPath );
  2166. }
  2167. if(pszDestLDAPServer){
  2168. FreeADsStr(pszDestLDAPServer);
  2169. }
  2170. if(pszDestLDAPDn){
  2171. FreeADsStr(pszDestLDAPDn);
  2172. }
  2173. if(pszLDAPServer){
  2174. FreeADsStr(pszLDAPServer);
  2175. }
  2176. if(pszLDAPDn){
  2177. FreeADsStr(pszLDAPDn);
  2178. }
  2179. if (pszLDAPServerTemp) {
  2180. FreeADsStr(pszLDAPServerTemp);
  2181. }
  2182. if (pszLDAPSourceDnParent) {
  2183. FreeADsStr(pszLDAPSourceDnParent);
  2184. }
  2185. if (pANSIServer) {
  2186. LocalFree(pANSIServer);
  2187. }
  2188. if (pSourceLD) {
  2189. LdapCloseObject(pSourceLD);
  2190. }
  2191. if (pszDestLDAPRelativeName) {
  2192. FreeADsStr(pszDestLDAPRelativeName);
  2193. }
  2194. RRETURN_EXP_IF_ERR(hr);
  2195. }
  2196. HRESULT
  2197. CLDAPGenObject::AllocateGenObject(
  2198. LPWSTR pszClassName,
  2199. CCredentials &Credentials,
  2200. CLDAPGenObject ** ppGenObject
  2201. )
  2202. {
  2203. CLDAPGenObject FAR * pGenObject = NULL;
  2204. CAggregatorDispMgr FAR * pDispMgr = NULL;
  2205. CPropertyCache FAR * pPropertyCache = NULL;
  2206. HRESULT hr = S_OK;
  2207. pGenObject = new CLDAPGenObject();
  2208. if (pGenObject == NULL) {
  2209. hr = E_OUTOFMEMORY;
  2210. }
  2211. BAIL_ON_FAILURE(hr);
  2212. pDispMgr = new CAggregatorDispMgr(Credentials);
  2213. if (pDispMgr == NULL) {
  2214. hr = E_OUTOFMEMORY;
  2215. }
  2216. BAIL_ON_FAILURE(hr);
  2217. hr = pDispMgr->LoadTypeInfoEntry(
  2218. LIBID_ADs,
  2219. IID_IADs,
  2220. (IADs *)pGenObject,
  2221. DISPID_REGULAR
  2222. );
  2223. BAIL_ON_FAILURE(hr);
  2224. hr = pDispMgr->LoadTypeInfoEntry(
  2225. LIBID_ADs,
  2226. IID_IADsContainer,
  2227. (IADsContainer *)pGenObject,
  2228. DISPID_NEWENUM
  2229. );
  2230. BAIL_ON_FAILURE(hr);
  2231. hr = pDispMgr->LoadTypeInfoEntry(
  2232. LIBID_ADs,
  2233. IID_IADsPropertyList,
  2234. (IADsPropertyList *)pGenObject,
  2235. DISPID_VALUE
  2236. );
  2237. BAIL_ON_FAILURE(hr);
  2238. hr = pDispMgr->LoadTypeInfoEntry(
  2239. LIBID_ADs,
  2240. IID_IADsObjectOptions,
  2241. (IADsObjectOptions *)pGenObject,
  2242. DISPID_REGULAR
  2243. );
  2244. BAIL_ON_FAILURE(hr);
  2245. hr = pDispMgr->LoadTypeInfoEntry(
  2246. LIBID_ADs,
  2247. IID_IADsDeleteOps,
  2248. (IADsDeleteOps *)pGenObject,
  2249. DISPID_REGULAR
  2250. );
  2251. BAIL_ON_FAILURE(hr);
  2252. hr = CPropertyCache::createpropertycache(
  2253. (CCoreADsObject FAR *) pGenObject,
  2254. (IGetAttributeSyntax *)pGenObject,
  2255. &pPropertyCache
  2256. );
  2257. BAIL_ON_FAILURE(hr);
  2258. pDispMgr->RegisterPropertyCache(pPropertyCache);
  2259. pGenObject->_pPropertyCache = pPropertyCache;
  2260. pGenObject->_pDispMgr = pDispMgr;
  2261. *ppGenObject = pGenObject;
  2262. RRETURN(hr);
  2263. error:
  2264. delete pPropertyCache;
  2265. delete pDispMgr;
  2266. delete pGenObject;
  2267. RRETURN_EXP_IF_ERR(hr);
  2268. }
  2269. //
  2270. // IADsObjOptPrivate methods, IADsObjectOptions are wrapped
  2271. // around this.
  2272. //
  2273. STDMETHODIMP
  2274. CLDAPGenObject::GetOption(
  2275. DWORD dwOption,
  2276. void *pValue
  2277. )
  2278. {
  2279. HRESULT hr = S_OK;
  2280. CtxtHandle hCtxtHandle;
  2281. DWORD dwErr = 0;
  2282. ULONG ulFlags = 0;
  2283. if (!pValue) {
  2284. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  2285. }
  2286. switch( dwOption ) {
  2287. case LDP_CACHE_ENTRY:
  2288. *((PADSLDP *) pValue) = _pLdapHandle;
  2289. break;
  2290. case LDAP_HANDLE:
  2291. *((LDAP **) pValue) = _pLdapHandle ? _pLdapHandle->LdapHandle : (LDAP *) NULL;
  2292. break;
  2293. case LDAP_SERVER:
  2294. //
  2295. // pValue here is expected to be a pointer to LPWSTR
  2296. //
  2297. hr = GetActualHostName((LPWSTR *)pValue);
  2298. break;
  2299. case LDAP_DN:
  2300. *((LPWSTR *) pValue) = _pszLDAPDn;
  2301. break;
  2302. case LDAP_CHASE_REFERRALS:
  2303. *((DWORD *) pValue) = _dwOptReferral;
  2304. break;
  2305. case LDAP_PAGESIZE:
  2306. *((DWORD *) pValue) = _dwPageSize;
  2307. break;
  2308. case LDAP_SECURITY_MASK:
  2309. *((SECURITY_INFORMATION*) pValue) = _seInfo;
  2310. break;
  2311. case LDAP_MUTUAL_AUTH_STATUS:
  2312. dwErr = ldap_get_option(
  2313. _pLdapHandle->LdapHandle,
  2314. LDAP_OPT_SECURITY_CONTEXT,
  2315. (void *) &hCtxtHandle
  2316. );
  2317. if (dwErr) {
  2318. BAIL_ON_FAILURE(hr = E_FAIL);
  2319. }
  2320. #if (!defined(WIN95))
  2321. dwErr = QueryContextAttributesWrapper(
  2322. &hCtxtHandle,
  2323. SECPKG_ATTR_FLAGS,
  2324. (void *) &ulFlags
  2325. );
  2326. if (dwErr) {
  2327. if (dwErr == SEC_E_INVALID_HANDLE) {
  2328. //
  2329. // This will happen when SSL is used for certain.
  2330. //
  2331. hr = E_ADS_BAD_PARAMETER;
  2332. }
  2333. else {
  2334. hr = HRESULT_FROM_WIN32(dwErr);
  2335. }
  2336. BAIL_ON_FAILURE(hr);
  2337. }
  2338. #else
  2339. ulFlags = 0;
  2340. #endif
  2341. *((ULONG *) pValue) = ulFlags;
  2342. break;
  2343. case LDAP_MEMBER_HAS_RANGE :
  2344. *((BOOL *) pValue) = _fRangeRetrieval;
  2345. break;
  2346. default:
  2347. *((DWORD *) pValue) = 0;
  2348. hr = E_ADS_BAD_PARAMETER;
  2349. }
  2350. error:
  2351. RRETURN_EXP_IF_ERR(hr);
  2352. }
  2353. STDMETHODIMP
  2354. CLDAPGenObject::SetOption(
  2355. DWORD dwOption,
  2356. void *pValue
  2357. )
  2358. {
  2359. HRESULT hr = S_OK;
  2360. int ldaperr = 0;
  2361. void *ldapOption = 0;
  2362. switch (dwOption) {
  2363. case LDAP_CHASE_REFERRALS:
  2364. switch (*((DWORD *)pValue) ) {
  2365. case ADS_CHASE_REFERRALS_NEVER:
  2366. _dwOptReferral = (DWORD) (DWORD_PTR) LDAP_OPT_OFF;
  2367. break;
  2368. case ADS_CHASE_REFERRALS_SUBORDINATE:
  2369. _dwOptReferral = LDAP_CHASE_SUBORDINATE_REFERRALS;
  2370. break;
  2371. case ADS_CHASE_REFERRALS_EXTERNAL:
  2372. _dwOptReferral = LDAP_CHASE_EXTERNAL_REFERRALS;
  2373. break;
  2374. case ADS_CHASE_REFERRALS_ALWAYS:
  2375. _dwOptReferral = (DWORD) (DWORD_PTR) LDAP_OPT_ON;
  2376. break;
  2377. default:
  2378. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  2379. }
  2380. break;
  2381. case LDAP_PAGESIZE:
  2382. _dwPageSize = *((DWORD *)pValue);
  2383. break;
  2384. case LDAP_SECURITY_MASK:
  2385. _seInfo = *((SECURITY_INFORMATION *) pValue);
  2386. _fExplicitSecurityMask = TRUE;
  2387. break;
  2388. default:
  2389. hr = E_ADS_BAD_PARAMETER;
  2390. break;
  2391. }
  2392. RRETURN_EXP_IF_ERR( hr );
  2393. }
  2394. //
  2395. // IADsObjecOptions methods - wrapper around IADsObjOptPrivate
  2396. //
  2397. STDMETHODIMP
  2398. CLDAPGenObject::GetOption(
  2399. THIS_ long lnControlCode,
  2400. VARIANT FAR* pvProp
  2401. )
  2402. {
  2403. HRESULT hr = S_OK;
  2404. LPWSTR pszServerTemp = NULL;
  2405. ULONG ulMutualAuth = 0;
  2406. VariantInit(pvProp);
  2407. switch (lnControlCode) {
  2408. case ADS_OPTION_SERVERNAME:
  2409. hr = GetOption(LDAP_SERVER, (void *) &pszServerTemp);
  2410. BAIL_ON_FAILURE(hr);
  2411. pvProp->vt = VT_BSTR;
  2412. hr = ADsAllocString(
  2413. pszServerTemp,
  2414. &(pvProp->bstrVal)
  2415. );
  2416. break;
  2417. case ADS_OPTION_SECURITY_MASK:
  2418. //
  2419. // No need to call GetOpion at least not now
  2420. //
  2421. pvProp->vt = VT_I4;
  2422. pvProp->lVal = (ULONG) _seInfo;
  2423. break;
  2424. case ADS_OPTION_REFERRALS :
  2425. pvProp->vt = VT_I4;
  2426. switch (_dwOptReferral) {
  2427. case ((DWORD) (DWORD_PTR)LDAP_OPT_OFF) :
  2428. pvProp->lVal = ADS_CHASE_REFERRALS_NEVER;
  2429. break;
  2430. case LDAP_CHASE_SUBORDINATE_REFERRALS :
  2431. pvProp->lVal = ADS_CHASE_REFERRALS_SUBORDINATE;
  2432. break;
  2433. case LDAP_CHASE_EXTERNAL_REFERRALS :
  2434. pvProp->lVal = ADS_CHASE_REFERRALS_EXTERNAL;
  2435. break;
  2436. case ((DWORD) (DWORD_PTR)LDAP_OPT_ON) :
  2437. pvProp->lVal = ADS_CHASE_REFERRALS_ALWAYS;
  2438. break;
  2439. default:
  2440. pvProp->lVal = 0;
  2441. hr = E_ADS_PROPERTY_INVALID;
  2442. }
  2443. break;
  2444. case ADS_OPTION_PAGE_SIZE :
  2445. pvProp->vt = VT_I4;
  2446. pvProp->lVal = (ULONG) _dwPageSize;
  2447. break;
  2448. case ADS_OPTION_MUTUAL_AUTH_STATUS :
  2449. hr = GetOption(LDAP_MUTUAL_AUTH_STATUS, (void *) &ulMutualAuth);
  2450. BAIL_ON_FAILURE(hr);
  2451. pvProp->vt = VT_I4;
  2452. pvProp->lVal = ulMutualAuth;
  2453. break;
  2454. default:
  2455. hr = E_ADS_BAD_PARAMETER;
  2456. }
  2457. error :
  2458. if (pszServerTemp) {
  2459. FreeADsStr(pszServerTemp);
  2460. }
  2461. RRETURN(hr);
  2462. }
  2463. STDMETHODIMP
  2464. CLDAPGenObject::SetOption(
  2465. THIS_ long lnControlCode,
  2466. VARIANT vProp
  2467. )
  2468. {
  2469. HRESULT hr = S_OK;
  2470. DWORD dwOptVal = 0;
  2471. VARIANT *pvProp = NULL;
  2472. //
  2473. // To make sure we handle variant by refs correctly.
  2474. //
  2475. pvProp = &vProp;
  2476. if (V_VT(pvProp) == (VT_BYREF|VT_VARIANT)) {
  2477. pvProp = V_VARIANTREF(&vProp);
  2478. }
  2479. switch (lnControlCode) {
  2480. case ADS_OPTION_REFERRALS :
  2481. hr = GetIntegerFromVariant(pvProp, &dwOptVal);
  2482. if (SUCCEEDED(hr))
  2483. hr = SetOption(LDAP_CHASE_REFERRALS, (void *) &dwOptVal);
  2484. break;
  2485. case ADS_OPTION_PAGE_SIZE :
  2486. hr = GetIntegerFromVariant(pvProp, &dwOptVal);
  2487. if (SUCCEEDED(hr))
  2488. hr = SetOption(LDAP_PAGESIZE, (void *) &dwOptVal);
  2489. break;
  2490. case ADS_OPTION_SECURITY_MASK :
  2491. hr = GetIntegerFromVariant(pvProp, &dwOptVal);
  2492. if (SUCCEEDED(hr)) {
  2493. _seInfo = (SECURITY_INFORMATION) dwOptVal;
  2494. _fExplicitSecurityMask = TRUE;
  2495. }
  2496. break;
  2497. case ADS_PRIVATE_OPTION_SPECIFIC_SERVER :
  2498. //
  2499. // If it is just a VT_BSTR, then this is old.
  2500. // If this is an array, then it should also
  2501. // have the domain information.
  2502. //
  2503. if (pvProp->vt == VT_BSTR) {
  2504. if (gpszStickyDomainName) {
  2505. FreeADsStr(gpszStickyDomainName);
  2506. gpszStickyDomainName = NULL;
  2507. }
  2508. if (gpszStickyServerName) {
  2509. FreeADsStr(gpszStickyServerName);
  2510. gpszStickyServerName = NULL;
  2511. }
  2512. //
  2513. // Set for LDAP layer
  2514. //
  2515. if (pvProp->bstrVal) {
  2516. gpszStickyServerName = AllocADsStr(pvProp->bstrVal);
  2517. if (!gpszStickyServerName) {
  2518. hr = E_OUTOFMEMORY;
  2519. }
  2520. }
  2521. if (SUCCEEDED(hr)) {
  2522. hr = LdapcSetStickyServer(NULL, pvProp->bstrVal);
  2523. }
  2524. }
  2525. else if ((pvProp->vt & VT_ARRAY)) {
  2526. hr = SetStickyServerWithDomain(pvProp);
  2527. }
  2528. break;
  2529. default:
  2530. hr = E_ADS_BAD_PARAMETER;
  2531. }
  2532. RRETURN(hr);
  2533. }
  2534. HRESULT
  2535. ConvertVariantToVariantArray(
  2536. VARIANT varData,
  2537. VARIANT ** ppVarArray,
  2538. DWORD * pdwNumValues
  2539. )
  2540. {
  2541. DWORD dwNumValues = 0;
  2542. VARIANT * pVarArray = NULL;
  2543. HRESULT hr = S_OK;
  2544. VARIANT * pvarData = NULL;
  2545. *ppVarArray = NULL;
  2546. *pdwNumValues = 0;
  2547. //
  2548. // Although no known automation controller passes
  2549. // VT_VARIANT|VT_BYREF into get_/put_ function
  2550. // as a reference to an array, we carry out the following
  2551. // check for extra safety.
  2552. //
  2553. pvarData = &varData;
  2554. if (V_VT(pvarData) == (VT_VARIANT|VT_BYREF)) {
  2555. pvarData = V_VARIANTREF(&varData);
  2556. }
  2557. if ((V_VT(pvarData) == (VT_VARIANT|VT_ARRAY|VT_BYREF)) ||
  2558. (V_VT(pvarData) == (VT_VARIANT|VT_ARRAY))) {
  2559. hr = ConvertSafeArrayToVariantArray(
  2560. *pvarData,
  2561. &pVarArray,
  2562. &dwNumValues
  2563. );
  2564. // returns E_FAIL if *pvarData is invalid
  2565. if (hr == E_FAIL)
  2566. hr = E_ADS_BAD_PARAMETER;
  2567. BAIL_ON_FAILURE(hr);
  2568. } else {
  2569. pVarArray = NULL;
  2570. dwNumValues = 0;
  2571. }
  2572. *ppVarArray = pVarArray;
  2573. *pdwNumValues = dwNumValues;
  2574. error:
  2575. RRETURN(hr);
  2576. }
  2577. void
  2578. FreeVariantArray(
  2579. VARIANT * pVarArray,
  2580. DWORD dwNumValues
  2581. )
  2582. {
  2583. if (pVarArray) {
  2584. DWORD i = 0;
  2585. for (i = 0; i < dwNumValues; i++) {
  2586. VariantClear(pVarArray + i);
  2587. }
  2588. FreeADsMem(pVarArray);
  2589. }
  2590. }
  2591. HRESULT
  2592. ConvertVariantToLdapValues(
  2593. VARIANT varData,
  2594. LPWSTR szPropertyName,
  2595. PDWORD pdwControlCode,
  2596. LDAPOBJECTARRAY * pldapDestObjects,
  2597. PDWORD pdwSyntaxId,
  2598. LPWSTR pszServer,
  2599. CCredentials* pCredentials,
  2600. DWORD dwPort
  2601. )
  2602. {
  2603. HRESULT hr = S_OK;
  2604. IADsPropertyEntry * pPropEntry = NULL;
  2605. IDispatch * pDispatch = NULL;
  2606. BSTR bstrPropName = NULL;
  2607. DWORD dwControlCode = 0;
  2608. DWORD dwAdsType = 0;
  2609. VARIANT varValues;
  2610. VARIANT * pVarArray = NULL;
  2611. DWORD dwNumValues = 0;
  2612. PADSVALUE pAdsValues = NULL;
  2613. DWORD dwAdsValues = 0;
  2614. PVARIANT pVar = NULL;
  2615. BOOL fNTDSType = TRUE;
  2616. BOOL fGenTime = FALSE;
  2617. DWORD dwServerSyntaxId = 0;
  2618. if (V_VT(&varData) != VT_DISPATCH) {
  2619. if (V_VT(&varData) != (VT_VARIANT | VT_BYREF)) {
  2620. RRETURN (hr = DISP_E_TYPEMISMATCH);
  2621. }
  2622. else {
  2623. pVar = V_VARIANTREF(&varData);
  2624. if (pVar == NULL || V_VT(pVar) != VT_DISPATCH) {
  2625. RRETURN (hr = DISP_E_TYPEMISMATCH);
  2626. }
  2627. else {
  2628. pDispatch = V_DISPATCH(pVar);
  2629. }
  2630. }
  2631. }
  2632. else {
  2633. pDispatch = V_DISPATCH(&varData);
  2634. }
  2635. VariantInit(&varValues);
  2636. hr = pDispatch->QueryInterface(
  2637. IID_IADsPropertyEntry,
  2638. (void **)&pPropEntry
  2639. );
  2640. BAIL_ON_FAILURE(hr);
  2641. hr = pPropEntry->get_Name(&bstrPropName);
  2642. BAIL_ON_FAILURE(hr);
  2643. wcscpy(szPropertyName, bstrPropName);
  2644. hr = pPropEntry->get_ControlCode((long *)&dwControlCode);
  2645. BAIL_ON_FAILURE(hr);
  2646. hr = pPropEntry->get_ADsType((long *)&dwAdsType);
  2647. BAIL_ON_FAILURE(hr);
  2648. hr = pPropEntry->get_Values(&varValues);
  2649. BAIL_ON_FAILURE(hr);
  2650. hr = ConvertVariantToVariantArray(
  2651. varValues,
  2652. &pVarArray,
  2653. &dwNumValues
  2654. );
  2655. BAIL_ON_FAILURE(hr);
  2656. if (dwNumValues) {
  2657. //
  2658. // At this point it is probably cheaper to read the
  2659. // server type and send the values to the conversion
  2660. // routines than to check if this is a securityDescriptor
  2661. // by walking the PropertyEntry and then looking at the variant.
  2662. // There is a good chance that this information is already cached.
  2663. //
  2664. hr = ReadServerType(
  2665. pszServer,
  2666. pCredentials,
  2667. &fNTDSType
  2668. );
  2669. BAIL_ON_FAILURE(hr);
  2670. hr = PropVariantToAdsType2(
  2671. pVarArray,
  2672. dwNumValues,
  2673. &pAdsValues,
  2674. &dwAdsValues,
  2675. pszServer,
  2676. pCredentials,
  2677. fNTDSType
  2678. );
  2679. BAIL_ON_FAILURE(hr);
  2680. if (dwAdsType == ADSTYPE_UTC_TIME) {
  2681. //
  2682. // See if this is a GenTime on the server
  2683. //
  2684. HRESULT hr;
  2685. hr = LdapGetSyntaxOfAttributeOnServer(
  2686. pszServer,
  2687. szPropertyName,
  2688. &dwServerSyntaxId,
  2689. *pCredentials,
  2690. dwPort
  2691. );
  2692. if (FAILED(hr)) {
  2693. hr = S_OK;
  2694. }
  2695. else if (dwServerSyntaxId == LDAPTYPE_GENERALIZEDTIME) {
  2696. fGenTime = TRUE;
  2697. }
  2698. }
  2699. hr = AdsTypeToLdapTypeCopyConstruct(
  2700. pAdsValues,
  2701. dwAdsValues,
  2702. pldapDestObjects,
  2703. pdwSyntaxId,
  2704. fGenTime
  2705. );
  2706. BAIL_ON_FAILURE(hr);
  2707. }
  2708. *pdwControlCode = dwControlCode;
  2709. cleanup:
  2710. if (bstrPropName) {
  2711. ADsFreeString(bstrPropName);
  2712. }
  2713. if (pAdsValues) {
  2714. AdsTypeFreeAdsObjects(
  2715. pAdsValues,
  2716. dwNumValues
  2717. );
  2718. }
  2719. if (pVarArray) {
  2720. FreeVariantArray(
  2721. pVarArray,
  2722. dwAdsValues
  2723. );
  2724. }
  2725. if (pPropEntry) {
  2726. pPropEntry->Release();
  2727. }
  2728. VariantClear(&varValues);
  2729. RRETURN(hr);
  2730. error:
  2731. LdapTypeFreeLdapObjects( pldapDestObjects );
  2732. goto cleanup;
  2733. }
  2734. HRESULT
  2735. MapAdsTypeToLdapType(
  2736. BSTR bstrPropName,
  2737. DWORD dwAdsType,
  2738. PDWORD pdwLdapType
  2739. )
  2740. {
  2741. RRETURN(S_OK);
  2742. }
  2743. HRESULT
  2744. ConvertLdapValuesToVariant(
  2745. BSTR bstrPropName,
  2746. LDAPOBJECTARRAY * pldapSrcObjects,
  2747. DWORD dwLdapType,
  2748. DWORD dwControlCode,
  2749. PVARIANT pVarProp,
  2750. LPWSTR pszServer,
  2751. CCredentials* pCredentials
  2752. )
  2753. {
  2754. HRESULT hr = S_OK;
  2755. PADSVALUE pAdsValues = NULL;
  2756. DWORD dwNumAdsValues = 0;
  2757. DWORD dwNumValues = 0;
  2758. DWORD dwAdsType = 0;
  2759. VARIANT varData;
  2760. IDispatch * pDispatch = NULL;
  2761. BOOL fNTDS = TRUE;
  2762. VariantInit(&varData);
  2763. VariantClear(&varData);
  2764. VariantInit(pVarProp);
  2765. // pldaSrcObject should never be null
  2766. ADsAssert(pldapSrcObjects);
  2767. if (dwControlCode != ADS_PROPERTY_DELETE ) {
  2768. hr = LdapTypeToAdsTypeCopyConstruct(
  2769. *pldapSrcObjects,
  2770. dwLdapType,
  2771. &pAdsValues,
  2772. &dwNumAdsValues,
  2773. &dwAdsType
  2774. );
  2775. if (SUCCEEDED(hr)) {
  2776. dwNumValues = pldapSrcObjects->dwCount;
  2777. //
  2778. // if the property is a security descriptor
  2779. // we need to set the server type also
  2780. //
  2781. if (dwAdsType == ADSTYPE_NT_SECURITY_DESCRIPTOR) {
  2782. hr = ReadServerType(
  2783. pszServer,
  2784. pCredentials,
  2785. &fNTDS
  2786. );
  2787. BAIL_ON_FAILURE(hr);
  2788. hr = AdsTypeToPropVariant2(
  2789. pAdsValues,
  2790. dwNumValues,
  2791. &varData,
  2792. pszServer,
  2793. pCredentials,
  2794. fNTDS
  2795. );
  2796. } else {
  2797. hr = AdsTypeToPropVariant(
  2798. pAdsValues,
  2799. dwNumValues,
  2800. &varData
  2801. );
  2802. }
  2803. BAIL_ON_FAILURE(hr);
  2804. } else {
  2805. // We could not convert the data type
  2806. // This maybe because we have the invalid data type
  2807. // so we will just return the variant data as null
  2808. // and also set the data type to 0 or invalid in that case
  2809. if (dwLdapType == LDAPTYPE_UNKNOWN) {
  2810. dwAdsType = 0;
  2811. hr = S_OK;
  2812. } else {
  2813. // since the datatpye was valid, we should
  2814. // send this back to the user.
  2815. BAIL_ON_FAILURE(hr);
  2816. }
  2817. }
  2818. } else {
  2819. dwAdsType = 0;
  2820. }
  2821. hr = CreatePropEntry(
  2822. bstrPropName,
  2823. dwAdsType,
  2824. dwNumValues,
  2825. dwControlCode,
  2826. varData,
  2827. IID_IDispatch,
  2828. (void **)&pDispatch
  2829. );
  2830. BAIL_ON_FAILURE(hr);
  2831. V_DISPATCH(pVarProp) = pDispatch;
  2832. V_VT(pVarProp) = VT_DISPATCH;
  2833. error:
  2834. VariantClear(&varData);
  2835. if (pAdsValues) {
  2836. AdsTypeFreeAdsObjects(
  2837. pAdsValues,
  2838. dwNumValues
  2839. );
  2840. }
  2841. RRETURN(hr);
  2842. }
  2843. //
  2844. // Needed for dynamic dispid's in the property cache.
  2845. //
  2846. HRESULT
  2847. CLDAPGenObject::GetAttributeSyntax(
  2848. LPWSTR szPropertyName,
  2849. PDWORD pdwSyntaxId
  2850. )
  2851. {
  2852. HRESULT hr;
  2853. hr = LdapGetSyntaxOfAttributeOnServer(
  2854. _pszLDAPServer,
  2855. szPropertyName,
  2856. pdwSyntaxId,
  2857. _Credentials,
  2858. _dwPort
  2859. );
  2860. RRETURN_EXP_IF_ERR(hr);
  2861. }
  2862. HRESULT
  2863. CLDAPGenObject::DeleteObject(
  2864. long lnFlags
  2865. )
  2866. {
  2867. HRESULT hr = S_OK;
  2868. LDAPControl SeInfoControlRecursDelete =
  2869. {
  2870. LDAP_SERVER_TREE_DELETE_OID_W,
  2871. { NULL, NULL},
  2872. FALSE
  2873. };
  2874. PLDAPControl ServerControls[2] =
  2875. {
  2876. &SeInfoControlRecursDelete,
  2877. NULL
  2878. };
  2879. hr = LdapDeleteExtS(
  2880. _pLdapHandle,
  2881. _pszLDAPDn,
  2882. (PLDAPControl *)&ServerControls,
  2883. NULL
  2884. );
  2885. BAIL_ON_FAILURE(hr);
  2886. error:
  2887. RRETURN(hr);
  2888. }
  2889. HRESULT
  2890. CLDAPGenObject::GetActualHostName(
  2891. LPWSTR * pValue
  2892. )
  2893. {
  2894. HRESULT hr = S_OK;
  2895. DWORD dwLength = MAX_PATH;
  2896. LPWSTR szHostName = NULL;
  2897. int err = 0;
  2898. LDAPMessage *pMsgResult = NULL;
  2899. LDAPMessage *pMsgEntry = NULL;
  2900. LDAP *pLdapCurrent = NULL;
  2901. LPWSTR Attributes[] = {L"objectClass", NULL};
  2902. //
  2903. // We need to get at the actual object as we may have a
  2904. // referral
  2905. //
  2906. hr = LdapSearchS(
  2907. _pLdapHandle,
  2908. _pszLDAPDn,
  2909. LDAP_SCOPE_BASE,
  2910. L"(objectClass=*)",
  2911. Attributes,
  2912. 0,
  2913. &pMsgResult
  2914. );
  2915. //
  2916. // Only one entry should be returned
  2917. //
  2918. BAIL_ON_FAILURE(hr);
  2919. hr = LdapFirstEntry(
  2920. _pLdapHandle,
  2921. pMsgResult,
  2922. &pMsgEntry
  2923. );
  2924. BAIL_ON_FAILURE(hr);
  2925. pLdapCurrent = pMsgResult->Connection;
  2926. err = ldap_get_optionW(
  2927. pLdapCurrent,
  2928. LDAP_OPT_HOST_NAME,
  2929. &szHostName
  2930. );
  2931. if (err != LDAP_SUCCESS || szHostName == NULL) {
  2932. BAIL_ON_FAILURE(hr = E_FAIL);
  2933. }
  2934. // If we are here we need to copy the name and return
  2935. *pValue = AllocADsStr(szHostName);
  2936. if(!(*pValue)) {
  2937. hr = E_OUTOFMEMORY;
  2938. BAIL_ON_FAILURE(hr);
  2939. }
  2940. error:
  2941. if (pMsgResult) {
  2942. LdapMsgFree(pMsgResult);
  2943. }
  2944. RRETURN(hr);
  2945. }
  2946. HRESULT
  2947. GetIntegerFromVariant(
  2948. VARIANT* pvProp,
  2949. DWORD* pdwVal)
  2950. {
  2951. HRESULT hr = S_OK;
  2952. *pdwVal = 0;
  2953. if (pvProp->vt == VT_I4) {
  2954. *pdwVal = pvProp->lVal;
  2955. }
  2956. else if(pvProp->vt == VT_I2) {
  2957. *pdwVal = pvProp->iVal;
  2958. } else
  2959. hr = E_ADS_BAD_PARAMETER;
  2960. RRETURN(hr);
  2961. }
  2962. //+------------------------------------------------------------------------
  2963. //
  2964. // Function: TraceTreeForClass
  2965. //
  2966. // Synopsis: Traces the inheritance hierarchy for the class being crerated
  2967. // and returns the list in the arg pppszNameArr. There are
  2968. // *plnNumElements in this array. This can be used later while
  2969. // creating the object so that all the extensions will be available.
  2970. //
  2971. // Arguments:
  2972. // Parent - The ADsPath of the parent,
  2973. // CommonName - RDN of the object being created,
  2974. // pszClassName- Class of the object being created,
  2975. // Credentials - Credentials blob,
  2976. // pppszNameArr- Return value - array of names of parent classes.
  2977. // plnNumItems - Return value - number of elements in above array.
  2978. //
  2979. //-------------------------------------------------------------------------
  2980. HRESULT
  2981. TraceTreeForClass(
  2982. BSTR Parent,
  2983. BSTR CommonName,
  2984. LPWSTR pszClassName,
  2985. CCredentials& Credentials,
  2986. PWCHAR **pppszNameArr,
  2987. PLONG plnNumElements
  2988. )
  2989. {
  2990. HRESULT hr = S_OK;
  2991. IADsClass *pIADsClass = NULL;
  2992. IUnknown *pUnk = NULL;
  2993. PWCHAR *pszRetVal = NULL;
  2994. WCHAR pszSchemaPathBase[MAX_PATH];
  2995. WCHAR pszSchemaPath[MAX_PATH];
  2996. LPWSTR pszServer = NULL;
  2997. LPWSTR pszLDAPDn = NULL;
  2998. LPWSTR pszCurVal = NULL;
  2999. DWORD dwPort = 0;
  3000. VARIANT vBstrVal;
  3001. CCredentials Creds = Credentials;
  3002. long lnNumItems = 1;
  3003. BOOL fDone = FALSE;
  3004. PClassesHierarchyList pClassListHead = NULL;
  3005. PClassesHierarchyList pClassListNode = NULL;
  3006. //
  3007. // We need to make sure that the ADS_AUTH_RESERVED flag is not set
  3008. // in the credentials because that will result in us not getting the
  3009. // IADsClass interface ptr we want.
  3010. //
  3011. Creds.SetAuthFlags(Creds.GetAuthFlags() & ~ADS_AUTH_RESERVED);
  3012. VariantInit(&vBstrVal);
  3013. //
  3014. // Build The schema name
  3015. //
  3016. hr = BuildLDAPPathFromADsPath2(
  3017. Parent,
  3018. &pszServer,
  3019. &pszLDAPDn,
  3020. &dwPort
  3021. );
  3022. BAIL_ON_FAILURE(hr);
  3023. if (pszServer) {
  3024. wsprintf(pszSchemaPathBase, L"LDAP://%s", pszServer);
  3025. } else {
  3026. wsprintf(pszSchemaPathBase, L"LDAP:/");
  3027. }
  3028. pszCurVal = AllocADsStr(pszClassName);
  3029. if (!pszCurVal) {
  3030. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  3031. }
  3032. while (!fDone && _wcsicmp(L"Top", pszCurVal)) {
  3033. lnNumItems++;
  3034. //
  3035. // Add a new node to the list
  3036. //
  3037. pClassListNode = (PClassesHierarchyList)
  3038. AllocADsMem(sizeof(ClassesHierarchyList));
  3039. if (!pClassListNode) {
  3040. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  3041. }
  3042. pClassListNode->pszClassName = AllocADsStr(pszCurVal);
  3043. if (!pClassListNode->pszClassName) {
  3044. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  3045. }
  3046. pClassListNode->pNext = pClassListHead;
  3047. pClassListHead = pClassListNode;
  3048. //
  3049. // Check for the next class on the list
  3050. //
  3051. wsprintf(pszSchemaPath, L"%s", pszSchemaPathBase);
  3052. wcscat(pszSchemaPath, L"/Schema/");
  3053. wcscat(pszSchemaPath, pszCurVal);
  3054. FreeADsStr(pszCurVal);
  3055. pszCurVal = NULL;
  3056. hr = GetObject(
  3057. pszSchemaPath,
  3058. Credentials,
  3059. (LPVOID *) &pUnk
  3060. );
  3061. BAIL_ON_FAILURE(hr);
  3062. hr = pUnk->QueryInterface(
  3063. IID_IADsClass,
  3064. (void **) &pIADsClass
  3065. );
  3066. BAIL_ON_FAILURE(hr);
  3067. //
  3068. // Release the ref on the pUnk
  3069. //
  3070. pUnk->Release();
  3071. pUnk = NULL;
  3072. hr = pIADsClass->get_DerivedFrom(&vBstrVal);
  3073. BAIL_ON_FAILURE(hr);
  3074. //
  3075. // Release the ptr as we no longer need it.
  3076. //
  3077. pIADsClass->Release();
  3078. if (vBstrVal.vt == (VT_VARIANT | VT_ARRAY)) {
  3079. //
  3080. // Server has complete list of classes in schema
  3081. //
  3082. hr = AddToClassesList(
  3083. vBstrVal,
  3084. &pszCurVal,
  3085. &pClassListHead,
  3086. &lnNumItems
  3087. );
  3088. BAIL_ON_FAILURE(hr);
  3089. //
  3090. // add one to the count for the value passed in
  3091. //
  3092. lnNumItems++;
  3093. fDone = TRUE;
  3094. }
  3095. else if (vBstrVal.vt == VT_BSTR) {
  3096. pszCurVal = AllocADsStr(vBstrVal.bstrVal);
  3097. VariantClear(&vBstrVal);
  3098. if (!pszCurVal) {
  3099. hr = E_OUTOFMEMORY;
  3100. }
  3101. }
  3102. else {
  3103. hr = E_FAIL;
  3104. }
  3105. BAIL_ON_FAILURE(hr);
  3106. }
  3107. //
  3108. // We now have the list as well as the number of items
  3109. //
  3110. pszRetVal = (PWCHAR *) AllocADsMem(sizeof(PWCHAR) * (lnNumItems + 1));
  3111. if (!pszRetVal) {
  3112. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  3113. }
  3114. //
  3115. // Do not move as we may call -- below
  3116. //
  3117. *plnNumElements = lnNumItems;
  3118. pszRetVal[lnNumItems] = NULL;
  3119. if (!fDone) {
  3120. //
  3121. // Add top to the list and set last to NULL
  3122. // only if we did not hit addclasses fn.
  3123. //
  3124. pszRetVal[lnNumItems - 1] = AllocADsStr(L"Top");
  3125. if (!pszRetVal[lnNumItems - 1]) {
  3126. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  3127. }
  3128. lnNumItems--;
  3129. }
  3130. while (pClassListHead && (lnNumItems > -1)) {
  3131. pszRetVal[--lnNumItems] =
  3132. AllocADsStr(pClassListHead->pszClassName);
  3133. if (!pszRetVal[lnNumItems]) {
  3134. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  3135. }
  3136. //
  3137. // Free the entry and advance list
  3138. //
  3139. FreeADsStr(pClassListHead->pszClassName);
  3140. pClassListNode = pClassListHead;
  3141. pClassListHead = pClassListHead->pNext;
  3142. FreeADsMem(pClassListNode);
  3143. pClassListNode = NULL;
  3144. }
  3145. //
  3146. // Put appropriate value in return arg.
  3147. //
  3148. *pppszNameArr = pszRetVal;
  3149. error:
  3150. if (pszServer) {
  3151. FreeADsStr(pszServer);
  3152. }
  3153. if (pszLDAPDn) {
  3154. FreeADsStr(pszLDAPDn);
  3155. }
  3156. if (pszCurVal) {
  3157. FreeADsStr(pszCurVal);
  3158. }
  3159. if (pUnk) {
  3160. pUnk->Release();
  3161. }
  3162. //
  3163. // Walk through and free the list if necessary
  3164. //
  3165. while (pClassListHead) {
  3166. pClassListNode = pClassListHead;
  3167. if (pClassListHead->pszClassName) {
  3168. FreeADsStr(pClassListHead->pszClassName);
  3169. }
  3170. pClassListHead = pClassListHead->pNext;
  3171. FreeADsMem(pClassListNode);
  3172. }
  3173. RRETURN(hr);
  3174. }
  3175. //
  3176. // Helper to get the values from the Variant and add to list
  3177. //
  3178. HRESULT
  3179. AddToClassesList(
  3180. VARIANT vProps,
  3181. LPWSTR *ppszCurClass,
  3182. PClassesHierarchyList *ppClassListHead,
  3183. PLONG plnNumItems
  3184. )
  3185. {
  3186. HRESULT hr = S_OK;
  3187. PClassesHierarchyList pClassNode = NULL;
  3188. VARIANT * pVarArray = NULL;
  3189. VARIANT * pvProp = NULL;
  3190. DWORD dwNumValues = 0, i = 0;
  3191. pvProp = &vProps;
  3192. hr = ConvertSafeArrayToVariantArray(
  3193. *pvProp,
  3194. &pVarArray,
  3195. &dwNumValues
  3196. );
  3197. BAIL_ON_FAILURE(hr);
  3198. //
  3199. // Go through the array adding nodes.
  3200. //
  3201. for (i = 0; i < dwNumValues; i++) {
  3202. pvProp = pVarArray + i;
  3203. if (pvProp->vt != VT_BSTR) {
  3204. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  3205. }
  3206. //
  3207. // Alloc node to add
  3208. //
  3209. pClassNode = (PClassesHierarchyList)
  3210. AllocADsMem(sizeof(ClassesHierarchyList));
  3211. if (!pClassNode) {
  3212. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  3213. }
  3214. pClassNode->pszClassName = AllocADsStr(pvProp->bstrVal);
  3215. if (!pClassNode->pszClassName) {
  3216. //
  3217. // Free pClassNode as we will let caller free the list
  3218. // if we run out of memory.
  3219. //
  3220. FreeADsMem(pClassNode);
  3221. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  3222. }
  3223. pClassNode->pNext = *ppClassListHead;
  3224. *ppClassListHead = pClassNode;
  3225. } // end for
  3226. *plnNumItems = dwNumValues;
  3227. error:
  3228. if (pVarArray) {
  3229. for (i = 0; i < dwNumValues; i++) {
  3230. VariantClear(pVarArray + i);
  3231. }
  3232. FreeADsMem(pVarArray);
  3233. }
  3234. RRETURN(hr);
  3235. }
  3236. //
  3237. // Helper routine that handles setting the sticky server private
  3238. // option when the input is an array.
  3239. //
  3240. HRESULT
  3241. SetStickyServerWithDomain(
  3242. PVARIANT pvProp
  3243. )
  3244. {
  3245. HRESULT hr = S_OK;
  3246. VARIANT *pvVarArray = NULL;
  3247. DWORD dwNumVariants = 0;
  3248. DWORD dwCtr = 0;
  3249. LPWSTR *ppszStringArray = NULL;
  3250. hr = ConvertSafeArrayToVariantArray(
  3251. *pvProp,
  3252. &pvVarArray,
  3253. &dwNumVariants
  3254. );
  3255. // returns E_FAIL if vProperties is invalid
  3256. if (hr == E_FAIL)
  3257. hr = E_ADS_BAD_PARAMETER;
  3258. BAIL_ON_FAILURE(hr);
  3259. //
  3260. // There have to be precisely 2 entries, one for domain
  3261. // and the second for the serverName.
  3262. //
  3263. if (dwNumVariants != 2) {
  3264. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  3265. }
  3266. hr = ConvertVariantArrayToLDAPStringArray(
  3267. pvVarArray,
  3268. &ppszStringArray,
  3269. dwNumVariants
  3270. );
  3271. BAIL_ON_FAILURE(hr);
  3272. if (!ppszStringArray
  3273. || !ppszStringArray[0]
  3274. || !*(ppszStringArray[0])
  3275. || !ppszStringArray[1]
  3276. || !*(ppszStringArray[1])
  3277. ) {
  3278. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  3279. }
  3280. if (gpszStickyServerName) {
  3281. FreeADsStr(gpszStickyServerName);
  3282. gpszStickyServerName = NULL;
  3283. }
  3284. if (gpszStickyDomainName) {
  3285. FreeADsStr(gpszStickyDomainName);
  3286. gpszStickyDomainName = NULL;
  3287. }
  3288. gpszStickyServerName = AllocADsStr(ppszStringArray[1]);
  3289. if (!gpszStickyServerName) {
  3290. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  3291. }
  3292. gpszStickyDomainName = AllocADsStr(ppszStringArray[0]);
  3293. if (!gpszStickyDomainName) {
  3294. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  3295. }
  3296. hr = LdapcSetStickyServer(
  3297. gpszStickyDomainName,
  3298. gpszStickyServerName
  3299. );
  3300. BAIL_ON_FAILURE(hr);
  3301. error:
  3302. if (FAILED(hr)) {
  3303. //
  3304. // Clear the global strings on failure.
  3305. //
  3306. if (gpszStickyServerName) {
  3307. FreeADsStr(gpszStickyServerName);
  3308. gpszStickyServerName = NULL;
  3309. }
  3310. if (gpszStickyDomainName) {
  3311. FreeADsStr(gpszStickyDomainName);
  3312. gpszStickyDomainName = NULL;
  3313. }
  3314. }
  3315. //
  3316. // Cleanup variant array and string array.
  3317. //
  3318. if (pvVarArray) {
  3319. for (dwCtr = 0; dwCtr < dwNumVariants; dwCtr++) {
  3320. VariantClear(pvVarArray + dwCtr);
  3321. }
  3322. FreeADsMem(pvVarArray);
  3323. }
  3324. if (ppszStringArray) {
  3325. for (dwCtr = 0; dwCtr < dwNumVariants; dwCtr++) {
  3326. if (ppszStringArray[dwCtr])
  3327. FreeADsStr(ppszStringArray[dwCtr]);
  3328. }
  3329. FreeADsMem(ppszStringArray);
  3330. }
  3331. RRETURN(hr);
  3332. }