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.

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