repl5_plugins.c 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439
  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. /*
  39. * repl5_consumer.c - consumer plugin functions
  40. */
  41. /*
  42. * LDAP Data Model Constraints...
  43. *
  44. * 1) Parent entry must exist.
  45. * 2) RDN must be unique.
  46. * 3) RDN components must be attribute values.
  47. * 4) Must conform to the schema constraints - Single Valued Attributes.
  48. * 5) Must conform to the schema constraints - Required Attributes.
  49. * 6) Must conform to the schema constraints - No Extra Attributes.
  50. * 7) Duplicate attribute values are not permited.
  51. * 8) Cycle in the ancestry graph not permitted.
  52. *
  53. * Update Resolution Procedures...
  54. * 1) ...
  55. * 2) Add the UniqueID to the RDN.
  56. * 3) Remove the not present RDN component.
  57. * Use the UniqueID if the RDN becomes empty.
  58. * 4) Keep the most recent value.
  59. * 5) Ignore.
  60. * 6) Ignore.
  61. * 7) Keep the largest CSN for the duplicate value.
  62. * 8) Don't check for this.
  63. */
  64. #include "repl5.h"
  65. #include "repl.h"
  66. #include "cl5_api.h"
  67. #include "urp.h"
  68. static char *local_purl = NULL;
  69. static char *purl_attrs[] = {"nsslapd-localhost", "nsslapd-port", "nsslapd-secureport", NULL};
  70. /* Forward declarations */
  71. static void copy_operation_parameters(Slapi_PBlock *pb);
  72. static int write_changelog_and_ruv(Slapi_PBlock *pb);
  73. static int process_postop (Slapi_PBlock *pb);
  74. static int cancel_opcsn (Slapi_PBlock *pb);
  75. static int ruv_tombstone_op (Slapi_PBlock *pb);
  76. static PRBool process_operation (Slapi_PBlock *pb, const CSN *csn);
  77. static PRBool is_mmr_replica (Slapi_PBlock *pb);
  78. static const char *replica_get_purl_for_op (const Replica *r, Slapi_PBlock *pb, const CSN *opcsn);
  79. static void strip_legacy_info (slapi_operation_parameters *op_params);
  80. /*
  81. * XXXggood - what to do if both ssl and non-ssl ports available? How
  82. * do you know which to use? Offer a choice in replication config?
  83. */
  84. int
  85. multimaster_set_local_purl()
  86. {
  87. int rc = 0;
  88. Slapi_Entry **entries;
  89. Slapi_PBlock *pb = NULL;
  90. pb = slapi_pblock_new ();
  91. slapi_search_internal_set_pb (pb, "cn=config", LDAP_SCOPE_BASE,
  92. "objectclass=*", purl_attrs, 0, NULL, NULL,
  93. repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
  94. slapi_search_internal_pb (pb);
  95. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  96. if (rc != 0)
  97. {
  98. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "multimaster_set_local_purl: "
  99. "unable to read server configuration: error %d\n", rc);
  100. }
  101. else
  102. {
  103. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  104. if (NULL == entries || NULL == entries[0])
  105. {
  106. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "multimaster_set_local_purl: "
  107. "server configuration missing\n");
  108. rc = -1;
  109. }
  110. else
  111. {
  112. char *host = slapi_entry_attr_get_charptr(entries[0], "nsslapd-localhost");
  113. char *port = slapi_entry_attr_get_charptr(entries[0], "nsslapd-port");
  114. char *sslport = slapi_entry_attr_get_charptr(entries[0], "nsslapd-secureport");
  115. if (host == NULL || ((port == NULL && sslport == NULL)))
  116. {
  117. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  118. "multimaster_set_local_purl: invalid server "
  119. "configuration\n");
  120. }
  121. else
  122. {
  123. local_purl = slapi_ch_smprintf("ldap://%s:%s", host, port);
  124. }
  125. /* slapi_ch_free acceptS NULL pointer */
  126. slapi_ch_free ((void**)&host);
  127. slapi_ch_free ((void**)&port);
  128. slapi_ch_free ((void**)&sslport);
  129. }
  130. }
  131. slapi_free_search_results_internal(pb);
  132. slapi_pblock_destroy (pb);
  133. return rc;
  134. }
  135. const char *
  136. multimaster_get_local_purl()
  137. {
  138. return local_purl;
  139. }
  140. /* ================= Multimaster Pre-Op Plugin Points ================== */
  141. int
  142. multimaster_preop_bind (Slapi_PBlock *pb)
  143. {
  144. return 0;
  145. }
  146. int
  147. multimaster_preop_add (Slapi_PBlock *pb)
  148. {
  149. Slapi_Operation *op;
  150. int is_replicated_operation;
  151. int is_fixup_operation;
  152. int is_legacy_operation;
  153. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  154. /* If there is no replica or it is a legacy consumer - we don't need to continue.
  155. Legacy plugin is handling 4.0 consumer code */
  156. /* but if it is legacy, csngen_handler needs to be assigned here */
  157. is_legacy_operation =
  158. operation_is_flag_set(op,OP_FLAG_LEGACY_REPLICATION_DN);
  159. if (is_legacy_operation)
  160. {
  161. copy_operation_parameters(pb);
  162. slapi_operation_set_csngen_handler(op,
  163. (void*)replica_generate_next_csn);
  164. return 0;
  165. }
  166. if (!is_mmr_replica (pb))
  167. {
  168. copy_operation_parameters(pb);
  169. return 0;
  170. }
  171. is_replicated_operation= operation_is_flag_set(op,OP_FLAG_REPLICATED);
  172. is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
  173. if(is_replicated_operation)
  174. {
  175. if(!is_fixup_operation)
  176. {
  177. LDAPControl **ctrlp;
  178. char sessionid[REPL_SESSION_ID_SIZE];
  179. get_repl_session_id (pb, sessionid, NULL);
  180. slapi_pblock_get(pb, SLAPI_REQCONTROLS, &ctrlp);
  181. if (NULL != ctrlp)
  182. {
  183. CSN *csn = NULL;
  184. char *target_uuid = NULL;
  185. char *superior_uuid= NULL;
  186. int drc = decode_NSDS50ReplUpdateInfoControl(ctrlp, &target_uuid, &superior_uuid, &csn, NULL /* modrdn_mods */);
  187. if (-1 == drc)
  188. {
  189. slapi_log_error(SLAPI_LOG_FATAL, REPLICATION_SUBSYSTEM,
  190. "%s An error occurred while decoding the replication update "
  191. "control - Add\n", sessionid);
  192. }
  193. else if (1 == drc)
  194. {
  195. /*
  196. * For add operations, we just set the operation csn. The entry's
  197. * uniqueid should already be an attribute of the replicated entry.
  198. */
  199. struct slapi_operation_parameters *op_params;
  200. /* we don't want to process replicated operations with csn smaller
  201. than the corresponding csn in the consumer's ruv */
  202. if (!process_operation (pb, csn))
  203. {
  204. slapi_send_ldap_result(pb, LDAP_SUCCESS, 0,
  205. "replication operation not processed, replica unavailable "
  206. "or csn ignored", 0, 0);
  207. csn_free (&csn);
  208. slapi_ch_free ((void**)&target_uuid);
  209. slapi_ch_free ((void**)&superior_uuid);
  210. return -1;
  211. }
  212. operation_set_csn(op, csn);
  213. slapi_pblock_set( pb, SLAPI_TARGET_UNIQUEID, target_uuid);
  214. slapi_pblock_get( pb, SLAPI_OPERATION_PARAMETERS, &op_params );
  215. /* JCMREPL - Complain if there's no superior uuid */
  216. op_params->p.p_add.parentuniqueid= superior_uuid; /* JCMREPL - Not very elegant */
  217. /* JCMREPL - When do these things get free'd? */
  218. if(target_uuid!=NULL)
  219. {
  220. /*
  221. * Make sure that the Unique Identifier in the Control is the
  222. * same as the one in the entry.
  223. */
  224. Slapi_Entry *addentry;
  225. char *entry_uuid;
  226. slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &addentry );
  227. entry_uuid= slapi_entry_attr_get_charptr( addentry, SLAPI_ATTR_UNIQUEID);
  228. if(entry_uuid==NULL)
  229. {
  230. /* Odd that the entry doesn't have a Unique Identifier. But, we can fix it. */
  231. slapi_entry_set_uniqueid(addentry, slapi_ch_strdup(target_uuid)); /* JCMREPL - strdup EVIL! There should be a uuid dup function. */
  232. }
  233. else
  234. {
  235. if(strcasecmp(entry_uuid,target_uuid)!=0)
  236. {
  237. slapi_log_error(SLAPI_LOG_FATAL, REPLICATION_SUBSYSTEM,
  238. "%s Replicated Add received with Control_UUID=%s and Entry_UUID=%s.\n",
  239. sessionid, target_uuid,entry_uuid);
  240. }
  241. slapi_ch_free ((void**)&entry_uuid);
  242. }
  243. }
  244. }
  245. }
  246. else
  247. {
  248. PR_ASSERT(0); /* JCMREPL - A Replicated Operation with no Repl Baggage control... What does that mean? */
  249. }
  250. }
  251. else
  252. {
  253. /* Replicated & Fixup Operation */
  254. }
  255. }
  256. else
  257. {
  258. slapi_operation_set_csngen_handler ( op, (void*)replica_generate_next_csn );
  259. }
  260. copy_operation_parameters(pb);
  261. return 0;
  262. }
  263. int
  264. multimaster_preop_delete (Slapi_PBlock *pb)
  265. {
  266. Slapi_Operation *op;
  267. int is_replicated_operation;
  268. int is_fixup_operation;
  269. int is_legacy_operation;
  270. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  271. /* If there is no replica or it is a legacy consumer - we don't need to continue.
  272. Legacy plugin is handling 4.0 consumer code */
  273. /* but if it is legacy, csngen_handler needs to be assigned here */
  274. is_legacy_operation =
  275. operation_is_flag_set(op,OP_FLAG_LEGACY_REPLICATION_DN);
  276. if (is_legacy_operation)
  277. {
  278. copy_operation_parameters(pb);
  279. slapi_operation_set_replica_attr_handler ( op, (void*)replica_get_attr );
  280. slapi_operation_set_csngen_handler(op,
  281. (void*)replica_generate_next_csn);
  282. return 0;
  283. }
  284. if (!is_mmr_replica (pb))
  285. {
  286. copy_operation_parameters(pb);
  287. return 0;
  288. }
  289. is_replicated_operation= operation_is_flag_set(op,OP_FLAG_REPLICATED);
  290. is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
  291. if(is_replicated_operation)
  292. {
  293. if(!is_fixup_operation)
  294. {
  295. LDAPControl **ctrlp;
  296. char sessionid[REPL_SESSION_ID_SIZE];
  297. get_repl_session_id (pb, sessionid, NULL);
  298. slapi_pblock_get(pb, SLAPI_REQCONTROLS, &ctrlp);
  299. if (NULL != ctrlp)
  300. {
  301. CSN *csn = NULL;
  302. char *target_uuid = NULL;
  303. int drc = decode_NSDS50ReplUpdateInfoControl(ctrlp, &target_uuid, NULL, &csn, NULL /* modrdn_mods */);
  304. if (-1 == drc)
  305. {
  306. slapi_log_error(SLAPI_LOG_FATAL, REPLICATION_SUBSYSTEM,
  307. "%s An error occurred while decoding the replication update "
  308. "control - Delete\n", sessionid);
  309. }
  310. else if (1 == drc)
  311. {
  312. /* we don't want to process replicated operations with csn smaller
  313. than the corresponding csn in the consumer's ruv */
  314. if (!process_operation (pb, csn))
  315. {
  316. slapi_send_ldap_result(pb, LDAP_SUCCESS, 0,
  317. "replication operation not processed, replica unavailable "
  318. "or csn ignored", 0, 0);
  319. slapi_log_error(SLAPI_LOG_REPL, REPLICATION_SUBSYSTEM,
  320. "%s replication operation not processed, replica unavailable "
  321. "or csn ignored\n", sessionid);
  322. csn_free (&csn);
  323. slapi_ch_free ((void**)&target_uuid);
  324. return -1;
  325. }
  326. /*
  327. * For delete operations, we pass the uniqueid of the deleted entry
  328. * to the backend and let it sort out which entry to really delete.
  329. * We also set the operation csn.
  330. */
  331. operation_set_csn(op, csn);
  332. slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, target_uuid);
  333. }
  334. }
  335. else
  336. {
  337. PR_ASSERT(0); /* JCMREPL - A Replicated Operation with no Repl Baggage control... What does that mean? */
  338. }
  339. }
  340. else
  341. {
  342. /* Replicated & Fixup Operation */
  343. }
  344. }
  345. else
  346. {
  347. slapi_operation_set_csngen_handler ( op, (void*)replica_generate_next_csn );
  348. }
  349. copy_operation_parameters(pb);
  350. slapi_operation_set_replica_attr_handler ( op, (void*)replica_get_attr );
  351. return 0;
  352. }
  353. int
  354. multimaster_preop_modify (Slapi_PBlock *pb)
  355. {
  356. Slapi_Operation *op;
  357. int is_replicated_operation;
  358. int is_fixup_operation;
  359. int is_legacy_operation;
  360. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  361. /* If there is no replica or it is a legacy consumer - we don't need to continue.
  362. Legacy plugin is handling 4.0 consumer code */
  363. /* but if it is legacy, csngen_handler needs to be assigned here */
  364. is_legacy_operation =
  365. operation_is_flag_set(op,OP_FLAG_LEGACY_REPLICATION_DN);
  366. if (is_legacy_operation)
  367. {
  368. copy_operation_parameters(pb);
  369. slapi_operation_set_csngen_handler(op,
  370. (void*)replica_generate_next_csn);
  371. return 0;
  372. }
  373. if (!is_mmr_replica (pb))
  374. {
  375. copy_operation_parameters(pb);
  376. return 0;
  377. }
  378. is_replicated_operation= operation_is_flag_set(op,OP_FLAG_REPLICATED);
  379. is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
  380. if(is_replicated_operation)
  381. {
  382. if(!is_fixup_operation)
  383. {
  384. LDAPControl **ctrlp;
  385. char sessionid[REPL_SESSION_ID_SIZE];
  386. get_repl_session_id (pb, sessionid, NULL);
  387. slapi_pblock_get(pb, SLAPI_REQCONTROLS, &ctrlp);
  388. if (NULL != ctrlp)
  389. {
  390. CSN *csn = NULL;
  391. char *target_uuid = NULL;
  392. int drc = decode_NSDS50ReplUpdateInfoControl(ctrlp, &target_uuid, NULL, &csn, NULL /* modrdn_mods */);
  393. if (-1 == drc)
  394. {
  395. slapi_log_error(SLAPI_LOG_FATAL, REPLICATION_SUBSYSTEM,
  396. "%s An error occurred while decoding the replication update "
  397. "control- Modify\n", sessionid);
  398. }
  399. else if (1 == drc)
  400. {
  401. /* we don't want to process replicated operations with csn smaller
  402. than the corresponding csn in the consumer's ruv */
  403. if (!process_operation (pb, csn))
  404. {
  405. slapi_send_ldap_result(pb, LDAP_SUCCESS, 0,
  406. "replication operation not processed, replica unavailable "
  407. "or csn ignored", 0, 0);
  408. slapi_log_error(SLAPI_LOG_REPL, REPLICATION_SUBSYSTEM,
  409. "%s replication operation not processed, replica unavailable "
  410. "or csn ignored\n", sessionid);
  411. csn_free (&csn);
  412. slapi_ch_free ((void**)&target_uuid);
  413. return -1;
  414. }
  415. /*
  416. * For modify operations, we pass the uniqueid of the modified entry
  417. * to the backend and let it sort out which entry to really modify.
  418. * We also set the operation csn.
  419. */
  420. operation_set_csn(op, csn);
  421. slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, target_uuid);
  422. }
  423. }
  424. else
  425. {
  426. PR_ASSERT(0); /* JCMREPL - A Replicated Operation with no Repl Baggage control... What does that mean? */
  427. }
  428. }
  429. else
  430. {
  431. /* Replicated & Fixup Operation */
  432. }
  433. }
  434. else
  435. {
  436. slapi_operation_set_csngen_handler ( op, (void*)replica_generate_next_csn );
  437. }
  438. copy_operation_parameters(pb);
  439. return 0;
  440. }
  441. int
  442. multimaster_preop_modrdn (Slapi_PBlock *pb)
  443. {
  444. Slapi_Operation *op;
  445. int is_replicated_operation;
  446. int is_fixup_operation;
  447. int is_legacy_operation;
  448. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  449. /* If there is no replica or it is a legacy consumer - we don't need to continue.
  450. Legacy plugin is handling 4.0 consumer code */
  451. /* but if it is legacy, csngen_handler needs to be assigned here */
  452. is_legacy_operation =
  453. operation_is_flag_set(op,OP_FLAG_LEGACY_REPLICATION_DN);
  454. if (is_legacy_operation)
  455. {
  456. copy_operation_parameters(pb);
  457. slapi_operation_set_csngen_handler(op,
  458. (void*)replica_generate_next_csn);
  459. return 0;
  460. }
  461. if (!is_mmr_replica (pb))
  462. {
  463. copy_operation_parameters(pb);
  464. return 0;
  465. }
  466. is_replicated_operation= operation_is_flag_set(op,OP_FLAG_REPLICATED);
  467. is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
  468. if(is_replicated_operation)
  469. {
  470. if(!is_fixup_operation)
  471. {
  472. LDAPControl **ctrlp;
  473. char sessionid[REPL_SESSION_ID_SIZE];
  474. get_repl_session_id (pb, sessionid, NULL);
  475. slapi_pblock_get(pb, SLAPI_REQCONTROLS, &ctrlp);
  476. if (NULL != ctrlp)
  477. {
  478. CSN *csn = NULL;
  479. char *target_uuid = NULL;
  480. char *newsuperior_uuid = NULL;
  481. LDAPMod **modrdn_mods = NULL;
  482. int drc = decode_NSDS50ReplUpdateInfoControl(ctrlp, &target_uuid, &newsuperior_uuid,
  483. &csn, &modrdn_mods);
  484. if (-1 == drc)
  485. {
  486. slapi_log_error(SLAPI_LOG_FATAL, REPLICATION_SUBSYSTEM,
  487. "%s An error occurred while decoding the replication update "
  488. "control - ModRDN\n", sessionid);
  489. }
  490. else if (1 == drc)
  491. {
  492. /*
  493. * For modrdn operations, we pass the uniqueid of the entry being
  494. * renamed to the backend and let it sort out which entry to really
  495. * rename. We also set the operation csn, and if the newsuperior_uuid
  496. * was sent, we decode that as well.
  497. */
  498. struct slapi_operation_parameters *op_params;
  499. /* we don't want to process replicated operations with csn smaller
  500. than the corresponding csn in the consumer's ruv */
  501. if (!process_operation (pb, csn))
  502. {
  503. slapi_send_ldap_result(pb, LDAP_SUCCESS, 0,
  504. "replication operation not processed, replica unavailable "
  505. "or csn ignored", 0, 0);
  506. csn_free (&csn);
  507. slapi_ch_free ((void**)&target_uuid);
  508. slapi_ch_free ((void**)&newsuperior_uuid);
  509. ldap_mods_free (modrdn_mods, 1);
  510. return -1;
  511. }
  512. operation_set_csn(op, csn);
  513. slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, target_uuid);
  514. slapi_pblock_get( pb, SLAPI_OPERATION_PARAMETERS, &op_params );
  515. op_params->p.p_modrdn.modrdn_newsuperior_address.uniqueid= newsuperior_uuid; /* JCMREPL - Not very elegant */
  516. }
  517. /*
  518. * The replicated modrdn operation may also contain a sequence
  519. * that contains side effects of the modrdn operation, e.g. the
  520. * modifiersname and modifytimestamp are updated.
  521. */
  522. if (NULL != modrdn_mods)
  523. {
  524. LDAPMod **mods;
  525. Slapi_Mods smods;
  526. int i;
  527. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  528. slapi_mods_init_passin(&smods, mods);
  529. for (i = 0; NULL != modrdn_mods[i]; i++)
  530. {
  531. slapi_mods_add_ldapmod(&smods, modrdn_mods[i]); /* Does not copy mod */
  532. }
  533. mods = slapi_mods_get_ldapmods_passout(&smods);
  534. slapi_pblock_set(pb, SLAPI_MODIFY_MODS, mods);
  535. slapi_mods_done(&smods);
  536. slapi_ch_free((void **)&modrdn_mods); /* Free container only - contents are referred to by array "mods" */
  537. }
  538. }
  539. else
  540. {
  541. PR_ASSERT(0); /* JCMREPL - A Replicated Operation with no Repl Baggage control... What does that mean? */
  542. }
  543. }
  544. else
  545. {
  546. /* Replicated & Fixup Operation */
  547. }
  548. }
  549. else
  550. {
  551. slapi_operation_set_csngen_handler ( op, (void*)replica_generate_next_csn );
  552. }
  553. copy_operation_parameters(pb);
  554. return 0;
  555. }
  556. int
  557. multimaster_preop_search (Slapi_PBlock *pb)
  558. {
  559. return 0;
  560. }
  561. int
  562. multimaster_preop_compare (Slapi_PBlock *pb)
  563. {
  564. return 0;
  565. }
  566. static void
  567. purge_entry_state_information (Slapi_PBlock *pb)
  568. {
  569. CSN *purge_csn;
  570. Object *repl_obj;
  571. Replica *replica;
  572. /* we don't want to trim RUV tombstone because we will
  573. deadlock with ourself */
  574. if (ruv_tombstone_op (pb))
  575. return;
  576. repl_obj = replica_get_replica_for_op(pb);
  577. if (NULL != repl_obj)
  578. {
  579. replica = object_get_data(repl_obj);
  580. if (NULL != replica)
  581. {
  582. purge_csn = replica_get_purge_csn(replica);
  583. }
  584. if (NULL != purge_csn)
  585. {
  586. Slapi_Entry *e;
  587. int optype;
  588. slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &optype);
  589. switch (optype)
  590. {
  591. case SLAPI_OPERATION_MODIFY:
  592. slapi_pblock_get(pb, SLAPI_MODIFY_EXISTING_ENTRY, &e);
  593. break;
  594. case SLAPI_OPERATION_MODRDN:
  595. /* XXXggood - the following always gives a NULL entry - why? */
  596. slapi_pblock_get(pb, SLAPI_MODRDN_EXISTING_ENTRY, &e);
  597. break;
  598. case SLAPI_OPERATION_DELETE:
  599. slapi_pblock_get(pb, SLAPI_DELETE_EXISTING_ENTRY, &e);
  600. break;
  601. default:
  602. e = NULL; /* Don't purge on ADD - not needed */
  603. break;
  604. }
  605. if (NULL != e)
  606. {
  607. char csn_str[CSN_STRSIZE];
  608. entry_purge_state_information(e, purge_csn);
  609. /* conntion is always null */
  610. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  611. "Purged state information from entry %s up to "
  612. "CSN %s\n", slapi_entry_get_dn(e),
  613. csn_as_string(purge_csn, PR_FALSE, csn_str));
  614. }
  615. csn_free(&purge_csn);
  616. }
  617. object_release(repl_obj);
  618. }
  619. }
  620. int
  621. multimaster_bepreop_add (Slapi_PBlock *pb)
  622. {
  623. int rc= 0;
  624. Slapi_Operation *op;
  625. int is_replicated_operation;
  626. int is_fixup_operation;
  627. int is_legacy_operation;
  628. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  629. is_replicated_operation= operation_is_flag_set(op,OP_FLAG_REPLICATED);
  630. is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
  631. is_legacy_operation= operation_is_flag_set(op,OP_FLAG_LEGACY_REPLICATION_DN);
  632. /* For replicated operations, apply URP algorithm */
  633. if (is_replicated_operation && !is_fixup_operation)
  634. {
  635. rc = urp_add_operation(pb);
  636. }
  637. return rc;
  638. }
  639. int
  640. multimaster_bepreop_delete (Slapi_PBlock *pb)
  641. {
  642. int rc= 0;
  643. Slapi_Operation *op;
  644. int is_replicated_operation;
  645. int is_fixup_operation;
  646. int is_legacy_operation;
  647. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  648. is_replicated_operation= operation_is_flag_set(op,OP_FLAG_REPLICATED);
  649. is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
  650. is_legacy_operation= operation_is_flag_set(op,OP_FLAG_LEGACY_REPLICATION_DN);
  651. /* For replicated operations, apply URP algorithm */
  652. if(is_replicated_operation && !is_fixup_operation)
  653. {
  654. rc = urp_delete_operation(pb);
  655. }
  656. return rc;
  657. }
  658. int
  659. multimaster_bepreop_modify (Slapi_PBlock *pb)
  660. {
  661. int rc= 0;
  662. Slapi_Operation *op;
  663. int is_replicated_operation;
  664. int is_fixup_operation;
  665. int is_legacy_operation;
  666. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  667. is_replicated_operation= operation_is_flag_set(op,OP_FLAG_REPLICATED);
  668. is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
  669. is_legacy_operation= operation_is_flag_set(op,OP_FLAG_LEGACY_REPLICATION_DN);
  670. /* For replicated operations, apply URP algorithm */
  671. if(is_replicated_operation && !is_fixup_operation)
  672. {
  673. rc = urp_modify_operation(pb);
  674. }
  675. /* Clean up old state information */
  676. purge_entry_state_information(pb);
  677. return rc;
  678. }
  679. int
  680. multimaster_bepreop_modrdn (Slapi_PBlock *pb)
  681. {
  682. int rc= 0;
  683. Slapi_Operation *op;
  684. int is_replicated_operation;
  685. int is_fixup_operation;
  686. int is_legacy_operation;
  687. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  688. is_replicated_operation= operation_is_flag_set(op,OP_FLAG_REPLICATED);
  689. is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
  690. is_legacy_operation= operation_is_flag_set(op,OP_FLAG_LEGACY_REPLICATION_DN);
  691. /* For replicated operations, apply URP algorithm */
  692. if(is_replicated_operation && !is_fixup_operation)
  693. {
  694. rc = urp_modrdn_operation(pb);
  695. }
  696. /* Clean up old state information */
  697. purge_entry_state_information(pb);
  698. return rc;
  699. }
  700. int
  701. multimaster_bepostop_modrdn (Slapi_PBlock *pb)
  702. {
  703. return 0;
  704. }
  705. int
  706. multimaster_bepostop_delete (Slapi_PBlock *pb)
  707. {
  708. return 0;
  709. }
  710. /* postop - write to changelog */
  711. int
  712. multimaster_postop_bind (Slapi_PBlock *pb)
  713. {
  714. return 0;
  715. }
  716. int
  717. multimaster_postop_add (Slapi_PBlock *pb)
  718. {
  719. return process_postop(pb);
  720. }
  721. int
  722. multimaster_postop_delete (Slapi_PBlock *pb)
  723. {
  724. int rc;
  725. Slapi_Operation *op;
  726. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  727. if ( ! operation_is_flag_set (op, OP_FLAG_REPL_FIXUP) )
  728. {
  729. urp_post_delete_operation (pb);
  730. }
  731. rc = process_postop(pb);
  732. return rc;
  733. }
  734. int
  735. multimaster_postop_modify (Slapi_PBlock *pb)
  736. {
  737. return process_postop(pb);
  738. }
  739. int
  740. multimaster_postop_modrdn (Slapi_PBlock *pb)
  741. {
  742. int rc;
  743. Slapi_Operation *op;
  744. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  745. if ( ! operation_is_flag_set (op, OP_FLAG_REPL_FIXUP) )
  746. {
  747. urp_post_modrdn_operation (pb);
  748. }
  749. rc = process_postop(pb);
  750. return rc;
  751. }
  752. /* Helper functions */
  753. /*
  754. * This function makes a copy of the operation parameters
  755. * and stashes them in the consumer operation extension.
  756. * This is where the 5.0 Change Log will get the operation
  757. * details from.
  758. */
  759. static void
  760. copy_operation_parameters(Slapi_PBlock *pb)
  761. {
  762. Slapi_Operation *op = NULL;
  763. struct slapi_operation_parameters *op_params;
  764. supplier_operation_extension *opext;
  765. Object *repl_obj;
  766. Replica *replica;
  767. repl_obj = replica_get_replica_for_op (pb);
  768. /* we are only interested in the updates to replicas */
  769. if (repl_obj)
  770. {
  771. /* we only save the original operation parameters for replicated operations
  772. since client operations don't go through urp engine and pblock data can be logged */
  773. slapi_pblock_get( pb, SLAPI_OPERATION, &op );
  774. PR_ASSERT (op);
  775. replica = (Replica*)object_get_data (repl_obj);
  776. PR_ASSERT (replica);
  777. opext = (supplier_operation_extension*) repl_sup_get_ext (REPL_SUP_EXT_OP, op);
  778. if (operation_is_flag_set(op,OP_FLAG_REPLICATED) &&
  779. !operation_is_flag_set(op, OP_FLAG_REPL_FIXUP))
  780. {
  781. slapi_pblock_get (pb, SLAPI_OPERATION_PARAMETERS, &op_params);
  782. opext->operation_parameters= operation_parameters_dup(op_params);
  783. }
  784. /* this condition is needed to avoid re-entering lock when
  785. ruv state is updated */
  786. if (!operation_is_flag_set(op, OP_FLAG_REPL_FIXUP))
  787. {
  788. /* save replica generation in case it changes */
  789. opext->repl_gen = replica_get_generation (replica);
  790. }
  791. object_release (repl_obj);
  792. }
  793. }
  794. /*
  795. * Helper function: update the RUV so that it reflects the
  796. * locally-processed update. This is called for both replicated
  797. * and non-replicated operations.
  798. */
  799. static void
  800. update_ruv_component(Replica *replica, CSN *opcsn, Slapi_PBlock *pb)
  801. {
  802. PRBool legacy;
  803. char *purl;
  804. if (!replica || !opcsn)
  805. return;
  806. /* Replica configured, so update its ruv */
  807. legacy = replica_is_legacy_consumer (replica);
  808. if (legacy)
  809. purl = replica_get_legacy_purl (replica);
  810. else
  811. purl = (char*)replica_get_purl_for_op (replica, pb, opcsn);
  812. replica_update_ruv(replica, opcsn, purl);
  813. if (legacy)
  814. {
  815. slapi_ch_free ((void**)&purl);
  816. }
  817. }
  818. /*
  819. * Write the changelog. Note: it is an error to call write_changelog_and_ruv() for fixup
  820. * operations. The caller should avoid calling this function if the operation is
  821. * a fixup op.
  822. * Also update the ruv - we need to do this while we have the replica lock acquired
  823. * so that the csn is written to the changelog and the ruv is updated with the csn
  824. * in one atomic operation - if there is no changelog, we still need to update
  825. * the ruv (e.g. for consumers)
  826. */
  827. static int
  828. write_changelog_and_ruv (Slapi_PBlock *pb)
  829. {
  830. int rc;
  831. slapi_operation_parameters *op_params = NULL;
  832. Object *repl_obj;
  833. int return_value = 0;
  834. Replica *r;
  835. /* we only log changes for operations applied to a replica */
  836. repl_obj = replica_get_replica_for_op (pb);
  837. if (repl_obj == NULL)
  838. return 0;
  839. r = (Replica*)object_get_data (repl_obj);
  840. PR_ASSERT (r);
  841. if (replica_is_flag_set (r, REPLICA_LOG_CHANGES) &&
  842. (cl5GetState () == CL5_STATE_OPEN))
  843. {
  844. supplier_operation_extension *opext = NULL;
  845. const char *repl_name;
  846. char *repl_gen;
  847. Slapi_Operation *op;
  848. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  849. opext = (supplier_operation_extension*) repl_sup_get_ext (REPL_SUP_EXT_OP, op);
  850. PR_ASSERT (opext);
  851. /* get replica generation and replica name to pass to the write function */
  852. repl_name = replica_get_name (r);
  853. repl_gen = opext->repl_gen;
  854. PR_ASSERT (repl_name && repl_gen);
  855. /* for replicated operations, we log the original, non-urp data which is
  856. saved in the operation extension */
  857. if (operation_is_flag_set(op,OP_FLAG_REPLICATED))
  858. {
  859. PR_ASSERT (opext->operation_parameters);
  860. op_params = opext->operation_parameters;
  861. }
  862. else /* since client operations don't go through urp, we log the operation data in pblock */
  863. {
  864. Slapi_Entry *e = NULL;
  865. const char *uniqueid = NULL;
  866. slapi_pblock_get (pb, SLAPI_OPERATION_PARAMETERS, &op_params);
  867. PR_ASSERT (op_params);
  868. /* need to set uniqueid operation parameter */
  869. /* we try to use the appropriate entry (pre op or post op)
  870. depending on the type of operation (add, delete, modify)
  871. However, in some cases, the backend operation may fail in
  872. a non fatal way (e.g. attempt to remove an attribute value
  873. that does not exist) but we still need to log the change.
  874. So, the POST_OP entry may not have been set in the FE modify
  875. code. In that case, we use the PRE_OP entry.
  876. */
  877. slapi_pblock_get (pb, SLAPI_ENTRY_POST_OP, &e);
  878. if ((e == NULL) ||
  879. (op_params->operation_type == SLAPI_OPERATION_DELETE))
  880. {
  881. slapi_pblock_get (pb, SLAPI_ENTRY_PRE_OP, &e);
  882. }
  883. PR_ASSERT (e);
  884. uniqueid = slapi_entry_get_uniqueid (e);
  885. PR_ASSERT (uniqueid);
  886. op_params->target_address.uniqueid = slapi_ch_strdup (uniqueid);
  887. }
  888. /* we might have stripped all the mods - in that case we do not
  889. log the operation */
  890. if (op_params->operation_type != SLAPI_OPERATION_MODIFY ||
  891. op_params->p.p_modify.modify_mods != NULL)
  892. {
  893. if (cl5_is_diskfull() && !cl5_diskspace_is_available())
  894. {
  895. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  896. "write_changelog_and_ruv: Skipped due to DISKFULL\n");
  897. return 0;
  898. }
  899. rc = cl5WriteOperation(repl_name, repl_gen, op_params,
  900. !operation_is_flag_set(op, OP_FLAG_REPLICATED));
  901. if (rc != CL5_SUCCESS)
  902. {
  903. char csn_str[CSN_STRSIZE];
  904. /* ONREPL - log error */
  905. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  906. "write_changelog_and_ruv: can't add a change for "
  907. "%s (uniqid: %s, optype: %u) to changelog csn %s\n",
  908. op_params->target_address.dn,
  909. op_params->target_address.uniqueid,
  910. op_params->operation_type,
  911. csn_as_string(op_params->csn, PR_FALSE, csn_str));
  912. return_value = 1;
  913. }
  914. }
  915. if (!operation_is_flag_set(op,OP_FLAG_REPLICATED))
  916. {
  917. slapi_ch_free((void**)&op_params->target_address.uniqueid);
  918. }
  919. }
  920. /*
  921. This was moved because we need to write the changelog and update
  922. the ruv in one atomic operation - I have seen cases where the inc
  923. protocol thread interrupts this thread between the time the changelog
  924. is written and the ruv is updated - this causes confusion in several
  925. places, especially in _cl5SkipReplayEntry since it cannot find the csn it
  926. just read from the changelog in either the supplier or consumer ruv
  927. */
  928. if (0 == return_value) {
  929. Slapi_Operation *op;
  930. CSN *opcsn;
  931. slapi_pblock_get( pb, SLAPI_OPERATION, &op );
  932. opcsn = operation_get_csn(op);
  933. update_ruv_component(r, opcsn, pb);
  934. }
  935. object_release (repl_obj);
  936. return return_value;
  937. }
  938. /*
  939. * Postop processing - write the changelog if the operation resulted in
  940. * an LDAP_SUCCESS result code, update the RUV, and notify the replication
  941. * agreements about the change.
  942. * If the result code is not LDAP_SUCCESS, then cancel the operation CSN.
  943. */
  944. static int
  945. process_postop (Slapi_PBlock *pb)
  946. {
  947. int rc = LDAP_SUCCESS;
  948. Slapi_Operation *op;
  949. Slapi_Backend *be;
  950. int is_replicated_operation = 0;
  951. CSN *opcsn = NULL;
  952. char sessionid[REPL_SESSION_ID_SIZE];
  953. /* we just let fixup operations through */
  954. slapi_pblock_get( pb, SLAPI_OPERATION, &op );
  955. if ((operation_is_flag_set(op, OP_FLAG_REPL_FIXUP)) ||
  956. (operation_is_flag_set(op, OP_FLAG_TOMBSTONE_ENTRY)))
  957. {
  958. return 0;
  959. }
  960. /* ignore operations intended for chaining backends - they will be
  961. replicated back to us or should be ignored anyway
  962. replicated operations should be processed normally, as they should
  963. be going to a local backend */
  964. is_replicated_operation= operation_is_flag_set(op,OP_FLAG_REPLICATED);
  965. slapi_pblock_get(pb, SLAPI_BACKEND, &be);
  966. if (!is_replicated_operation &&
  967. slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA))
  968. {
  969. return 0;
  970. }
  971. get_repl_session_id (pb, sessionid, &opcsn);
  972. slapi_pblock_get(pb, SLAPI_RESULT_CODE, &rc);
  973. /*
  974. * Don't abandon writing changelog since we'd do everything
  975. * possible to keep the changelog in sync with the backend
  976. * db which was committed before this function was called.
  977. *
  978. * if (rc == LDAP_SUCCESS && !slapi_op_abandoned(pb))
  979. */
  980. if (rc == LDAP_SUCCESS)
  981. {
  982. rc = write_changelog_and_ruv(pb);
  983. if (rc == 0)
  984. {
  985. agmtlist_notify_all(pb);
  986. }
  987. else
  988. {
  989. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "%s process postop: error writing changelog and ruv\n", sessionid);
  990. }
  991. }
  992. else if (opcsn)
  993. {
  994. rc = cancel_opcsn (pb);
  995. /* Don't try to get session id since conn is always null */
  996. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  997. "%s process postop: canceling operation csn\n", sessionid);
  998. }
  999. /* the target unique id is set in the modify_preop above, so
  1000. we need to free it */
  1001. /* The following bunch of frees code does not belong to this place
  1002. * but rather to operation_free who should be responsible for calling
  1003. * operation_parameters_free and it doesn't. I guess this is like this
  1004. * because several crashes happened in the past regarding some opparams
  1005. * that were getting individually freed before they should. Whatever
  1006. * the case, this is not the place and we should make sure that this
  1007. * code gets removed for 5.next and substituted by the strategy (operation_free).
  1008. * For 5.0, such change is too risky, so this will be done here */
  1009. if (is_replicated_operation)
  1010. {
  1011. slapi_operation_parameters *op_params = NULL;
  1012. int optype = 0;
  1013. /* target uid and csn are set for all repl operations. Free them */
  1014. char *target_uuid = NULL;
  1015. slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &optype);
  1016. slapi_pblock_get(pb, SLAPI_TARGET_UNIQUEID, &target_uuid);
  1017. slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, NULL);
  1018. slapi_ch_free((void**)&target_uuid);
  1019. if (optype == SLAPI_OPERATION_ADD) {
  1020. slapi_pblock_get( pb, SLAPI_OPERATION_PARAMETERS, &op_params );
  1021. slapi_ch_free((void **) &op_params->p.p_add.parentuniqueid);
  1022. }
  1023. if (optype == SLAPI_OPERATION_MODRDN) {
  1024. slapi_pblock_get( pb, SLAPI_OPERATION_PARAMETERS, &op_params );
  1025. slapi_ch_free((void **) &op_params->p.p_modrdn.modrdn_newsuperior_address.uniqueid);
  1026. }
  1027. }
  1028. if (NULL == opcsn)
  1029. opcsn = operation_get_csn(op);
  1030. if (opcsn)
  1031. csn_free(&opcsn);
  1032. return rc;
  1033. }
  1034. /*
  1035. * Cancel an operation CSN. This removes it from any CSN pending lists.
  1036. * This function is called when a previously-generated CSN will not
  1037. * be needed, e.g. if the update operation produced an error.
  1038. */
  1039. static int
  1040. cancel_opcsn (Slapi_PBlock *pb)
  1041. {
  1042. Object *repl_obj;
  1043. Slapi_Operation *op = NULL;
  1044. PR_ASSERT (pb);
  1045. repl_obj = replica_get_replica_for_op (pb);
  1046. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  1047. PR_ASSERT (op);
  1048. if (repl_obj)
  1049. {
  1050. Replica *r;
  1051. Object *gen_obj;
  1052. CSNGen *gen;
  1053. CSN *opcsn;
  1054. r = (Replica*)object_get_data (repl_obj);
  1055. PR_ASSERT (r);
  1056. opcsn = operation_get_csn(op);
  1057. if (!operation_is_flag_set(op,OP_FLAG_REPLICATED))
  1058. {
  1059. /* get csn generator for the replica */
  1060. gen_obj = replica_get_csngen (r);
  1061. PR_ASSERT (gen_obj);
  1062. gen = (CSNGen*)object_get_data (gen_obj);
  1063. if (NULL != opcsn)
  1064. {
  1065. csngen_abort_csn (gen, operation_get_csn(op));
  1066. }
  1067. object_release (gen_obj);
  1068. }
  1069. else if (!operation_is_flag_set(op,OP_FLAG_REPL_FIXUP))
  1070. {
  1071. Object *ruv_obj;
  1072. ruv_obj = replica_get_ruv (r);
  1073. PR_ASSERT (ruv_obj);
  1074. ruv_cancel_csn_inprogress ((RUV*)object_get_data (ruv_obj), opcsn);
  1075. object_release (ruv_obj);
  1076. }
  1077. object_release (repl_obj);
  1078. }
  1079. return 0;
  1080. }
  1081. /*
  1082. * Return non-zero if the target entry DN is the DN of the RUV tombstone
  1083. * entry.
  1084. * The entry has rdn of nsuniqueid = ffffffff-ffffffff-ffffffff-ffffffff
  1085. */
  1086. static int
  1087. ruv_tombstone_op (Slapi_PBlock *pb)
  1088. {
  1089. char *uniqueid;
  1090. int rc;
  1091. slapi_pblock_get (pb, SLAPI_TARGET_UNIQUEID, &uniqueid);
  1092. rc = uniqueid && strcasecmp (uniqueid, RUV_STORAGE_ENTRY_UNIQUEID) == 0;
  1093. return rc;
  1094. }
  1095. /* we don't want to process replicated operations with csn smaller
  1096. than the corresponding csn in the consumer's ruv */
  1097. static PRBool
  1098. process_operation (Slapi_PBlock *pb, const CSN *csn)
  1099. {
  1100. Object *r_obj;
  1101. Replica *r;
  1102. Object *ruv_obj;
  1103. RUV *ruv;
  1104. int rc;
  1105. r_obj = replica_get_replica_for_op(pb);
  1106. if (r_obj == NULL)
  1107. {
  1108. char sessionid[REPL_SESSION_ID_SIZE];
  1109. get_repl_session_id (pb, sessionid, NULL);
  1110. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "%s process_operation: "
  1111. "can't locate replica for the replicated operation\n",
  1112. sessionid );
  1113. return PR_FALSE;
  1114. }
  1115. r = (Replica*)object_get_data (r_obj);
  1116. PR_ASSERT (r);
  1117. ruv_obj = replica_get_ruv (r);
  1118. PR_ASSERT (ruv_obj);
  1119. ruv = (RUV*)object_get_data (ruv_obj);
  1120. PR_ASSERT (ruv);
  1121. rc = ruv_add_csn_inprogress (ruv, csn);
  1122. object_release (ruv_obj);
  1123. object_release (r_obj);
  1124. return (rc == RUV_SUCCESS);
  1125. }
  1126. static PRBool
  1127. is_mmr_replica (Slapi_PBlock *pb)
  1128. {
  1129. Object *r_obj;
  1130. Replica *r;
  1131. PRBool mmr;
  1132. r_obj = replica_get_replica_for_op(pb);
  1133. if (r_obj == NULL)
  1134. {
  1135. return PR_FALSE;
  1136. }
  1137. r = (Replica*)object_get_data (r_obj);
  1138. PR_ASSERT (r);
  1139. mmr = !replica_is_legacy_consumer (r);
  1140. object_release (r_obj);
  1141. return mmr;
  1142. }
  1143. static const char *replica_get_purl_for_op (const Replica *r, Slapi_PBlock *pb, const CSN *opcsn)
  1144. {
  1145. int is_replicated_op;
  1146. const char *purl;
  1147. slapi_pblock_get(pb, SLAPI_IS_MMR_REPLICATED_OPERATION, &is_replicated_op);
  1148. if (!is_replicated_op)
  1149. {
  1150. purl = multimaster_get_local_purl();
  1151. }
  1152. else
  1153. {
  1154. /* Get the appropriate partial URL from the supplier RUV */
  1155. Slapi_Connection *conn;
  1156. consumer_connection_extension *connext;
  1157. slapi_pblock_get(pb, SLAPI_CONNECTION, &conn);
  1158. connext = (consumer_connection_extension *)repl_con_get_ext(
  1159. REPL_CON_EXT_CONN, conn);
  1160. if (NULL == connext || NULL == connext->supplier_ruv)
  1161. {
  1162. char sessionid[REPL_SESSION_ID_SIZE];
  1163. get_repl_session_id (pb, sessionid, NULL);
  1164. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "%s replica_get_purl_for_op: "
  1165. "cannot obtain consumer connection extension or supplier_ruv.\n",
  1166. sessionid);
  1167. }
  1168. else
  1169. {
  1170. purl = ruv_get_purl_for_replica(connext->supplier_ruv,
  1171. csn_get_replicaid(opcsn));
  1172. }
  1173. }
  1174. return purl;
  1175. }
  1176. /* ONREPL at the moment, I decided not to trim copiedFrom and copyingFrom
  1177. attributes when sending operation to replicas. This is because, each
  1178. operation results in a state information stored in the database and
  1179. if we don't replay all operations we will endup with state inconsistency.
  1180. Keeping the function just in case
  1181. */
  1182. static void strip_legacy_info (slapi_operation_parameters *op_params)
  1183. {
  1184. switch (op_params->operation_type)
  1185. {
  1186. case SLAPI_OPERATION_ADD:
  1187. slapi_entry_delete_values_sv(op_params->p.p_add.target_entry,
  1188. type_copiedFrom, NULL);
  1189. slapi_entry_delete_values_sv(op_params->p.p_add.target_entry,
  1190. type_copyingFrom, NULL);
  1191. break;
  1192. case SLAPI_OPERATION_MODIFY:
  1193. {
  1194. Slapi_Mods smods;
  1195. LDAPMod *mod;
  1196. slapi_mods_init_byref(&smods, op_params->p.p_modify.modify_mods);
  1197. mod = slapi_mods_get_first_mod(&smods);
  1198. while (mod)
  1199. {
  1200. /* modify just to update copiedFrom or copyingFrom attribute
  1201. does not contain modifiersname or modifytime - so we don't
  1202. have to strip them */
  1203. if (strcasecmp (mod->mod_type, type_copiedFrom) == 0 ||
  1204. strcasecmp (mod->mod_type, type_copyingFrom) == 0)
  1205. slapi_mods_remove(&smods);
  1206. mod = slapi_mods_get_next_mod(&smods);
  1207. }
  1208. op_params->p.p_modify.modify_mods = slapi_mods_get_ldapmods_passout (&smods);
  1209. slapi_mods_done (&smods);
  1210. break;
  1211. }
  1212. default: break;
  1213. }
  1214. }
  1215. /* this function is called when state of a backend changes */
  1216. void
  1217. multimaster_be_state_change (void *handle, char *be_name, int old_be_state, int new_be_state)
  1218. {
  1219. Object *r_obj;
  1220. Replica *r;
  1221. /* check if we have replica associated with the backend */
  1222. r_obj = replica_get_for_backend (be_name);
  1223. if (r_obj == NULL)
  1224. return;
  1225. r = (Replica*)object_get_data (r_obj);
  1226. PR_ASSERT (r);
  1227. if (new_be_state == SLAPI_BE_STATE_ON)
  1228. {
  1229. /* backend came back online - restart replication */
  1230. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "multimaster_be_state_change: "
  1231. "replica %s is coming online; enabling replication\n",
  1232. slapi_sdn_get_ndn (replica_get_root (r)));
  1233. replica_enable_replication (r);
  1234. }
  1235. else if (new_be_state == SLAPI_BE_STATE_OFFLINE)
  1236. {
  1237. /* backend is about to be taken down - disable replication */
  1238. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "multimaster_be_state_change: "
  1239. "replica %s is going offline; disabling replication\n",
  1240. slapi_sdn_get_ndn (replica_get_root (r)));
  1241. replica_disable_replication (r, r_obj);
  1242. }
  1243. else if (new_be_state == SLAPI_BE_STATE_DELETE)
  1244. {
  1245. /* backend is about to be removed - disable replication */
  1246. if (old_be_state == SLAPI_BE_STATE_ON)
  1247. {
  1248. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "multimaster_be_state_change: "
  1249. "replica %s is about to be deleted; disabling replication\n",
  1250. slapi_sdn_get_ndn (replica_get_root (r)));
  1251. replica_disable_replication (r, r_obj);
  1252. }
  1253. }
  1254. object_release (r_obj);
  1255. }
  1256. static void
  1257. close_changelog_for_replica (Object *r_obj)
  1258. {
  1259. if (cl5GetState () == CL5_STATE_OPEN)
  1260. cl5CloseDB (r_obj);
  1261. }