cl4_api.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /* cl4_api.h - implementation of the minimal interface to 4.0 changelog necessary to
  42. link 4.0 changelog to 5.0 replication
  43. */
  44. #include "repl.h"
  45. #include "cl4_api.h"
  46. #include "csnpl.h"
  47. #include "cl4.h"
  48. /*** Data Structures ***/
  49. /* changelog internal data */
  50. typedef struct cl4priv
  51. {
  52. CSNPL *csnPL; /* csn pending list */
  53. int regID; /* csn function registration id */
  54. }CL4Private;
  55. /* callback data to get result of internal operations */
  56. typedef struct cl4ret
  57. {
  58. int err; /* error code */
  59. Slapi_Entry *e; /* target entry */
  60. }CL4Ret;
  61. /* Global Data */
  62. static CL4Private s_cl4Desc; /* represents changelog state */
  63. /*** Helper functions forward declarations ***/
  64. static int _cl4WriteOperation (const slapi_operation_parameters *op);
  65. static void _cl4AssignCSNCallback (const CSN *csn, void *data);
  66. static void _cl4AbortCSNCallback (const CSN *csn, void *data);
  67. static char* _cl4MakeCSNDN (const CSN* csn);
  68. static int _cl4GetEntry (const CSN *csn, Slapi_Entry **entry);
  69. static void _cl4ResultCallback (int err, void *callback_data);
  70. static int _cl4EntryCallback (Slapi_Entry *e, void *callback_data);
  71. static PRBool _cl4CanAssignChangeNumber (const CSN *csn);
  72. static int _cl4ResolveTargetDN (Slapi_Entry *entry, Slapi_DN **newTargetDN);
  73. static int _cl4GetTargetEntry (Slapi_DN *targetDN, const char *uniqueid, Slapi_Entry **entry);
  74. static int _cl4FindTargetDN (const CSN *csn, const char *uniqueid,
  75. const Slapi_DN *targetSDN, Slapi_DN **newTargetDN);
  76. static int _cl4AssignChangeNumber (changeNumber *cnum);
  77. static int _cl4UpdateEntry (const CSN *csn, const char *changeType, const Slapi_DN *newTargetDN, changeNumber cnum);
  78. /*** API ***/
  79. int cl4Init ()
  80. {
  81. s_cl4Desc.csnPL = csnplNew ();
  82. if (s_cl4Desc.csnPL == NULL)
  83. {
  84. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cl4Init: failed to create CSN pending list\n");
  85. return CL4_CSNPL_ERROR;
  86. }
  87. s_cl4Desc.regID = csnRegisterNewCSNCb(_cl4AssignCSNCallback, NULL,
  88. _cl4AbortCSNCallback, NULL);
  89. return CL4_SUCCESS;
  90. }
  91. void cl4Cleanup ()
  92. {
  93. if (s_cl4Desc.regID >= 0)
  94. {
  95. csnRemoveNewCSNCb(s_cl4Desc.regID);
  96. s_cl4Desc.regID = -1;
  97. }
  98. if (s_cl4Desc.csnPL == NULL)
  99. csnplFree (&s_cl4Desc.csnPL);
  100. }
  101. int cl4WriteOperation (const slapi_operation_parameters *op)
  102. {
  103. int rc;
  104. ReplicaId rd;
  105. if (op == NULL || !IsValidOperation (op))
  106. {
  107. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cl4WriteEntry: invalid entry\n");
  108. return CL4_BAD_DATA;
  109. }
  110. rc = _cl4WriteOperation (op);
  111. if (rc != CL4_SUCCESS)
  112. {
  113. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cl4WriteEntry: failed to write changelog entry\n");
  114. return rc;
  115. }
  116. /* the entry is generated by this server - remove the entry from the pending list */
  117. rd= csn_get_replicaid(op->csn);
  118. if (rd == slapi_get_replicaid ())
  119. {
  120. rc = csnplRemove (s_cl4Desc.csnPL, op->csn);
  121. if (rc != 0)
  122. {
  123. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  124. "cl4WriteEntry: failed to remove CSN from the pending list\n");
  125. rc = CL4_CSNPL_ERROR;
  126. }
  127. }
  128. return rc;
  129. }
  130. int cl4ChangeTargetDN (const CSN *csn, const char *newDN)
  131. {
  132. Slapi_PBlock *pb;
  133. char *changeEntryDN;
  134. Slapi_Mods smods;
  135. int res;
  136. if (csn == NULL || newDN == NULL)
  137. {
  138. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cl4ChangeTargetDN: invalid argument\n");
  139. return CL4_BAD_DATA;
  140. }
  141. /* construct dn of the change entry */
  142. changeEntryDN = _cl4MakeCSNDN (csn);
  143. if (changeEntryDN == NULL)
  144. {
  145. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  146. "cl4ChangeTargetDN: failed to construct change entry dn\n");
  147. return CL4_MEMORY_ERROR;
  148. }
  149. pb = slapi_pblock_new ();
  150. slapi_mods_init(&smods, 1);
  151. slapi_mods_add(&smods, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, attr_targetdn,
  152. strlen (newDN), newDN);
  153. slapi_modify_internal_set_pb(pb, changeEntryDN, slapi_mods_get_ldapmods_byref(&smods),
  154. NULL, NULL, repl_get_plugin_identity(PLUGIN_LEGACY_REPLICATION), 0);
  155. slapi_modify_internal_pb (pb);
  156. slapi_mods_done(&smods);
  157. slapi_ch_free ((void**)&changeEntryDN);
  158. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
  159. slapi_pblock_destroy(pb);
  160. if (res != LDAP_SUCCESS)
  161. {
  162. char s[CSN_STRSIZE];
  163. slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
  164. "cl4ChangeTargetDN: an error occured while modifying change entry with csn %s: %s. "
  165. "Logging of changes is disabled.\n", csn_as_string(csn,PR_FALSE,s), ldap_err2string(res));
  166. /* GGOODREPL g_set_repl_backend( NULL ); */
  167. return CL4_LDAP_ERROR;
  168. }
  169. return CL4_SUCCESS;
  170. }
  171. void cl4AssignChangeNumbers (time_t when, void *arg)
  172. {
  173. int rc = CL4_SUCCESS;
  174. Slapi_Entry *entry;
  175. CSN *csn = NULL;
  176. Slapi_DN *newTargetDN;
  177. changeNumber cnum;
  178. char *changetype;
  179. /* we are looping though the entries ready to be commited updating there target dn
  180. and assigning change numbers */
  181. while (_cl4GetEntry (csn, &entry) == CL4_SUCCESS)
  182. {
  183. /* ONREPL - I think we need to free previous csn */
  184. csn = csn_new_by_string(slapi_entry_attr_get_charptr (entry, attr_csn));
  185. /* all conflicts involving this entry have been resolved */
  186. if (_cl4CanAssignChangeNumber (csn))
  187. {
  188. /* figure out the name of the target entry that corresponds to change csn */
  189. rc = _cl4ResolveTargetDN (entry, &newTargetDN);
  190. slapi_entry_free (entry);
  191. if (rc != CL4_SUCCESS)
  192. {
  193. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cl4AssignChangeNumbers: failed to resolve target dn\n");
  194. break;
  195. }
  196. _cl4AssignChangeNumber (&cnum);
  197. changetype = slapi_entry_attr_get_charptr (entry, attr_changetype);
  198. /* update change entry: write change number and remove csn attribute.
  199. Note that we leave uniqueid in the entry to avoid an extra update.
  200. This is ok since uniqueid is an operational attribute not returned
  201. to the client by default. */
  202. rc = _cl4UpdateEntry (csn, changetype, newTargetDN, cnum);
  203. if (newTargetDN)
  204. {
  205. slapi_sdn_free (&newTargetDN);
  206. }
  207. slapi_ch_free ((void**)&changetype);
  208. if (rc != CL4_SUCCESS)
  209. {
  210. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  211. "cl4AssignChangeNumbers: failed to update changelog entry\n");
  212. break;
  213. }
  214. }
  215. else /* went too far */
  216. {
  217. slapi_entry_free (entry);
  218. break;
  219. }
  220. }
  221. }
  222. /*** Helper Functions ***/
  223. /* adds new change record to 4.0 changelog */
  224. static int _cl4WriteOperation (const slapi_operation_parameters *op)
  225. {
  226. int rc = CL4_SUCCESS, res;
  227. char *changeEntryDN, *timeStr;
  228. Slapi_Entry *e = NULL;
  229. Slapi_PBlock *pb = NULL;
  230. Slapi_Value *values[3];
  231. char s[CSN_STRSIZE];
  232. slapi_log_error (SLAPI_LOG_PLUGIN, repl_plugin_name,
  233. "_cl4WriteEntry: writing change record with csn %s for dn: \"%s\"\n",
  234. csn_as_string(op->csn,PR_FALSE,s), op->target_address.dn);
  235. /* create change entry dn */
  236. changeEntryDN = _cl4MakeCSNDN (op->csn);
  237. if (changeEntryDN == NULL)
  238. {
  239. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  240. "_cl4WriteEntry: failed to create entry dn\n");
  241. return CL4_MEMORY_ERROR;
  242. }
  243. /*
  244. * Create the entry struct, and fill in fields common to all types
  245. * of change records.
  246. */
  247. e = slapi_entry_alloc();
  248. if (e == NULL)
  249. {
  250. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  251. "_cl4WriteEntry: failed to allocate change entry\n");
  252. return CL4_MEMORY_ERROR;
  253. }
  254. slapi_entry_set_dn(e, slapi_ch_strdup (changeEntryDN));
  255. /* Set the objectclass attribute */
  256. values [0] = slapi_value_new (NULL);
  257. values [1] = slapi_value_new (NULL);
  258. values [2] = NULL;
  259. slapi_value_set_string(values[0], "top");
  260. slapi_value_set_string(values[1], "changelogentry");
  261. slapi_entry_add_values_sv (e, "objectclass", values);
  262. /* ONREPL - for now we have to free Slapi_Values since api makes copy;
  263. this will change when a new set of api is added */
  264. slapi_value_free (&(values[0]));
  265. slapi_value_free (&(values[1]));
  266. /* Set the changeNumber attribute */
  267. /* Need to set this because it is required by schema */
  268. slapi_entry_attr_set_charptr (e, attr_changenumber, "0");
  269. /* Set the targetentrydn attribute */
  270. if (op->operation_type == SLAPI_OPERATION_ADD) /* use raw dn */
  271. slapi_entry_attr_set_charptr (e, attr_targetdn, slapi_entry_get_dn (op->p.p_add.target_entry));
  272. else /* use normolized dn */
  273. slapi_entry_attr_set_charptr (e, attr_targetdn, op->target_address.dn);
  274. /* ONREPL - set dbid attribute */
  275. /* Set the changeTime attribute */
  276. timeStr = format_localTime (current_time());
  277. slapi_entry_attr_set_charptr (e, attr_changetime, timeStr);
  278. slapi_ch_free((void**)&timeStr);
  279. /*
  280. * Finish constructing the entry. How to do it depends on the type
  281. * of modification being logged.
  282. */
  283. switch (op->operation_type)
  284. {
  285. case SLAPI_OPERATION_ADD: if (entry2reple(e, op->p.p_add.target_entry) != 0 )
  286. {
  287. rc = CL4_INTERNAL_ERROR;
  288. goto done;
  289. }
  290. break;
  291. case SLAPI_OPERATION_MODIFY: if (mods2reple(e, op->p.p_modify.modify_mods) != 0)
  292. {
  293. rc = CL4_INTERNAL_ERROR;
  294. goto done;
  295. }
  296. break;
  297. case SLAPI_OPERATION_MODDN: if (modrdn2reple(e, op->p.p_modrdn.modrdn_newrdn,
  298. op->p.p_modrdn.modrdn_deloldrdn, op->p.p_modrdn.modrdn_mods) != 0)
  299. {
  300. rc = CL4_INTERNAL_ERROR;
  301. goto done;
  302. }
  303. break;
  304. case SLAPI_OPERATION_DELETE: /* Set the changetype attribute */
  305. slapi_entry_attr_set_charptr (e, attr_changetype, "delete");
  306. break;
  307. }
  308. pb = slapi_pblock_new (pb);
  309. slapi_add_entry_internal_set_pb (pb, e, NULL, repl_get_plugin_identity (PLUGIN_LEGACY_REPLICATION), 0);
  310. slapi_add_internal_pb (pb);
  311. e = NULL; /* add consumes entry */
  312. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
  313. slapi_pblock_destroy(pb);
  314. if (res != LDAP_SUCCESS)
  315. {
  316. char s[CSN_STRSIZE];
  317. slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
  318. "_cl4WriteEntry: an error occured while adding change entry with csn %s, dn = %s: %s. "
  319. "Logging of changes is disabled.\n", csn_as_string(op->csn,PR_FALSE,s), op->target_address.dn,
  320. ldap_err2string(res));
  321. /* GGOODREPL g_set_repl_backend( NULL ); */
  322. rc = CL4_LDAP_ERROR;
  323. }
  324. done:
  325. slapi_entry_free(e);
  326. if (changeEntryDN)
  327. slapi_ch_free((void **) &changeEntryDN);
  328. return rc;
  329. }
  330. static void _cl4AssignCSNCallback (const CSN *csn, void *data)
  331. {
  332. int rc;
  333. if (csn == NULL)
  334. {
  335. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4AssignCSNCallback: null csn\n");
  336. return;
  337. }
  338. rc = csnplInsert (s_cl4Desc.csnPL, csn);
  339. if (rc == -1)
  340. {
  341. char s[CSN_STRSIZE];
  342. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  343. "_cl4AssignCSNCallback: failed to insert csn %s to the pending list\n",
  344. csn_as_string(csn,PR_FALSE,s));
  345. }
  346. }
  347. static void _cl4AbortCSNCallback (const CSN *csn, void *data)
  348. {
  349. int rc;
  350. if (csn == NULL)
  351. {
  352. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4AbortCSNCallback: null csn\n");
  353. return;
  354. }
  355. rc = csnplRemove (s_cl4Desc.csnPL, csn);
  356. if (rc == -1)
  357. {
  358. char s[CSN_STRSIZE];
  359. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  360. "_cl4AbortCSNCallback: failed to remove csn %s from the pending list\n",
  361. csn_as_string(csn,PR_FALSE,s));
  362. }
  363. }
  364. /* initial dn format: csn=<csn>,<changelog suffix>. For instance, csn=013744022939465,cn=changelog4 */
  365. static char* _cl4MakeCSNDN (const CSN* csn)
  366. {
  367. char *pat, *edn;
  368. char *suffix = changelog4_get_suffix ();
  369. char s[CSN_STRSIZE];
  370. if (suffix == NULL)
  371. return NULL;
  372. /* Construct the dn of this change record */
  373. edn = slapi_ch_smprintf("%s=%s,%s", attr_csn, csn_as_string(csn,PR_FALSE,s), suffix);
  374. slapi_ch_free ((void **)&suffix);
  375. return edn;
  376. }
  377. static int _cl4GetEntry (const CSN *csn, Slapi_Entry **entry)
  378. {
  379. int rc;
  380. char *suffix = changelog4_get_suffix ();
  381. int type;
  382. const char *value;
  383. CL4Ret ret;
  384. char s[CSN_STRSIZE];
  385. if (csn == NULL) /* entry with smallest csn */
  386. {
  387. type = SLAPI_SEQ_FIRST;
  388. value = NULL;
  389. }
  390. else /* entry with next csn */
  391. {
  392. type = SLAPI_SEQ_NEXT;
  393. value = csn_as_string(csn,PR_FALSE,s);
  394. }
  395. rc = slapi_seq_callback(suffix, type, attr_csn, (char*)value, NULL, 0, &ret, NULL,
  396. _cl4ResultCallback, _cl4EntryCallback, NULL);
  397. slapi_ch_free ((void**)&suffix);
  398. if (rc != 0 || ret.err != 0)
  399. {
  400. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4GetEntry: failed to get next changelog entry\n");
  401. return CL4_INTERNAL_ERROR;
  402. }
  403. *entry = ret.e;
  404. return CL4_SUCCESS;
  405. }
  406. static void _cl4ResultCallback (int err, void *callback_data)
  407. {
  408. CL4Ret *ret = (CL4Ret *)callback_data;
  409. if (ret)
  410. {
  411. ret->err = err;
  412. }
  413. }
  414. static int _cl4EntryCallback (Slapi_Entry *e, void *callback_data)
  415. {
  416. CL4Ret *ret = (CL4Ret *)callback_data;
  417. if (ret)
  418. {
  419. ret->e = slapi_entry_dup (e);
  420. }
  421. return 0;
  422. }
  423. static PRBool _cl4CanAssignChangeNumber (const CSN *csn)
  424. {
  425. CSN *commitCSN = NULL;
  426. /* th CSN is withtin region that can be commited */
  427. if (csn && csn_compare(csn, commitCSN) < 0)
  428. return PR_TRUE;
  429. return PR_FALSE;
  430. }
  431. /* ONREPL - describe algorithm */
  432. static int _cl4ResolveTargetDN (Slapi_Entry *entry, Slapi_DN **newTargetDN)
  433. {
  434. int rc;
  435. char *csnStr = slapi_entry_attr_get_charptr (entry, attr_csn);
  436. char *targetdn = slapi_entry_attr_get_charptr (entry, attr_targetdn);
  437. const char *uniqueid = slapi_entry_get_uniqueid (entry);
  438. char *changetype = slapi_entry_attr_get_charptr (entry, attr_changetype);
  439. CSN *csn = csn_new_by_string (csnStr);
  440. Slapi_Entry *targetEntry = NULL;
  441. const Slapi_DN *teSDN;
  442. Slapi_DN *targetSDN;
  443. const CSN *teDNCSN = NULL;
  444. *newTargetDN = NULL;
  445. targetSDN = slapi_sdn_new();
  446. if (strcasecmp (changetype, "add") == 0) /* this is add operation - we have rawdn */
  447. slapi_sdn_set_dn_byref (targetSDN, targetdn);
  448. else
  449. slapi_sdn_set_normdn_byref (targetSDN, targetdn);
  450. /* read the entry to which the change was applied */
  451. rc = _cl4GetTargetEntry (targetSDN, uniqueid, &targetEntry);
  452. if (rc != CL4_SUCCESS)
  453. {
  454. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4ResolveTargetDN: failed to get target entry\n");
  455. goto done;
  456. }
  457. teDNCSN = entry_get_dncsn(targetEntry);
  458. if (teDNCSN == NULL)
  459. {
  460. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4ResolveTargetDN: failed to get target entry dn\n");
  461. rc = CL4_BAD_FORMAT;
  462. goto done;
  463. }
  464. if (csn_compare(teDNCSN, csn) <= 0)
  465. {
  466. /* the change entry target dn should be the same as target entry dn */
  467. teSDN = slapi_entry_get_sdn_const(targetEntry);
  468. /* target dn of change entry is not the same as dn of the target entry - update */
  469. if (slapi_sdn_compare (teSDN, targetSDN) != 0)
  470. {
  471. *newTargetDN = slapi_sdn_dup (targetSDN);
  472. }
  473. }
  474. else /* the target entry was renamed since this change occur - find the right target dn */
  475. {
  476. rc = _cl4FindTargetDN (csn, uniqueid, targetSDN, newTargetDN);
  477. }
  478. done:;
  479. if (csnStr)
  480. slapi_ch_free ((void**)&csnStr);
  481. if (targetdn)
  482. slapi_ch_free ((void**)&targetdn);
  483. if (uniqueid)
  484. slapi_ch_free ((void**)&uniqueid);
  485. if (changetype)
  486. slapi_ch_free ((void**)&changetype);
  487. if (targetEntry)
  488. slapi_entry_free (targetEntry);
  489. if (targetSDN)
  490. slapi_sdn_free (&targetSDN);
  491. return rc;
  492. }
  493. static int _cl4GetTargetEntry (Slapi_DN *sdn, const char *uniqueid, Slapi_Entry **entry)
  494. {
  495. Slapi_PBlock *pb;
  496. char filter [128];
  497. int res, rc = CL4_SUCCESS;
  498. Slapi_Entry **entries = NULL;
  499. /* read corresponding database entry based on its uniqueid */
  500. PR_snprintf (filter, sizeof(filter), "uniqueid=%s", uniqueid);
  501. pb = slapi_pblock_new ();
  502. slapi_search_internal_set_pb (pb, (char*)slapi_sdn_get_ndn(sdn), LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL,
  503. repl_get_plugin_identity (PLUGIN_LEGACY_REPLICATION), 0);
  504. slapi_search_internal_pb (pb);
  505. if (pb == NULL)
  506. {
  507. rc = CL4_LDAP_ERROR;
  508. goto done;
  509. }
  510. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
  511. if (res == LDAP_NO_SUCH_OBJECT) /* entry not found */
  512. {
  513. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4GetTargetEntry: entry (%s) not found\n",
  514. slapi_sdn_get_ndn(sdn));
  515. rc = CL4_NOT_FOUND;
  516. goto done;
  517. }
  518. if (res != LDAP_SUCCESS)
  519. {
  520. slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
  521. "_cl4ResolveTargetDN: an error occured while searching for directory entry with uniqueid %s: %s. "
  522. "Logging of changes is disabled.\n", uniqueid, ldap_err2string(res));
  523. /* GGOODREPL g_set_repl_backend( NULL ); */
  524. rc = CL4_LDAP_ERROR;
  525. goto done;
  526. }
  527. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  528. if (entries == NULL || entries [0] == NULL)
  529. {
  530. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4GetTargetEntry: entry (%s) not found\n",
  531. slapi_sdn_get_ndn(sdn));
  532. rc = CL4_NOT_FOUND;
  533. goto done;
  534. }
  535. *entry = slapi_entry_dup (entries[0]);
  536. done:
  537. if (pb)
  538. {
  539. slapi_free_search_results_internal(pb);
  540. slapi_pblock_destroy (pb);
  541. }
  542. return rc;
  543. }
  544. static int _cl4FindTargetDN (const CSN *csn, const char *uniqueid,
  545. const Slapi_DN *targetSDN, Slapi_DN **newTargetDN)
  546. {
  547. int rc = CL4_SUCCESS;
  548. int res, i;
  549. Slapi_PBlock *pb;
  550. char *suffix = changelog4_get_suffix ();
  551. char filter [128];
  552. Slapi_Entry **entries;
  553. int minIndex = 0;
  554. CSN *minCSN = NULL, *curCSN;
  555. char *curType;
  556. const Slapi_DN *sdn;
  557. char s[CSN_STRSIZE];
  558. *newTargetDN = NULL;
  559. /* Look for all modifications to the target entry with csn larger than
  560. this csn. We are only interested in rename operations, but change type
  561. is currently not indexed */
  562. PR_snprintf (filter, 128, "&(uniqueid=%s)(csn>%s)", uniqueid, csn_as_string(csn,PR_FALSE,s));
  563. pb = slapi_pblock_new ();
  564. slapi_search_internal_set_pb (pb, suffix, LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL,
  565. repl_get_plugin_identity (PLUGIN_LEGACY_REPLICATION), 0);
  566. slapi_search_internal_pb (pb);
  567. slapi_ch_free ((void**)&suffix);
  568. if (pb == NULL)
  569. {
  570. rc = CL4_LDAP_ERROR;
  571. goto done;
  572. }
  573. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
  574. if (res == LDAP_NO_SUCH_OBJECT) /* entry not found */
  575. {
  576. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4FindTargetDN: no entries much filter (%s)\n",
  577. filter);
  578. rc = CL4_NOT_FOUND;
  579. goto done;
  580. }
  581. if (res != LDAP_SUCCESS)
  582. {
  583. slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
  584. "_cl4ResolveTargetDN: an error occured while searching change entries matching filter %s: %s. "
  585. "Logging of changes is disabled.\n", filter, ldap_err2string(res));
  586. /* GGOODREPL g_set_repl_backend( NULL ); */
  587. rc = CL4_LDAP_ERROR;
  588. goto done;
  589. }
  590. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  591. if (entries == NULL)
  592. {
  593. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4FindTargetDN: no entries much filter (%s)\n",
  594. filter);
  595. rc = CL4_NOT_FOUND;
  596. goto done;
  597. }
  598. i = 0;
  599. /* find rename operation with smallest csn - its target dn should be the name
  600. of our change entry */
  601. while (entries[i])
  602. {
  603. curType = slapi_entry_attr_get_charptr (entries[i], attr_changetype);
  604. if (curType && strcasecmp (curType, "modrdn") == 0)
  605. {
  606. curCSN = csn_new_by_string (slapi_entry_attr_get_charptr (entries[i], attr_csn));
  607. if (minCSN == NULL || csn_compare (curCSN, minCSN) < 0)
  608. {
  609. minCSN = curCSN;
  610. minIndex = i;
  611. }
  612. }
  613. if (curType)
  614. slapi_ch_free ((void**)&curType);
  615. i ++;
  616. }
  617. if (curCSN == NULL)
  618. {
  619. rc = CL4_NOT_FOUND;
  620. goto done;
  621. }
  622. /* update targetDN of our entry if necessary */
  623. sdn = slapi_entry_get_sdn_const(entries[minIndex]);
  624. /* target dn does not match to renaming operation - rename change entry */
  625. if (slapi_sdn_compare (sdn, targetSDN) != 0)
  626. *newTargetDN = slapi_sdn_dup (sdn);
  627. done:
  628. if (pb)
  629. {
  630. slapi_free_search_results_internal(pb);
  631. slapi_pblock_destroy (pb);
  632. }
  633. return rc;
  634. }
  635. static int _cl4AssignChangeNumber (changeNumber *cnum)
  636. {
  637. *cnum = ldapi_assign_changenumber();
  638. return CL4_SUCCESS;
  639. }
  640. static int _cl4UpdateEntry (const CSN *csn, const char *changeType,
  641. const Slapi_DN *newDN, changeNumber cnum)
  642. {
  643. Slapi_PBlock *pb;
  644. char *dn;
  645. const char *dnTemp;
  646. int res;
  647. Slapi_Mods smods;
  648. char cnumbuf[32];
  649. if (csn == NULL || changeType == NULL)
  650. {
  651. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4UpdateEntry: invalid argument\n");
  652. return CL4_BAD_DATA;
  653. }
  654. dn = _cl4MakeCSNDN (csn);
  655. if (dn == NULL)
  656. {
  657. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4UpdateEntry: failed to create entry dn\n");
  658. return CL4_MEMORY_ERROR;
  659. }
  660. slapi_mods_init(&smods, 2);
  661. if (newDN)
  662. {
  663. if (strcasecmp (changeType, "add") == 0)
  664. dnTemp = slapi_sdn_get_dn (newDN);
  665. else
  666. dnTemp = slapi_sdn_get_ndn (newDN);
  667. slapi_mods_add(&smods, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, attr_targetdn,
  668. strlen (dnTemp), dnTemp);
  669. }
  670. /* Set the changeNumber attribute */
  671. sprintf(cnumbuf, "%lu", cnum);
  672. slapi_mods_add (&smods, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, attr_changenumber,
  673. strlen (cnumbuf), cnumbuf);
  674. pb = slapi_pblock_new ();
  675. slapi_modify_internal_set_pb (pb, dn, slapi_mods_get_ldapmods_byref(&smods), NULL, NULL,
  676. repl_get_plugin_identity (PLUGIN_LEGACY_REPLICATION), 0);
  677. slapi_modify_internal_pb (pb);
  678. slapi_mods_done(&smods);
  679. slapi_ch_free ((void**)&dn);
  680. if (pb == NULL)
  681. {
  682. return CL4_LDAP_ERROR;
  683. }
  684. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
  685. slapi_pblock_destroy(pb);
  686. if (res != LDAP_SUCCESS)
  687. {
  688. char s[CSN_STRSIZE];
  689. slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
  690. "cl4ChangeTargetDN: an error occured while modifying change entry with csn %s: %s. "
  691. "Logging of changes is disabled.\n", csn_as_string(csn,PR_FALSE,s), ldap_err2string(res));
  692. /* GGOODREPL g_set_repl_backend( NULL ); */
  693. return CL4_LDAP_ERROR;
  694. }
  695. if ( ldapi_get_first_changenumber() == (changeNumber) 0L )
  696. {
  697. ldapi_set_first_changenumber( cnum );
  698. }
  699. ldapi_commit_changenumber(cnum);
  700. return CL4_SUCCESS;
  701. }