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.

1322 lines
33 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. //
  4. // Microsoft Windows
  5. // Copyright (C) Microsoft Corporation, 1992 - 1997
  6. //
  7. // File: cdsobj.cxx
  8. //
  9. // Contents: Microsoft ADs LDAP Provider DSObject
  10. //
  11. //
  12. // History: 02-20-97 yihsins Created.
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "ldapc.hxx"
  16. #pragma hdrstop
  17. //
  18. //Hard Coded Support for RootDSE object
  19. //
  20. LPWSTR SpecialSyntaxesTable[] =
  21. {
  22. LDAP_OPATT_CURRENT_TIME_W,
  23. LDAP_OPATT_SUBSCHEMA_SUBENTRY_W,
  24. LDAP_OPATT_SERVER_NAME_W,
  25. LDAP_OPATT_NAMING_CONTEXTS_W,
  26. LDAP_OPATT_DEFAULT_NAMING_CONTEXT_W,
  27. LDAP_OPATT_SCHEMA_NAMING_CONTEXT_W,
  28. LDAP_OPATT_CONFIG_NAMING_CONTEXT_W,
  29. LDAP_OPATT_ROOT_DOMAIN_NAMING_CONTEXT_W,
  30. LDAP_OPATT_SUPPORTED_CONTROL_W,
  31. LDAP_OPATT_SUPPORTED_LDAP_VERSION_W,
  32. L"lowestUncommittedUSN",
  33. L"allowedAttributesEffective",
  34. L"supportedExtension",
  35. L"altServer",
  36. NULL
  37. };
  38. HRESULT
  39. ComputeAttributeBufferSize(
  40. PADS_ATTR_INFO pAdsAttributes,
  41. DWORD dwNumAttributes,
  42. PDWORD pdwSize,
  43. PDWORD pdwNumValues
  44. );
  45. LPBYTE
  46. CopyAttributeName(
  47. PADS_ATTR_INFO pThisAdsSrcAttribute,
  48. PADS_ATTR_INFO pThisAdsTargAttribute,
  49. LPBYTE pDataBuffer
  50. );
  51. HRESULT
  52. ADsSetObjectAttributes(
  53. ADS_LDP *ld,
  54. LPTSTR pszLDAPServer,
  55. LPTSTR pszLDAPDn,
  56. CCredentials Credentials,
  57. DWORD dwPort,
  58. SECURITY_INFORMATION seInfo,
  59. PADS_ATTR_INFO pAttributeEntries,
  60. DWORD dwNumAttributes,
  61. DWORD *pdwNumAttributesModified
  62. )
  63. {
  64. HRESULT hr = S_OK;
  65. DWORD i = 0;
  66. DWORD j = 0;
  67. PADS_ATTR_INFO pThisAttribute = NULL;
  68. LDAPOBJECTARRAY ldapObjectArray;
  69. DWORD dwSyntaxId = 0;
  70. LDAPMod **aMods = NULL;
  71. LDAPModW *aModsBuffer = NULL;
  72. DWORD dwNumAttributesReturn = 0;
  73. BOOL fNTSecDescriptor = FALSE;
  74. int ldaperr = 0;
  75. DWORD dwOptions = 0;
  76. DWORD dwSecDescType = ADSI_LDAPC_SECDESC_NONE;
  77. BOOL fModifyDone = FALSE;
  78. BYTE berValue[8];
  79. memset(berValue, 0, 8);
  80. berValue[0] = 0x30; // Start sequence tag
  81. berValue[1] = 0x03; // Length in bytes of following
  82. berValue[2] = 0x02; // Actual value this and next 2
  83. berValue[3] = 0x01;
  84. berValue[4] = (BYTE)((ULONG)seInfo);
  85. LDAPControl SeInfoControl =
  86. {
  87. LDAP_SERVER_SD_FLAGS_OID_W,
  88. {
  89. 5, (PCHAR) berValue
  90. },
  91. TRUE
  92. };
  93. LDAPControl ModifyControl =
  94. {
  95. LDAP_SERVER_PERMISSIVE_MODIFY_OID_W,
  96. {
  97. 0, NULL
  98. },
  99. FALSE
  100. };
  101. PLDAPControl ServerControls[2] =
  102. {
  103. &SeInfoControl,
  104. NULL
  105. };
  106. PLDAPControl ServerControlsOnlyModify[2] =
  107. {
  108. &ModifyControl,
  109. NULL
  110. };
  111. PLDAPControl ServerControlsAll[3] =
  112. {
  113. &SeInfoControl,
  114. &ModifyControl,
  115. NULL
  116. };
  117. BOOL fServerIsAD = FALSE;
  118. *pdwNumAttributesModified = 0;
  119. //
  120. // Allocate memory to send the modify request
  121. //
  122. aMods = (LDAPModW **) AllocADsMem((dwNumAttributes+1) * sizeof(LDAPModW*));
  123. if ( aMods == NULL )
  124. {
  125. hr = E_OUTOFMEMORY;
  126. BAIL_ON_FAILURE(hr);
  127. }
  128. aModsBuffer = (LDAPModW *) AllocADsMem( dwNumAttributes * sizeof(LDAPModW));
  129. if ( aModsBuffer == NULL )
  130. {
  131. hr = E_OUTOFMEMORY;
  132. BAIL_ON_FAILURE(hr);
  133. }
  134. //
  135. // Format the modify request
  136. //
  137. for (i = 0; i < dwNumAttributes; i++) {
  138. BOOL fGenTime = FALSE;
  139. LDAPOBJECTARRAY_INIT(ldapObjectArray);
  140. pThisAttribute = pAttributeEntries + i;
  141. if (!fNTSecDescriptor
  142. && _wcsicmp(L"ntSecurityDescriptor", pThisAttribute->pszAttrName)
  143. == 0)
  144. {
  145. {
  146. // we need to use appropriate controls if the operation
  147. // is modify the security descriptor. Specifically we do
  148. // not want to use any control if the operation is a clear
  149. // and default to whatever the server deems fit.
  150. if (pThisAttribute->dwControlCode != ADS_ATTR_CLEAR) {
  151. fNTSecDescriptor = TRUE;
  152. }
  153. }
  154. }
  155. if (pThisAttribute->dwControlCode != ADS_ATTR_CLEAR) {
  156. //
  157. // If this is a time attribute, see if it is GenTime or
  158. // UTCTime and set the syntax the flag appropriately
  159. //
  160. if (pThisAttribute->dwADsType == ADSTYPE_UTC_TIME) {
  161. hr = LdapGetSyntaxOfAttributeOnServer(
  162. pszLDAPServer,
  163. pThisAttribute->pszAttrName,
  164. &dwSyntaxId,
  165. Credentials,
  166. dwPort
  167. );
  168. if (SUCCEEDED(hr) && (dwSyntaxId == LDAPTYPE_GENERALIZEDTIME)) {
  169. //
  170. // Use GenTime conversion
  171. //
  172. fGenTime = TRUE;
  173. }
  174. }
  175. }
  176. switch (pThisAttribute->dwControlCode) {
  177. case ADS_ATTR_UPDATE:
  178. hr = AdsTypeToLdapTypeCopyConstruct(
  179. pThisAttribute->pADsValues,
  180. pThisAttribute->dwNumValues,
  181. &ldapObjectArray,
  182. &dwSyntaxId,
  183. fGenTime
  184. );
  185. BAIL_ON_FAILURE(hr);
  186. aMods[i] = &aModsBuffer[i];
  187. aModsBuffer[i].mod_type = pThisAttribute->pszAttrName;
  188. if ( ldapObjectArray.fIsString )
  189. {
  190. aModsBuffer[i].mod_values = (TCHAR **) ldapObjectArray.pLdapObjects;
  191. }
  192. else
  193. {
  194. aModsBuffer[i].mod_bvalues = (struct berval **) ldapObjectArray.pLdapObjects;
  195. aModsBuffer[i].mod_op = LDAP_MOD_BVALUES;
  196. }
  197. aModsBuffer[i].mod_op |= LDAP_MOD_REPLACE;
  198. dwNumAttributesReturn++;
  199. break;
  200. case ADS_ATTR_APPEND:
  201. hr = AdsTypeToLdapTypeCopyConstruct(
  202. pThisAttribute->pADsValues,
  203. pThisAttribute->dwNumValues,
  204. &ldapObjectArray,
  205. &dwSyntaxId,
  206. fGenTime
  207. );
  208. BAIL_ON_FAILURE(hr);
  209. aMods[i] = &aModsBuffer[i];
  210. aModsBuffer[i].mod_type = pThisAttribute->pszAttrName;
  211. if ( ldapObjectArray.fIsString )
  212. {
  213. aModsBuffer[i].mod_values = (TCHAR **) ldapObjectArray.pLdapObjects;
  214. }
  215. else
  216. {
  217. aModsBuffer[i].mod_bvalues = (struct berval **) ldapObjectArray.pLdapObjects;
  218. aModsBuffer[i].mod_op = LDAP_MOD_BVALUES;
  219. }
  220. aModsBuffer[i].mod_op |= LDAP_MOD_ADD;
  221. dwNumAttributesReturn++;
  222. break;
  223. case ADS_ATTR_CLEAR:
  224. aMods[i] = &aModsBuffer[i];
  225. aModsBuffer[i].mod_type = pThisAttribute->pszAttrName;
  226. aModsBuffer[i].mod_bvalues = NULL;
  227. aModsBuffer[i].mod_op |= LDAP_MOD_DELETE;
  228. dwNumAttributesReturn++;
  229. break;
  230. case ADS_ATTR_DELETE:
  231. hr = AdsTypeToLdapTypeCopyConstruct(
  232. pThisAttribute->pADsValues,
  233. pThisAttribute->dwNumValues,
  234. &ldapObjectArray,
  235. &dwSyntaxId,
  236. fGenTime
  237. );
  238. BAIL_ON_FAILURE(hr);
  239. aMods[i] = &aModsBuffer[i];
  240. aModsBuffer[i].mod_type = pThisAttribute->pszAttrName;
  241. if ( ldapObjectArray.fIsString )
  242. {
  243. aModsBuffer[i].mod_values = (TCHAR **) ldapObjectArray.pLdapObjects;
  244. }
  245. else
  246. {
  247. aModsBuffer[i].mod_bvalues = (struct berval **) ldapObjectArray.pLdapObjects;
  248. aModsBuffer[i].mod_op = LDAP_MOD_BVALUES;
  249. }
  250. aModsBuffer[i].mod_op |= LDAP_MOD_DELETE;
  251. dwNumAttributesReturn++;
  252. break;
  253. default:
  254. //
  255. // ignore this attribute and move on
  256. //
  257. break;
  258. }
  259. }
  260. //
  261. // Find out if server is AD.
  262. //
  263. hr = ReadServerSupportsIsADControl(
  264. pszLDAPServer,
  265. &fServerIsAD,
  266. Credentials,
  267. dwPort
  268. );
  269. if (FAILED(hr)) {
  270. //
  271. // Assume it is not AD and continue, there is no
  272. // good reason for this to fail on AD.
  273. //
  274. fServerIsAD = FALSE;
  275. }
  276. //
  277. // Modify the object with appropriate call
  278. //
  279. if (fNTSecDescriptor) {
  280. //
  281. // Check if we are V3
  282. //
  283. ldaperr = ldap_get_option(
  284. ld->LdapHandle,
  285. LDAP_OPT_VERSION,
  286. &dwOptions
  287. );
  288. //
  289. // check supported controls and set accordingly
  290. //
  291. if (ldaperr == LDAP_SUCCESS && (dwOptions == LDAP_VERSION3)) {
  292. //
  293. // Read the security descriptor type if applicable
  294. //
  295. hr = ReadSecurityDescriptorControlType(
  296. pszLDAPServer,
  297. &dwSecDescType,
  298. Credentials,
  299. dwPort
  300. );
  301. if (SUCCEEDED(hr) && (dwSecDescType == ADSI_LDAPC_SECDESC_NT)) {
  302. hr = LdapModifyExtS(
  303. ld,
  304. pszLDAPDn,
  305. aMods,
  306. fServerIsAD ?
  307. (PLDAPControl *) &ServerControlsAll :
  308. (PLDAPControl *) &ServerControls,
  309. NULL
  310. );
  311. fModifyDone = TRUE;
  312. }
  313. } // If Read Version succeeded
  314. }
  315. //
  316. // Perform a simple modify - only if fModifyDone is false
  317. //
  318. if (!fModifyDone) {
  319. if (fServerIsAD) {
  320. //
  321. // Need to send the OID that allows delete on empty attributes
  322. // without sending an error - for clients that have gotten used
  323. // to bad practices.
  324. //
  325. hr = LdapModifyExtS(
  326. ld,
  327. pszLDAPDn,
  328. aMods,
  329. (PLDAPControl *)&ServerControlsOnlyModify,
  330. NULL
  331. );
  332. }
  333. else {
  334. //
  335. // Regular calls from most folks not using AD.
  336. //
  337. hr = LdapModifyS(
  338. ld,
  339. pszLDAPDn,
  340. aMods
  341. );
  342. }
  343. }
  344. BAIL_ON_FAILURE(hr);
  345. *pdwNumAttributesModified = dwNumAttributesReturn;
  346. error:
  347. if ( aModsBuffer )
  348. {
  349. for ( j = 0; j < i; j++ )
  350. {
  351. if ( aModsBuffer[j].mod_op & LDAP_MOD_BVALUES )
  352. {
  353. if ( aModsBuffer[j].mod_bvalues )
  354. {
  355. for ( DWORD k = 0; aModsBuffer[j].mod_bvalues[k]; k++ )
  356. FreeADsMem( aModsBuffer[j].mod_bvalues[k] );
  357. FreeADsMem( aModsBuffer[j].mod_bvalues );
  358. }
  359. }
  360. else if ( aModsBuffer[j].mod_values )
  361. {
  362. for ( DWORD k = 0; aModsBuffer[j].mod_values[k]; k++ )
  363. FreeADsMem( aModsBuffer[j].mod_values[k] );
  364. FreeADsMem( aModsBuffer[j].mod_values );
  365. }
  366. }
  367. FreeADsMem( aModsBuffer );
  368. }
  369. if ( aMods )
  370. FreeADsMem( aMods );
  371. return hr;
  372. }
  373. HRESULT
  374. ADsGetObjectAttributes(
  375. ADS_LDP *ld,
  376. LPTSTR pszLDAPServer,
  377. LPTSTR pszLDAPDn,
  378. CCredentials Credentials,
  379. DWORD dwPort,
  380. SECURITY_INFORMATION seInfo,
  381. LPWSTR *pAttributeNames,
  382. DWORD dwNumberAttributes,
  383. PADS_ATTR_INFO *ppAttributeEntries,
  384. DWORD * pdwNumAttributesReturned
  385. )
  386. {
  387. HRESULT hr = S_OK;
  388. DWORD i = 0;
  389. DWORD j = 0;
  390. LPWSTR *aStrings = NULL;
  391. LDAPMessage *res = NULL;
  392. LDAPMessage *entry = NULL;
  393. void *ptr;
  394. DWORD dwNumberOfEntries = 0;
  395. LPTSTR pszAttrName = NULL;
  396. LDAPOBJECTARRAY ldapObjectArray;
  397. PADSVALUE pAdsDestValues = NULL;
  398. DWORD dwNumAdsValues = 0;
  399. DWORD dwAdsType = 0;
  400. DWORD dwSyntaxId = 0;
  401. PADS_ATTR_INFO pAdsAttributes = NULL;
  402. PADS_ATTR_INFO pThisAttributeDef = NULL;
  403. LPBYTE pAttributeBuffer = NULL;
  404. DWORD dwAttrCount = 0;
  405. DWORD dwMemSize = 0;
  406. DWORD dwTotalValues = 0;
  407. DWORD dwNumValues = 0;
  408. LPBYTE pValueBuffer = NULL;
  409. LPBYTE pDataBuffer = NULL;
  410. PADS_ATTR_INFO pAttrEntry = NULL;
  411. PADSVALUE pAttrValue = NULL;
  412. PADS_ATTR_INFO pThisAdsSrcAttribute = NULL;
  413. PADS_ATTR_INFO pThisAdsTargAttribute = NULL;
  414. PADSVALUE pThisAdsSrcValue = NULL;
  415. PADSVALUE pThisAdsTargValue = NULL;
  416. *ppAttributeEntries = NULL;
  417. *pdwNumAttributesReturned = 0;
  418. DWORD ldaperr = 0;
  419. DWORD dwOptions = 0;
  420. BOOLEAN getSecDesc = FALSE;
  421. DWORD dwSecDescType = ADSI_LDAPC_SECDESC_NONE;
  422. BOOLEAN fSearchDone = FALSE;
  423. BYTE berValue[8];
  424. memset(berValue, 0, 8);
  425. berValue[0] = 0x30; // Start sequence tag
  426. berValue[1] = 0x03; // Length in bytes of following
  427. berValue[2] = 0x02; // Actual value this and next 2
  428. berValue[3] = 0x01;
  429. berValue[4] = (BYTE)((ULONG)seInfo);
  430. LDAPControl SeInfoControl =
  431. {
  432. LDAP_SERVER_SD_FLAGS_OID_W,
  433. {
  434. 5, (PCHAR) berValue
  435. },
  436. TRUE
  437. };
  438. PLDAPControl ServerControls[2] =
  439. {
  440. &SeInfoControl,
  441. NULL
  442. };
  443. LDAPOBJECTARRAY_INIT(ldapObjectArray);
  444. if (dwNumberAttributes != (DWORD)-1)
  445. {
  446. if ( dwNumberAttributes == 0 )
  447. return S_OK;
  448. //
  449. // Package attributes
  450. //
  451. aStrings = (LPWSTR *) AllocADsMem( sizeof(LPTSTR) * (dwNumberAttributes + 1));
  452. if ( aStrings == NULL )
  453. {
  454. hr = E_OUTOFMEMORY;
  455. BAIL_ON_FAILURE(hr);
  456. }
  457. for ( i = 0; i < dwNumberAttributes; i++)
  458. {
  459. aStrings[i] = pAttributeNames[i];
  460. if (!getSecDesc &&
  461. _wcsicmp(L"ntSecurityDescriptor", pAttributeNames[i]) == 0) {
  462. // we need go to get the security descriptor
  463. getSecDesc = TRUE;
  464. }
  465. }
  466. }
  467. else
  468. {
  469. //
  470. // If all attributes are requested, we will mark as read
  471. // security descriptor also. Further down, the decision to
  472. // use or not use a control is made.
  473. //
  474. getSecDesc = TRUE;
  475. }
  476. //
  477. // Read the DS Object
  478. //
  479. // modified from LdapSearchS to LdapSearchExtS to get all attributes
  480. // including SecurityDescriptor by one call
  481. if (getSecDesc) {
  482. ldaperr = ldap_get_option(
  483. ld->LdapHandle,
  484. LDAP_OPT_VERSION,
  485. &dwOptions
  486. );
  487. if (dwOptions == LDAP_VERSION3) {
  488. //
  489. // Read the security descriptor type if applicable
  490. //
  491. hr = ReadSecurityDescriptorControlType(
  492. pszLDAPServer,
  493. &dwSecDescType,
  494. Credentials,
  495. dwPort
  496. );
  497. //
  498. // If we could no get the control information for whatever reason,
  499. // just try the SearchS.
  500. //
  501. if (SUCCEEDED(hr) && (dwSecDescType == ADSI_LDAPC_SECDESC_NT)) {
  502. hr = LdapSearchExtS(
  503. ld,
  504. pszLDAPDn,
  505. LDAP_SCOPE_BASE,
  506. TEXT("(objectClass=*)"),
  507. aStrings,
  508. 0,
  509. (PLDAPControl *)&ServerControls,
  510. NULL,
  511. NULL,
  512. 10000,
  513. &res
  514. );
  515. fSearchDone = TRUE;
  516. }
  517. }
  518. }
  519. //
  520. // Perform just a LdapSearchS if the flag indicates that
  521. // no search has been done. We do not try a second search
  522. // if the first tone failed (saves packets on the wire).
  523. //
  524. if (!fSearchDone) {
  525. hr = LdapSearchS(
  526. ld,
  527. pszLDAPDn,
  528. LDAP_SCOPE_BASE,
  529. TEXT("(objectClass=*)"),
  530. aStrings,
  531. 0,
  532. &res
  533. );
  534. fSearchDone = TRUE;
  535. BAIL_ON_FAILURE(hr);
  536. }
  537. //
  538. // Should only contain one entry
  539. //
  540. if ( LdapCountEntries( ld, res ) == 0 )
  541. goto error;
  542. hr = LdapFirstEntry( ld, res, &entry );
  543. BAIL_ON_FAILURE(hr);
  544. //
  545. // Compute the number of attributes in the
  546. // read buffer.
  547. //
  548. hr = LdapFirstAttribute( ld, entry, &ptr, &pszAttrName );
  549. BAIL_ON_FAILURE(hr);
  550. while ( pszAttrName != NULL )
  551. {
  552. dwNumberOfEntries++;
  553. LdapAttributeFree( pszAttrName );
  554. pszAttrName = NULL;
  555. hr = LdapNextAttribute( ld, entry, ptr, &pszAttrName );
  556. if (FAILED(hr))
  557. break; // error occurred, ignore the rest of the attributes
  558. }
  559. //
  560. // Allocate an attribute buffer which is as large as the
  561. // number of attributes present
  562. //
  563. //
  564. // Note that pADsAttributes is inited to Null
  565. if (dwNumberOfEntries != 0) {
  566. pAdsAttributes = (PADS_ATTR_INFO)AllocADsMem(
  567. sizeof(ADS_ATTR_INFO) * dwNumberOfEntries
  568. );
  569. if (!pAdsAttributes)
  570. {
  571. hr = E_OUTOFMEMORY;
  572. BAIL_ON_FAILURE(hr);
  573. }
  574. }
  575. dwAttrCount = 0;
  576. ptr = NULL;
  577. hr = LdapFirstAttribute( ld, entry, &ptr, &pszAttrName );
  578. while ( SUCCEEDED(hr)
  579. && ( pszAttrName != NULL )
  580. && ( dwAttrCount < dwNumberOfEntries )
  581. )
  582. {
  583. //
  584. // Get the syntax of the attribute. Force only
  585. // if we know that the this is not the RootDSE
  586. // as RootDSE attributes are not in schema.
  587. //
  588. hr = LdapGetSyntaxOfAttributeOnServer(
  589. pszLDAPServer,
  590. pszAttrName,
  591. &dwSyntaxId,
  592. Credentials,
  593. dwPort,
  594. pszLDAPDn ? TRUE : FALSE
  595. );
  596. //
  597. // If it failed with errorcode 0x8000500D which is
  598. // E_ADS_PROPERTY_NOT_FOUND,
  599. // see if it is one of the RootDSE syntaxes,
  600. // if so set Syntax to ADSTYPE_CASE_IGNORE_STRING
  601. //
  602. if (hr == E_ADS_PROPERTY_NOT_FOUND) {
  603. //
  604. // search the hardcoded table to see if it is a known entry
  605. //
  606. BOOLEAN valFound = FALSE;
  607. DWORD ctr = 0;
  608. while (SpecialSyntaxesTable[ctr] && !valFound) {
  609. if (!_wcsicmp(pszAttrName, SpecialSyntaxesTable[ctr])) {
  610. dwSyntaxId = ADSTYPE_CASE_IGNORE_STRING;
  611. hr = S_OK;
  612. valFound = TRUE;
  613. }
  614. ctr++;
  615. }
  616. }else {
  617. if (!_wcsicmp(pszAttrName, L"ntSecurityDescriptor")) {
  618. dwSyntaxId = LDAPTYPE_SECURITY_DESCRIPTOR;
  619. }
  620. }
  621. if ( hr == E_ADS_PROPERTY_NOT_FOUND ) {
  622. //
  623. // We will default to provider specific
  624. //
  625. dwSyntaxId = LDAPTYPE_UNKNOWN;
  626. }
  627. else if (FAILED(hr)) {
  628. //
  629. // Some other failure so skip attribute
  630. //
  631. goto NextAttr;
  632. }
  633. //
  634. // Get the values of the current attribute
  635. //
  636. hr = UnMarshallLDAPToLDAPSynID(
  637. pszAttrName,
  638. ld,
  639. entry,
  640. dwSyntaxId,
  641. &ldapObjectArray
  642. );
  643. if ( FAILED(hr))
  644. goto NextAttr;
  645. hr = LdapTypeToAdsTypeCopyConstruct(
  646. ldapObjectArray,
  647. dwSyntaxId,
  648. &pAdsDestValues,
  649. &dwNumAdsValues,
  650. &dwAdsType
  651. );
  652. if (FAILED(hr))
  653. goto NextAttr;
  654. pThisAttributeDef = pAdsAttributes + dwAttrCount;
  655. pThisAttributeDef->pszAttrName = AllocADsStr(pszAttrName);
  656. if ( !pThisAttributeDef->pszAttrName )
  657. {
  658. hr = E_OUTOFMEMORY;
  659. BAIL_ON_FAILURE(hr);
  660. }
  661. pThisAttributeDef->pADsValues = pAdsDestValues;
  662. if ( pThisAttributeDef->dwNumValues = ldapObjectArray.dwCount )
  663. pThisAttributeDef->dwADsType = pAdsDestValues[0].dwType;
  664. dwAttrCount++;
  665. NextAttr:
  666. if ( pszAttrName ) {
  667. LdapAttributeFree( pszAttrName );
  668. pszAttrName = NULL;
  669. }
  670. if ( ldapObjectArray.pLdapObjects )
  671. {
  672. if ( ldapObjectArray.fIsString )
  673. LdapValueFree( (TCHAR **) ldapObjectArray.pLdapObjects );
  674. else
  675. LdapValueFreeLen( (struct berval **) ldapObjectArray.pLdapObjects );
  676. LDAPOBJECTARRAY_INIT(ldapObjectArray);
  677. }
  678. if ( hr == E_OUTOFMEMORY ) // break on serious error
  679. break;
  680. hr = LdapNextAttribute( ld, entry, ptr, &pszAttrName );
  681. }
  682. BAIL_ON_FAILURE(hr);
  683. if ( dwAttrCount == 0 )
  684. goto error;
  685. //
  686. // Now package this data into a single contiguous buffer
  687. //
  688. hr = ComputeAttributeBufferSize(
  689. pAdsAttributes,
  690. dwAttrCount,
  691. &dwMemSize,
  692. &dwTotalValues
  693. );
  694. BAIL_ON_FAILURE(hr);
  695. pAttributeBuffer = (LPBYTE) AllocADsMem( dwMemSize );
  696. if (!pAttributeBuffer) {
  697. hr = E_OUTOFMEMORY;
  698. BAIL_ON_FAILURE(hr);
  699. }
  700. pValueBuffer = pAttributeBuffer + dwAttrCount * (sizeof(ADS_ATTR_INFO));
  701. pDataBuffer = pValueBuffer + dwTotalValues * sizeof(ADSVALUE);
  702. pAttrEntry = (PADS_ATTR_INFO) pAttributeBuffer;
  703. pAttrValue = (PADSVALUE) pValueBuffer;
  704. for (i = 0; i < dwAttrCount; i++) {
  705. pThisAdsSrcAttribute = pAdsAttributes + i;
  706. pThisAdsTargAttribute = pAttrEntry + i;
  707. dwNumValues = pThisAdsSrcAttribute->dwNumValues;
  708. pThisAdsTargAttribute->dwNumValues = dwNumValues;
  709. pThisAdsTargAttribute->dwADsType = pThisAdsSrcAttribute->dwADsType;
  710. pThisAdsTargAttribute->pADsValues = pAttrValue;
  711. pThisAdsSrcValue = pThisAdsSrcAttribute->pADsValues;
  712. pThisAdsTargValue = pAttrValue;
  713. if (!pDataBuffer) {
  714. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  715. }
  716. for ( j = 0; j < dwNumValues; j++) {
  717. pDataBuffer = AdsTypeCopy(
  718. pThisAdsSrcValue,
  719. pThisAdsTargValue,
  720. pDataBuffer
  721. );
  722. pAttrValue++;
  723. pThisAdsTargValue = pAttrValue;
  724. pThisAdsSrcValue++;
  725. }
  726. if (!pDataBuffer) {
  727. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  728. }
  729. pDataBuffer = CopyAttributeName(
  730. pThisAdsSrcAttribute,
  731. pThisAdsTargAttribute,
  732. pDataBuffer
  733. );
  734. }
  735. hr = S_OK;
  736. error:
  737. if ( aStrings )
  738. FreeADsMem( aStrings );
  739. if ( res )
  740. LdapMsgFree( res );
  741. //
  742. // Clean up the header based Ods structures
  743. //
  744. if ( pAdsAttributes ) {
  745. for (i = 0; i < dwAttrCount; i++)
  746. {
  747. pThisAttributeDef = pAdsAttributes + i;
  748. FreeADsStr( pThisAttributeDef->pszAttrName );
  749. AdsTypeFreeAdsObjects( pThisAttributeDef->pADsValues,
  750. pThisAttributeDef->dwNumValues );
  751. }
  752. FreeADsMem( pAdsAttributes );
  753. }
  754. if (FAILED(hr))
  755. {
  756. if ( pAttributeBuffer )
  757. FreeADsMem(pAttributeBuffer);
  758. *ppAttributeEntries = NULL;
  759. *pdwNumAttributesReturned = 0;
  760. }
  761. else
  762. {
  763. *ppAttributeEntries = (PADS_ATTR_INFO)pAttributeBuffer;
  764. *pdwNumAttributesReturned = dwAttrCount;
  765. }
  766. return hr;
  767. }
  768. HRESULT
  769. ADsCreateDSObjectExt(
  770. ADS_LDP *ld,
  771. LPTSTR ADsPath,
  772. LPWSTR pszRDNName,
  773. PADS_ATTR_INFO pAttributeEntries,
  774. DWORD dwNumAttributes,
  775. SECURITY_INFORMATION seInfo,
  776. BOOL fSecDesc
  777. )
  778. {
  779. HRESULT hr = S_OK;
  780. LPTSTR pszAbsoluteName = NULL;
  781. TCHAR *pszLDAPServer = NULL;
  782. LPWSTR pszLDAPDn = NULL;
  783. DWORD dwSyntaxId = 0;
  784. DWORD dwPort = 0;
  785. DWORD i = 0;
  786. DWORD j = 0;
  787. PADS_ATTR_INFO pThisAttribute = NULL;
  788. LDAPOBJECTARRAY ldapObjectArray;
  789. LDAPMod **aMods = NULL;
  790. LDAPModW *aModsBuffer = NULL;
  791. BYTE berValue[8];
  792. memset(berValue, 0, 8);
  793. berValue[0] = 0x30; // Start sequence tag
  794. berValue[1] = 0x03; // Length in bytes of following
  795. berValue[2] = 0x02; // Actual value this and next 2
  796. berValue[3] = 0x01;
  797. berValue[4] = (BYTE)((ULONG)seInfo);
  798. LDAPControl SeInfoControl =
  799. {
  800. LDAP_SERVER_SD_FLAGS_OID_W,
  801. {
  802. 5, (PCHAR) berValue
  803. },
  804. TRUE
  805. };
  806. PLDAPControl ServerControls[2] =
  807. {
  808. &SeInfoControl,
  809. NULL
  810. };
  811. //
  812. // Get the LDAP path of the object to create
  813. //
  814. hr = BuildADsPathFromParent(
  815. ADsPath,
  816. pszRDNName,
  817. &pszAbsoluteName
  818. );
  819. BAIL_ON_FAILURE(hr);
  820. hr = BuildLDAPPathFromADsPath2(
  821. pszAbsoluteName,
  822. &pszLDAPServer,
  823. &pszLDAPDn,
  824. &dwPort
  825. );
  826. BAIL_ON_FAILURE(hr);
  827. //
  828. // Allocate memory to store the add request
  829. //
  830. aMods = (LDAPModW **) AllocADsMem((dwNumAttributes+1) * sizeof(LDAPModW*));
  831. if ( aMods == NULL )
  832. {
  833. hr = E_OUTOFMEMORY;
  834. BAIL_ON_FAILURE(hr);
  835. }
  836. aModsBuffer = (LDAPModW *) AllocADsMem( dwNumAttributes * sizeof(LDAPModW));
  837. if ( aModsBuffer == NULL )
  838. {
  839. hr = E_OUTOFMEMORY;
  840. BAIL_ON_FAILURE(hr);
  841. }
  842. //
  843. // Format the add request
  844. //
  845. for (i = 0; i < dwNumAttributes; i++) {
  846. BOOL fGenTime = FALSE;
  847. LDAPOBJECTARRAY_INIT(ldapObjectArray);
  848. pThisAttribute = pAttributeEntries + i;
  849. if (pThisAttribute->dwControlCode != ADS_ATTR_CLEAR) {
  850. //
  851. // If this is a time attribute, see if it is GenTime or
  852. // UTCTime and set the syntax the flag appropriately
  853. //
  854. if (pThisAttribute->dwADsType == ADSTYPE_UTC_TIME) {
  855. hr = LdapGetSyntaxOfAttributeOnServer(
  856. pszLDAPServer,
  857. pThisAttribute->pszAttrName,
  858. &dwSyntaxId,
  859. (*ld->pCredentials),
  860. ld->PortNumber
  861. );
  862. if (SUCCEEDED(hr) && (dwSyntaxId == LDAPTYPE_GENERALIZEDTIME)) {
  863. //
  864. // Use GenTime conversion
  865. //
  866. fGenTime = TRUE;
  867. }
  868. }
  869. }
  870. hr = AdsTypeToLdapTypeCopyConstruct(
  871. pThisAttribute->pADsValues,
  872. pThisAttribute->dwNumValues,
  873. &ldapObjectArray,
  874. &dwSyntaxId,
  875. fGenTime
  876. );
  877. BAIL_ON_FAILURE(hr);
  878. aMods[i] = &aModsBuffer[i];
  879. aModsBuffer[i].mod_type = pThisAttribute->pszAttrName;
  880. if ( ldapObjectArray.fIsString )
  881. {
  882. aModsBuffer[i].mod_values = (TCHAR **) ldapObjectArray.pLdapObjects;
  883. }
  884. else
  885. {
  886. aModsBuffer[i].mod_bvalues = (struct berval **) ldapObjectArray.pLdapObjects;
  887. aModsBuffer[i].mod_op = LDAP_MOD_BVALUES;
  888. }
  889. aModsBuffer[i].mod_op |= LDAP_MOD_REPLACE;
  890. }
  891. if (fSecDesc) {
  892. hr = LdapAddExtS(
  893. ld,
  894. pszLDAPDn,
  895. aMods,
  896. (PLDAPControl *)&ServerControls,
  897. NULL
  898. );
  899. }
  900. else {
  901. //
  902. // Now, send the add request
  903. //
  904. hr = LdapAddS(
  905. ld,
  906. pszLDAPDn,
  907. aMods
  908. );
  909. }
  910. BAIL_ON_FAILURE(hr);
  911. error:
  912. if ( pszAbsoluteName ) {
  913. FreeADsStr( pszAbsoluteName );
  914. }
  915. if ( pszLDAPServer ) {
  916. FreeADsStr( pszLDAPServer );
  917. }
  918. if (pszLDAPDn) {
  919. FreeADsStr( pszLDAPDn);
  920. }
  921. if ( aModsBuffer )
  922. {
  923. for ( j = 0; j < i; j++ )
  924. {
  925. if ( aModsBuffer[j].mod_op & LDAP_MOD_BVALUES )
  926. {
  927. if ( aModsBuffer[j].mod_bvalues )
  928. {
  929. for ( DWORD k = 0; aModsBuffer[j].mod_bvalues[k]; k++ )
  930. FreeADsMem( aModsBuffer[j].mod_bvalues[k] );
  931. FreeADsMem( aModsBuffer[j].mod_bvalues );
  932. }
  933. }
  934. else if ( aModsBuffer[j].mod_values )
  935. {
  936. for ( DWORD k = 0; aModsBuffer[j].mod_values[k]; k++ )
  937. FreeADsMem( aModsBuffer[j].mod_values[k] );
  938. FreeADsMem( aModsBuffer[j].mod_values );
  939. }
  940. }
  941. FreeADsMem( aModsBuffer );
  942. }
  943. if ( aMods )
  944. FreeADsMem( aMods );
  945. return hr;
  946. }
  947. HRESULT
  948. ADsCreateDSObject(
  949. ADS_LDP *ld,
  950. LPTSTR ADsPath,
  951. LPWSTR pszRDNName,
  952. PADS_ATTR_INFO pAttributeEntries,
  953. DWORD dwNumAttributes
  954. )
  955. {
  956. RRETURN ( ADsCreateDSObjectExt(
  957. ld,
  958. ADsPath,
  959. pszRDNName,
  960. pAttributeEntries,
  961. dwNumAttributes,
  962. 0, // for seInfo since it is ignored
  963. FALSE
  964. )
  965. );
  966. }
  967. HRESULT
  968. ADsDeleteDSObject(
  969. ADS_LDP *ld,
  970. LPTSTR ADsPath,
  971. LPWSTR pszRDNName
  972. )
  973. {
  974. HRESULT hr = S_OK;
  975. LPTSTR pszAbsoluteName = NULL;
  976. TCHAR *pszLDAPServer = NULL;
  977. LPWSTR pszLDAPDn = NULL;
  978. DWORD dwPort = 0;
  979. //
  980. // Get the LDAP path of the object to delete
  981. //
  982. hr = BuildADsPathFromParent(
  983. ADsPath,
  984. pszRDNName,
  985. &pszAbsoluteName
  986. );
  987. BAIL_ON_FAILURE(hr);
  988. hr = BuildLDAPPathFromADsPath2(
  989. pszAbsoluteName,
  990. &pszLDAPServer,
  991. &pszLDAPDn,
  992. &dwPort
  993. );
  994. BAIL_ON_FAILURE(hr);
  995. //
  996. // Now, send the delete request
  997. //
  998. hr = LdapDeleteS(
  999. ld,
  1000. pszLDAPDn
  1001. );
  1002. BAIL_ON_FAILURE(hr);
  1003. error:
  1004. if ( pszAbsoluteName ) {
  1005. FreeADsStr( pszAbsoluteName );
  1006. }
  1007. if ( pszLDAPServer ) {
  1008. FreeADsStr( pszLDAPServer );
  1009. }
  1010. if (pszLDAPDn) {
  1011. FreeADsStr(pszLDAPDn);
  1012. }
  1013. return hr;
  1014. }
  1015. HRESULT
  1016. ComputeAttributeBufferSize(
  1017. PADS_ATTR_INFO pAdsAttributes,
  1018. DWORD dwNumAttributes,
  1019. PDWORD pdwSize,
  1020. PDWORD pdwNumValues
  1021. )
  1022. {
  1023. PADS_ATTR_INFO pThisAttribute = NULL;
  1024. PADSVALUE pAdsSrcValues = NULL;
  1025. DWORD dwNumValues = 0;
  1026. DWORD dwSize = 0;
  1027. DWORD dwTotalNumValues = 0;
  1028. for ( DWORD i = 0; i < dwNumAttributes; i++) {
  1029. pThisAttribute = pAdsAttributes + i;
  1030. dwNumValues = pThisAttribute->dwNumValues;
  1031. dwTotalNumValues += dwNumValues;
  1032. pAdsSrcValues = pThisAttribute->pADsValues;
  1033. for ( DWORD j = 0; j < dwNumValues; j++)
  1034. dwSize += AdsTypeSize(pAdsSrcValues + j) + sizeof(ADSVALUE);
  1035. dwSize += sizeof(ADS_ATTR_INFO);
  1036. dwSize += ((wcslen(pThisAttribute->pszAttrName) + 1)*sizeof(WCHAR)) + (ALIGN_WORD-1);
  1037. }
  1038. *pdwSize = dwSize;
  1039. *pdwNumValues = dwTotalNumValues;
  1040. return S_OK;
  1041. }
  1042. LPBYTE
  1043. CopyAttributeName(
  1044. PADS_ATTR_INFO pThisAdsSrcAttribute,
  1045. PADS_ATTR_INFO pThisAdsTargAttribute,
  1046. LPBYTE pDataBuffer
  1047. )
  1048. {
  1049. //
  1050. // strings should be WCHAR (i.e., WORD) aligned
  1051. //
  1052. pDataBuffer = (LPBYTE) ROUND_UP_POINTER(pDataBuffer, ALIGN_WORD);
  1053. LPWSTR pCurrentPos = (LPWSTR)pDataBuffer;
  1054. wcscpy(pCurrentPos, pThisAdsSrcAttribute->pszAttrName);
  1055. pThisAdsTargAttribute->pszAttrName = pCurrentPos;
  1056. pDataBuffer = pDataBuffer + (wcslen(pThisAdsSrcAttribute->pszAttrName) + 1)*sizeof(WCHAR);
  1057. return(pDataBuffer);
  1058. }