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.

777 lines
18 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* pszPropertyName = NULL;
  313. DWORD dwSyntaxId = 0;
  314. LDAPOBJECTARRAY_INIT(ldapDestObjects);
  315. hr = ConvertVariantToLdapValues(
  316. varData,
  317. &pszPropertyName,
  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. pszPropertyName,
  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( pszPropertyName );
  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. pszPropertyName,
  385. dwFlags,
  386. dwSyntaxId,
  387. ldapDestObjects
  388. );
  389. BAIL_ON_FAILURE(hr);
  390. error:
  391. LdapTypeFreeLdapObjects( &ldapDestObjects );
  392. if(pszPropertyName)
  393. {
  394. FreeADsStr(pszPropertyName);
  395. }
  396. RRETURN_EXP_IF_ERR(hr);
  397. }
  398. HRESULT
  399. CreatePropEntry(
  400. LPWSTR szPropName,
  401. DWORD ADsType,
  402. DWORD numValues,
  403. DWORD dwOperation,
  404. VARIANT varData,
  405. REFIID riid,
  406. LPVOID * ppDispatch
  407. )
  408. {
  409. HRESULT hr = S_OK;
  410. IADsPropertyEntry * pPropEntry = NULL;
  411. hr = CoCreateInstance(
  412. CLSID_PropertyEntry,
  413. NULL,
  414. CLSCTX_INPROC_SERVER,
  415. IID_IADsPropertyEntry,
  416. (void **)&pPropEntry
  417. );
  418. BAIL_ON_FAILURE(hr);
  419. hr = pPropEntry->put_Name(szPropName);
  420. BAIL_ON_FAILURE(hr);
  421. hr = pPropEntry->put_ADsType(ADsType);
  422. BAIL_ON_FAILURE(hr);
  423. hr = pPropEntry->put_Values(varData);
  424. BAIL_ON_FAILURE(hr);
  425. if (dwOperation) {
  426. hr = pPropEntry->put_ControlCode((long)dwOperation);
  427. }
  428. BAIL_ON_FAILURE(hr);
  429. hr = pPropEntry->QueryInterface(
  430. riid,
  431. ppDispatch
  432. );
  433. BAIL_ON_FAILURE(hr);
  434. error:
  435. if (pPropEntry) {
  436. pPropEntry->Release();
  437. }
  438. RRETURN(hr);
  439. }
  440. STDMETHODIMP
  441. CLDAPGenObject::Item(
  442. THIS_ VARIANT varIndex,
  443. VARIANT * pVariant
  444. )
  445. {
  446. HRESULT hr = S_OK;
  447. DWORD dwSyntaxId;
  448. LDAPOBJECTARRAY ldapSrcObjects;
  449. PADSVALUE pAdsValues = NULL;
  450. DWORD dwNumAdsValues = 0;
  451. DWORD dwAdsType = 0;
  452. DWORD dwNumValues = 0;
  453. LPWSTR szPropName = NULL;
  454. DWORD dwPropStatus = 0;
  455. DWORD dwCtrlCode = (DWORD) -1;
  456. VARIANT * pvVar = &varIndex;
  457. LDAPOBJECTARRAY_INIT(ldapSrcObjects);
  458. //
  459. // retrieve data object from cache; if one exis
  460. //
  461. // If the object has been deleted (and is in the cache
  462. // marked for deletion), we return
  463. // the item with DELETE ctrl code in all
  464. // the cases below. This is consistent with GetPropertyItem's
  465. // behavior as well.
  466. if (V_VT(pvVar) == (VT_BYREF|VT_VARIANT)) {
  467. //
  468. // The value is being passed in byref so we need to
  469. // deref it for vbs stuff to work
  470. //
  471. pvVar = V_VARIANTREF(&varIndex);
  472. }
  473. switch (V_VT(pvVar)) {
  474. case VT_BSTR:
  475. //
  476. // retrieve data object from cache; if one exists
  477. //
  478. hr = _pPropertyCache->unboundgetproperty(
  479. V_BSTR(pvVar),
  480. &dwSyntaxId,
  481. &dwPropStatus,
  482. &ldapSrcObjects
  483. );
  484. BAIL_ON_FAILURE(hr);
  485. dwCtrlCode = MapPropCacheFlagToControlCode(dwPropStatus);
  486. hr = ConvertLdapValuesToVariant(
  487. V_BSTR(pvVar),
  488. &ldapSrcObjects,
  489. dwSyntaxId,
  490. dwCtrlCode,
  491. pVariant,
  492. _pszLDAPServer,
  493. &_Credentials
  494. );
  495. BAIL_ON_FAILURE(hr);
  496. break;
  497. case VT_I4:
  498. hr = _pPropertyCache->unboundgetproperty(
  499. (DWORD)V_I4(pvVar),
  500. &dwSyntaxId,
  501. &dwPropStatus,
  502. &ldapSrcObjects
  503. );
  504. BAIL_ON_FAILURE(hr);
  505. szPropName = _pPropertyCache->get_PropName(
  506. (DWORD)V_I4(pvVar)
  507. );
  508. dwCtrlCode = MapPropCacheFlagToControlCode(dwPropStatus);
  509. hr = ConvertLdapValuesToVariant(
  510. szPropName,
  511. &ldapSrcObjects,
  512. dwSyntaxId,
  513. dwCtrlCode,
  514. pVariant,
  515. _pszLDAPServer,
  516. &_Credentials
  517. );
  518. BAIL_ON_FAILURE(hr);
  519. break;
  520. case VT_I2:
  521. hr = _pPropertyCache->unboundgetproperty(
  522. (DWORD)V_I2(pvVar),
  523. &dwSyntaxId,
  524. &dwPropStatus,
  525. &ldapSrcObjects
  526. );
  527. BAIL_ON_FAILURE(hr);
  528. szPropName = _pPropertyCache->get_PropName(
  529. (DWORD)V_I2(pvVar)
  530. );
  531. dwCtrlCode = MapPropCacheFlagToControlCode(dwPropStatus);
  532. hr = ConvertLdapValuesToVariant(
  533. szPropName,
  534. &ldapSrcObjects,
  535. dwSyntaxId,
  536. dwCtrlCode,
  537. pVariant,
  538. _pszLDAPServer,
  539. &_Credentials
  540. );
  541. BAIL_ON_FAILURE(hr);
  542. break;
  543. default:
  544. hr = E_FAIL;
  545. BAIL_ON_FAILURE(hr);
  546. }
  547. //
  548. // translate the Ldap objects to variants
  549. //
  550. error:
  551. LdapTypeFreeLdapObjects( &ldapSrcObjects );
  552. RRETURN_EXP_IF_ERR(hr);
  553. }
  554. STDMETHODIMP
  555. CLDAPGenObject::PurgePropertyList()
  556. {
  557. _pPropertyCache->flushpropertycache();
  558. RRETURN(S_OK);
  559. }
  560. DWORD
  561. MapPropCacheFlagToControlCode(
  562. DWORD dwPropStatus
  563. )
  564. {
  565. DWORD dwADsCtrlCode = (DWORD) -1;
  566. switch (dwPropStatus) {
  567. case PROPERTY_INIT:
  568. //
  569. // 0 is not defined as any of the ADS_PROPERTY_ flags
  570. // use it to indicate that property is in init state
  571. //
  572. dwADsCtrlCode = 0;
  573. break;
  574. case PROPERTY_UPDATE:
  575. dwADsCtrlCode = ADS_PROPERTY_UPDATE;
  576. break;
  577. case PROPERTY_ADD:
  578. dwADsCtrlCode = ADS_PROPERTY_APPEND;
  579. break;
  580. case PROPERTY_DELETE:
  581. dwADsCtrlCode = ADS_PROPERTY_CLEAR;
  582. break;
  583. case PROPERTY_DELETE_VALUE:
  584. dwADsCtrlCode = ADS_PROPERTY_DELETE;
  585. break;
  586. default:
  587. // set to speical value to indicate unknow code
  588. dwADsCtrlCode = (DWORD) -1;
  589. break;
  590. }
  591. return dwADsCtrlCode;
  592. }