repl5_replica_config.c 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126
  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. /* repl5_replica_config.c - replica configuration over ldap */
  42. #include <ctype.h> /* for isdigit() */
  43. #include "repl.h" /* ONREPL - this is bad */
  44. #include "repl5.h"
  45. #include "cl5_api.h"
  46. #include "cl5.h"
  47. /* CONFIG_BASE: no need to optimize */
  48. #define CONFIG_BASE "cn=mapping tree,cn=config"
  49. #define CONFIG_FILTER "(objectclass=nsDS5Replica)"
  50. #define TASK_ATTR "nsds5Task"
  51. #define CL2LDIF_TASK "CL2LDIF"
  52. #define LDIF2CL_TASK "LDIF2CL"
  53. #define CLEANRUV "CLEANRUV"
  54. #define CLEANRUVLEN 8
  55. #define REPLICA_RDN "cn=replica"
  56. int slapi_log_urp = SLAPI_LOG_REPL;
  57. /* Forward Declartions */
  58. static int replica_config_add (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
  59. static int replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
  60. static int replica_config_post_modify (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
  61. static int replica_config_delete (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
  62. static int replica_config_search (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
  63. static int replica_config_change_type_and_id (Replica *r, const char *new_type, const char *new_id, char *returntext, int apply_mods);
  64. static int replica_config_change_updatedn (Replica *r, const LDAPMod *mod, char *returntext, int apply_mods);
  65. static int replica_config_change_flags (Replica *r, const char *new_flags, char *returntext, int apply_mods);
  66. static int replica_execute_task (Object *r, const char *task_name, char *returntext, int apply_mods);
  67. static int replica_execute_cl2ldif_task (Object *r, char *returntext);
  68. static int replica_execute_ldif2cl_task (Object *r, char *returntext);
  69. static int replica_execute_cleanruv_task (Object *r, ReplicaId rid, char *returntext);
  70. static int replica_cleanup_task (Object *r, const char *task_name, char *returntext, int apply_mods);
  71. static int replica_task_done(Replica *replica);
  72. static multimaster_mtnode_extension * _replica_config_get_mtnode_ext (const Slapi_Entry *e);
  73. static PRLock *s_configLock;
  74. static int
  75. dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
  76. {
  77. *returncode = LDAP_UNWILLING_TO_PERFORM;
  78. return SLAPI_DSE_CALLBACK_ERROR;
  79. }
  80. int
  81. replica_config_init()
  82. {
  83. s_configLock = PR_NewLock ();
  84. if (s_configLock == NULL)
  85. {
  86. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_init: "
  87. "failed to cretate configuration lock; NSPR error - %d\n",
  88. PR_GetError ());
  89. return -1;
  90. }
  91. /* config DSE must be initialized before we get here */
  92. slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  93. CONFIG_FILTER, replica_config_add, NULL);
  94. slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  95. CONFIG_FILTER, replica_config_modify,NULL);
  96. slapi_config_register_callback(SLAPI_OPERATION_MODRDN, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  97. CONFIG_FILTER, dont_allow_that, NULL);
  98. slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  99. CONFIG_FILTER, replica_config_delete,NULL);
  100. slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  101. CONFIG_FILTER, replica_config_search,NULL);
  102. slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_POSTOP,
  103. CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  104. CONFIG_FILTER, replica_config_post_modify,
  105. NULL);
  106. return 0;
  107. }
  108. void
  109. replica_config_destroy ()
  110. {
  111. if (s_configLock)
  112. {
  113. PR_DestroyLock (s_configLock);
  114. s_configLock = NULL;
  115. }
  116. /* config DSE must be initialized before we get here */
  117. slapi_config_remove_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  118. CONFIG_FILTER, replica_config_add);
  119. slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  120. CONFIG_FILTER, replica_config_modify);
  121. slapi_config_remove_callback(SLAPI_OPERATION_MODRDN, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  122. CONFIG_FILTER, dont_allow_that);
  123. slapi_config_remove_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  124. CONFIG_FILTER, replica_config_delete);
  125. slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  126. CONFIG_FILTER, replica_config_search);
  127. slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP,
  128. CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  129. CONFIG_FILTER, replica_config_post_modify);
  130. }
  131. static int
  132. replica_config_add (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
  133. int *returncode, char *errorbuf, void *arg)
  134. {
  135. Replica *r = NULL;
  136. multimaster_mtnode_extension *mtnode_ext;
  137. char *replica_root = (char*)slapi_entry_attr_get_charptr (e, attr_replicaRoot);
  138. char buf [SLAPI_DSE_RETURNTEXT_SIZE];
  139. char *errortext = errorbuf ? errorbuf : buf;
  140. if (errorbuf)
  141. {
  142. errorbuf[0] = '\0';
  143. }
  144. *returncode = LDAP_SUCCESS;
  145. PR_Lock (s_configLock);
  146. /* add the dn to the dn hash so we can tell this replica is being configured */
  147. replica_add_by_dn(replica_root);
  148. mtnode_ext = _replica_config_get_mtnode_ext (e);
  149. PR_ASSERT (mtnode_ext);
  150. if (mtnode_ext->replica)
  151. {
  152. PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "replica already configured for %s", replica_root);
  153. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_add: %s\n", errortext);
  154. *returncode = LDAP_UNWILLING_TO_PERFORM;
  155. goto done;
  156. }
  157. /* create replica object */
  158. r = replica_new_from_entry (e, errortext, PR_TRUE /* is a newly added entry */);
  159. if (r == NULL)
  160. {
  161. *returncode = LDAP_OPERATIONS_ERROR;
  162. goto done;
  163. }
  164. /* Set the mapping tree node state, and the referrals from the RUV */
  165. /* if this server is a 4.0 consumer the referrals are set by legacy plugin */
  166. if (!replica_is_legacy_consumer (r))
  167. consumer5_set_mapping_tree_state_for_replica(r, NULL);
  168. /* ONREPL if replica is added as writable we need to execute protocol that
  169. introduces new writable replica to the topology */
  170. mtnode_ext->replica = object_new (r, replica_destroy); /* Refcnt is 1 */
  171. /* add replica object to the hash */
  172. *returncode = replica_add_by_name (replica_get_name (r), mtnode_ext->replica); /* Increments object refcnt */
  173. /* delete the dn from the dn hash - done with configuration */
  174. replica_delete_by_dn(replica_root);
  175. done:
  176. PR_Unlock (s_configLock);
  177. /* slapi_ch_free accepts NULL pointer */
  178. slapi_ch_free ((void**)&replica_root);
  179. if (*returncode != LDAP_SUCCESS)
  180. {
  181. if (mtnode_ext->replica)
  182. object_release (mtnode_ext->replica);
  183. return SLAPI_DSE_CALLBACK_ERROR;
  184. }
  185. else
  186. return SLAPI_DSE_CALLBACK_OK;
  187. }
  188. static int
  189. replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
  190. int *returncode, char *returntext, void *arg)
  191. {
  192. int rc= 0;
  193. LDAPMod **mods;
  194. int i, apply_mods;
  195. multimaster_mtnode_extension *mtnode_ext;
  196. Replica *r = NULL;
  197. char *replica_root = NULL;
  198. char buf [SLAPI_DSE_RETURNTEXT_SIZE];
  199. char *errortext = returntext ? returntext : buf;
  200. char *config_attr, *config_attr_value;
  201. Slapi_Operation *op;
  202. void *identity;
  203. if (returntext)
  204. {
  205. returntext[0] = '\0';
  206. }
  207. *returncode = LDAP_SUCCESS;
  208. /* just let internal operations originated from replication plugin to go through */
  209. slapi_pblock_get (pb, SLAPI_OPERATION, &op);
  210. slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);
  211. if (operation_is_flag_set(op, OP_FLAG_INTERNAL) &&
  212. (identity == repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION)))
  213. {
  214. *returncode = LDAP_SUCCESS;
  215. return SLAPI_DSE_CALLBACK_OK;
  216. }
  217. replica_root = (char*)slapi_entry_attr_get_charptr (e, attr_replicaRoot);
  218. PR_Lock (s_configLock);
  219. mtnode_ext = _replica_config_get_mtnode_ext (e);
  220. PR_ASSERT (mtnode_ext);
  221. if (mtnode_ext->replica)
  222. object_acquire (mtnode_ext->replica);
  223. if (mtnode_ext->replica == NULL)
  224. {
  225. PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "replica does not exist for %s", replica_root);
  226. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n",
  227. errortext);
  228. *returncode = LDAP_OPERATIONS_ERROR;
  229. goto done;
  230. }
  231. r = object_get_data (mtnode_ext->replica);
  232. PR_ASSERT (r);
  233. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  234. for (apply_mods = 0; apply_mods <= 1; apply_mods++)
  235. {
  236. /* we only allow the replica ID and type to be modified together e.g.
  237. if converting a read only replica to a master or vice versa -
  238. we will need to change both the replica ID and the type at the same
  239. time - we must disallow changing the replica ID if the type is not
  240. being changed and vice versa
  241. */
  242. char *new_repl_id = NULL;
  243. char *new_repl_type = NULL;
  244. if (*returncode != LDAP_SUCCESS)
  245. break;
  246. for (i = 0; (mods[i] && (LDAP_SUCCESS == rc)); i++)
  247. {
  248. if (*returncode != LDAP_SUCCESS)
  249. break;
  250. config_attr = (char *) mods[i]->mod_type;
  251. PR_ASSERT (config_attr);
  252. /* disallow modifications or removal of replica root,
  253. replica name and replica state attributes */
  254. if (strcasecmp (config_attr, attr_replicaRoot) == 0 ||
  255. strcasecmp (config_attr, attr_replicaName) == 0 ||
  256. strcasecmp (config_attr, attr_state) == 0)
  257. {
  258. *returncode = LDAP_UNWILLING_TO_PERFORM;
  259. PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "modification of %s attribute is not allowed",
  260. config_attr);
  261. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n",
  262. errortext);
  263. }
  264. /* this is a request to delete an attribute */
  265. else if (mods[i]->mod_op & LDAP_MOD_DELETE || mods[i]->mod_bvalues == NULL
  266. || mods[i]->mod_bvalues[0]->bv_val == NULL)
  267. {
  268. /* currently, you can only remove referral,
  269. legacy consumer or bind dn attribute */
  270. if (strcasecmp (config_attr, attr_replicaBindDn) == 0)
  271. {
  272. *returncode = replica_config_change_updatedn (r, mods[i], errortext, apply_mods);
  273. }
  274. else if (strcasecmp (config_attr, attr_replicaReferral) == 0)
  275. {
  276. if (apply_mods) {
  277. replica_set_referrals(r, NULL);
  278. if (!replica_is_legacy_consumer (r)) {
  279. consumer5_set_mapping_tree_state_for_replica(r, NULL);
  280. }
  281. }
  282. }
  283. else if (strcasecmp (config_attr, type_replicaLegacyConsumer) == 0)
  284. {
  285. if (apply_mods)
  286. replica_set_legacy_consumer (r, PR_FALSE);
  287. }
  288. else
  289. {
  290. *returncode = LDAP_UNWILLING_TO_PERFORM;
  291. PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "deletion of %s attribute is not allowed", config_attr);
  292. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n",
  293. errortext);
  294. }
  295. }
  296. else /* modify an attribute */
  297. {
  298. config_attr_value = (char *) mods[i]->mod_bvalues[0]->bv_val;
  299. if (strcasecmp (config_attr, attr_replicaBindDn) == 0)
  300. {
  301. *returncode = replica_config_change_updatedn (r, mods[i],
  302. errortext, apply_mods);
  303. }
  304. else if (strcasecmp (config_attr, attr_replicaType) == 0)
  305. {
  306. new_repl_type = slapi_ch_strdup(config_attr_value);
  307. }
  308. else if (strcasecmp (config_attr, attr_replicaId) == 0)
  309. {
  310. new_repl_id = slapi_ch_strdup(config_attr_value);
  311. }
  312. else if (strcasecmp (config_attr, attr_flags) == 0)
  313. {
  314. *returncode = replica_config_change_flags (r, config_attr_value,
  315. errortext, apply_mods);
  316. }
  317. else if (strcasecmp (config_attr, TASK_ATTR) == 0)
  318. {
  319. *returncode = replica_execute_task (mtnode_ext->replica, config_attr_value,
  320. errortext, apply_mods);
  321. }
  322. else if (strcasecmp (config_attr, attr_replicaReferral) == 0)
  323. {
  324. if (apply_mods)
  325. {
  326. Slapi_Mod smod;
  327. Slapi_ValueSet *vs= slapi_valueset_new();
  328. slapi_mod_init_byref(&smod,mods[i]);
  329. slapi_valueset_set_from_smod(vs, &smod);
  330. replica_set_referrals (r, vs);
  331. slapi_mod_done(&smod);
  332. slapi_valueset_free(vs);
  333. if (!replica_is_legacy_consumer (r)) {
  334. consumer5_set_mapping_tree_state_for_replica(r, NULL);
  335. }
  336. }
  337. }
  338. else if (strcasecmp (config_attr, type_replicaPurgeDelay) == 0)
  339. {
  340. if (apply_mods && config_attr_value && config_attr_value[0])
  341. {
  342. PRUint32 delay;
  343. if (isdigit (config_attr_value[0]))
  344. {
  345. delay = (unsigned int)atoi(config_attr_value);
  346. replica_set_purge_delay(r, delay);
  347. }
  348. else
  349. *returncode = LDAP_OPERATIONS_ERROR;
  350. }
  351. }
  352. else if (strcasecmp (config_attr, type_replicaTombstonePurgeInterval) == 0)
  353. {
  354. if (apply_mods && config_attr_value && config_attr_value[0])
  355. {
  356. long interval;
  357. interval = atol (config_attr_value);
  358. replica_set_tombstone_reap_interval (r, interval);
  359. }
  360. }
  361. else if (strcasecmp (config_attr, type_replicaLegacyConsumer) == 0)
  362. {
  363. if (apply_mods)
  364. {
  365. PRBool legacy = (strcasecmp (config_attr_value, "on") == 0) ||
  366. (strcasecmp (config_attr_value, "true") == 0) ||
  367. (strcasecmp (config_attr_value, "yes") == 0) ||
  368. (strcasecmp (config_attr_value, "1") == 0);
  369. replica_set_legacy_consumer (r, legacy);
  370. }
  371. }
  372. /* ignore modifiers attributes added by the server */
  373. else if (strcasecmp (config_attr, "modifytimestamp") == 0 ||
  374. strcasecmp (config_attr, "modifiersname") == 0)
  375. {
  376. *returncode = LDAP_SUCCESS;
  377. }
  378. else
  379. {
  380. *returncode = LDAP_UNWILLING_TO_PERFORM;
  381. PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE,
  382. "modification of attribute %s is not allowed in replica entry", config_attr);
  383. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n",
  384. errortext);
  385. }
  386. }
  387. }
  388. if (new_repl_id || new_repl_type)
  389. {
  390. *returncode = replica_config_change_type_and_id(r, new_repl_type,
  391. new_repl_id, errortext,
  392. apply_mods);
  393. slapi_ch_free_string(&new_repl_id);
  394. slapi_ch_free_string(&new_repl_type);
  395. }
  396. }
  397. done:
  398. if (mtnode_ext->replica)
  399. object_release (mtnode_ext->replica);
  400. /* slapi_ch_free accepts NULL pointer */
  401. slapi_ch_free ((void**)&replica_root);
  402. PR_Unlock (s_configLock);
  403. if (*returncode != LDAP_SUCCESS)
  404. {
  405. return SLAPI_DSE_CALLBACK_ERROR;
  406. }
  407. else
  408. {
  409. return SLAPI_DSE_CALLBACK_OK;
  410. }
  411. }
  412. static int
  413. replica_config_post_modify(Slapi_PBlock *pb,
  414. Slapi_Entry* entryBefore,
  415. Slapi_Entry* e,
  416. int *returncode,
  417. char *returntext,
  418. void *arg)
  419. {
  420. int rc= 0;
  421. LDAPMod **mods;
  422. int i, apply_mods;
  423. multimaster_mtnode_extension *mtnode_ext;
  424. Replica *r = NULL;
  425. char *replica_root = NULL;
  426. char buf [SLAPI_DSE_RETURNTEXT_SIZE];
  427. char *errortext = returntext ? returntext : buf;
  428. char *config_attr, *config_attr_value;
  429. Slapi_Operation *op;
  430. void *identity;
  431. if (returntext)
  432. {
  433. returntext[0] = '\0';
  434. }
  435. *returncode = LDAP_SUCCESS;
  436. /* just let internal operations originated from replication plugin to go through */
  437. slapi_pblock_get (pb, SLAPI_OPERATION, &op);
  438. slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);
  439. if (operation_is_flag_set(op, OP_FLAG_INTERNAL) &&
  440. (identity == repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION)))
  441. {
  442. *returncode = LDAP_SUCCESS;
  443. return SLAPI_DSE_CALLBACK_OK;
  444. }
  445. replica_root = (char*)slapi_entry_attr_get_charptr (e, attr_replicaRoot);
  446. PR_Lock (s_configLock);
  447. mtnode_ext = _replica_config_get_mtnode_ext (e);
  448. PR_ASSERT (mtnode_ext);
  449. if (mtnode_ext->replica)
  450. object_acquire (mtnode_ext->replica);
  451. if (mtnode_ext->replica == NULL)
  452. {
  453. PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE,
  454. "replica does not exist for %s", replica_root);
  455. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  456. "replica_config_post_modify: %s\n",
  457. errortext);
  458. *returncode = LDAP_OPERATIONS_ERROR;
  459. goto done;
  460. }
  461. r = object_get_data (mtnode_ext->replica);
  462. PR_ASSERT (r);
  463. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  464. for (apply_mods = 0; apply_mods <= 1; apply_mods++)
  465. {
  466. /* we only allow the replica ID and type to be modified together e.g.
  467. if converting a read only replica to a master or vice versa -
  468. we will need to change both the replica ID and the type at the same
  469. time - we must disallow changing the replica ID if the type is not
  470. being changed and vice versa
  471. */
  472. if (*returncode != LDAP_SUCCESS)
  473. break;
  474. for (i = 0; (mods[i] && (LDAP_SUCCESS == rc)); i++)
  475. {
  476. if (*returncode != LDAP_SUCCESS)
  477. break;
  478. config_attr = (char *) mods[i]->mod_type;
  479. PR_ASSERT (config_attr);
  480. /* disallow modifications or removal of replica root,
  481. replica name and replica state attributes */
  482. if (strcasecmp (config_attr, attr_replicaRoot) == 0 ||
  483. strcasecmp (config_attr, attr_replicaName) == 0 ||
  484. strcasecmp (config_attr, attr_state) == 0)
  485. {
  486. *returncode = LDAP_UNWILLING_TO_PERFORM;
  487. PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE,
  488. "modification of %s attribute is not allowed",
  489. config_attr);
  490. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  491. "replica_config_post_modify: %s\n",
  492. errortext);
  493. }
  494. /* this is a request to delete an attribute */
  495. else if (mods[i]->mod_op & LDAP_MOD_DELETE ||
  496. mods[i]->mod_bvalues == NULL ||
  497. mods[i]->mod_bvalues[0]->bv_val == NULL)
  498. {
  499. ;
  500. }
  501. else /* modify an attribute */
  502. {
  503. config_attr_value = (char *) mods[i]->mod_bvalues[0]->bv_val;
  504. if (strcasecmp (config_attr, TASK_ATTR) == 0)
  505. {
  506. *returncode = replica_cleanup_task(mtnode_ext->replica,
  507. config_attr_value,
  508. errortext, apply_mods);
  509. }
  510. }
  511. }
  512. }
  513. done:
  514. if (mtnode_ext->replica)
  515. object_release (mtnode_ext->replica);
  516. /* slapi_ch_free accepts NULL pointer */
  517. slapi_ch_free ((void**)&replica_root);
  518. PR_Unlock (s_configLock);
  519. if (*returncode != LDAP_SUCCESS)
  520. {
  521. return SLAPI_DSE_CALLBACK_ERROR;
  522. }
  523. else
  524. {
  525. return SLAPI_DSE_CALLBACK_OK;
  526. }
  527. }
  528. static int
  529. replica_config_delete (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
  530. int *returncode, char *returntext, void *arg)
  531. {
  532. multimaster_mtnode_extension *mtnode_ext;
  533. Replica *r;
  534. PR_Lock (s_configLock);
  535. mtnode_ext = _replica_config_get_mtnode_ext (e);
  536. PR_ASSERT (mtnode_ext);
  537. if (mtnode_ext->replica)
  538. {
  539. char ebuf[BUFSIZ];
  540. /* remove object from the hash */
  541. r = (Replica*)object_get_data (mtnode_ext->replica);
  542. PR_ASSERT (r);
  543. /* The changelog for this replica is no longer valid, so we should remove it. */
  544. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_delete: "
  545. "Warning: The changelog for replica %s is no longer valid since "
  546. "the replica config is being deleted. Removing the changelog.\n",
  547. escape_string(slapi_sdn_get_dn(replica_get_root(r)),ebuf));
  548. cl5DeleteDBSync(mtnode_ext->replica);
  549. replica_delete_by_name (replica_get_name (r));
  550. object_release (mtnode_ext->replica);
  551. mtnode_ext->replica = NULL;
  552. }
  553. PR_Unlock (s_configLock);
  554. *returncode = LDAP_SUCCESS;
  555. return SLAPI_DSE_CALLBACK_OK;
  556. }
  557. static int
  558. replica_config_search (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode,
  559. char *returntext, void *arg)
  560. {
  561. multimaster_mtnode_extension *mtnode_ext;
  562. int changeCount = 0;
  563. PRBool reapActive = PR_FALSE;
  564. char val [64];
  565. /* add attribute that contains number of entries in the changelog for this replica */
  566. PR_Lock (s_configLock);
  567. mtnode_ext = _replica_config_get_mtnode_ext (e);
  568. PR_ASSERT (mtnode_ext);
  569. if (mtnode_ext->replica) {
  570. Replica *replica;
  571. object_acquire (mtnode_ext->replica);
  572. if (cl5GetState () == CL5_STATE_OPEN) {
  573. changeCount = cl5GetOperationCount (mtnode_ext->replica);
  574. }
  575. replica = (Replica*)object_get_data (mtnode_ext->replica);
  576. if (replica) {
  577. reapActive = replica_get_tombstone_reap_active(replica);
  578. }
  579. object_release (mtnode_ext->replica);
  580. }
  581. sprintf (val, "%d", changeCount);
  582. slapi_entry_add_string (e, type_replicaChangeCount, val);
  583. slapi_entry_attr_set_int(e, "nsds5replicaReapActive", (int)reapActive);
  584. PR_Unlock (s_configLock);
  585. return SLAPI_DSE_CALLBACK_OK;
  586. }
  587. static int
  588. replica_config_change_type_and_id (Replica *r, const char *new_type,
  589. const char *new_id, char *returntext,
  590. int apply_mods)
  591. {
  592. int type;
  593. ReplicaType oldtype;
  594. ReplicaId rid;
  595. ReplicaId oldrid;
  596. PR_ASSERT (r);
  597. oldtype = replica_get_type(r);
  598. oldrid = replica_get_rid(r);
  599. if (new_type == NULL) /* by default - replica is read-only */
  600. {
  601. type = REPLICA_TYPE_READONLY;
  602. }
  603. else
  604. {
  605. type = atoi (new_type);
  606. if (type <= REPLICA_TYPE_UNKNOWN || type >= REPLICA_TYPE_END)
  607. {
  608. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "invalid replica type %d", type);
  609. return LDAP_OPERATIONS_ERROR;
  610. }
  611. }
  612. /* disallow changing type to itself just to permit a replica ID change */
  613. if (oldtype == type)
  614. {
  615. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "replica type is already %d - not changing", type);
  616. return LDAP_OPERATIONS_ERROR;
  617. }
  618. if (type == REPLICA_TYPE_READONLY)
  619. {
  620. rid = READ_ONLY_REPLICA_ID; /* default rid for read only */
  621. }
  622. else if (!new_id)
  623. {
  624. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "a replica ID is required when changing replica type to read-write");
  625. return LDAP_UNWILLING_TO_PERFORM;
  626. }
  627. else
  628. {
  629. int temprid = atoi (new_id);
  630. if (temprid <= 0 || temprid >= READ_ONLY_REPLICA_ID)
  631. {
  632. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  633. "attribute %s must have a value greater than 0 "
  634. "and less than %d",
  635. attr_replicaId, READ_ONLY_REPLICA_ID);
  636. return LDAP_UNWILLING_TO_PERFORM;
  637. }
  638. else
  639. {
  640. rid = (ReplicaId)temprid;
  641. }
  642. }
  643. /* error if old rid == new rid */
  644. if (oldrid == rid)
  645. {
  646. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "replica ID is already %d - not changing", rid);
  647. return LDAP_OPERATIONS_ERROR;
  648. }
  649. if (apply_mods)
  650. {
  651. replica_set_type (r, type);
  652. replica_set_rid(r, rid);
  653. /* Set the mapping tree node, and the list of referrals */
  654. /* if this server is a 4.0 consumer the referrals are set by legacy plugin */
  655. if (!replica_is_legacy_consumer(r))
  656. consumer5_set_mapping_tree_state_for_replica(r, NULL);
  657. }
  658. return LDAP_SUCCESS;
  659. }
  660. static int
  661. replica_config_change_updatedn (Replica *r, const LDAPMod *mod, char *returntext,
  662. int apply_mods)
  663. {
  664. PR_ASSERT (r);
  665. if (apply_mods)
  666. {
  667. Slapi_Mod smod;
  668. Slapi_ValueSet *vs= slapi_valueset_new();
  669. slapi_mod_init_byref(&smod, (LDAPMod *)mod); /* cast away const */
  670. slapi_valueset_set_from_smod(vs, &smod);
  671. replica_set_updatedn(r, vs, mod->mod_op);
  672. slapi_mod_done(&smod);
  673. slapi_valueset_free(vs);
  674. }
  675. return LDAP_SUCCESS;
  676. }
  677. static int replica_config_change_flags (Replica *r, const char *new_flags,
  678. char *returntext, int apply_mods)
  679. {
  680. PR_ASSERT (r);
  681. if (apply_mods)
  682. {
  683. PRUint32 flags;
  684. flags = atol (new_flags);
  685. replica_replace_flags (r, flags);
  686. }
  687. return LDAP_SUCCESS;
  688. }
  689. static int replica_execute_task (Object *r, const char *task_name, char *returntext,
  690. int apply_mods)
  691. {
  692. if (strcasecmp (task_name, CL2LDIF_TASK) == 0)
  693. {
  694. if (apply_mods)
  695. {
  696. return replica_execute_cl2ldif_task (r, returntext);
  697. }
  698. else
  699. return LDAP_SUCCESS;
  700. }
  701. else if (strcasecmp (task_name, LDIF2CL_TASK) == 0)
  702. {
  703. if (apply_mods)
  704. {
  705. return replica_execute_ldif2cl_task (r, returntext);
  706. }
  707. else
  708. return LDAP_SUCCESS;
  709. }
  710. else if (strncasecmp (task_name, CLEANRUV, CLEANRUVLEN) == 0)
  711. {
  712. int temprid = atoi(&(task_name[CLEANRUVLEN]));
  713. if (temprid <= 0 || temprid >= READ_ONLY_REPLICA_ID){
  714. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  715. "Invalid replica id for task - %s", task_name);
  716. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  717. "replica_execute_task: %s\n", returntext);
  718. return LDAP_OPERATIONS_ERROR;
  719. }
  720. if (apply_mods)
  721. {
  722. return replica_execute_cleanruv_task (r, (ReplicaId)temprid, returntext);
  723. }
  724. else
  725. return LDAP_SUCCESS;
  726. }
  727. else
  728. {
  729. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "unsupported replica task - %s", task_name);
  730. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  731. "replica_execute_task: %s\n", returntext);
  732. return LDAP_OPERATIONS_ERROR;
  733. }
  734. }
  735. static int
  736. replica_cleanup_task (Object *r, const char *task_name, char *returntext,
  737. int apply_mods)
  738. {
  739. int rc = LDAP_SUCCESS;
  740. if (apply_mods) {
  741. Replica *replica = (Replica*)object_get_data (r);
  742. if (NULL == replica) {
  743. rc = LDAP_OPERATIONS_ERROR;
  744. } else {
  745. rc = replica_task_done(replica);
  746. }
  747. }
  748. return rc;
  749. }
  750. static int
  751. replica_task_done(Replica *replica)
  752. {
  753. int rc = LDAP_OPERATIONS_ERROR;
  754. char *replica_dn = NULL;
  755. Slapi_PBlock *pb = NULL;
  756. LDAPMod *mods [2];
  757. LDAPMod mod;
  758. if (NULL == replica) {
  759. return rc;
  760. }
  761. /* dn: cn=replica,cn=dc\3Dexample\2Cdc\3Dcom,cn=mapping tree,cn=config */
  762. replica_dn = slapi_create_dn_string("%s,cn=\"%s\",%s",
  763. REPLICA_RDN,
  764. slapi_sdn_get_dn(replica_get_root(replica)),
  765. CONFIG_BASE);
  766. if (NULL == replica_dn) {
  767. return rc;
  768. }
  769. pb = slapi_pblock_new();
  770. mods[0] = &mod;
  771. mods[1] = NULL;
  772. mod.mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
  773. mod.mod_type = (char *)TASK_ATTR;
  774. mod.mod_bvalues = NULL;
  775. slapi_modify_internal_set_pb(pb, replica_dn, mods, NULL/* controls */,
  776. NULL/* uniqueid */,
  777. repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION),
  778. 0/* flags */);
  779. slapi_modify_internal_pb (pb);
  780. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  781. if ((rc != LDAP_SUCCESS) && (rc != LDAP_NO_SUCH_ATTRIBUTE)) {
  782. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  783. "replica_task_done: "
  784. "failed to remove (%s) attribute from (%s) entry; "
  785. "LDAP error - %d\n",
  786. TASK_ATTR, replica_dn, rc);
  787. }
  788. slapi_pblock_destroy (pb);
  789. slapi_ch_free_string(&replica_dn);
  790. return rc;
  791. }
  792. static int replica_execute_cl2ldif_task (Object *r, char *returntext)
  793. {
  794. int rc;
  795. Object *rlist [2];
  796. Replica *replica;
  797. char fName [MAXPATHLEN];
  798. char *clDir = NULL;
  799. if (cl5GetState () != CL5_STATE_OPEN)
  800. {
  801. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "changelog is not open");
  802. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  803. "replica_execute_cl2ldif_task: %s\n", returntext);
  804. rc = LDAP_OPERATIONS_ERROR;
  805. goto bail;
  806. }
  807. rlist[0] = r;
  808. rlist[1] = NULL;
  809. /* file is stored in the changelog directory and is named
  810. <replica name>.ldif */
  811. clDir = cl5GetDir ();
  812. if (NULL == clDir) {
  813. rc = LDAP_OPERATIONS_ERROR;
  814. goto bail;
  815. }
  816. replica = (Replica*)object_get_data (r);
  817. if (NULL == replica) {
  818. rc = LDAP_OPERATIONS_ERROR;
  819. goto bail;
  820. }
  821. PR_snprintf (fName, MAXPATHLEN, "%s/%s.ldif", clDir, replica_get_name (replica));
  822. slapi_ch_free_string (&clDir);
  823. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  824. "Beginning changelog export of replica \"%s\"\n",
  825. replica_get_name(replica));
  826. rc = cl5ExportLDIF (fName, rlist);
  827. if (rc == CL5_SUCCESS) {
  828. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  829. "Finished changelog export of replica \"%s\"\n",
  830. replica_get_name(replica));
  831. rc = LDAP_SUCCESS;
  832. } else {
  833. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  834. "Failed changelog export replica %s; "
  835. "changelog error - %d", replica_get_name(replica), rc);
  836. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  837. "replica_execute_cl2ldif_task: %s\n", returntext);
  838. rc = LDAP_OPERATIONS_ERROR;
  839. }
  840. bail:
  841. return rc;
  842. }
  843. static int replica_execute_ldif2cl_task (Object *r, char *returntext)
  844. {
  845. int rc, imprc = 0;
  846. Object *rlist [2];
  847. Replica *replica;
  848. char fName [MAXPATHLEN];
  849. char *clDir = NULL;
  850. changelog5Config config;
  851. if (cl5GetState () != CL5_STATE_OPEN)
  852. {
  853. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "changelog is not open");
  854. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  855. "replica_execute_ldif2cl_task: %s\n", returntext);
  856. rc = LDAP_OPERATIONS_ERROR;
  857. goto bail;
  858. }
  859. rlist[0] = r;
  860. rlist[1] = NULL;
  861. /* file is stored in the changelog directory and is named
  862. <replica name>.ldif */
  863. clDir = cl5GetDir ();
  864. if (NULL == clDir) {
  865. rc = LDAP_OPERATIONS_ERROR;
  866. goto bail;
  867. }
  868. replica = (Replica*)object_get_data (r);
  869. if (NULL == replica) {
  870. rc = LDAP_OPERATIONS_ERROR;
  871. goto bail;
  872. }
  873. PR_snprintf (fName, MAXPATHLEN, "%s/%s.ldif", clDir, replica_get_name (replica));
  874. rc = cl5Close();
  875. if (rc != CL5_SUCCESS)
  876. {
  877. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  878. "failed to close changelog to import changelog data; "
  879. "changelog error - %d", rc);
  880. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  881. "replica_execute_ldif2cl_task: %s\n", returntext);
  882. rc = LDAP_OPERATIONS_ERROR;
  883. goto bail;
  884. }
  885. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  886. "Beginning changelog import of replica \"%s\"\n",
  887. replica_get_name(replica));
  888. imprc = cl5ImportLDIF (clDir, fName, rlist);
  889. slapi_ch_free_string (&clDir);
  890. if (CL5_SUCCESS == imprc)
  891. {
  892. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  893. "Finished changelog import of replica \"%s\"\n",
  894. replica_get_name(replica));
  895. }
  896. else
  897. {
  898. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  899. "Failed changelog import replica %s; "
  900. "changelog error - %d", replica_get_name(replica), rc);
  901. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  902. "replica_execute_ldif2cl_task: %s\n", returntext);
  903. imprc = LDAP_OPERATIONS_ERROR;
  904. }
  905. changelog5_read_config (&config);
  906. /* restart changelog */
  907. rc = cl5Open (config.dir, &config.dbconfig);
  908. if (CL5_SUCCESS == rc)
  909. {
  910. rc = LDAP_SUCCESS;
  911. }
  912. else
  913. {
  914. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  915. "replica_execute_ldif2cl_task: failed to start changelog at %s\n",
  916. config.dir);
  917. rc = LDAP_OPERATIONS_ERROR;
  918. }
  919. bail:
  920. changelog5_config_done(&config);
  921. /* if cl5ImportLDIF returned an error, report it first. */
  922. return imprc?imprc:rc;
  923. }
  924. static multimaster_mtnode_extension *
  925. _replica_config_get_mtnode_ext (const Slapi_Entry *e)
  926. {
  927. const char *replica_root;
  928. Slapi_DN *sdn = NULL;
  929. mapping_tree_node *mtnode;
  930. multimaster_mtnode_extension *ext = NULL;
  931. char ebuf[BUFSIZ];
  932. /* retirve root of the tree for which replica is configured */
  933. replica_root = slapi_entry_attr_get_charptr (e, attr_replicaRoot);
  934. if (replica_root == NULL)
  935. {
  936. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_add: "
  937. "configuration entry %s missing %s attribute\n",
  938. escape_string(slapi_entry_get_dn((Slapi_Entry *)e), ebuf),
  939. attr_replicaRoot);
  940. return NULL;
  941. }
  942. sdn = slapi_sdn_new_dn_passin (replica_root);
  943. /* locate mapping tree node for the specified subtree */
  944. mtnode = slapi_get_mapping_tree_node_by_dn (sdn);
  945. if (mtnode == NULL)
  946. {
  947. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_add: "
  948. "failed to locate mapping tree node for dn %s\n",
  949. escape_string(slapi_sdn_get_dn(sdn), ebuf));
  950. }
  951. else
  952. {
  953. /* check if replica object already exists for the specified subtree */
  954. ext = (multimaster_mtnode_extension *)repl_con_get_ext (REPL_CON_EXT_MTNODE, mtnode);
  955. }
  956. slapi_sdn_free (&sdn);
  957. return ext;
  958. }
  959. static int
  960. replica_execute_cleanruv_task (Object *r, ReplicaId rid, char *returntext)
  961. {
  962. int rc = 0;
  963. Object *RUVObj;
  964. RUV *local_ruv = NULL;
  965. Replica *replica = (Replica*)object_get_data (r);
  966. PR_ASSERT (replica);
  967. RUVObj = replica_get_ruv(replica);
  968. PR_ASSERT(RUVObj);
  969. local_ruv = (RUV*)object_get_data (RUVObj);
  970. /* Need to check that :
  971. * - rid is not the local one
  972. * - rid is not the last one
  973. */
  974. if ((replica_get_rid(replica) == rid) ||
  975. (ruv_replica_count(local_ruv) <= 1)) {
  976. return LDAP_UNWILLING_TO_PERFORM;
  977. }
  978. rc = ruv_delete_replica(local_ruv, rid);
  979. replica_set_ruv_dirty(replica);
  980. replica_write_ruv(replica);
  981. object_release(RUVObj);
  982. /* Update Mapping Tree to reflect RUV changes */
  983. consumer5_set_mapping_tree_state_for_replica(replica, NULL);
  984. if (rc != RUV_SUCCESS){
  985. return LDAP_OPERATIONS_ERROR;
  986. }
  987. return LDAP_SUCCESS;
  988. }