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.

550 lines
12 KiB

  1. #include "ldap.hxx"
  2. #pragma hdrstop
  3. HRESULT
  4. CopyObject(
  5. IN LPWSTR pszSrcADsPath,
  6. IN LPWSTR pszDestContainer,
  7. IN ADS_LDP *ldDest, // LDAP handle of destination container
  8. IN SCHEMAINFO * pSchemaInfo, // SCHEMAINFO for the dest container
  9. IN LPWSTR pszCommonName, // optional
  10. OUT IUnknown ** ppObject
  11. )
  12. {
  13. HRESULT hr = S_OK;
  14. WCHAR szLDAPSrcPath[MAX_PATH];
  15. WCHAR szLDAPDestContainer[MAX_PATH];
  16. ADS_LDP *ldapSrc = NULL, *ldapDest = NULL;
  17. LDAPMessage *ldpSrcMsg =NULL;
  18. SCHEMAINFO *pDestSchemaInfo = NULL;
  19. WCHAR **avalues;
  20. DWORD nCount, nNumberOfEntries;
  21. WCHAR szADsClass[MAX_PATH];
  22. WCHAR szName[MAX_PATH];
  23. WCHAR szParent[MAX_PATH];
  24. LPWSTR pszRelativeName = NULL;
  25. hr = BuildADsParentPath(
  26. pszSrcADsPath,
  27. szParent,
  28. szName
  29. );
  30. BAIL_ON_FAILURE(hr);
  31. hr = GetInfoFromSrcObject(
  32. pszSrcADsPath,
  33. szLDAPSrcPath,
  34. &ldapSrc,
  35. &ldpSrcMsg,
  36. &avalues,
  37. &nCount
  38. );
  39. BAIL_ON_FAILURE(hr);
  40. if(ldDest){
  41. ldapDest = ldDest;
  42. }
  43. if(pSchemaInfo){
  44. pDestSchemaInfo = pSchemaInfo;
  45. }
  46. hr = CreateDestObjectCopy(
  47. pszDestContainer,
  48. avalues,
  49. nCount,
  50. ldapSrc,
  51. &ldapDest,
  52. ldpSrcMsg,
  53. &pDestSchemaInfo,
  54. pszCommonName,
  55. szLDAPDestContainer
  56. );
  57. BAIL_ON_FAILURE(hr);
  58. if (pszCommonName){
  59. pszRelativeName = pszCommonName;
  60. } else {
  61. pszRelativeName = szName;
  62. }
  63. hr = InstantiateCopiedObject(
  64. pszDestContainer,
  65. avalues,
  66. nCount,
  67. pszRelativeName,
  68. ppObject
  69. );
  70. error:
  71. if (!pSchemaInfo && pDestSchemaInfo){
  72. pDestSchemaInfo ->Release();
  73. }
  74. if (!ldDest && ldapDest)
  75. {
  76. LdapCloseObject(ldapDest);
  77. ldapDest = NULL;
  78. }
  79. if (ldapSrc)
  80. {
  81. LdapCloseObject(ldapSrc);
  82. ldapSrc = NULL;
  83. }
  84. if(avalues){
  85. LdapValueFree(avalues);
  86. }
  87. if(ldpSrcMsg){
  88. LdapMsgFree( ldpSrcMsg);
  89. }
  90. RRETURN(hr);
  91. }
  92. HRESULT
  93. GetInfoFromSrcObject(
  94. IN LPWSTR pszSrcADsPath,
  95. OUT LPWSTR szLDAPSrcPath,
  96. OUT ADS_LDP ** pldapSrc,
  97. OUT LDAPMessage **pldpSrcMsg,
  98. OUT WCHAR ***pavalues,
  99. OUT DWORD *pnCount
  100. )
  101. {
  102. ADS_LDP *ldapSrc = NULL;
  103. LDAPMessage *ldpSrcMsg =NULL;
  104. WCHAR **avalues;
  105. DWORD nCount, nNumberOfEntries;
  106. HRESULT hr = S_OK;
  107. OBJECTINFO ObjectInfo;
  108. POBJECTINFO pObjectInfo = &ObjectInfo;
  109. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  110. hr = BuildLDAPPathFromADsPath(
  111. pszSrcADsPath,
  112. szLDAPSrcPath );
  113. BAIL_ON_FAILURE(hr);
  114. hr = LdapOpenObject(
  115. szLDAPSrcPath,
  116. &ldapSrc
  117. );
  118. BAIL_ON_FAILURE(hr);
  119. hr = LdapSearchS(
  120. ldapSrc,
  121. GET_LDAPDN_FROM_PATH(szLDAPSrcPath),
  122. LDAP_SCOPE_BASE,
  123. TEXT("(objectClass=*)"),
  124. NULL,
  125. 0,
  126. &ldpSrcMsg
  127. );
  128. BAIL_ON_FAILURE(hr);
  129. //
  130. // get the object class of the source object. We need to do this so
  131. // that we can use the information so obtained to test whether there
  132. // is the same object class in the destination location
  133. //
  134. hr = ADsObject(pszSrcADsPath, pObjectInfo);
  135. BAIL_ON_FAILURE(hr);
  136. hr = LdapReadAttribute(
  137. szLDAPSrcPath,
  138. TEXT("objectClass"),
  139. &avalues,
  140. (int *)&nCount,
  141. &ldapSrc,
  142. pObjectInfo->PortNumber
  143. );
  144. BAIL_ON_FAILURE(hr);
  145. if ( nCount == 0 ){
  146. // This object exists but does not have an objectClass. We
  147. // can't do anything without the objectClass. Hence, return
  148. // bad path error.
  149. hr = E_ADS_BAD_PATHNAME;
  150. BAIL_ON_FAILURE(hr);
  151. }
  152. //
  153. // we have succeeded in getting all the information from the source
  154. // object. We need to validate to see if there is such an object in
  155. // in the destination.
  156. *pldapSrc = ldapSrc;
  157. *pldpSrcMsg = ldpSrcMsg;
  158. *pavalues = avalues;
  159. *pnCount = nCount;
  160. error:
  161. FreeObjectInfo(pObjectInfo);
  162. RRETURN(hr);
  163. }
  164. HRESULT
  165. CreateDestObjectCopy(
  166. IN LPWSTR pszDestContainer,
  167. IN WCHAR **avalues,
  168. IN DWORD nCount,
  169. IN ADS_LDP *ldapSrc,
  170. IN OUT ADS_LDP **pldDest,
  171. IN LDAPMessage *ldpSrcMsg,
  172. IN OUT SCHEMAINFO **ppSchemaInfo,
  173. IN LPWSTR pszCommonName,
  174. OUT LPWSTR szLDAPDestContainer
  175. )
  176. {
  177. ADS_LDP *ldapDest = NULL;
  178. LDAPModW *aModsBuffer = NULL;
  179. LDAPMessage *ldpAttrMsg = NULL;
  180. SCHEMAINFO *pDestSchemaInfo = NULL;
  181. DWORD nNumberOfEntries;
  182. HRESULT hr = S_OK;
  183. DWORD index = 0, dwCount = 0,nNumberOfValues, dwSyntax;
  184. VOID *ptr;
  185. LPWSTR pszAttrName = NULL;
  186. DWORD i= 0, j=0;
  187. PLDAPOBJECT *ppaValues = NULL;
  188. PLDAPOBJECT paObjClass = NULL;
  189. OBJECTINFO ObjectInfo;
  190. POBJECTINFO pObjectInfo = &ObjectInfo;
  191. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  192. hr = BuildLDAPPathFromADsPath(
  193. pszDestContainer,
  194. szLDAPDestContainer
  195. );
  196. BAIL_ON_FAILURE(hr);
  197. if (*pldDest){
  198. ldapDest = *pldDest;
  199. } else {
  200. hr = LdapOpenObject(
  201. szLDAPDestContainer,
  202. &ldapDest
  203. );
  204. BAIL_ON_FAILURE(hr);
  205. *pldDest = ldapDest;
  206. }
  207. if(*ppSchemaInfo){
  208. pDestSchemaInfo = *ppSchemaInfo;
  209. } else {
  210. hr = ADsObject(pszDestContainer, pObjectInfo);
  211. BAIL_ON_FAILURE(hr);
  212. hr = LdapGetSchema( szLDAPDestContainer,
  213. ldapDest,
  214. &pDestSchemaInfo,
  215. pObjectInfo->PortNumber
  216. );
  217. BAIL_ON_FAILURE(hr);
  218. *ppSchemaInfo = pDestSchemaInfo;
  219. }
  220. //
  221. // check to see if the object class of source exists in the naming
  222. // context of the destination
  223. //
  224. /*
  225. index = FindEntryInSearchTable( avalues[nCount -1],
  226. pDestSchemaInfo->aClassesSearchTable,
  227. 2 * pDestSchemaInfo->nNumOfClasses );
  228. if ( index == -1 ) {
  229. // Cannot find the class name
  230. hr = E_ADS_BAD_PARAMETER;
  231. BAIL_ON_FAILURE(hr);
  232. }
  233. */
  234. //
  235. // Now we need to find the number of entries in the ldap message
  236. //
  237. hr = LdapFirstEntry( ldapSrc, ldpSrcMsg, &ldpAttrMsg );
  238. BAIL_ON_FAILURE(hr);
  239. dwCount = 0;
  240. hr = LdapFirstAttribute(ldapSrc, ldpAttrMsg, &ptr, &pszAttrName);
  241. BAIL_ON_FAILURE(hr);
  242. do {
  243. dwCount++;
  244. hr = LdapNextAttribute(
  245. ldapSrc,
  246. ldpAttrMsg,
  247. ptr,
  248. &pszAttrName
  249. );
  250. if (pszAttrName) {
  251. FreeADsMem(pszAttrName);
  252. }
  253. if (FAILED(hr)){
  254. break;
  255. }
  256. } while(pszAttrName != NULL);
  257. aModsBuffer = (LDAPModW *) AllocADsMem((dwCount +1) *
  258. sizeof(LDAPModW ));
  259. if ( aModsBuffer == NULL ) {
  260. hr = E_OUTOFMEMORY;
  261. BAIL_ON_FAILURE(hr);
  262. }
  263. //
  264. // memory has been allocated. we now need to scan the list again
  265. // and copy the entries from the LDAPMessage structure to the
  266. // LDAPModW structure
  267. //
  268. ppaValues= (PLDAPOBJECT *)AllocADsMem(dwCount * sizeof(PLDAPOBJECT));
  269. if (!ppaValues){
  270. hr = E_OUTOFMEMORY;
  271. goto error;
  272. }
  273. paObjClass = (PLDAPOBJECT)AllocADsMem(sizeof(LDAPOBJECT));
  274. if (!ppaValues){
  275. hr = E_OUTOFMEMORY;
  276. goto error;
  277. }
  278. hr = LdapFirstAttribute(ldapSrc, ldpAttrMsg, &ptr, &pszAttrName);
  279. BAIL_ON_FAILURE(hr);
  280. i=0;
  281. j = 0;
  282. do {
  283. hr = LdapGetValuesLen( ldapSrc, ldpAttrMsg, pszAttrName,
  284. &ppaValues[j], (int *)&nNumberOfValues );
  285. BAIL_ON_FAILURE(hr);
  286. dwSyntax = GetSyntaxOfAttribute(
  287. pszAttrName,
  288. pDestSchemaInfo
  289. );
  290. if (dwSyntax != LDAPTYPE_UNKNOWN ){
  291. if (wcscmp(pszAttrName, TEXT("distinguishedName"))== 0){
  292. hr = LdapNextAttribute( ldapSrc,
  293. ldpAttrMsg,
  294. ptr,
  295. &pszAttrName );
  296. if (FAILED(hr)){
  297. break;
  298. }
  299. j++;
  300. continue;
  301. }
  302. if (wcscmp(pszAttrName, TEXT("objectClass"))== 0){
  303. VARIANT v;
  304. V_VT(&v)= VT_BSTR;
  305. V_BSTR(&v)= avalues[nCount-1];
  306. hr = VarTypeToLdapTypeString( &v, paObjClass);
  307. BAIL_ON_FAILURE(hr);
  308. aModsBuffer[i].mod_bvalues = paObjClass;
  309. aModsBuffer[i].mod_op = LDAP_MOD_BVALUES | LDAP_MOD_ADD;
  310. } else {
  311. aModsBuffer[i].mod_type = pszAttrName;
  312. aModsBuffer[i].mod_bvalues = ppaValues[j];
  313. aModsBuffer[i].mod_op = LDAP_MOD_BVALUES | LDAP_MOD_ADD;
  314. }
  315. i++;
  316. }
  317. FreeADsMem( pszAttrName );
  318. hr = LdapNextAttribute( ldapSrc, ldpAttrMsg, ptr, &pszAttrName );
  319. if (FAILED(hr)){
  320. break;
  321. }
  322. j++;
  323. } while(pszAttrName != NULL);
  324. hr = LdapAddS(
  325. ldapDest,
  326. GET_LDAPDN_FROM_PATH(szLDAPDestContainer),
  327. &aModsBuffer
  328. );
  329. BAIL_ON_FAILURE(hr);
  330. error:
  331. FreeObjectInfo(pObjectInfo);
  332. for(j=0; j< dwCount; j++){
  333. if(ppaValues[j]){
  334. LdapValueFreeLen(ppaValues[j]);
  335. }
  336. }
  337. if(ldpAttrMsg){
  338. LdapMsgFree( ldpAttrMsg);
  339. }
  340. if(aModsBuffer){
  341. FreeADsMem(aModsBuffer);
  342. }
  343. if (pszAttrName) {
  344. FreeADsMem(pszAttrName);
  345. }
  346. if(ppaValues){
  347. FreeADsMem(ppaValues);
  348. }
  349. if(paObjClass){
  350. FreeADsMem(paObjClass);
  351. }
  352. RRETURN(hr);
  353. }
  354. HRESULT
  355. InstantiateCopiedObject(
  356. IN LPWSTR pszDestContainer,
  357. IN WCHAR ** avalues,
  358. IN DWORD nCount,
  359. IN LPWSTR pszRelativeName,
  360. OUT IUnknown ** ppObject
  361. )
  362. {
  363. HRESULT hr = S_OK;
  364. IADs *pADs = NULL;
  365. WCHAR szADsClassName[MAX_PATH];
  366. MapLdapClassToADsClass( avalues, nCount, szADsClassName );
  367. hr = CLDAPGenObject::CreateGenericObject(
  368. pszDestContainer,
  369. pszRelativeName,
  370. szADsClassName,
  371. avalues[nCount-1],
  372. ADS_OBJECT_BOUND,
  373. IID_IADs,
  374. (void **) &pADs
  375. );
  376. BAIL_ON_FAILURE(hr);
  377. //
  378. // InstantiateDerivedObject should add-ref this pointer for us.
  379. //
  380. hr = InstantiateDerivedObject(
  381. pADs,
  382. szADsClassName,
  383. IID_IUnknown,
  384. (void **)ppObject
  385. );
  386. if (FAILED(hr)) {
  387. hr = pADs->QueryInterface(
  388. IID_IUnknown,
  389. (void **)ppObject
  390. );
  391. BAIL_ON_FAILURE(hr);
  392. }
  393. error:
  394. if(pADs){
  395. pADs->Release();
  396. }
  397. RRETURN(hr);
  398. }