1
0

repl5_replica_config.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  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. #define CONFIG_BASE "cn=mapping tree,cn=config"
  47. #define CONFIG_FILTER "(objectclass=nsDS5Replica)"
  48. #define TASK_ATTR "nsds5Task"
  49. #define CL2LDIF_TASK "CL2LDIF"
  50. #define CLEANRUV "CLEANRUV"
  51. #define CLEANRUVLEN 8
  52. int slapi_log_urp = SLAPI_LOG_REPL;
  53. /* Forward Declartions */
  54. static int replica_config_add (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
  55. static int replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
  56. static int replica_config_delete (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
  57. static int replica_config_search (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
  58. static int replica_config_change_type_and_id (Replica *r, const char *new_type, const char *new_id, char *returntext, int apply_mods);
  59. static int replica_config_change_updatedn (Replica *r, const LDAPMod *mod, char *returntext, int apply_mods);
  60. static int replica_config_change_flags (Replica *r, const char *new_flags, char *returntext, int apply_mods);
  61. static int replica_execute_task (Object *r, const char *task_name, char *returntext, int apply_mods);
  62. static int replica_execute_cl2ldif_task (Object *r, char *returntext);
  63. static int replica_execute_cleanruv_task (Object *r, ReplicaId rid, char *returntext);
  64. static multimaster_mtnode_extension * _replica_config_get_mtnode_ext (const Slapi_Entry *e);
  65. static PRLock *s_configLock;
  66. static int
  67. dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
  68. {
  69. *returncode = LDAP_UNWILLING_TO_PERFORM;
  70. return SLAPI_DSE_CALLBACK_ERROR;
  71. }
  72. int
  73. replica_config_init()
  74. {
  75. s_configLock = PR_NewLock ();
  76. if (s_configLock == NULL)
  77. {
  78. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_init: "
  79. "failed to cretate configuration lock; NSPR error - %d\n",
  80. PR_GetError ());
  81. return -1;
  82. }
  83. /* config DSE must be initialized before we get here */
  84. slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  85. CONFIG_FILTER, replica_config_add, NULL);
  86. slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  87. CONFIG_FILTER, replica_config_modify,NULL);
  88. slapi_config_register_callback(SLAPI_OPERATION_MODRDN, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  89. CONFIG_FILTER, dont_allow_that, NULL);
  90. slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  91. CONFIG_FILTER, replica_config_delete,NULL);
  92. slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  93. CONFIG_FILTER, replica_config_search,NULL);
  94. return 0;
  95. }
  96. void
  97. replica_config_destroy ()
  98. {
  99. if (s_configLock)
  100. {
  101. PR_DestroyLock (s_configLock);
  102. s_configLock = NULL;
  103. }
  104. /* config DSE must be initialized before we get here */
  105. slapi_config_remove_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  106. CONFIG_FILTER, replica_config_add);
  107. slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  108. CONFIG_FILTER, replica_config_modify);
  109. slapi_config_remove_callback(SLAPI_OPERATION_MODRDN, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  110. CONFIG_FILTER, dont_allow_that);
  111. slapi_config_remove_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  112. CONFIG_FILTER, replica_config_delete);
  113. slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
  114. CONFIG_FILTER, replica_config_search);
  115. }
  116. static int
  117. replica_config_add (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
  118. int *returncode, char *errorbuf, void *arg)
  119. {
  120. Replica *r = NULL;
  121. multimaster_mtnode_extension *mtnode_ext;
  122. char *replica_root = (char*)slapi_entry_attr_get_charptr (e, attr_replicaRoot);
  123. char buf [SLAPI_DSE_RETURNTEXT_SIZE];
  124. char *errortext = errorbuf ? errorbuf : buf;
  125. if (errorbuf)
  126. {
  127. errorbuf[0] = '\0';
  128. }
  129. *returncode = LDAP_SUCCESS;
  130. PR_Lock (s_configLock);
  131. /* add the dn to the dn hash so we can tell this replica is being configured */
  132. replica_add_by_dn(replica_root);
  133. mtnode_ext = _replica_config_get_mtnode_ext (e);
  134. PR_ASSERT (mtnode_ext);
  135. if (mtnode_ext->replica)
  136. {
  137. PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "replica already configured for %s", replica_root);
  138. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_add: %s\n", errortext);
  139. *returncode = LDAP_UNWILLING_TO_PERFORM;
  140. goto done;
  141. }
  142. /* create replica object */
  143. r = replica_new_from_entry (e, errortext, PR_TRUE /* is a newly added entry */);
  144. if (r == NULL)
  145. {
  146. *returncode = LDAP_OPERATIONS_ERROR;
  147. goto done;
  148. }
  149. /* Set the mapping tree node state, and the referrals from the RUV */
  150. /* if this server is a 4.0 consumer the referrals are set by legacy plugin */
  151. if (!replica_is_legacy_consumer (r))
  152. consumer5_set_mapping_tree_state_for_replica(r, NULL);
  153. /* ONREPL if replica is added as writable we need to execute protocol that
  154. introduces new writable replica to the topology */
  155. mtnode_ext->replica = object_new (r, replica_destroy); /* Refcnt is 1 */
  156. /* add replica object to the hash */
  157. *returncode = replica_add_by_name (replica_get_name (r), mtnode_ext->replica); /* Increments object refcnt */
  158. /* delete the dn from the dn hash - done with configuration */
  159. replica_delete_by_dn(replica_root);
  160. done:
  161. PR_Unlock (s_configLock);
  162. /* slapi_ch_free accepts NULL pointer */
  163. slapi_ch_free ((void**)&replica_root);
  164. if (*returncode != LDAP_SUCCESS)
  165. {
  166. if (mtnode_ext->replica)
  167. object_release (mtnode_ext->replica);
  168. return SLAPI_DSE_CALLBACK_ERROR;
  169. }
  170. else
  171. return SLAPI_DSE_CALLBACK_OK;
  172. }
  173. static int
  174. replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
  175. int *returncode, char *returntext, void *arg)
  176. {
  177. int rc= 0;
  178. LDAPMod **mods;
  179. int i, apply_mods;
  180. multimaster_mtnode_extension *mtnode_ext;
  181. Replica *r = NULL;
  182. char *replica_root = NULL;
  183. char buf [SLAPI_DSE_RETURNTEXT_SIZE];
  184. char *errortext = returntext ? returntext : buf;
  185. char *config_attr, *config_attr_value;
  186. Slapi_Operation *op;
  187. void *identity;
  188. if (returntext)
  189. {
  190. returntext[0] = '\0';
  191. }
  192. *returncode = LDAP_SUCCESS;
  193. /* just let internal operations originated from replication plugin to go through */
  194. slapi_pblock_get (pb, SLAPI_OPERATION, &op);
  195. slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);
  196. if (operation_is_flag_set(op, OP_FLAG_INTERNAL) &&
  197. (identity == repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION)))
  198. {
  199. *returncode = LDAP_SUCCESS;
  200. return SLAPI_DSE_CALLBACK_OK;
  201. }
  202. replica_root = (char*)slapi_entry_attr_get_charptr (e, attr_replicaRoot);
  203. PR_Lock (s_configLock);
  204. mtnode_ext = _replica_config_get_mtnode_ext (e);
  205. PR_ASSERT (mtnode_ext);
  206. if (mtnode_ext->replica)
  207. object_acquire (mtnode_ext->replica);
  208. if (mtnode_ext->replica == NULL)
  209. {
  210. PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "replica does not exist for %s", replica_root);
  211. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n",
  212. errortext);
  213. *returncode = LDAP_OPERATIONS_ERROR;
  214. goto done;
  215. }
  216. r = object_get_data (mtnode_ext->replica);
  217. PR_ASSERT (r);
  218. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  219. for (apply_mods = 0; apply_mods <= 1; apply_mods++)
  220. {
  221. /* we only allow the replica ID and type to be modified together e.g.
  222. if converting a read only replica to a master or vice versa -
  223. we will need to change both the replica ID and the type at the same
  224. time - we must disallow changing the replica ID if the type is not
  225. being changed and vice versa
  226. */
  227. char *new_repl_id = NULL;
  228. char *new_repl_type = NULL;
  229. if (*returncode != LDAP_SUCCESS)
  230. break;
  231. for (i = 0; (mods[i] && (LDAP_SUCCESS == rc)); i++)
  232. {
  233. if (*returncode != LDAP_SUCCESS)
  234. break;
  235. config_attr = (char *) mods[i]->mod_type;
  236. PR_ASSERT (config_attr);
  237. /* disallow modifications or removal of replica root,
  238. replica name and replica state attributes */
  239. if (strcasecmp (config_attr, attr_replicaRoot) == 0 ||
  240. strcasecmp (config_attr, attr_replicaName) == 0 ||
  241. strcasecmp (config_attr, attr_state) == 0)
  242. {
  243. *returncode = LDAP_UNWILLING_TO_PERFORM;
  244. PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "modification of %s attribute is not allowed",
  245. config_attr);
  246. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n",
  247. errortext);
  248. }
  249. /* this is a request to delete an attribute */
  250. else if (mods[i]->mod_op & LDAP_MOD_DELETE || mods[i]->mod_bvalues == NULL
  251. || mods[i]->mod_bvalues[0]->bv_val == NULL)
  252. {
  253. /* currently, you can only remove referral,
  254. legacy consumer or bind dn attribute */
  255. if (strcasecmp (config_attr, attr_replicaBindDn) == 0)
  256. {
  257. *returncode = replica_config_change_updatedn (r, mods[i], errortext, apply_mods);
  258. }
  259. else if (strcasecmp (config_attr, attr_replicaReferral) == 0)
  260. {
  261. if (apply_mods) {
  262. replica_set_referrals(r, NULL);
  263. if (!replica_is_legacy_consumer (r)) {
  264. consumer5_set_mapping_tree_state_for_replica(r, NULL);
  265. }
  266. }
  267. }
  268. else if (strcasecmp (config_attr, type_replicaLegacyConsumer) == 0)
  269. {
  270. if (apply_mods)
  271. replica_set_legacy_consumer (r, PR_FALSE);
  272. }
  273. else
  274. {
  275. *returncode = LDAP_UNWILLING_TO_PERFORM;
  276. PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "deletion of %s attribute is not allowed", config_attr);
  277. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n",
  278. errortext);
  279. }
  280. }
  281. else /* modify an attribute */
  282. {
  283. config_attr_value = (char *) mods[i]->mod_bvalues[0]->bv_val;
  284. if (strcasecmp (config_attr, attr_replicaBindDn) == 0)
  285. {
  286. *returncode = replica_config_change_updatedn (r, mods[i],
  287. errortext, apply_mods);
  288. }
  289. else if (strcasecmp (config_attr, attr_replicaType) == 0)
  290. {
  291. new_repl_type = slapi_ch_strdup(config_attr_value);
  292. }
  293. else if (strcasecmp (config_attr, attr_replicaId) == 0)
  294. {
  295. new_repl_id = slapi_ch_strdup(config_attr_value);
  296. }
  297. else if (strcasecmp (config_attr, attr_flags) == 0)
  298. {
  299. *returncode = replica_config_change_flags (r, config_attr_value,
  300. errortext, apply_mods);
  301. }
  302. else if (strcasecmp (config_attr, TASK_ATTR) == 0)
  303. {
  304. *returncode = replica_execute_task (mtnode_ext->replica, config_attr_value,
  305. errortext, apply_mods);
  306. }
  307. else if (strcasecmp (config_attr, attr_replicaReferral) == 0)
  308. {
  309. if (apply_mods)
  310. {
  311. Slapi_Mod smod;
  312. Slapi_ValueSet *vs= slapi_valueset_new();
  313. slapi_mod_init_byref(&smod,mods[i]);
  314. slapi_valueset_set_from_smod(vs, &smod);
  315. replica_set_referrals (r, vs);
  316. slapi_mod_done(&smod);
  317. slapi_valueset_free(vs);
  318. if (!replica_is_legacy_consumer (r)) {
  319. consumer5_set_mapping_tree_state_for_replica(r, NULL);
  320. }
  321. }
  322. }
  323. else if (strcasecmp (config_attr, type_replicaPurgeDelay) == 0)
  324. {
  325. if (apply_mods && config_attr_value && config_attr_value[0])
  326. {
  327. PRUint32 delay;
  328. if (isdigit (config_attr_value[0]))
  329. {
  330. delay = (unsigned int)atoi(config_attr_value);
  331. replica_set_purge_delay(r, delay);
  332. }
  333. else
  334. *returncode = LDAP_OPERATIONS_ERROR;
  335. }
  336. }
  337. else if (strcasecmp (config_attr, type_replicaTombstonePurgeInterval) == 0)
  338. {
  339. if (apply_mods && config_attr_value && config_attr_value[0])
  340. {
  341. long interval;
  342. interval = atol (config_attr_value);
  343. replica_set_tombstone_reap_interval (r, interval);
  344. }
  345. }
  346. else if (strcasecmp (config_attr, type_replicaLegacyConsumer) == 0)
  347. {
  348. if (apply_mods)
  349. {
  350. PRBool legacy = (strcasecmp (config_attr_value, "on") == 0) ||
  351. (strcasecmp (config_attr_value, "true") == 0) ||
  352. (strcasecmp (config_attr_value, "yes") == 0) ||
  353. (strcasecmp (config_attr_value, "1") == 0);
  354. replica_set_legacy_consumer (r, legacy);
  355. }
  356. }
  357. /* ignore modifiers attributes added by the server */
  358. else if (strcasecmp (config_attr, "modifytimestamp") == 0 ||
  359. strcasecmp (config_attr, "modifiersname") == 0)
  360. {
  361. *returncode = LDAP_SUCCESS;
  362. }
  363. else
  364. {
  365. *returncode = LDAP_UNWILLING_TO_PERFORM;
  366. PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE,
  367. "modification of attribute %s is not allowed in replica entry", config_attr);
  368. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n",
  369. errortext);
  370. }
  371. }
  372. }
  373. if (new_repl_id || new_repl_type)
  374. {
  375. *returncode = replica_config_change_type_and_id(r, new_repl_type,
  376. new_repl_id, errortext,
  377. apply_mods);
  378. slapi_ch_free_string(&new_repl_id);
  379. slapi_ch_free_string(&new_repl_type);
  380. }
  381. }
  382. done:
  383. if (mtnode_ext->replica)
  384. object_release (mtnode_ext->replica);
  385. /* slapi_ch_free accepts NULL pointer */
  386. slapi_ch_free ((void**)&replica_root);
  387. PR_Unlock (s_configLock);
  388. if (*returncode != LDAP_SUCCESS)
  389. {
  390. return SLAPI_DSE_CALLBACK_ERROR;
  391. }
  392. else
  393. {
  394. return SLAPI_DSE_CALLBACK_OK;
  395. }
  396. }
  397. static int
  398. replica_config_delete (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
  399. int *returncode, char *returntext, void *arg)
  400. {
  401. multimaster_mtnode_extension *mtnode_ext;
  402. Replica *r;
  403. PR_Lock (s_configLock);
  404. mtnode_ext = _replica_config_get_mtnode_ext (e);
  405. PR_ASSERT (mtnode_ext);
  406. if (mtnode_ext->replica)
  407. {
  408. char ebuf[BUFSIZ];
  409. /* remove object from the hash */
  410. r = (Replica*)object_get_data (mtnode_ext->replica);
  411. PR_ASSERT (r);
  412. /* The changelog for this replica is no longer valid, so we should remove it. */
  413. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_delete: "
  414. "Warning: The changelog for replica %s is no longer valid since "
  415. "the replica config is being deleted. Removing the changelog.\n",
  416. escape_string(slapi_sdn_get_dn(replica_get_root(r)),ebuf));
  417. cl5DeleteDBSync(mtnode_ext->replica);
  418. replica_delete_by_name (replica_get_name (r));
  419. object_release (mtnode_ext->replica);
  420. mtnode_ext->replica = NULL;
  421. }
  422. PR_Unlock (s_configLock);
  423. *returncode = LDAP_SUCCESS;
  424. return SLAPI_DSE_CALLBACK_OK;
  425. }
  426. static int
  427. replica_config_search (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode,
  428. char *returntext, void *arg)
  429. {
  430. multimaster_mtnode_extension *mtnode_ext;
  431. int changeCount = 0;
  432. PRBool reapActive = PR_FALSE;
  433. char val [64];
  434. /* add attribute that contains number of entries in the changelog for this replica */
  435. PR_Lock (s_configLock);
  436. mtnode_ext = _replica_config_get_mtnode_ext (e);
  437. PR_ASSERT (mtnode_ext);
  438. if (mtnode_ext->replica) {
  439. Replica *replica;
  440. object_acquire (mtnode_ext->replica);
  441. if (cl5GetState () == CL5_STATE_OPEN) {
  442. changeCount = cl5GetOperationCount (mtnode_ext->replica);
  443. }
  444. replica = (Replica*)object_get_data (mtnode_ext->replica);
  445. if (replica) {
  446. reapActive = replica_get_tombstone_reap_active(replica);
  447. }
  448. object_release (mtnode_ext->replica);
  449. }
  450. sprintf (val, "%d", changeCount);
  451. slapi_entry_add_string (e, type_replicaChangeCount, val);
  452. slapi_entry_attr_set_int(e, "nsds5replicaReapActive", (int)reapActive);
  453. PR_Unlock (s_configLock);
  454. return SLAPI_DSE_CALLBACK_OK;
  455. }
  456. static int
  457. replica_config_change_type_and_id (Replica *r, const char *new_type,
  458. const char *new_id, char *returntext,
  459. int apply_mods)
  460. {
  461. int type;
  462. ReplicaType oldtype;
  463. ReplicaId rid;
  464. ReplicaId oldrid;
  465. PR_ASSERT (r);
  466. oldtype = replica_get_type(r);
  467. oldrid = replica_get_rid(r);
  468. if (new_type == NULL) /* by default - replica is read-only */
  469. {
  470. type = REPLICA_TYPE_READONLY;
  471. }
  472. else
  473. {
  474. type = atoi (new_type);
  475. if (type <= REPLICA_TYPE_UNKNOWN || type >= REPLICA_TYPE_END)
  476. {
  477. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "invalid replica type %d", type);
  478. return LDAP_OPERATIONS_ERROR;
  479. }
  480. }
  481. /* disallow changing type to itself just to permit a replica ID change */
  482. if (oldtype == type)
  483. {
  484. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "replica type is already %d - not changing", type);
  485. return LDAP_OPERATIONS_ERROR;
  486. }
  487. if (type == REPLICA_TYPE_READONLY)
  488. {
  489. rid = READ_ONLY_REPLICA_ID; /* default rid for read only */
  490. }
  491. else if (!new_id)
  492. {
  493. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "a replica ID is required when changing replica type to read-write");
  494. return LDAP_UNWILLING_TO_PERFORM;
  495. }
  496. else
  497. {
  498. int temprid = atoi (new_id);
  499. if (temprid <= 0 || temprid >= READ_ONLY_REPLICA_ID)
  500. {
  501. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  502. "attribute %s must have a value greater than 0 "
  503. "and less than %d",
  504. attr_replicaId, READ_ONLY_REPLICA_ID);
  505. return LDAP_UNWILLING_TO_PERFORM;
  506. }
  507. else
  508. {
  509. rid = (ReplicaId)temprid;
  510. }
  511. }
  512. /* error if old rid == new rid */
  513. if (oldrid == rid)
  514. {
  515. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "replica ID is already %d - not changing", rid);
  516. return LDAP_OPERATIONS_ERROR;
  517. }
  518. if (apply_mods)
  519. {
  520. replica_set_type (r, type);
  521. replica_set_rid(r, rid);
  522. /* Set the mapping tree node, and the list of referrals */
  523. /* if this server is a 4.0 consumer the referrals are set by legacy plugin */
  524. if (!replica_is_legacy_consumer(r))
  525. consumer5_set_mapping_tree_state_for_replica(r, NULL);
  526. }
  527. return LDAP_SUCCESS;
  528. }
  529. static int
  530. replica_config_change_updatedn (Replica *r, const LDAPMod *mod, char *returntext,
  531. int apply_mods)
  532. {
  533. PR_ASSERT (r);
  534. if (apply_mods)
  535. {
  536. Slapi_Mod smod;
  537. Slapi_ValueSet *vs= slapi_valueset_new();
  538. slapi_mod_init_byref(&smod, (LDAPMod *)mod); /* cast away const */
  539. slapi_valueset_set_from_smod(vs, &smod);
  540. replica_set_updatedn(r, vs, mod->mod_op);
  541. slapi_mod_done(&smod);
  542. slapi_valueset_free(vs);
  543. }
  544. return LDAP_SUCCESS;
  545. }
  546. static int replica_config_change_flags (Replica *r, const char *new_flags,
  547. char *returntext, int apply_mods)
  548. {
  549. PR_ASSERT (r);
  550. if (apply_mods)
  551. {
  552. PRUint32 flags;
  553. flags = atol (new_flags);
  554. replica_replace_flags (r, flags);
  555. }
  556. return LDAP_SUCCESS;
  557. }
  558. static int replica_execute_task (Object *r, const char *task_name, char *returntext,
  559. int apply_mods)
  560. {
  561. if (strcasecmp (task_name, CL2LDIF_TASK) == 0)
  562. {
  563. if (apply_mods)
  564. {
  565. return replica_execute_cl2ldif_task (r, returntext);
  566. }
  567. else
  568. return LDAP_SUCCESS;
  569. }
  570. else if (strncasecmp (task_name, CLEANRUV, CLEANRUVLEN) == 0)
  571. {
  572. int temprid = atoi(&(task_name[CLEANRUVLEN]));
  573. if (temprid <= 0 || temprid >= READ_ONLY_REPLICA_ID){
  574. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
  575. "Invalid replica id for task - %s", task_name);
  576. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  577. "replica_execute_task: %s\n", returntext);
  578. return LDAP_OPERATIONS_ERROR;
  579. }
  580. if (apply_mods)
  581. {
  582. return replica_execute_cleanruv_task (r, (ReplicaId)temprid, returntext);
  583. }
  584. else
  585. return LDAP_SUCCESS;
  586. }
  587. else
  588. {
  589. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "unsupported replica task - %s", task_name);
  590. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  591. "replica_execute_task: %s\n", returntext);
  592. return LDAP_OPERATIONS_ERROR;
  593. }
  594. }
  595. static int replica_execute_cl2ldif_task (Object *r, char *returntext)
  596. {
  597. int rc;
  598. Object *rlist [2];
  599. Replica *replica;
  600. char fName [MAXPATHLEN];
  601. char *clDir;
  602. if (cl5GetState () != CL5_STATE_OPEN)
  603. {
  604. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "changelog is not open");
  605. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  606. "replica_execute_cl2ldif_task: %s\n", returntext);
  607. return LDAP_OPERATIONS_ERROR;
  608. }
  609. rlist[0] = r;
  610. rlist[1] = NULL;
  611. /* file is stored in the changelog directory and is named
  612. <replica name>.ldif */
  613. clDir = cl5GetDir ();
  614. PR_ASSERT (clDir);
  615. replica = (Replica*)object_get_data (r);
  616. PR_ASSERT (replica);
  617. PR_snprintf (fName, MAXPATHLEN, "%s/%s.ldif", clDir, replica_get_name (replica));
  618. slapi_ch_free ((void**)&clDir);
  619. rc = cl5ExportLDIF (fName, rlist);
  620. if (rc != CL5_SUCCESS)
  621. {
  622. PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "failed to export changelog data to file %s; "
  623. "changelog error - %d", fName, rc);
  624. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  625. "replica_execute_cl2ldif_task: %s\n", returntext);
  626. return LDAP_OPERATIONS_ERROR;
  627. }
  628. return LDAP_SUCCESS;
  629. }
  630. static multimaster_mtnode_extension *
  631. _replica_config_get_mtnode_ext (const Slapi_Entry *e)
  632. {
  633. const char *replica_root;
  634. Slapi_DN *sdn = NULL;
  635. mapping_tree_node *mtnode;
  636. multimaster_mtnode_extension *ext = NULL;
  637. char ebuf[BUFSIZ];
  638. /* retirve root of the tree for which replica is configured */
  639. replica_root = slapi_entry_attr_get_charptr (e, attr_replicaRoot);
  640. if (replica_root == NULL)
  641. {
  642. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_add: "
  643. "configuration entry %s missing %s attribute\n",
  644. escape_string(slapi_entry_get_dn((Slapi_Entry *)e), ebuf),
  645. attr_replicaRoot);
  646. return NULL;
  647. }
  648. sdn = slapi_sdn_new_dn_passin (replica_root);
  649. /* locate mapping tree node for the specified subtree */
  650. mtnode = slapi_get_mapping_tree_node_by_dn (sdn);
  651. if (mtnode == NULL)
  652. {
  653. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_add: "
  654. "failed to locate mapping tree node for dn %s\n",
  655. escape_string(slapi_sdn_get_dn(sdn), ebuf));
  656. }
  657. else
  658. {
  659. /* check if replica object already exists for the specified subtree */
  660. ext = (multimaster_mtnode_extension *)repl_con_get_ext (REPL_CON_EXT_MTNODE, mtnode);
  661. }
  662. slapi_sdn_free (&sdn);
  663. return ext;
  664. }
  665. static int
  666. replica_execute_cleanruv_task (Object *r, ReplicaId rid, char *returntext)
  667. {
  668. int rc = 0;
  669. Object *RUVObj;
  670. RUV *local_ruv = NULL;
  671. Replica *replica = (Replica*)object_get_data (r);
  672. PR_ASSERT (replica);
  673. RUVObj = replica_get_ruv(replica);
  674. PR_ASSERT(RUVObj);
  675. local_ruv = (RUV*)object_get_data (RUVObj);
  676. /* Need to check that :
  677. * - rid is not the local one
  678. * - rid is not the last one
  679. */
  680. if ((replica_get_rid(replica) == rid) ||
  681. (ruv_replica_count(local_ruv) <= 1)) {
  682. return LDAP_UNWILLING_TO_PERFORM;
  683. }
  684. rc = ruv_delete_replica(local_ruv, rid);
  685. replica_set_ruv_dirty(replica);
  686. replica_write_ruv(replica);
  687. object_release(RUVObj);
  688. /* Update Mapping Tree to reflect RUV changes */
  689. consumer5_set_mapping_tree_state_for_replica(replica, NULL);
  690. if (rc != RUV_SUCCESS){
  691. return LDAP_OPERATIONS_ERROR;
  692. }
  693. return LDAP_SUCCESS;
  694. }