Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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