Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

772 lines
17 KiB

  1. //
  2. // Microsoft Windows
  3. // Copyright (C) Microsoft Corporation, 1992 - 1996
  4. //
  5. // File: cgenobj.cxx
  6. //
  7. // Contents: Microsoft ADs LDAP Provider Generic Object
  8. //
  9. //
  10. // History: 08-30-96 yihsins Created.
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "ldap.hxx"
  14. #pragma hdrstop
  15. HRESULT
  16. CLDAPGenObject::get_PropertyCount(
  17. THIS_ long FAR *plCount
  18. )
  19. {
  20. HRESULT hr = E_FAIL;
  21. BSTR bstrProperty = NULL;
  22. SAFEARRAY *psaProperty = NULL;
  23. SAFEARRAYBOUND rgsabound[1];
  24. long lsaDim[1];
  25. VARIANT varProperty;
  26. // ??? _pPropertyCache canNOT be NULL or bailed out during
  27. // CLDAPGenObject creation already
  28. // assert(_PropertyCache);
  29. if (_pPropertyCache) {
  30. hr = _pPropertyCache->get_PropertyCount((PDWORD)plCount);
  31. }
  32. RRETURN_EXP_IF_ERR(hr);
  33. }
  34. ////////////////////////////////////////////////////////////////////////////
  35. //
  36. // - Return the "next" item (item with the current index) in cache, if any,
  37. // in a property entry [*pVariant].
  38. // - Return E_ADS_PROPERTY_NOT_FOUND when current index is out of bound.
  39. //
  40. ////////////////////////////////////////////////////////////////////////////
  41. STDMETHODIMP
  42. CLDAPGenObject::Next(
  43. THIS_ VARIANT FAR *pVariant
  44. )
  45. {
  46. HRESULT hr = E_FAIL;
  47. DWORD dwSyntaxId = 0;
  48. DWORD dwNumValues = 0;
  49. LDAPOBJECTARRAY ldapSrcObjects;
  50. IDispatch * pDispatch = NULL;
  51. DWORD dwNumAdsValues = 0;
  52. DWORD dwAdsType = 0;
  53. DWORD dwPropStatus = 0;
  54. DWORD dwCtrlCode = 0;
  55. if(!_pPropertyCache->index_valid())
  56. RRETURN_EXP_IF_ERR(E_FAIL);
  57. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  58. hr = _pPropertyCache->unboundgetproperty(
  59. _pPropertyCache->get_CurrentIndex(),
  60. &dwSyntaxId,
  61. &dwPropStatus,
  62. &ldapSrcObjects
  63. );
  64. BAIL_ON_FAILURE(hr);
  65. dwCtrlCode = MapPropCacheFlagToControlCode(dwPropStatus);
  66. //
  67. // translate the LDAP objects to variants
  68. //
  69. hr = ConvertLdapValuesToVariant(
  70. _pPropertyCache->get_CurrentPropName(),
  71. &ldapSrcObjects,
  72. dwSyntaxId,
  73. dwCtrlCode,
  74. pVariant,
  75. _pszLDAPServer,
  76. &_Credentials
  77. );
  78. BAIL_ON_FAILURE(hr);
  79. error:
  80. //
  81. // - goto next one even if error to avoid infinite looping at a property
  82. // which we cannot convert (e.g. schemaless server property.)
  83. // - do not return the result of Skip() as current operation does not
  84. // depend on the sucess of Skip().
  85. //
  86. Skip(1);
  87. LdapTypeFreeLdapObjects(&ldapSrcObjects);
  88. RRETURN_EXP_IF_ERR(hr);
  89. }
  90. STDMETHODIMP
  91. CLDAPGenObject::Skip(
  92. THIS_ long cElements
  93. )
  94. {
  95. HRESULT hr = S_OK;
  96. hr = _pPropertyCache->skip_propindex(
  97. cElements
  98. );
  99. RRETURN_EXP_IF_ERR(hr);
  100. }
  101. STDMETHODIMP
  102. CLDAPGenObject::Reset(
  103. )
  104. {
  105. _pPropertyCache->reset_propindex();
  106. RRETURN_EXP_IF_ERR(S_OK);
  107. }
  108. STDMETHODIMP
  109. CLDAPGenObject::ResetPropertyItem(THIS_ VARIANT varEntry)
  110. {
  111. HRESULT hr = S_OK;
  112. DWORD dwIndex = 0;
  113. switch (V_VT(&varEntry)) {
  114. case VT_BSTR:
  115. hr = _pPropertyCache->findproperty(
  116. V_BSTR(&varEntry),
  117. &dwIndex
  118. );
  119. BAIL_ON_FAILURE(hr);
  120. break;
  121. case VT_I4:
  122. dwIndex = V_I4(&varEntry);
  123. break;
  124. case VT_I2:
  125. dwIndex = V_I2(&varEntry);
  126. break;
  127. default:
  128. hr = E_FAIL;
  129. BAIL_ON_FAILURE(hr);
  130. }
  131. hr = _pPropertyCache->deleteproperty(
  132. dwIndex
  133. );
  134. error:
  135. RRETURN_EXP_IF_ERR(hr);
  136. }
  137. //////////////////////////////////////////////////////////////////////////
  138. //
  139. // Retrieve property [bstrName] from the cache (only, no wire calls) as
  140. // a PropertyEntry.
  141. //
  142. // [*pVariant]
  143. // - store ptr to IDispatch of the PropertyEntry.
  144. //
  145. // If the property in cache has control code = ADS_PROPERTY_DELETE,
  146. // - PropertyEntry will contain an empty variant and
  147. // - adstype = ADSTYPE_INVALID.
  148. //
  149. // If property in cache has UNKNWON type, (not deleted, for schemaless-server
  150. // property which is not in ADSI default schema)
  151. // - [lnAdsType] must be a valid type (NO ADSTYPE_UNKNWON/INVALID)
  152. // - property will be retrieved as [lnADsType]
  153. //
  154. // If property in cache has KNOWN type,
  155. // - [lnADsType] must either match type in cache or == ADSTYPE_UNKNOWN
  156. // - property will be retreived as the type in cache.
  157. //
  158. /////////////////////////////////////////////////////////////////////////////
  159. STDMETHODIMP
  160. CLDAPGenObject::GetPropertyItem(
  161. THIS_
  162. IN BSTR bstrName,
  163. IN LONG lnADsType,
  164. IN OUT VARIANT * pVariant
  165. )
  166. {
  167. HRESULT hr = S_OK;
  168. DWORD dwCachedSyntax = LDAPTYPE_UNKNOWN;
  169. DWORD dwUserSyntax = LDAPTYPE_UNKNOWN;
  170. DWORD dwSyntaxUsed = LDAPTYPE_UNKNOWN; // extra, make code easier to read
  171. DWORD dwPropStatus = 0;
  172. DWORD dwCtrlCode = 0;
  173. LDAPOBJECTARRAY ldapSrcObjects;
  174. LDAPOBJECTARRAY ldapSrc2Objects;
  175. LDAPOBJECTARRAY * pLdapSrcObjects = NULL;
  176. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  177. LDAPOBJECTARRAY_INIT(ldapSrc2Objects);
  178. if (!bstrName || !pVariant)
  179. RRETURN(E_ADS_BAD_PARAMETER);
  180. //
  181. // retrieve property from cache; CONTINUE if property exist but
  182. // has no value (control code flag as a DELETE)
  183. //
  184. hr = _pPropertyCache->unboundgetproperty(
  185. bstrName,
  186. &dwCachedSyntax,
  187. &dwPropStatus,
  188. &ldapSrcObjects
  189. );
  190. BAIL_ON_FAILURE(hr);
  191. // For backward compatibility -- no issue as you
  192. // need to return a value even if it is delete.
  193. //
  194. // map adstype from client to ldap type;
  195. //
  196. dwUserSyntax = MapADSTypeToLDAPType((ADSTYPE)lnADsType);
  197. //
  198. // determine the syntax to retrieve property in
  199. //
  200. if ( (dwCachedSyntax == LDAPTYPE_UNKNOWN)
  201. ||
  202. (dwCachedSyntax == 0) // should NOT be 0, but misuse of 0 everywhere
  203. ) // and in case i didn't clean up all
  204. {
  205. //
  206. // syntax not stored in cache, user must spcify a valid sytax
  207. // Exception: cleared property values have LDAPTYPE_UNKNOWN, and we
  208. // return them as ADSTYPE_UNKNOWN
  209. //
  210. if ((dwUserSyntax == LDAPTYPE_UNKNOWN) && (dwPropStatus != PROPERTY_DELETE))
  211. {
  212. hr = E_ADS_CANT_CONVERT_DATATYPE;
  213. BAIL_ON_FAILURE(hr);
  214. }
  215. dwSyntaxUsed = dwUserSyntax;
  216. //
  217. // convert from cached data from ldap binary format to ldap string
  218. // IFF necessary based on dwUserSyntax
  219. //
  220. hr = LdapTypeBinaryToString(
  221. dwSyntaxUsed,
  222. &ldapSrcObjects,
  223. &ldapSrc2Objects
  224. );
  225. //
  226. // dwSyntaxUsed (dwUserSyntax) must be valid from
  227. // MapADSTypeToLDAPType() or code bug in MapADsTypeToLDAPType() !!
  228. //
  229. ADsAssert(SUCCEEDED(hr));
  230. if (hr==S_OK)
  231. {
  232. pLdapSrcObjects = &ldapSrc2Objects; // conversion done
  233. }
  234. else // hr == S_FALSE
  235. {
  236. pLdapSrcObjects = &ldapSrcObjects; // no conversion
  237. }
  238. }
  239. else // dwCachedSyntax known and valid
  240. {
  241. //
  242. // syntax stored in cache, user MUST either specify
  243. // 1) ADSTYPE_UNKNWON or
  244. // 2) a syntax which matches the one in cache. The comparision must
  245. // be done in ADsType, not LdapType, since LdapType To ADSType
  246. // is n to 1 mapping and as long as ADsType match, ok.
  247. //
  248. if ( ! (
  249. (dwUserSyntax == LDAPTYPE_UNKNOWN)
  250. ||
  251. ( (ADSTYPE) lnADsType == MapLDAPTypeToADSType(dwCachedSyntax))
  252. )
  253. )
  254. {
  255. if (dwUserSyntax != dwCachedSyntax) {
  256. //
  257. // Check if the user wants the data back for the
  258. // security descriptor as an octet or vice versa
  259. //
  260. if ( (dwUserSyntax == LDAPTYPE_OCTETSTRING
  261. && dwCachedSyntax == LDAPTYPE_SECURITY_DESCRIPTOR)
  262. ||(dwUserSyntax == LDAPTYPE_SECURITY_DESCRIPTOR
  263. && dwCachedSyntax == LDAPTYPE_OCTETSTRING))
  264. {
  265. dwCachedSyntax = dwUserSyntax;
  266. } else {
  267. //
  268. // Check for UTC/GenTime mismatch before ret error.
  269. //
  270. if (!((dwCachedSyntax == LDAPTYPE_GENERALIZEDTIME)
  271. && (dwUserSyntax == LDAPTYPE_UTCTIME))) {
  272. hr = E_ADS_CANT_CONVERT_DATATYPE;
  273. BAIL_ON_FAILURE(hr);
  274. }
  275. }
  276. } // if dwUserSyntax != dwCachedSyntax
  277. }
  278. dwSyntaxUsed = dwCachedSyntax;
  279. pLdapSrcObjects = &ldapSrcObjects; // no conversion needed
  280. }
  281. //
  282. // translate ldap prop status to ads control code
  283. //
  284. dwCtrlCode = MapPropCacheFlagToControlCode(dwPropStatus);
  285. //
  286. // translate the property from Ldap objects to a PropertyEntry
  287. //
  288. hr = ConvertLdapValuesToVariant(
  289. bstrName,
  290. pLdapSrcObjects,
  291. dwSyntaxUsed,
  292. dwCtrlCode,
  293. pVariant,
  294. _pszLDAPServer,
  295. &_Credentials
  296. );
  297. error:
  298. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  299. LdapTypeFreeLdapObjects( &ldapSrc2Objects );
  300. RRETURN_EXP_IF_ERR(hr);
  301. }
  302. STDMETHODIMP
  303. CLDAPGenObject::PutPropertyItem(
  304. THIS_ VARIANT varData
  305. )
  306. {
  307. HRESULT hr = S_OK;
  308. DWORD dwFlags = 0;
  309. DWORD dwIndex = 0;
  310. DWORD dwControlCode = 0;
  311. LDAPOBJECTARRAY ldapDestObjects;
  312. WCHAR szPropertyName[MAX_PATH];
  313. DWORD dwSyntaxId = 0;
  314. LDAPOBJECTARRAY_INIT(ldapDestObjects);
  315. hr = ConvertVariantToLdapValues(
  316. varData,
  317. szPropertyName,
  318. &dwControlCode,
  319. &ldapDestObjects,
  320. &dwSyntaxId,
  321. _pszLDAPServer,
  322. &_Credentials,
  323. _dwPort
  324. );
  325. BAIL_ON_FAILURE(hr);
  326. switch ( dwControlCode ) {
  327. case 0 :
  328. //
  329. // Users better know what they are doing here,
  330. // This the property as cleared so we do not send it
  331. // on the wire on th next SetInfo.
  332. //
  333. dwFlags = PROPERTY_INIT;
  334. break;
  335. case ADS_PROPERTY_CLEAR:
  336. //
  337. // Clears an entire property
  338. //
  339. dwFlags = PROPERTY_DELETE;
  340. break;
  341. case ADS_PROPERTY_UPDATE:
  342. //
  343. // Updates the entire property
  344. //
  345. dwFlags = PROPERTY_UPDATE;
  346. break;
  347. case ADS_PROPERTY_APPEND:
  348. //
  349. // Appends a set of values to the property
  350. //
  351. dwFlags = PROPERTY_ADD;
  352. break;
  353. case ADS_PROPERTY_DELETE:
  354. //
  355. // Delete a value(s) from the property
  356. dwFlags = PROPERTY_DELETE_VALUE;
  357. break;
  358. default:
  359. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  360. }
  361. //
  362. // Find this property in the cache
  363. //
  364. hr = _pPropertyCache->findproperty(
  365. szPropertyName,
  366. &dwIndex
  367. );
  368. //
  369. // If this property does not exist in the
  370. // cache, add this property into the cache.
  371. //
  372. if (FAILED(hr)) {
  373. hr = _pPropertyCache->addproperty( szPropertyName );
  374. //
  375. // If dwNumValues == 0 ( delete the property ) but couldn't find
  376. // the property, or if the add operation fails, return the error.
  377. //
  378. BAIL_ON_FAILURE(hr);
  379. }
  380. //
  381. // Now update the property in the cache
  382. //
  383. hr = _pPropertyCache->putproperty(
  384. szPropertyName,
  385. dwFlags,
  386. dwSyntaxId,
  387. ldapDestObjects
  388. );
  389. BAIL_ON_FAILURE(hr);
  390. error:
  391. LdapTypeFreeLdapObjects( &ldapDestObjects );
  392. RRETURN_EXP_IF_ERR(hr);
  393. }
  394. HRESULT
  395. CreatePropEntry(
  396. LPWSTR szPropName,
  397. DWORD ADsType,
  398. DWORD numValues,
  399. DWORD dwOperation,
  400. VARIANT varData,
  401. REFIID riid,
  402. LPVOID * ppDispatch
  403. )
  404. {
  405. HRESULT hr = S_OK;
  406. IADsPropertyEntry * pPropEntry = NULL;
  407. hr = CoCreateInstance(
  408. CLSID_PropertyEntry,
  409. NULL,
  410. CLSCTX_INPROC_SERVER,
  411. IID_IADsPropertyEntry,
  412. (void **)&pPropEntry
  413. );
  414. BAIL_ON_FAILURE(hr);
  415. hr = pPropEntry->put_Name(szPropName);
  416. BAIL_ON_FAILURE(hr);
  417. hr = pPropEntry->put_ADsType(ADsType);
  418. BAIL_ON_FAILURE(hr);
  419. hr = pPropEntry->put_Values(varData);
  420. BAIL_ON_FAILURE(hr);
  421. if (dwOperation) {
  422. hr = pPropEntry->put_ControlCode((long)dwOperation);
  423. }
  424. BAIL_ON_FAILURE(hr);
  425. hr = pPropEntry->QueryInterface(
  426. riid,
  427. ppDispatch
  428. );
  429. BAIL_ON_FAILURE(hr);
  430. error:
  431. if (pPropEntry) {
  432. pPropEntry->Release();
  433. }
  434. RRETURN(hr);
  435. }
  436. STDMETHODIMP
  437. CLDAPGenObject::Item(
  438. THIS_ VARIANT varIndex,
  439. VARIANT * pVariant
  440. )
  441. {
  442. HRESULT hr = S_OK;
  443. DWORD dwSyntaxId;
  444. LDAPOBJECTARRAY ldapSrcObjects;
  445. PADSVALUE pAdsValues = NULL;
  446. DWORD dwNumAdsValues = 0;
  447. DWORD dwAdsType = 0;
  448. DWORD dwNumValues = 0;
  449. LPWSTR szPropName = NULL;
  450. DWORD dwPropStatus = 0;
  451. DWORD dwCtrlCode = (DWORD) -1;
  452. VARIANT * pvVar = &varIndex;
  453. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  454. //
  455. // retrieve data object from cache; if one exis
  456. //
  457. // If the object has been deleted (and is in the cache
  458. // marked for deletion), we return
  459. // the item with DELETE ctrl code in all
  460. // the cases below. This is consistent with GetPropertyItem's
  461. // behavior as well.
  462. if (V_VT(pvVar) == (VT_BYREF|VT_VARIANT)) {
  463. //
  464. // The value is being passed in byref so we need to
  465. // deref it for vbs stuff to work
  466. //
  467. pvVar = V_VARIANTREF(&varIndex);
  468. }
  469. switch (V_VT(pvVar)) {
  470. case VT_BSTR:
  471. //
  472. // retrieve data object from cache; if one exists
  473. //
  474. hr = _pPropertyCache->unboundgetproperty(
  475. V_BSTR(pvVar),
  476. &dwSyntaxId,
  477. &dwPropStatus,
  478. &ldapSrcObjects
  479. );
  480. BAIL_ON_FAILURE(hr);
  481. dwCtrlCode = MapPropCacheFlagToControlCode(dwPropStatus);
  482. hr = ConvertLdapValuesToVariant(
  483. V_BSTR(pvVar),
  484. &ldapSrcObjects,
  485. dwSyntaxId,
  486. dwCtrlCode,
  487. pVariant,
  488. _pszLDAPServer,
  489. &_Credentials
  490. );
  491. BAIL_ON_FAILURE(hr);
  492. break;
  493. case VT_I4:
  494. hr = _pPropertyCache->unboundgetproperty(
  495. (DWORD)V_I4(pvVar),
  496. &dwSyntaxId,
  497. &dwPropStatus,
  498. &ldapSrcObjects
  499. );
  500. BAIL_ON_FAILURE(hr);
  501. szPropName = _pPropertyCache->get_PropName(
  502. (DWORD)V_I4(pvVar)
  503. );
  504. dwCtrlCode = MapPropCacheFlagToControlCode(dwPropStatus);
  505. hr = ConvertLdapValuesToVariant(
  506. szPropName,
  507. &ldapSrcObjects,
  508. dwSyntaxId,
  509. dwCtrlCode,
  510. pVariant,
  511. _pszLDAPServer,
  512. &_Credentials
  513. );
  514. BAIL_ON_FAILURE(hr);
  515. break;
  516. case VT_I2:
  517. hr = _pPropertyCache->unboundgetproperty(
  518. (DWORD)V_I2(pvVar),
  519. &dwSyntaxId,
  520. &dwPropStatus,
  521. &ldapSrcObjects
  522. );
  523. BAIL_ON_FAILURE(hr);
  524. szPropName = _pPropertyCache->get_PropName(
  525. (DWORD)V_I2(pvVar)
  526. );
  527. dwCtrlCode = MapPropCacheFlagToControlCode(dwPropStatus);
  528. hr = ConvertLdapValuesToVariant(
  529. szPropName,
  530. &ldapSrcObjects,
  531. dwSyntaxId,
  532. dwCtrlCode,
  533. pVariant,
  534. _pszLDAPServer,
  535. &_Credentials
  536. );
  537. BAIL_ON_FAILURE(hr);
  538. break;
  539. default:
  540. hr = E_FAIL;
  541. BAIL_ON_FAILURE(hr);
  542. }
  543. //
  544. // translate the Ldap objects to variants
  545. //
  546. error:
  547. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  548. RRETURN_EXP_IF_ERR(hr);
  549. }
  550. STDMETHODIMP
  551. CLDAPGenObject::PurgePropertyList()
  552. {
  553. _pPropertyCache->flushpropertycache();
  554. RRETURN(S_OK);
  555. }
  556. DWORD
  557. MapPropCacheFlagToControlCode(
  558. DWORD dwPropStatus
  559. )
  560. {
  561. DWORD dwADsCtrlCode = (DWORD) -1;
  562. switch (dwPropStatus) {
  563. case PROPERTY_INIT:
  564. //
  565. // 0 is not defined as any of the ADS_PROPERTY_ flags
  566. // use it to indicate that property is in init state
  567. //
  568. dwADsCtrlCode = 0;
  569. break;
  570. case PROPERTY_UPDATE:
  571. dwADsCtrlCode = ADS_PROPERTY_UPDATE;
  572. break;
  573. case PROPERTY_ADD:
  574. dwADsCtrlCode = ADS_PROPERTY_APPEND;
  575. break;
  576. case PROPERTY_DELETE:
  577. dwADsCtrlCode = ADS_PROPERTY_CLEAR;
  578. break;
  579. case PROPERTY_DELETE_VALUE:
  580. dwADsCtrlCode = ADS_PROPERTY_DELETE;
  581. break;
  582. default:
  583. // set to speical value to indicate unknow code
  584. dwADsCtrlCode = (DWORD) -1;
  585. break;
  586. }
  587. return dwADsCtrlCode;
  588. }