repl5_agmt.c 85 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122
  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_agmt.c */
  42. /*
  43. Support for 5.0-style replication agreements.
  44. Directory Server 5.0 replication agreements contain information about
  45. replication consumers that we are supplying.
  46. This module encapsulates the methods available for adding, deleting,
  47. modifying, and firing replication agreements.
  48. Methods:
  49. agmt_new - Create a new replication agreement, in response to a new
  50. replication agreement being added over LDAP.
  51. agmt_delete - Destroy an agreement. It is an error to destroy an
  52. agreement that has not been stopped.
  53. agmt_getstatus - get the status of this replication agreement.
  54. agmt_replicate_now - initiate a replication session asap, even if the
  55. schedule says we shouldn't.
  56. agmt_start - start replicating, according to schedule. Starts a new
  57. thread to handle replication.
  58. agmt_stop - stop replicating asap and end replication thread.
  59. agmt_notify_change - notify the replication agreement about a change that
  60. has been logged. The replication agreement will
  61. decide if it needs to take some action, e.g. start a
  62. replication session.
  63. agmt_initialize_replica - start a complete replica refresh.
  64. agmt_set_schedule_from_entry - (re)set the schedule associated with this
  65. replication agreement based on a RA entry's contents.
  66. agmt_set_credentials_from_entry - (re)set the credentials used to bind
  67. to the remote replica.
  68. agmt_set_binddn_from_entry - (re)set the DN used to bind
  69. to the remote replica.
  70. agmt_set_bind_method_from_entry - (re)set the bind method used to bind
  71. to the remote replica (SIMPLE or SSLCLIENTAUTH).
  72. agmt_set_transportinfo_from_entry - (re)set the transport used to bind
  73. to the remote replica (SSL or not)
  74. */
  75. #include "repl5.h"
  76. #include "repl5_prot_private.h"
  77. #include "cl5_api.h"
  78. #include "slapi-plugin.h"
  79. #define DEFAULT_TIMEOUT 600 /* (seconds) default outbound LDAP connection */
  80. #define STATUS_LEN 1024
  81. struct changecounter {
  82. ReplicaId rid;
  83. PRUint32 num_replayed;
  84. PRUint32 num_skipped;
  85. };
  86. typedef struct repl5agmt {
  87. char *hostname; /* remote hostname */
  88. int port; /* port of remote server */
  89. PRUint32 transport_flags; /* SSL, TLS, etc. */
  90. char *binddn; /* DN to bind as */
  91. struct berval *creds; /* Password, or certificate */
  92. int bindmethod; /* Bind method - simple, SSL */
  93. Slapi_DN *replarea; /* DN of replicated area */
  94. char **frac_attrs; /* list of fractional attributes to be replicated */
  95. char **frac_attrs_total; /* list of fractional attributes to be replicated for total update protocol */
  96. Schedule *schedule; /* Scheduling information */
  97. int auto_initialize; /* 1 = automatically re-initialize replica */
  98. const Slapi_DN *dn; /* DN of replication agreement entry */
  99. const Slapi_RDN *rdn; /* RDN of replication agreement entry */
  100. char *long_name; /* Long name (rdn + host, port) of entry, for logging */
  101. Repl_Protocol *protocol; /* Protocol object - manages protocol */
  102. struct changecounter **changecounters; /* changes sent/skipped since server start up */
  103. int num_changecounters;
  104. int max_changecounters;
  105. time_t last_update_start_time; /* Local start time of last update session */
  106. time_t last_update_end_time; /* Local end time of last update session */
  107. char last_update_status[STATUS_LEN]; /* Status of last update. Format = numeric code <space> textual description */
  108. PRBool update_in_progress;
  109. PRBool is_enabled;
  110. time_t last_init_start_time; /* Local start time of last total init */
  111. time_t last_init_end_time; /* Local end time of last total init */
  112. char last_init_status[STATUS_LEN]; /* Status of last total init. Format = numeric code <space> textual description */
  113. PRLock *lock;
  114. Object *consumerRUV; /* last RUV received from the consumer - used for changelog purging */
  115. CSN *consumerSchemaCSN; /* last schema CSN received from the consumer */
  116. ReplicaId consumerRID; /* indicates if the consumer is the originator of a CSN */
  117. int tmpConsumerRID; /* Indicates the consumer rid was set from the agmt maxcsn - it should be refreshed */
  118. long timeout; /* timeout (in seconds) for outbound LDAP connections to remote server */
  119. PRBool stop_in_progress; /* set by agmt_stop when shutting down */
  120. long busywaittime; /* time in seconds to wait after getting a REPLICA BUSY from the consumer -
  121. to allow another supplier to finish sending its updates -
  122. if set to 0, this means to use the default value if we get a busy
  123. signal from the consumer */
  124. long pausetime; /* time in seconds to pause after sending updates -
  125. to allow another supplier to send its updates -
  126. should be greater than busywaittime -
  127. if set to 0, this means do not pause */
  128. void *priv; /* private data, used for windows-specific agreement data
  129. for sync agreements or for replication session plug-in
  130. private data for normal replication agreements */
  131. char **attrs_to_strip; /* for fractional replication, if a "mod" is empty, strip out these attributes:
  132. * modifiersname, modifytimestamp, internalModifiersname, internalModifyTimestamp, etc */
  133. int agreement_type;
  134. Slapi_Counter *protocol_timeout;
  135. char *maxcsn; /* agmt max csn */
  136. Slapi_RWLock *attr_lock; /* RW lock for all the stripped attrs */
  137. } repl5agmt;
  138. /* Forward declarations */
  139. void agmt_delete(void **rap);
  140. static void update_window_state_change_callback (void *arg, PRBool opened);
  141. static int get_agmt_status(Slapi_PBlock *pb, Slapi_Entry* e,
  142. Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
  143. static int agmt_set_bind_method_no_lock(Repl_Agmt *ra, const Slapi_Entry *e);
  144. static int agmt_set_transportinfo_no_lock(Repl_Agmt *ra, const Slapi_Entry *e);
  145. static ReplicaId agmt_maxcsn_get_rid(char *maxcsn);
  146. /*
  147. Schema for replication agreement:
  148. cn
  149. nsds5ReplicaHost - hostname
  150. nsds5ReplicaPort - port number
  151. nsds5ReplicaTransportInfo - "SSL", "startTLS", or may be absent;
  152. nsds5ReplicaBindDN
  153. nsds5ReplicaCredentials
  154. nsds5ReplicaBindMethod - "SIMPLE" or "SSLCLIENTAUTH".
  155. nsds5ReplicaRoot - Replicated suffix
  156. nsds5ReplicatedAttributeList - Fractional attrs for incremental update protocol (and total if not separately defined)
  157. nsds5ReplicatedAttributeListTotal - Fractional attrs for total update protocol
  158. nsds5ReplicaUpdateSchedule
  159. nsds5ReplicaTimeout - Outbound repl operations timeout
  160. nsds50ruv - consumer's RUV
  161. nsds5ReplicaBusyWaitTime - time to wait after getting a REPLICA BUSY from the consumer
  162. nsds5ReplicaSessionPauseTime - time to pause after sending updates to allow another supplier to send
  163. */
  164. /*
  165. * Validate an agreement, making sure that it's valid.
  166. * Return 1 if the agreement is valid, 0 otherwise.
  167. */
  168. static int
  169. agmt_is_valid(Repl_Agmt *ra)
  170. {
  171. int return_value = 1; /* assume valid, initially */
  172. PR_ASSERT(NULL != ra);
  173. PR_ASSERT(NULL != ra->dn);
  174. if (NULL == ra->hostname)
  175. {
  176. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Replication agreement \"%s\" "
  177. "is malformed: missing host name.\n", slapi_sdn_get_dn(ra->dn));
  178. return_value = 0;
  179. }
  180. if (ra->port <= 0)
  181. {
  182. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Replication agreement \"%s\" "
  183. "is malformed: invalid port number %d.\n", slapi_sdn_get_dn(ra->dn), ra->port);
  184. return_value = 0;
  185. }
  186. if (ra->timeout < 0)
  187. {
  188. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Replication agreement \"%s\" "
  189. "is malformed: invalid timeout %ld.\n", slapi_sdn_get_dn(ra->dn), ra->timeout);
  190. return_value = 0;
  191. }
  192. if (ra->busywaittime < 0)
  193. {
  194. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Replication agreement \"%s\" "
  195. "is malformed: invalid busy wait time %ld.\n", slapi_sdn_get_dn(ra->dn), ra->busywaittime);
  196. return_value = 0;
  197. }
  198. if (ra->pausetime < 0)
  199. {
  200. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Replication agreement \"%s\" "
  201. "is malformed: invalid pausetime %ld.\n", slapi_sdn_get_dn(ra->dn), ra->pausetime);
  202. return_value = 0;
  203. }
  204. if ((0 == ra->transport_flags) && (BINDMETHOD_SSL_CLIENTAUTH == ra->bindmethod)) {
  205. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Replication agreement \"%s\" "
  206. " is malformed: cannot use SSLCLIENTAUTH if using plain LDAP - please "
  207. "change %s to SSL or TLS before changing %s to use SSLCLIENTAUTH\n",
  208. slapi_sdn_get_dn(ra->dn), type_nsds5TransportInfo, type_nsds5ReplicaBindMethod);
  209. return_value = 0;
  210. }
  211. /*
  212. * If we are not using GSSAPI or SSL Client Auth, then a bind dn and password must be present
  213. */
  214. if(BINDMETHOD_SASL_GSSAPI != ra->bindmethod && BINDMETHOD_SSL_CLIENTAUTH != ra->bindmethod){
  215. if(strcmp(ra->binddn,"") == 0 || ra->creds->bv_val == NULL){
  216. char *auth_mech;
  217. if(ra->bindmethod == BINDMETHOD_SIMPLE_AUTH){
  218. auth_mech = "SIMPLE";
  219. } else if (ra->bindmethod == BINDMETHOD_SASL_DIGEST_MD5){
  220. auth_mech = "SASL/DIGEST-MD5";
  221. } else {
  222. auth_mech = "Unknown";
  223. }
  224. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Replication agreement \"%s\" "
  225. "is malformed: a bind DN and password must be supplied for authentication "
  226. "method \"%s\"\n", slapi_sdn_get_dn(ra->dn), auth_mech);
  227. return_value = 0;
  228. }
  229. }
  230. return return_value;
  231. }
  232. Repl_Agmt *
  233. agmt_new_from_entry(Slapi_Entry *e)
  234. {
  235. Repl_Agmt *ra;
  236. Slapi_Attr *sattr;
  237. char *tmpstr;
  238. char **denied_attrs = NULL;
  239. char *auto_initialize = NULL;
  240. char *val_nsds5BeginReplicaRefresh = "start";
  241. ra = (Repl_Agmt *)slapi_ch_calloc(1, sizeof(repl5agmt));
  242. if ((ra->lock = PR_NewLock()) == NULL)
  243. {
  244. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Unable to create new lock "
  245. "for replication agreement \"%s\" - agreement ignored.\n",
  246. slapi_entry_get_dn_const(e));
  247. goto loser;
  248. }
  249. if ((ra->attr_lock = slapi_new_rwlock()) == NULL)
  250. {
  251. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Unable to create new attr lock "
  252. "for replication agreement \"%s\" - agreement ignored.\n",
  253. slapi_entry_get_dn_const(e));
  254. goto loser;
  255. }
  256. ra->protocol_timeout = slapi_counter_new();
  257. /* Find all the stuff we need for the agreement */
  258. /* To Allow Consumer Initialisation when adding an agreement: */
  259. /*
  260. Using 'auto_initialize' member of 'repl5agmt' structure to
  261. store the effect of 'nsds5BeginReplicaRefresh' attribute's value
  262. in it.
  263. */
  264. auto_initialize = slapi_entry_attr_get_charptr(e, type_nsds5BeginReplicaRefresh);
  265. if ((auto_initialize != NULL) && (strcasecmp(auto_initialize, val_nsds5BeginReplicaRefresh) == 0))
  266. {
  267. ra->auto_initialize = STATE_PERFORMING_TOTAL_UPDATE;
  268. }
  269. else
  270. {
  271. ra->auto_initialize = STATE_PERFORMING_INCREMENTAL_UPDATE;
  272. }
  273. if (auto_initialize)
  274. {
  275. slapi_ch_free_string (&auto_initialize);
  276. }
  277. /* Host name of remote replica */
  278. ra->hostname = slapi_entry_attr_get_charptr(e, type_nsds5ReplicaHost);
  279. /* Port number for remote replica instance */
  280. ra->port = slapi_entry_attr_get_int(e, type_nsds5ReplicaPort);
  281. /* SSL, TLS, or other transport stuff */
  282. ra->transport_flags = 0;
  283. agmt_set_transportinfo_no_lock(ra, e);
  284. /* DN to use when binding. May be empty if certain SASL auth is to be used e.g. EXTERNAL GSSAPI. */
  285. ra->binddn = slapi_entry_attr_get_charptr(e, type_nsds5ReplicaBindDN);
  286. if (NULL == ra->binddn)
  287. {
  288. ra->binddn = slapi_ch_strdup("");
  289. }
  290. /* Credentials to use when binding. */
  291. ra->creds = (struct berval *)slapi_ch_malloc(sizeof(struct berval));
  292. ra->creds->bv_val = NULL;
  293. ra->creds->bv_len = 0;
  294. if (slapi_entry_attr_find(e, type_nsds5ReplicaCredentials, &sattr) == 0)
  295. {
  296. Slapi_Value *sval;
  297. if (slapi_attr_first_value(sattr, &sval) == 0)
  298. {
  299. const struct berval *bv = slapi_value_get_berval(sval);
  300. if (NULL != bv)
  301. {
  302. slapi_ber_bvcpy(ra->creds, bv);
  303. }
  304. }
  305. }
  306. /* How to bind */
  307. (void)agmt_set_bind_method_no_lock(ra, e);
  308. /* timeout. */
  309. ra->timeout = DEFAULT_TIMEOUT;
  310. if (slapi_entry_attr_find(e, type_nsds5ReplicaTimeout, &sattr) == 0)
  311. {
  312. Slapi_Value *sval;
  313. if (slapi_attr_first_value(sattr, &sval) == 0)
  314. {
  315. ra->timeout = slapi_value_get_long(sval);
  316. }
  317. }
  318. /* DN of entry at root of replicated area */
  319. tmpstr = slapi_entry_attr_get_charptr(e, type_nsds5ReplicaRoot);
  320. if (NULL != tmpstr)
  321. {
  322. Object *repl_obj;
  323. Replica *replica;
  324. PRUint64 ptimeout = 0;
  325. ra->replarea = slapi_sdn_new_dn_passin(tmpstr);
  326. /* now that we set the repl area, when can bump our agmt count */
  327. if((repl_obj = replica_get_replica_from_dn(ra->replarea))){
  328. if((replica = (Replica*)object_get_data (repl_obj))){
  329. replica_incr_agmt_count(replica);
  330. }
  331. }
  332. /* If this agmt has its own timeout, grab it, otherwise use the replica's protocol timeout */
  333. ptimeout = slapi_entry_attr_get_int(e, type_replicaProtocolTimeout);
  334. if(ptimeout){
  335. slapi_counter_set_value(ra->protocol_timeout, ptimeout);
  336. }
  337. }
  338. /* Replica enabled */
  339. tmpstr = slapi_entry_attr_get_charptr(e, type_nsds5ReplicaEnabled);
  340. if (NULL != tmpstr)
  341. {
  342. if(strcasecmp(tmpstr, "off") == 0){
  343. ra->is_enabled = PR_FALSE;
  344. } else if(strcasecmp(tmpstr, "on") == 0){
  345. ra->is_enabled = PR_TRUE;
  346. } else {
  347. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Warning invalid value "
  348. "for nsds5ReplicaEnabled (%s), value must be \"on\" or \"off\". Ignoring "
  349. "this repl agreement.\n",tmpstr);
  350. slapi_ch_free_string(&tmpstr);
  351. goto loser;
  352. }
  353. slapi_ch_free_string(&tmpstr);
  354. } else {
  355. ra->is_enabled = PR_TRUE;
  356. }
  357. /* Replication schedule */
  358. ra->schedule = schedule_new(update_window_state_change_callback, ra, agmt_get_long_name(ra));
  359. if (slapi_entry_attr_find(e, type_nsds5ReplicaUpdateSchedule, &sattr) == 0)
  360. {
  361. schedule_set(ra->schedule, sattr);
  362. }
  363. /* busy wait time - time to wait after getting REPLICA BUSY from consumer */
  364. ra->busywaittime = slapi_entry_attr_get_long(e, type_nsds5ReplicaBusyWaitTime);
  365. /* pause time - time to pause after a session has ended */
  366. ra->pausetime = slapi_entry_attr_get_long(e, type_nsds5ReplicaSessionPauseTime);
  367. /* consumer's RUV */
  368. if (slapi_entry_attr_find(e, type_ruvElement, &sattr) == 0)
  369. {
  370. RUV *ruv;
  371. if (ruv_init_from_slapi_attr(sattr, &ruv) == 0)
  372. {
  373. ra->consumerRUV = object_new (ruv, (FNFree)ruv_destroy);
  374. }
  375. }
  376. ra->consumerRID = 0;
  377. /* DN and RDN of the replication agreement entry itself */
  378. ra->dn = slapi_sdn_dup(slapi_entry_get_sdn((Slapi_Entry *)e));
  379. ra->rdn = slapi_rdn_new_sdn(ra->dn);
  380. /* Compute long name */
  381. {
  382. const char *agmtname = slapi_rdn_get_rdn(ra->rdn);
  383. char hostname[128];
  384. char *dot;
  385. strncpy(hostname, ra->hostname ? ra->hostname : "(unknown)", sizeof(hostname));
  386. hostname[sizeof(hostname)-1] = '\0';
  387. dot = strchr(hostname, '.');
  388. if (dot) {
  389. *dot = '\0';
  390. }
  391. ra->long_name = slapi_ch_smprintf("agmt=\"%s\" (%s:%d)", agmtname, hostname, ra->port);
  392. }
  393. /* DBDB: review this code */
  394. if (slapi_entry_attr_hasvalue(e, "objectclass", "nsDSWindowsReplicationAgreement"))
  395. {
  396. ra->agreement_type = REPLICA_TYPE_WINDOWS;
  397. windows_init_agreement_from_entry(ra,e);
  398. }
  399. else
  400. {
  401. ra->agreement_type = REPLICA_TYPE_MULTIMASTER;
  402. repl_session_plugin_call_agmt_init_cb(ra);
  403. }
  404. /* Initialize status information */
  405. ra->last_update_start_time = 0UL;
  406. ra->last_update_end_time = 0UL;
  407. ra->last_update_status[0] = '\0';
  408. ra->update_in_progress = PR_FALSE;
  409. ra->stop_in_progress = PR_FALSE;
  410. ra->last_init_end_time = 0UL;
  411. ra->last_init_start_time = 0UL;
  412. ra->last_init_status[0] = '\0';
  413. ra->changecounters = (struct changecounter**) slapi_ch_calloc(MAX_NUM_OF_MASTERS + 1,
  414. sizeof(struct changecounter *));
  415. ra->num_changecounters = 0;
  416. ra->max_changecounters = MAX_NUM_OF_MASTERS;
  417. /* Fractional attributes */
  418. slapi_entry_attr_find(e, type_nsds5ReplicatedAttributeList, &sattr);
  419. /* New set of excluded attributes */
  420. /* Note: even if sattrs is empty, we have to call this func since there
  421. * could be a default excluded attr list in cn=plugin default config */
  422. if (agmt_set_replicated_attributes_from_attr(ra, sattr) != 0)
  423. {
  424. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  425. "agmtlist_add_callback: failed to parse "
  426. "replicated attributes for agreement %s\n",
  427. agmt_get_long_name(ra));
  428. }
  429. /* Check that there are no verboten attributes in the exclude list */
  430. denied_attrs = agmt_validate_replicated_attributes(ra, 0 /* incremental */);
  431. if (denied_attrs)
  432. {
  433. /* Report the error to the client */
  434. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  435. "WARNING: Attempt to exclude illegal attributes "
  436. "from a fractional agreement\n");
  437. /* Free the list */
  438. slapi_ch_array_free(denied_attrs);
  439. goto loser;
  440. }
  441. /* Total update fractional attributes */
  442. slapi_entry_attr_find(e, type_nsds5ReplicatedAttributeListTotal, &sattr);
  443. if (sattr && agmt_set_replicated_attributes_total_from_attr(ra, sattr) != 0)
  444. {
  445. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  446. "agmtlist_add_callback: failed to parse total "
  447. "update replicated attributes for agreement %s\n",
  448. agmt_get_long_name(ra));
  449. }
  450. /* Check that there are no verboten attributes in the exclude list */
  451. denied_attrs = agmt_validate_replicated_attributes(ra, 1 /* total */);
  452. if (denied_attrs)
  453. {
  454. /* Report the error to the client */
  455. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  456. "WARNING: Attempt to exclude illegal attributes "
  457. "from a fractional agreement for total update protocol\n");
  458. /* Free the list */
  459. slapi_ch_array_free(denied_attrs);
  460. goto loser;
  461. }
  462. /*
  463. * Extract the attributes to strip for "empty" mods
  464. */
  465. ra->attrs_to_strip = NULL;
  466. tmpstr = slapi_entry_attr_get_charptr(e, type_nsds5ReplicaStripAttrs);
  467. if (NULL != tmpstr)
  468. {
  469. ra->attrs_to_strip = slapi_str2charray_ext(tmpstr, " ", 0);
  470. slapi_ch_free_string(&tmpstr);
  471. }
  472. if (!agmt_is_valid(ra))
  473. {
  474. goto loser;
  475. }
  476. /* Now that the agreement is done, just check if changelog is configured */
  477. if (cl5GetState() != CL5_STATE_OPEN) {
  478. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "WARNING: "
  479. "Replication agreement added but there is no changelog configured. "
  480. "No change will be replicated until a changelog is configured.\n");
  481. }
  482. /*
  483. * Establish a callback for this agreement's entry, so we can
  484. * adorn it with status information when read.
  485. */
  486. slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, slapi_sdn_get_ndn(ra->dn),
  487. LDAP_SCOPE_BASE, "(objectclass=*)", get_agmt_status, ra);
  488. return ra;
  489. loser:
  490. agmt_delete((void **)&ra);
  491. return NULL;
  492. }
  493. Repl_Agmt *
  494. agmt_new_from_pblock(Slapi_PBlock *pb)
  495. {
  496. Slapi_Entry *e;
  497. slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e);
  498. return agmt_new_from_entry(e);
  499. }
  500. /*
  501. This should never be called directly - only should be called
  502. as a destructor. XXXggood this is not finished
  503. */
  504. void
  505. agmt_delete(void **rap)
  506. {
  507. Repl_Agmt *ra;
  508. Replica *replica = NULL;
  509. Object *repl_obj = NULL;
  510. PR_ASSERT(NULL != rap);
  511. PR_ASSERT(NULL != *rap);
  512. ra = (Repl_Agmt *)*rap;
  513. /* do prot_delete first - we may be doing some processing using this
  514. replication agreement, and prot_delete will make sure the
  515. processing is complete - then it should be safe to clean up the
  516. other fields below
  517. */
  518. prot_delete(&ra->protocol);
  519. /*
  520. * Remove the callback for this agreement's entry
  521. */
  522. slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP,
  523. slapi_sdn_get_ndn(ra->dn),
  524. LDAP_SCOPE_BASE, "(objectclass=*)",
  525. get_agmt_status);
  526. /*
  527. * Call the replication session cleanup callback. We
  528. * need to do this before we free replarea.
  529. */
  530. if (ra->agreement_type != REPLICA_TYPE_WINDOWS) {
  531. repl_session_plugin_call_destroy_agmt_cb(ra);
  532. }
  533. slapi_sdn_free((Slapi_DN **)&ra->dn);
  534. slapi_rdn_free((Slapi_RDN **)&ra->rdn);
  535. slapi_ch_free_string(&ra->hostname);
  536. slapi_ch_free_string(&ra->binddn);
  537. slapi_ch_array_free(ra->frac_attrs);
  538. slapi_ch_array_free(ra->frac_attrs_total);
  539. if (NULL != ra->creds)
  540. {
  541. ber_bvfree(ra->creds);
  542. }
  543. if (NULL != ra->replarea)
  544. {
  545. /*
  546. * Get the replica for this agreement from the repl area
  547. * so we can decrement the agmt count
  548. */
  549. repl_obj = replica_get_replica_from_dn(ra->replarea);
  550. if (repl_obj) {
  551. replica = (Replica*)object_get_data (repl_obj);
  552. replica_decr_agmt_count(replica);
  553. object_release(repl_obj);
  554. }
  555. slapi_sdn_free(&ra->replarea);
  556. }
  557. if (NULL != ra->consumerRUV)
  558. {
  559. object_release (ra->consumerRUV);
  560. }
  561. csn_free (&ra->consumerSchemaCSN);
  562. while ( --(ra->num_changecounters) >= 0 )
  563. {
  564. slapi_ch_free((void **)&ra->changecounters[ra->num_changecounters]);
  565. }
  566. slapi_ch_free((void **)&ra->changecounters);
  567. if (ra->agreement_type == REPLICA_TYPE_WINDOWS)
  568. {
  569. windows_agreement_delete(ra);
  570. }
  571. if(ra->attrs_to_strip){
  572. slapi_ch_array_free(ra->attrs_to_strip);
  573. }
  574. if(ra->maxcsn){
  575. slapi_ch_free_string(&ra->maxcsn);
  576. }
  577. schedule_destroy(ra->schedule);
  578. slapi_ch_free_string(&ra->long_name);
  579. slapi_counter_destroy(&ra->protocol_timeout);
  580. /* free the locks */
  581. PR_DestroyLock(ra->lock);
  582. slapi_destroy_rwlock(ra->attr_lock);
  583. slapi_ch_free((void **)rap);
  584. }
  585. /*
  586. * Allow replication for this replica to begin. Replication will
  587. * occur at the next scheduled time. Returns 0 on success, -1 on
  588. * failure.
  589. */
  590. int
  591. agmt_start(Repl_Agmt *ra)
  592. {
  593. Repl_Protocol *prot = NULL;
  594. int protocol_state;
  595. /* To Allow Consumer Initialisation when adding an agreement: */
  596. if (ra->auto_initialize == STATE_PERFORMING_TOTAL_UPDATE)
  597. {
  598. protocol_state = STATE_PERFORMING_TOTAL_UPDATE;
  599. }
  600. else
  601. {
  602. protocol_state = STATE_PERFORMING_INCREMENTAL_UPDATE;
  603. }
  604. /* First, create a new protocol object */
  605. if ((prot = prot_new(ra, protocol_state)) == NULL) {
  606. return -1;
  607. }
  608. /* Now it is safe to own the agreement lock */
  609. PR_Lock(ra->lock);
  610. /* Check that replication is not already started */
  611. if (ra->protocol != NULL) {
  612. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "replication already started for agreement \"%s\"\n", agmt_get_long_name(ra));
  613. PR_Unlock(ra->lock);
  614. prot_free(&prot);
  615. return 0;
  616. }
  617. ra->protocol = prot;
  618. /* Start the protocol thread */
  619. prot_start(ra->protocol);
  620. agmt_set_maxcsn(ra);
  621. PR_Unlock(ra->lock);
  622. return 0;
  623. }
  624. /*
  625. * Allow replication for this replica to begin. Replication will
  626. * occur at the next scheduled time. Returns 0 on success, -1 on
  627. * failure.
  628. */
  629. int
  630. windows_agmt_start(Repl_Agmt *ra)
  631. {
  632. Repl_Protocol *prot = NULL;
  633. int protocol_state;
  634. /* To Allow Consumer Initialisation when adding an agreement: */
  635. if (ra->auto_initialize == STATE_PERFORMING_TOTAL_UPDATE)
  636. {
  637. protocol_state = STATE_PERFORMING_TOTAL_UPDATE;
  638. }
  639. else
  640. {
  641. protocol_state = STATE_PERFORMING_INCREMENTAL_UPDATE;
  642. }
  643. /* First, create a new protocol object */
  644. if ((prot = prot_new(ra, protocol_state)) == NULL) {
  645. return -1;
  646. }
  647. /* Now it is safe to own the agreement lock */
  648. PR_Lock(ra->lock);
  649. /* Check that replication is not already started */
  650. if (ra->protocol != NULL) {
  651. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "replication already started for agreement \"%s\"\n", agmt_get_long_name(ra));
  652. PR_Unlock(ra->lock);
  653. prot_free(&prot);
  654. return 0;
  655. }
  656. ra->protocol = prot;
  657. /* Start the protocol thread */
  658. prot_start(ra->protocol);
  659. PR_Unlock(ra->lock);
  660. return 0;
  661. }
  662. /*
  663. Cease replicating to this replica as soon as possible.
  664. */
  665. int
  666. agmt_stop(Repl_Agmt *ra)
  667. {
  668. int return_value = 0;
  669. Repl_Protocol *rp = NULL;
  670. PR_Lock(ra->lock);
  671. if (ra->stop_in_progress)
  672. {
  673. PR_Unlock(ra->lock);
  674. return return_value;
  675. }
  676. ra->stop_in_progress = PR_TRUE;
  677. rp = ra->protocol;
  678. PR_Unlock(ra->lock);
  679. if (NULL != rp) /* we use this pointer outside the lock - dangerous? */
  680. {
  681. prot_stop(rp);
  682. }
  683. PR_Lock(ra->lock);
  684. ra->stop_in_progress = PR_FALSE;
  685. /* we do not reuse the protocol object so free it */
  686. prot_free(&ra->protocol);
  687. PR_Unlock(ra->lock);
  688. return return_value;
  689. }
  690. /*
  691. Send any pending updates as soon as possible, ignoring any replication
  692. schedules.
  693. */
  694. int
  695. agmt_replicate_now(Repl_Agmt *ra)
  696. {
  697. int return_value = 0;
  698. return return_value;
  699. }
  700. /*
  701. * Return a copy of the remote replica's hostname.
  702. */
  703. char *
  704. agmt_get_hostname(const Repl_Agmt *ra)
  705. {
  706. char *return_value;
  707. PR_ASSERT(NULL != ra);
  708. PR_Lock(ra->lock);
  709. return_value = slapi_ch_strdup(ra->hostname);
  710. PR_Unlock(ra->lock);
  711. return return_value;
  712. }
  713. /*
  714. * Return the port number of the remote replica's instance.
  715. */
  716. int
  717. agmt_get_port(const Repl_Agmt *ra)
  718. {
  719. int return_value;
  720. PR_ASSERT(NULL != ra);
  721. PR_Lock(ra->lock);
  722. return_value = ra->port;
  723. PR_Unlock(ra->lock);
  724. return return_value;
  725. }
  726. /*
  727. * Return the transport flags for this agreement.
  728. */
  729. PRUint32
  730. agmt_get_transport_flags(const Repl_Agmt *ra)
  731. {
  732. unsigned int return_value;
  733. PR_ASSERT(NULL != ra);
  734. PR_Lock(ra->lock);
  735. return_value = ra->transport_flags;
  736. PR_Unlock(ra->lock);
  737. return return_value;
  738. }
  739. /*
  740. * Return a copy of the bind dn to be used with this
  741. * agreement (may return NULL if no binddn is required,
  742. * e.g. SSL client auth.
  743. */
  744. char *
  745. agmt_get_binddn(const Repl_Agmt *ra)
  746. {
  747. char *return_value;
  748. PR_ASSERT(NULL != ra);
  749. PR_Lock(ra->lock);
  750. return_value = ra->binddn == NULL ? NULL : slapi_ch_strdup(ra->binddn);
  751. PR_Unlock(ra->lock);
  752. return return_value;
  753. }
  754. /*
  755. * Return a copy of the credentials.
  756. */
  757. struct berval *
  758. agmt_get_credentials(const Repl_Agmt *ra)
  759. {
  760. struct berval *return_value;
  761. PR_ASSERT(NULL != ra);
  762. PR_Lock(ra->lock);
  763. return_value = (struct berval *)slapi_ch_malloc(sizeof(struct berval));
  764. return_value->bv_val = (char *)slapi_ch_malloc(ra->creds->bv_len + 1);
  765. return_value->bv_len = ra->creds->bv_len;
  766. memcpy(return_value->bv_val, ra->creds->bv_val, ra->creds->bv_len);
  767. return_value->bv_val[return_value->bv_len] = '\0'; /* just in case */
  768. PR_Unlock(ra->lock);
  769. return return_value;
  770. }
  771. int
  772. agmt_get_bindmethod(const Repl_Agmt *ra)
  773. {
  774. int return_value;
  775. PR_ASSERT(NULL != ra);
  776. PR_Lock(ra->lock);
  777. return_value = ra->bindmethod;
  778. PR_Unlock(ra->lock);
  779. return return_value;
  780. }
  781. /*
  782. * Return a copy of the dn at the top of the replicated area.
  783. */
  784. Slapi_DN *
  785. agmt_get_replarea(const Repl_Agmt *ra)
  786. {
  787. Slapi_DN *return_value;
  788. PR_ASSERT(NULL != ra);
  789. PR_Lock(ra->lock);
  790. return_value = slapi_sdn_new();
  791. slapi_sdn_copy(ra->replarea, return_value);
  792. PR_Unlock(ra->lock);
  793. return return_value;
  794. }
  795. int
  796. agmt_is_fractional(const Repl_Agmt *ra)
  797. {
  798. int return_value;
  799. PR_ASSERT(NULL != ra);
  800. PR_Lock(ra->lock);
  801. return_value = ra->frac_attrs != NULL;
  802. PR_Unlock(ra->lock);
  803. return return_value;
  804. }
  805. /* Returns a COPY of the attr list, remember to free it */
  806. char **
  807. agmt_get_fractional_attrs(const Repl_Agmt *ra)
  808. {
  809. char ** return_value = NULL;
  810. PR_ASSERT(NULL != ra);
  811. if (NULL == ra->frac_attrs)
  812. {
  813. return NULL;
  814. }
  815. slapi_rwlock_rdlock(ra->attr_lock);
  816. return_value = charray_dup(ra->frac_attrs);
  817. slapi_rwlock_unlock(ra->attr_lock);
  818. return return_value;
  819. }
  820. /* Returns a COPY of the attr list, remember to free it */
  821. char **
  822. agmt_get_fractional_attrs_total(const Repl_Agmt *ra)
  823. {
  824. char ** return_value = NULL;
  825. PR_ASSERT(NULL != ra);
  826. if (NULL == ra->frac_attrs_total)
  827. {
  828. return agmt_get_fractional_attrs(ra);
  829. }
  830. PR_Lock(ra->lock);
  831. return_value = charray_dup(ra->frac_attrs_total);
  832. PR_Unlock(ra->lock);
  833. return return_value;
  834. }
  835. int
  836. agmt_is_fractional_attr(const Repl_Agmt *ra, const char *attrname)
  837. {
  838. int return_value;
  839. PR_ASSERT(NULL != ra);
  840. if (NULL == ra->frac_attrs)
  841. {
  842. return 0;
  843. }
  844. slapi_rwlock_rdlock(ra->attr_lock);
  845. /* Scan the list looking for a match */
  846. return_value = charray_inlist(ra->frac_attrs,(char*)attrname);
  847. slapi_rwlock_unlock(ra->attr_lock);
  848. return return_value;
  849. }
  850. int agmt_is_fractional_attr_total(const Repl_Agmt *ra, const char *attrname)
  851. {
  852. int return_value;
  853. PR_ASSERT(NULL != ra);
  854. if (NULL == ra->frac_attrs_total)
  855. {
  856. return agmt_is_fractional_attr(ra, attrname);
  857. }
  858. PR_Lock(ra->lock);
  859. /* Scan the list looking for a match */
  860. return_value = charray_inlist(ra->frac_attrs_total,(char*)attrname);
  861. PR_Unlock(ra->lock);
  862. return return_value;
  863. }
  864. int
  865. agmt_get_auto_initialize(const Repl_Agmt *ra)
  866. {
  867. int return_value;
  868. PR_ASSERT(NULL != ra);
  869. PR_Lock(ra->lock);
  870. return_value = ra->auto_initialize;
  871. PR_Unlock(ra->lock);
  872. return return_value;
  873. }
  874. long
  875. agmt_get_timeout(const Repl_Agmt *ra)
  876. {
  877. long return_value;
  878. PR_ASSERT(NULL != ra);
  879. PR_Lock(ra->lock);
  880. return_value = ra->timeout;
  881. PR_Unlock(ra->lock);
  882. return return_value;
  883. }
  884. long
  885. agmt_get_busywaittime(const Repl_Agmt *ra)
  886. {
  887. long return_value;
  888. PR_ASSERT(NULL != ra);
  889. PR_Lock(ra->lock);
  890. return_value = ra->busywaittime;
  891. PR_Unlock(ra->lock);
  892. return return_value;
  893. }
  894. long
  895. agmt_get_pausetime(const Repl_Agmt *ra)
  896. {
  897. long return_value;
  898. PR_ASSERT(NULL != ra);
  899. PR_Lock(ra->lock);
  900. return_value = ra->pausetime;
  901. PR_Unlock(ra->lock);
  902. return return_value;
  903. }
  904. /*
  905. * Warning - reference to the long name of the agreement is returned.
  906. * The long name of an agreement is the DN of the agreement entry,
  907. * followed by the host/port for the replica.
  908. */
  909. const char *
  910. agmt_get_long_name(const Repl_Agmt *ra)
  911. {
  912. char *return_value = NULL;
  913. return_value = ra ? ra->long_name : "";
  914. return return_value;
  915. }
  916. /*
  917. * Warning - reference to dn is returned. However, since the dn of
  918. * the replication agreement is its name, it won't change during the
  919. * lifetime of the replication agreement object.
  920. */
  921. const Slapi_DN *
  922. agmt_get_dn_byref(const Repl_Agmt *ra)
  923. {
  924. const Slapi_DN *return_value = NULL;
  925. PR_ASSERT(NULL != ra);
  926. if (NULL != ra)
  927. {
  928. return_value = ra->dn;
  929. }
  930. return return_value;
  931. }
  932. /* Return 1 if name matches the replication Dn, 0 otherwise */
  933. int
  934. agmt_matches_name(const Repl_Agmt *ra, const Slapi_DN *name)
  935. {
  936. int return_value = 0;
  937. PR_ASSERT(NULL != ra);
  938. if (NULL != ra)
  939. {
  940. PR_Lock(ra->lock);
  941. if (slapi_sdn_compare(name, ra->dn) == 0)
  942. {
  943. return_value = 1;
  944. }
  945. PR_Unlock(ra->lock);
  946. }
  947. return return_value;
  948. }
  949. /* Return 1 if name matches the replication area, 0 otherwise */
  950. int
  951. agmt_replarea_matches(const Repl_Agmt *ra, const Slapi_DN *name)
  952. {
  953. int return_value = 0;
  954. PR_ASSERT(NULL != ra);
  955. if (NULL != ra)
  956. {
  957. PR_Lock(ra->lock);
  958. if (slapi_sdn_compare(name, ra->replarea) == 0)
  959. {
  960. return_value = 1;
  961. }
  962. PR_Unlock(ra->lock);
  963. }
  964. return return_value;
  965. }
  966. int
  967. agmt_schedule_in_window_now(const Repl_Agmt *ra)
  968. {
  969. int return_value;
  970. PR_ASSERT(NULL != ra);
  971. PR_Lock(ra->lock);
  972. if (NULL != ra->schedule && schedule_in_window_now(ra->schedule))
  973. {
  974. return_value = 1;
  975. }
  976. else
  977. {
  978. return_value = 0;
  979. }
  980. PR_Unlock(ra->lock);
  981. return return_value;
  982. }
  983. /*
  984. * Set or reset the credentials used to bind to the remote replica.
  985. *
  986. * Returns 0 if credentials set, or -1 if an error occurred.
  987. */
  988. int
  989. agmt_set_credentials_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
  990. {
  991. Slapi_Attr *sattr = NULL;
  992. int return_value = 0;
  993. PR_ASSERT(NULL != ra);
  994. slapi_entry_attr_find(e, type_nsds5ReplicaCredentials, &sattr);
  995. PR_Lock(ra->lock);
  996. slapi_ber_bvdone(ra->creds);
  997. if (NULL != sattr)
  998. {
  999. Slapi_Value *sval = NULL;
  1000. slapi_attr_first_value(sattr, &sval);
  1001. if (NULL != sval)
  1002. {
  1003. const struct berval *bv = slapi_value_get_berval(sval);
  1004. slapi_ber_bvcpy(ra->creds, bv);
  1005. }
  1006. }
  1007. /* If no credentials set, set to zero-length string */
  1008. ra->creds->bv_val = NULL == ra->creds->bv_val ? slapi_ch_strdup("") : ra->creds->bv_val;
  1009. PR_Unlock(ra->lock);
  1010. prot_notify_agmt_changed(ra->protocol, ra->long_name);
  1011. return return_value;
  1012. }
  1013. /*
  1014. * Set or reset the DN used to bind to the remote replica.
  1015. *
  1016. * Returns 0 if DN set, or -1 if an error occurred.
  1017. */
  1018. int
  1019. agmt_set_binddn_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
  1020. {
  1021. Slapi_Attr *sattr = NULL;
  1022. int return_value = 0;
  1023. PR_ASSERT(NULL != ra);
  1024. slapi_entry_attr_find(e, type_nsds5ReplicaBindDN, &sattr);
  1025. PR_Lock(ra->lock);
  1026. slapi_ch_free((void **)&ra->binddn);
  1027. ra->binddn = NULL;
  1028. if (NULL != sattr)
  1029. {
  1030. Slapi_Value *sval = NULL;
  1031. slapi_attr_first_value(sattr, &sval);
  1032. if (NULL != sval)
  1033. {
  1034. const char *val = slapi_value_get_string(sval);
  1035. ra->binddn = slapi_ch_strdup(val);
  1036. }
  1037. }
  1038. /* If no BindDN set, set to zero-length string */
  1039. if (ra->binddn == NULL) {
  1040. ra->binddn = slapi_ch_strdup("");
  1041. }
  1042. PR_Unlock(ra->lock);
  1043. prot_notify_agmt_changed(ra->protocol, ra->long_name);
  1044. return return_value;
  1045. }
  1046. /*
  1047. * Reset the port number of the remote replica.
  1048. *
  1049. * Returns 0 if port set, or -1 if an error occurred.
  1050. */
  1051. int
  1052. agmt_set_port_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
  1053. {
  1054. Slapi_Attr *sattr = NULL;
  1055. int return_value = -1;
  1056. PR_ASSERT(NULL != ra);
  1057. slapi_entry_attr_find(e, type_nsds5ReplicaPort, &sattr);
  1058. PR_Lock(ra->lock);
  1059. if (NULL != sattr)
  1060. {
  1061. Slapi_Value *sval = NULL;
  1062. slapi_attr_first_value(sattr, &sval);
  1063. if (NULL != sval)
  1064. {
  1065. ra->port = slapi_value_get_int(sval);
  1066. return_value = 0;
  1067. }
  1068. }
  1069. PR_Unlock(ra->lock);
  1070. prot_notify_agmt_changed(ra->protocol, ra->long_name);
  1071. return return_value;
  1072. }
  1073. static int
  1074. agmt_parse_excluded_attrs_filter(const char *attr_string, size_t *offset)
  1075. {
  1076. char *filterstring = "(objectclass=*) ";
  1077. size_t filterstringlen = strlen(filterstring);
  1078. int retval = 0;
  1079. if (strncmp(attr_string + *offset,filterstring,filterstringlen) == 0)
  1080. {
  1081. (*offset) += filterstringlen;
  1082. } else
  1083. {
  1084. retval = -1;
  1085. }
  1086. return retval;
  1087. }
  1088. static int
  1089. agmt_parse_excluded_attrs_exclude(const char *attr_string, size_t *offset)
  1090. {
  1091. char *excludestring = "$ EXCLUDE ";
  1092. size_t excludestringlen = strlen(excludestring);
  1093. int retval = 0;
  1094. if (strncmp(attr_string + *offset,excludestring,excludestringlen) == 0)
  1095. {
  1096. (*offset) += excludestringlen;
  1097. } else
  1098. {
  1099. retval = -1;
  1100. }
  1101. return retval;
  1102. }
  1103. static int
  1104. agmt_parse_excluded_attrs_next(const char *attr_string, size_t *offset, char*** attrs)
  1105. {
  1106. int retval = 0;
  1107. char *beginstr = ((char*) attr_string) + *offset;
  1108. char *tmpstr = NULL;
  1109. size_t stringlen = 0;
  1110. char c = 0;
  1111. /* Find the end of the current attribute name, if one is present */
  1112. while (1)
  1113. {
  1114. c = *(beginstr + stringlen);
  1115. if ('\0' == c || ' ' == c)
  1116. {
  1117. break;
  1118. }
  1119. stringlen++;
  1120. }
  1121. if (0 != stringlen)
  1122. {
  1123. tmpstr = slapi_ch_malloc(stringlen + 1);
  1124. strncpy(tmpstr,beginstr,stringlen);
  1125. tmpstr[stringlen] = '\0';
  1126. if (charray_inlist(*attrs, tmpstr)) /* tmpstr is already in attrs */
  1127. {
  1128. slapi_ch_free_string(&tmpstr);
  1129. }
  1130. else
  1131. {
  1132. charray_add(attrs,tmpstr);
  1133. }
  1134. (*offset) += stringlen;
  1135. /* Skip a delimiting space */
  1136. if (c == ' ')
  1137. {
  1138. (*offset)++;
  1139. }
  1140. } else
  1141. {
  1142. retval = -1;
  1143. }
  1144. return retval;
  1145. }
  1146. /* It looks like this:
  1147. * nsDS5ReplicatedAttributeList: (objectclass=*) $ EXCLUDE jpegPhoto telephoneNumber
  1148. * This function could be called multiple times: to set excluded attrs in the
  1149. * plugin default config and to set the ones in the replica agreement.
  1150. * The excluded attrs from replica agreement are added to the ones from
  1151. * default config. (Therefore, *attrs should not be initialized in this
  1152. * function.)
  1153. */
  1154. static int
  1155. agmt_parse_excluded_attrs_config_attr(const char *attr_string, char ***attrs)
  1156. {
  1157. int retval = 0;
  1158. size_t offset = 0;
  1159. char **new_attrs = NULL;
  1160. /* First parse and skip the filter */
  1161. retval = agmt_parse_excluded_attrs_filter(attr_string, &offset);
  1162. if (retval)
  1163. {
  1164. goto error;
  1165. }
  1166. /* Now look for the 'EXCLUDE' keyword */
  1167. retval = agmt_parse_excluded_attrs_exclude(attr_string, &offset);
  1168. if (retval)
  1169. {
  1170. goto error;
  1171. }
  1172. /* Finally walk the list of attrs, storing in our chararray */
  1173. while (!retval)
  1174. {
  1175. retval = agmt_parse_excluded_attrs_next(attr_string, &offset, &new_attrs);
  1176. }
  1177. /* If we got to here, we can't have an error */
  1178. retval = 0;
  1179. if (new_attrs)
  1180. {
  1181. charray_merge_nodup(attrs, new_attrs, 1);
  1182. slapi_ch_array_free(new_attrs);
  1183. }
  1184. error:
  1185. return retval;
  1186. }
  1187. /*
  1188. * _agmt_set_default_fractional_attrs
  1189. * helper function to set nsds5ReplicatedAttributeList value (from cn=plugin
  1190. * default config,cn=config) to frac_attrs in Repl_Agmt.
  1191. * nsds5ReplicatedAttributeList set in each agreement is added to the
  1192. * default list set in this function.
  1193. */
  1194. static int
  1195. _agmt_set_default_fractional_attrs(Repl_Agmt *ra)
  1196. {
  1197. Slapi_PBlock *newpb = NULL;
  1198. Slapi_Entry **entries = NULL;
  1199. int rc = LDAP_SUCCESS;
  1200. char *attrs[2];
  1201. attrs[0] = (char *)type_nsds5ReplicatedAttributeList;
  1202. attrs[1] = NULL;
  1203. newpb = slapi_pblock_new();
  1204. slapi_search_internal_set_pb(newpb,
  1205. SLAPI_PLUGIN_DEFAULT_CONFIG, /* Base DN */
  1206. LDAP_SCOPE_BASE,
  1207. "(objectclass=*)",
  1208. attrs, /* Attrs */
  1209. 0, /* AttrOnly */
  1210. NULL, /* Controls */
  1211. NULL, /* UniqueID */
  1212. repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
  1213. 0);
  1214. slapi_search_internal_pb(newpb);
  1215. slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  1216. slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  1217. ra->frac_attrs = NULL;
  1218. if (LDAP_SUCCESS == rc && entries && *entries) /* default config entry exists */
  1219. {
  1220. Slapi_Attr *attr;
  1221. Slapi_Value *sval = NULL;
  1222. if (0 == slapi_entry_attr_find(*entries,
  1223. type_nsds5ReplicatedAttributeList, &attr))
  1224. {
  1225. int i;
  1226. const char *val = NULL;
  1227. for (i = slapi_attr_first_value(attr, &sval);
  1228. i >= 0; i = slapi_attr_next_value(attr, i, &sval)) {
  1229. val = slapi_value_get_string(sval);
  1230. rc = agmt_parse_excluded_attrs_config_attr(val,
  1231. &(ra->frac_attrs));
  1232. if (0 != rc) {
  1233. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  1234. "_agmt_set_default_fractional_attrs: failed to "
  1235. "parse default config (%s) attribute %s value: %s\n",
  1236. SLAPI_PLUGIN_DEFAULT_CONFIG,
  1237. type_nsds5ReplicatedAttributeList, val);
  1238. }
  1239. }
  1240. }
  1241. }
  1242. slapi_free_search_results_internal(newpb);
  1243. slapi_pblock_destroy(newpb);
  1244. return rc;
  1245. }
  1246. /*
  1247. * Set or reset the set of replicated attributes.
  1248. *
  1249. * Returns 0 if DN set, or -1 if an error occurred.
  1250. */
  1251. int
  1252. agmt_set_replicated_attributes_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
  1253. {
  1254. Slapi_Attr *sattr = NULL;
  1255. int return_value = 0;
  1256. PR_ASSERT(NULL != ra);
  1257. slapi_entry_attr_find(e, type_nsds5ReplicatedAttributeList, &sattr);
  1258. slapi_rwlock_wrlock(ra->attr_lock);
  1259. if (ra->frac_attrs)
  1260. {
  1261. slapi_ch_array_free(ra->frac_attrs);
  1262. ra->frac_attrs = NULL;
  1263. }
  1264. _agmt_set_default_fractional_attrs(ra);
  1265. if (NULL != sattr)
  1266. {
  1267. Slapi_Value *sval = NULL;
  1268. slapi_attr_first_value(sattr, &sval);
  1269. if (NULL != sval)
  1270. {
  1271. const char *val = slapi_value_get_string(sval);
  1272. return_value = agmt_parse_excluded_attrs_config_attr(val,&(ra->frac_attrs));
  1273. }
  1274. }
  1275. slapi_rwlock_unlock(ra->attr_lock);
  1276. prot_notify_agmt_changed(ra->protocol, ra->long_name);
  1277. return return_value;
  1278. }
  1279. /*
  1280. * Set or reset the set of total update replicated attributes.
  1281. *
  1282. * Returns 0 if DN set, or -1 if an error occurred.
  1283. */
  1284. int
  1285. agmt_set_replicated_attributes_total_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
  1286. {
  1287. Slapi_Attr *sattr = NULL;
  1288. int return_value = 0;
  1289. PR_ASSERT(NULL != ra);
  1290. slapi_entry_attr_find(e, type_nsds5ReplicatedAttributeListTotal, &sattr);
  1291. PR_Lock(ra->lock);
  1292. if (ra->frac_attrs_total)
  1293. {
  1294. slapi_ch_array_free(ra->frac_attrs_total);
  1295. ra->frac_attrs_total = NULL;
  1296. }
  1297. if (NULL != sattr)
  1298. {
  1299. Slapi_Value *sval = NULL;
  1300. slapi_attr_first_value(sattr, &sval);
  1301. if (NULL != sval)
  1302. {
  1303. const char *val = slapi_value_get_string(sval);
  1304. return_value = agmt_parse_excluded_attrs_config_attr(val,&(ra->frac_attrs_total));
  1305. }
  1306. }
  1307. PR_Unlock(ra->lock);
  1308. prot_notify_agmt_changed(ra->protocol, ra->long_name);
  1309. return return_value;
  1310. }
  1311. /*
  1312. * Set or reset the set of replicated attributes.
  1313. *
  1314. * Returns 0 if DN set, or -1 if an error occurred.
  1315. */
  1316. int
  1317. agmt_set_replicated_attributes_from_attr(Repl_Agmt *ra, Slapi_Attr *sattr)
  1318. {
  1319. int return_value = 0;
  1320. PR_ASSERT(NULL != ra);
  1321. slapi_rwlock_wrlock(ra->attr_lock);
  1322. if (ra->frac_attrs)
  1323. {
  1324. slapi_ch_array_free(ra->frac_attrs);
  1325. ra->frac_attrs = NULL;
  1326. }
  1327. _agmt_set_default_fractional_attrs(ra);
  1328. if (NULL != sattr)
  1329. {
  1330. Slapi_Value *sval = NULL;
  1331. slapi_attr_first_value(sattr, &sval);
  1332. if (NULL != sval)
  1333. {
  1334. const char *val = slapi_value_get_string(sval);
  1335. return_value = agmt_parse_excluded_attrs_config_attr(val,&(ra->frac_attrs));
  1336. }
  1337. }
  1338. slapi_rwlock_unlock(ra->attr_lock);
  1339. return return_value;
  1340. }
  1341. /*
  1342. * Set or reset the set of total update replicated attributes.
  1343. *
  1344. * Returns 0 if DN set, or -1 if an error occurred.
  1345. */
  1346. int
  1347. agmt_set_replicated_attributes_total_from_attr(Repl_Agmt *ra, Slapi_Attr *sattr)
  1348. {
  1349. int return_value = 0;
  1350. PR_ASSERT(NULL != ra);
  1351. PR_Lock(ra->lock);
  1352. if (ra->frac_attrs_total)
  1353. {
  1354. slapi_ch_array_free(ra->frac_attrs_total);
  1355. ra->frac_attrs_total = NULL;
  1356. }
  1357. if (NULL != sattr)
  1358. {
  1359. Slapi_Value *sval = NULL;
  1360. slapi_attr_first_value(sattr, &sval);
  1361. if (NULL != sval)
  1362. {
  1363. const char *val = slapi_value_get_string(sval);
  1364. return_value = agmt_parse_excluded_attrs_config_attr(val,&(ra->frac_attrs_total));
  1365. }
  1366. }
  1367. PR_Unlock(ra->lock);
  1368. return return_value;
  1369. }
  1370. char **
  1371. agmt_validate_replicated_attributes(Repl_Agmt *ra, int total)
  1372. {
  1373. static char* verbotten_attrs[] = {
  1374. "nsuniqueid",
  1375. "modifiersname",
  1376. "lastmodifiedtime",
  1377. "dc", "o", "ou", "cn", "objectclass",
  1378. NULL
  1379. };
  1380. char **retval = NULL;
  1381. char **frac_attrs = NULL;
  1382. /* If checking for total update, use the total attr list
  1383. * if it exists. If oen is not set, use the incremental
  1384. * attr list. */
  1385. if (total && ra->frac_attrs_total)
  1386. {
  1387. frac_attrs = ra->frac_attrs_total;
  1388. }
  1389. else
  1390. {
  1391. frac_attrs = ra->frac_attrs;
  1392. }
  1393. /* Iterate over the frac attrs */
  1394. if (frac_attrs)
  1395. {
  1396. char *this_attr = NULL;
  1397. int i = 0;
  1398. for (i = 0; (this_attr = frac_attrs[i]); i++)
  1399. {
  1400. if (charray_inlist(verbotten_attrs,this_attr)) {
  1401. int k = 0;
  1402. charray_add(&retval,this_attr);
  1403. /* Remove this attr from the list */
  1404. for (k = i; frac_attrs[k] ; k++)
  1405. {
  1406. frac_attrs[k] = frac_attrs[k+1];
  1407. }
  1408. i--;
  1409. }
  1410. }
  1411. }
  1412. return retval;
  1413. }
  1414. /*
  1415. * Set or reset the bind method used to bind to the remote replica.
  1416. *
  1417. * Returns 0 if bind method set, or -1 if an error occurred.
  1418. */
  1419. static int
  1420. agmt_set_bind_method_no_lock(Repl_Agmt *ra, const Slapi_Entry *e)
  1421. {
  1422. char *tmpstr = NULL;
  1423. int return_value = 0;
  1424. PR_ASSERT(NULL != ra);
  1425. tmpstr = slapi_entry_attr_get_charptr(e, type_nsds5ReplicaBindMethod);
  1426. if (NULL == tmpstr || strcasecmp(tmpstr, "SIMPLE") == 0)
  1427. {
  1428. ra->bindmethod = BINDMETHOD_SIMPLE_AUTH;
  1429. }
  1430. else if (strcasecmp(tmpstr, "SSLCLIENTAUTH") == 0)
  1431. {
  1432. ra->bindmethod = BINDMETHOD_SSL_CLIENTAUTH;
  1433. }
  1434. else if (strcasecmp(tmpstr, "SASL/GSSAPI") == 0)
  1435. {
  1436. ra->bindmethod = BINDMETHOD_SASL_GSSAPI;
  1437. }
  1438. else if (strcasecmp(tmpstr, "SASL/DIGEST-MD5") == 0)
  1439. {
  1440. ra->bindmethod = BINDMETHOD_SASL_DIGEST_MD5;
  1441. }
  1442. else
  1443. {
  1444. ra->bindmethod = BINDMETHOD_SIMPLE_AUTH;
  1445. }
  1446. slapi_ch_free((void **)&tmpstr);
  1447. return return_value;
  1448. }
  1449. int
  1450. agmt_set_bind_method_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
  1451. {
  1452. int return_value = 0;
  1453. PR_ASSERT(NULL != ra);
  1454. PR_Lock(ra->lock);
  1455. if (ra->stop_in_progress)
  1456. {
  1457. PR_Unlock(ra->lock);
  1458. return return_value;
  1459. }
  1460. return_value = agmt_set_bind_method_no_lock(ra, e);
  1461. PR_Unlock(ra->lock);
  1462. prot_notify_agmt_changed(ra->protocol, ra->long_name);
  1463. return return_value;
  1464. }
  1465. /*
  1466. * Set or reset the transport used to bind to the remote replica.
  1467. *
  1468. * Returns 0 if transport set, or -1 if an error occurred.
  1469. */
  1470. static int
  1471. agmt_set_transportinfo_no_lock(Repl_Agmt *ra, const Slapi_Entry *e)
  1472. {
  1473. char *tmpstr;
  1474. int rc = 0;
  1475. tmpstr = slapi_entry_attr_get_charptr(e, type_nsds5TransportInfo);
  1476. if (!tmpstr || !strcasecmp(tmpstr, "LDAP")) {
  1477. ra->transport_flags = 0;
  1478. } else if (strcasecmp(tmpstr, "SSL") == 0) {
  1479. ra->transport_flags = TRANSPORT_FLAG_SSL;
  1480. } else if (strcasecmp(tmpstr, "TLS") == 0) {
  1481. ra->transport_flags = TRANSPORT_FLAG_TLS;
  1482. }
  1483. /* else do nothing - invalid value is a no-op */
  1484. slapi_ch_free_string(&tmpstr);
  1485. return (rc);
  1486. }
  1487. int
  1488. agmt_set_transportinfo_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
  1489. {
  1490. int return_value = 0;
  1491. PR_ASSERT(NULL != ra);
  1492. PR_Lock(ra->lock);
  1493. if (ra->stop_in_progress)
  1494. {
  1495. PR_Unlock(ra->lock);
  1496. return return_value;
  1497. }
  1498. return_value = agmt_set_transportinfo_no_lock(ra, e);
  1499. PR_Unlock(ra->lock);
  1500. prot_notify_agmt_changed(ra->protocol, ra->long_name);
  1501. return return_value;
  1502. }
  1503. /*
  1504. * Set or reset the replication schedule. Notify the protocol handler
  1505. * that a change has been made.
  1506. *
  1507. * Returns 0 if schedule was set or -1 if an error occurred.
  1508. */
  1509. int
  1510. agmt_set_schedule_from_entry( Repl_Agmt *ra, const Slapi_Entry *e )
  1511. {
  1512. Slapi_Attr *sattr;
  1513. int return_value = 0;
  1514. PR_ASSERT(NULL != ra);
  1515. PR_Lock(ra->lock);
  1516. if (ra->stop_in_progress)
  1517. {
  1518. PR_Unlock(ra->lock);
  1519. return return_value;
  1520. }
  1521. PR_Unlock(ra->lock);
  1522. if (slapi_entry_attr_find(e, type_nsds5ReplicaUpdateSchedule, &sattr) != 0)
  1523. {
  1524. sattr = NULL; /* no schedule ==> delete any existing one */
  1525. }
  1526. /* make it so */
  1527. return_value = schedule_set(ra->schedule, sattr);
  1528. if ( 0 == return_value ) {
  1529. /* schedule set OK -- spread the news */
  1530. prot_notify_agmt_changed(ra->protocol, ra->long_name);
  1531. }
  1532. return return_value;
  1533. }
  1534. /*
  1535. * Set or reset the timeout used to bind to the remote replica.
  1536. *
  1537. * Returns 0 if timeout set, or -1 if an error occurred.
  1538. */
  1539. int
  1540. agmt_set_timeout_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
  1541. {
  1542. Slapi_Attr *sattr = NULL;
  1543. int return_value = -1;
  1544. PR_ASSERT(NULL != ra);
  1545. PR_Lock(ra->lock);
  1546. if (ra->stop_in_progress)
  1547. {
  1548. PR_Unlock(ra->lock);
  1549. return return_value;
  1550. }
  1551. slapi_entry_attr_find(e, type_nsds5ReplicaTimeout, &sattr);
  1552. if (NULL != sattr)
  1553. {
  1554. Slapi_Value *sval = NULL;
  1555. slapi_attr_first_value(sattr, &sval);
  1556. if (NULL != sval)
  1557. {
  1558. long tmpval = slapi_value_get_long(sval);
  1559. if (tmpval >= 0) {
  1560. ra->timeout = tmpval;
  1561. return_value = 0; /* success! */
  1562. }
  1563. }
  1564. }
  1565. PR_Unlock(ra->lock);
  1566. if (return_value == 0)
  1567. {
  1568. prot_notify_agmt_changed(ra->protocol, ra->long_name);
  1569. }
  1570. return return_value;
  1571. }
  1572. int
  1573. agmt_set_timeout(Repl_Agmt *ra, long timeout)
  1574. {
  1575. PR_Lock(ra->lock);
  1576. if (ra->stop_in_progress){
  1577. PR_Unlock(ra->lock);
  1578. return -1;
  1579. }
  1580. ra->timeout = timeout;
  1581. PR_Unlock(ra->lock);
  1582. return 0;
  1583. }
  1584. /*
  1585. * Set or reset the busywaittime
  1586. *
  1587. * Returns 0 if busywaittime set, or -1 if an error occurred.
  1588. */
  1589. int
  1590. agmt_set_busywaittime_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
  1591. {
  1592. Slapi_Attr *sattr = NULL;
  1593. int return_value = -1;
  1594. PR_ASSERT(NULL != ra);
  1595. PR_Lock(ra->lock);
  1596. if (ra->stop_in_progress)
  1597. {
  1598. PR_Unlock(ra->lock);
  1599. return return_value;
  1600. }
  1601. slapi_entry_attr_find(e, type_nsds5ReplicaBusyWaitTime, &sattr);
  1602. if (NULL != sattr)
  1603. {
  1604. Slapi_Value *sval = NULL;
  1605. slapi_attr_first_value(sattr, &sval);
  1606. if (NULL != sval)
  1607. {
  1608. long tmpval = slapi_value_get_long(sval);
  1609. if (tmpval >= 0) {
  1610. ra->busywaittime = tmpval;
  1611. return_value = 0; /* success! */
  1612. }
  1613. }
  1614. }
  1615. PR_Unlock(ra->lock);
  1616. if (return_value == 0)
  1617. {
  1618. prot_notify_agmt_changed(ra->protocol, ra->long_name);
  1619. }
  1620. return return_value;
  1621. }
  1622. /*
  1623. * Set or reset the pausetime
  1624. *
  1625. * Returns 0 if pausetime set, or -1 if an error occurred.
  1626. */
  1627. int
  1628. agmt_set_pausetime_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
  1629. {
  1630. Slapi_Attr *sattr = NULL;
  1631. int return_value = -1;
  1632. PR_ASSERT(NULL != ra);
  1633. PR_Lock(ra->lock);
  1634. if (ra->stop_in_progress)
  1635. {
  1636. PR_Unlock(ra->lock);
  1637. return return_value;
  1638. }
  1639. slapi_entry_attr_find(e, type_nsds5ReplicaSessionPauseTime, &sattr);
  1640. if (NULL != sattr)
  1641. {
  1642. Slapi_Value *sval = NULL;
  1643. slapi_attr_first_value(sattr, &sval);
  1644. if (NULL != sval)
  1645. {
  1646. long tmpval = slapi_value_get_long(sval);
  1647. if (tmpval >= 0) {
  1648. ra->pausetime = tmpval;
  1649. return_value = 0; /* success! */
  1650. }
  1651. }
  1652. }
  1653. PR_Unlock(ra->lock);
  1654. if (return_value == 0)
  1655. {
  1656. prot_notify_agmt_changed(ra->protocol, ra->long_name);
  1657. }
  1658. return return_value;
  1659. }
  1660. /* XXXggood - also make this pass an arg that tells if there was
  1661. * an update to a priority attribute */
  1662. void
  1663. agmt_notify_change(Repl_Agmt *agmt, Slapi_PBlock *pb)
  1664. {
  1665. if (NULL != pb)
  1666. {
  1667. /* Is the entry within our replicated area? */
  1668. Slapi_DN *target_sdn = NULL;
  1669. int change_is_relevant = 0;
  1670. PR_ASSERT(NULL != agmt);
  1671. PR_Lock(agmt->lock);
  1672. if (agmt->stop_in_progress)
  1673. {
  1674. PR_Unlock(agmt->lock);
  1675. return;
  1676. }
  1677. slapi_pblock_get(pb, SLAPI_TARGET_SDN, &target_sdn);
  1678. if (NULL == target_sdn) {
  1679. PR_Unlock(agmt->lock);
  1680. return;
  1681. }
  1682. if (slapi_sdn_issuffix(target_sdn, agmt->replarea))
  1683. {
  1684. /*
  1685. * Yep, it's in our replicated area. Is this a fractional
  1686. * replication agreement?
  1687. */
  1688. if (NULL != agmt->frac_attrs)
  1689. {
  1690. /*
  1691. * Yep, it's fractional. See if the change should be
  1692. * tossed because it doesn't affect any of the replicated
  1693. * attributes.
  1694. */
  1695. int optype;
  1696. int affects_non_fractional_attribute = 0;
  1697. slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &optype);
  1698. if (SLAPI_OPERATION_MODIFY == optype)
  1699. {
  1700. LDAPMod **mods;
  1701. int i, j;
  1702. slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
  1703. slapi_rwlock_rdlock(agmt->attr_lock);
  1704. for (i = 0; !affects_non_fractional_attribute && NULL != agmt->frac_attrs[i]; i++)
  1705. {
  1706. for (j = 0; !affects_non_fractional_attribute && NULL != mods[j]; j++)
  1707. {
  1708. if (!slapi_attr_types_equivalent(agmt->frac_attrs[i],
  1709. mods[j]->mod_type))
  1710. {
  1711. affects_non_fractional_attribute = 1;
  1712. }
  1713. }
  1714. }
  1715. slapi_rwlock_unlock(agmt->attr_lock);
  1716. }
  1717. else
  1718. {
  1719. /*
  1720. * Add, delete, and modrdn always cause some sort of
  1721. * operation replay, even if agreement is fractional.
  1722. */
  1723. affects_non_fractional_attribute = 1;
  1724. }
  1725. if (affects_non_fractional_attribute)
  1726. {
  1727. change_is_relevant = 1;
  1728. }
  1729. }
  1730. else
  1731. {
  1732. /* Not a fractional agreement */
  1733. change_is_relevant = 1;
  1734. }
  1735. }
  1736. PR_Unlock(agmt->lock);
  1737. if (change_is_relevant)
  1738. {
  1739. /* Notify the protocol that a change has occurred */
  1740. prot_notify_update(agmt->protocol);
  1741. }
  1742. }
  1743. }
  1744. int
  1745. agmt_is_50_mm_protocol(const Repl_Agmt *agmt)
  1746. {
  1747. return 1; /* XXXggood could support > 1 protocol */
  1748. }
  1749. int
  1750. agmt_initialize_replica(const Repl_Agmt *agmt)
  1751. {
  1752. PR_ASSERT(NULL != agmt);
  1753. PR_Lock(agmt->lock);
  1754. if (agmt->stop_in_progress)
  1755. {
  1756. PR_Unlock(agmt->lock);
  1757. return 0;
  1758. }
  1759. PR_Unlock(agmt->lock);
  1760. /* Call prot_initialize_replica only if the suffix is enabled (agmt->protocol != NULL) */
  1761. if (NULL != agmt->protocol) {
  1762. prot_initialize_replica(agmt->protocol);
  1763. }
  1764. else {
  1765. /* agmt->protocol == NULL --> Suffix is disabled */
  1766. return -1;
  1767. }
  1768. return 0;
  1769. }
  1770. /* delete nsds5BeginReplicaRefresh attribute to indicate to the clients
  1771. that replica initialization have completed */
  1772. void
  1773. agmt_replica_init_done (const Repl_Agmt *agmt)
  1774. {
  1775. int rc;
  1776. Slapi_PBlock *pb = slapi_pblock_new ();
  1777. LDAPMod *mods [2];
  1778. LDAPMod mod;
  1779. mods[0] = &mod;
  1780. mods[1] = NULL;
  1781. mod.mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
  1782. mod.mod_type = (char*)type_nsds5ReplicaInitialize;
  1783. mod.mod_bvalues = NULL;
  1784. slapi_modify_internal_set_pb_ext(pb, agmt->dn, mods, NULL/* controls */,
  1785. NULL/* uniqueid */, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0/* flags */);
  1786. slapi_modify_internal_pb (pb);
  1787. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  1788. if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_ATTRIBUTE)
  1789. {
  1790. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "agmt_replica_init_done: "
  1791. "failed to remove (%s) attribute from (%s) entry; LDAP error - %d\n",
  1792. type_nsds5ReplicaInitialize, slapi_sdn_get_ndn (agmt->dn), rc);
  1793. }
  1794. slapi_pblock_destroy (pb);
  1795. }
  1796. /* Agreement object is acquired on behalf of the caller.
  1797. The caller is responsible for releasing the object
  1798. when it is no longer used */
  1799. Object*
  1800. agmt_get_consumer_ruv (Repl_Agmt *ra)
  1801. {
  1802. Object *rt = NULL;
  1803. PR_ASSERT(NULL != ra);
  1804. PR_Lock(ra->lock);
  1805. if (ra->consumerRUV)
  1806. {
  1807. object_acquire (ra->consumerRUV);
  1808. rt = ra->consumerRUV;
  1809. }
  1810. PR_Unlock(ra->lock);
  1811. return rt;
  1812. }
  1813. int
  1814. agmt_set_consumer_ruv (Repl_Agmt *ra, RUV *ruv)
  1815. {
  1816. if (ra == NULL || ruv == NULL)
  1817. {
  1818. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmt_set_consumer_ruv: invalid argument"
  1819. " agmt - %p, ruv - %p\n", ra, ruv);
  1820. return -1;
  1821. }
  1822. PR_Lock(ra->lock);
  1823. if (ra->consumerRUV)
  1824. {
  1825. object_release (ra->consumerRUV);
  1826. }
  1827. ra->consumerRUV = object_new (ruv_dup (ruv), (FNFree)ruv_destroy);
  1828. PR_Unlock(ra->lock);
  1829. return 0;
  1830. }
  1831. void
  1832. agmt_update_consumer_ruv (Repl_Agmt *ra)
  1833. {
  1834. int rc;
  1835. RUV *ruv;
  1836. Slapi_Mod smod;
  1837. Slapi_Mod smod_last_modified;
  1838. Slapi_PBlock *pb;
  1839. LDAPMod *mods[3];
  1840. PR_ASSERT (ra);
  1841. PR_Lock(ra->lock);
  1842. if (ra->consumerRUV)
  1843. {
  1844. ruv = (RUV*) object_get_data (ra->consumerRUV);
  1845. PR_ASSERT (ruv);
  1846. ruv_to_smod(ruv, &smod);
  1847. ruv_last_modified_to_smod(ruv, &smod_last_modified);
  1848. /* it is ok to release the lock here because we are done with the agreement data.
  1849. we have to do it before issuing the modify operation because it causes
  1850. agmtlist_notify_all to be called which uses the same lock - hence the deadlock */
  1851. PR_Unlock(ra->lock);
  1852. pb = slapi_pblock_new ();
  1853. mods[0] = (LDAPMod *)slapi_mod_get_ldapmod_byref(&smod);
  1854. mods[1] = (LDAPMod *)slapi_mod_get_ldapmod_byref(&smod_last_modified);
  1855. mods[2] = NULL;
  1856. slapi_modify_internal_set_pb_ext (pb, ra->dn, mods, NULL, NULL,
  1857. repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
  1858. slapi_modify_internal_pb (pb);
  1859. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  1860. if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_ATTRIBUTE)
  1861. {
  1862. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "%s: agmt_update_consumer_ruv: "
  1863. "failed to update consumer's RUV; LDAP error - %d\n",
  1864. ra->long_name, rc);
  1865. }
  1866. slapi_mod_done (&smod);
  1867. slapi_mod_done (&smod_last_modified);
  1868. slapi_pblock_destroy (pb);
  1869. }
  1870. else
  1871. PR_Unlock(ra->lock);
  1872. }
  1873. CSN*
  1874. agmt_get_consumer_schema_csn (Repl_Agmt *ra)
  1875. {
  1876. CSN *rt;
  1877. PR_ASSERT(NULL != ra);
  1878. PR_Lock(ra->lock);
  1879. rt = ra->consumerSchemaCSN;
  1880. PR_Unlock(ra->lock);
  1881. return rt;
  1882. }
  1883. void
  1884. agmt_set_consumer_schema_csn (Repl_Agmt *ra, CSN *csn)
  1885. {
  1886. PR_ASSERT(NULL != ra);
  1887. PR_Lock(ra->lock);
  1888. csn_free(&ra->consumerSchemaCSN);
  1889. ra->consumerSchemaCSN = csn;
  1890. PR_Unlock(ra->lock);
  1891. }
  1892. void
  1893. agmt_set_last_update_start (Repl_Agmt *ra, time_t start_time)
  1894. {
  1895. PR_ASSERT(NULL != ra);
  1896. if (NULL != ra)
  1897. {
  1898. ra->last_update_start_time = start_time;
  1899. ra->last_update_end_time = 0UL;
  1900. }
  1901. }
  1902. void
  1903. agmt_set_last_update_end (Repl_Agmt *ra, time_t end_time)
  1904. {
  1905. PR_ASSERT(NULL != ra);
  1906. if (NULL != ra)
  1907. {
  1908. ra->last_update_end_time = end_time;
  1909. }
  1910. }
  1911. void
  1912. agmt_set_last_init_start (Repl_Agmt *ra, time_t start_time)
  1913. {
  1914. PR_ASSERT(NULL != ra);
  1915. if (NULL != ra)
  1916. {
  1917. ra->last_init_start_time = start_time;
  1918. ra->last_init_end_time = 0UL;
  1919. }
  1920. }
  1921. void
  1922. agmt_set_last_init_end (Repl_Agmt *ra, time_t end_time)
  1923. {
  1924. PR_ASSERT(NULL != ra);
  1925. if (NULL != ra)
  1926. {
  1927. ra->last_init_end_time = end_time;
  1928. }
  1929. }
  1930. void
  1931. agmt_set_last_update_status (Repl_Agmt *ra, int ldaprc, int replrc, const char *message)
  1932. {
  1933. PR_ASSERT(NULL != ra);
  1934. if (NULL != ra)
  1935. {
  1936. if (replrc == NSDS50_REPL_UPTODATE)
  1937. {
  1938. /* no session started, no status update */
  1939. }
  1940. else if (ldaprc != LDAP_SUCCESS)
  1941. {
  1942. char *replmsg = NULL;
  1943. if ( replrc ) {
  1944. replmsg = protocol_response2string(replrc);
  1945. /* Do not mix the unknown replication error with the known ldap one */
  1946. if ( strcasecmp(replmsg, "unknown error") == 0 ) {
  1947. replmsg = NULL;
  1948. }
  1949. }
  1950. PR_snprintf(ra->last_update_status, STATUS_LEN, "%d %s%sLDAP error: %s%s%s",
  1951. ldaprc, message?message:"",message?"":" - ",
  1952. slapi_err2string(ldaprc), replmsg ? " - " : "", replmsg ? replmsg : "");
  1953. }
  1954. /* ldaprc == LDAP_SUCCESS */
  1955. else if (replrc != 0)
  1956. {
  1957. if (replrc == NSDS50_REPL_REPLICA_BUSY)
  1958. {
  1959. PR_snprintf(ra->last_update_status, STATUS_LEN,
  1960. "%d Can't acquire busy replica", replrc );
  1961. }
  1962. else if (replrc == NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED)
  1963. {
  1964. PR_snprintf(ra->last_update_status, STATUS_LEN, "%d %s",
  1965. ldaprc, "Replication session successful");
  1966. }
  1967. else if (replrc == NSDS50_REPL_DISABLED)
  1968. {
  1969. PR_snprintf(ra->last_update_status, STATUS_LEN, "%d Incremental update aborted: "
  1970. "Replication agreement for %s\n can not be updated while the replica is disabled.\n"
  1971. "(If the suffix is disabled you must enable it then restart the server for replication to take place).",
  1972. replrc, ra->long_name ? ra->long_name : "a replica");
  1973. /* Log into the errors log, as "ra->long_name" is not accessible from the caller */
  1974. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  1975. "Incremental update aborted: Replication agreement for \"%s\" "
  1976. "can not be updated while the replica is disabled\n", ra->long_name ? ra->long_name : "a replica");
  1977. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  1978. "(If the suffix is disabled you must enable it then restart the server for replication to take place).\n");
  1979. }
  1980. else
  1981. {
  1982. PR_snprintf(ra->last_update_status, STATUS_LEN,
  1983. "%d Replication error acquiring replica: %s%s%s",
  1984. replrc, protocol_response2string(replrc),
  1985. message?" - ":"",message?message:"");
  1986. }
  1987. }
  1988. else if (message != NULL) /* replrc == NSDS50_REPL_REPLICA_READY == 0 */
  1989. {
  1990. PR_snprintf(ra->last_update_status, STATUS_LEN,
  1991. "%d Replica acquired successfully: %s",
  1992. ldaprc, message);
  1993. }
  1994. else
  1995. { /* agmt_set_last_update_status(0,0,NULL) to reset agmt */
  1996. PR_snprintf(ra->last_update_status, STATUS_LEN, "%d", ldaprc);
  1997. }
  1998. }
  1999. }
  2000. void
  2001. agmt_set_last_init_status (Repl_Agmt *ra, int ldaprc, int replrc, const char *message)
  2002. {
  2003. PR_ASSERT(NULL != ra);
  2004. if (NULL != ra)
  2005. {
  2006. if (ldaprc != LDAP_SUCCESS)
  2007. {
  2008. char *replmsg = NULL;
  2009. if ( replrc ) {
  2010. replmsg = protocol_response2string(replrc);
  2011. /* Do not mix the unknown replication error with the known ldap one */
  2012. if ( strcasecmp(replmsg, "unknown error") == 0 ) {
  2013. replmsg = NULL;
  2014. }
  2015. }
  2016. PR_snprintf(ra->last_init_status, STATUS_LEN, "%d %s%sLDAP error: %s%s%s",
  2017. ldaprc, message?message:"",message?"":" - ",
  2018. slapi_err2string(ldaprc), replmsg ? " - " : "", replmsg ? replmsg : "");
  2019. }
  2020. /* ldaprc == LDAP_SUCCESS */
  2021. else if (replrc != 0)
  2022. {
  2023. if (replrc == NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED)
  2024. {
  2025. PR_snprintf(ra->last_init_status, STATUS_LEN, "%d %s",
  2026. ldaprc, "Replication session successful");
  2027. }
  2028. else if (replrc == NSDS50_REPL_DISABLED)
  2029. {
  2030. if(agmt_is_enabled(ra)){
  2031. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Total update aborted: "
  2032. "Replication agreement for \"%s\" can not be updated while the suffix is disabled.\n"
  2033. "You must enable it then restart the server for replication to take place).\n",
  2034. ra->long_name ? ra->long_name : "a replica");
  2035. PR_snprintf(ra->last_init_status, STATUS_LEN, "%d Total update aborted: "
  2036. "Replication agreement for \"%s\" can not be updated while the suffix is disabled.\n"
  2037. "You must enable it then restart the server for replication to take place).",
  2038. replrc, ra->long_name ? ra->long_name : "a replica");
  2039. } else {
  2040. /* You do not need to restart the server after enabling the agreement */
  2041. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Total update aborted: "
  2042. "Replication agreement for \"%s\" can not be updated while the agreement is disabled\n",
  2043. ra->long_name ? ra->long_name : "a replica");
  2044. PR_snprintf(ra->last_init_status, STATUS_LEN, "%d Total update aborted: "
  2045. "Replication agreement for \"%s\" can not be updated while the agreement is disabled.",
  2046. replrc, ra->long_name ? ra->long_name : "a replica");
  2047. }
  2048. }
  2049. else
  2050. {
  2051. PR_snprintf(ra->last_init_status, STATUS_LEN,
  2052. "%d Replication error acquiring replica: %s%s%s",
  2053. replrc, protocol_response2string(replrc),
  2054. message?" - ":"",message?message:"");
  2055. }
  2056. }
  2057. else if (message != NULL) /* replrc == NSDS50_REPL_REPLICA_READY == 0 */
  2058. {
  2059. PR_snprintf(ra->last_init_status, STATUS_LEN,
  2060. "%d %s",
  2061. ldaprc, message);
  2062. }
  2063. else
  2064. { /* agmt_set_last_init_status(0,0,NULL) to reset agmt */
  2065. PR_snprintf(ra->last_init_status, STATUS_LEN, "%d", ldaprc);
  2066. }
  2067. }
  2068. }
  2069. void
  2070. agmt_set_update_in_progress (Repl_Agmt *ra, PRBool in_progress)
  2071. {
  2072. PR_ASSERT(NULL != ra);
  2073. if (NULL != ra)
  2074. {
  2075. ra->update_in_progress = in_progress;
  2076. }
  2077. }
  2078. PRBool
  2079. agmt_get_update_in_progress (const Repl_Agmt *ra)
  2080. {
  2081. PR_ASSERT(NULL != ra);
  2082. if (NULL != ra)
  2083. {
  2084. return ra->update_in_progress;
  2085. }
  2086. return PR_FALSE;
  2087. }
  2088. void
  2089. agmt_inc_last_update_changecount (Repl_Agmt *ra, ReplicaId rid, int skipped)
  2090. {
  2091. PR_ASSERT(NULL != ra);
  2092. if (NULL != ra)
  2093. {
  2094. int i;
  2095. for ( i = 0; i < ra->num_changecounters; i++ )
  2096. {
  2097. if ( ra->changecounters[i]->rid == rid )
  2098. break;
  2099. }
  2100. if ( i < ra->num_changecounters )
  2101. {
  2102. if ( skipped )
  2103. ra->changecounters[i]->num_skipped ++;
  2104. else
  2105. ra->changecounters[i]->num_replayed ++;
  2106. }
  2107. else
  2108. {
  2109. ra->num_changecounters++;
  2110. if(ra->num_changecounters > ra->max_changecounters){
  2111. ra->changecounters = (struct changecounter**) slapi_ch_realloc((char *)ra->changecounters,
  2112. (ra->num_changecounters + 1) * sizeof(struct changecounter*));
  2113. ra->max_changecounters = ra->num_changecounters;
  2114. }
  2115. ra->changecounters[i] = (struct changecounter*) slapi_ch_calloc(1, sizeof(struct changecounter));
  2116. ra->changecounters[i]->rid = rid;
  2117. if ( skipped )
  2118. ra->changecounters[i]->num_skipped = 1;
  2119. else
  2120. ra->changecounters[i]->num_replayed = 1;
  2121. }
  2122. }
  2123. }
  2124. void
  2125. agmt_get_changecount_string (Repl_Agmt *ra, char *buf, int bufsize)
  2126. {
  2127. char tmp_buf[32]; /* 5 digit RID, 10 digit each replayed and skipped */
  2128. int i;
  2129. int buflen = 0;
  2130. *buf = '\0';
  2131. if (NULL != ra)
  2132. {
  2133. for ( i = 0; i < ra->num_changecounters; i++ )
  2134. {
  2135. PR_snprintf (tmp_buf, sizeof(tmp_buf), "%u:%u/%u ",
  2136. ra->changecounters[i]->rid,
  2137. ra->changecounters[i]->num_replayed,
  2138. ra->changecounters[i]->num_skipped);
  2139. PR_snprintf (buf+buflen, bufsize-buflen, "%s", tmp_buf);
  2140. buflen += strlen (tmp_buf);
  2141. }
  2142. }
  2143. }
  2144. static int
  2145. get_agmt_status(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
  2146. int *returncode, char *returntext, void *arg)
  2147. {
  2148. char *time_tmp = NULL;
  2149. char changecount_string[BUFSIZ];
  2150. Repl_Agmt *ra = (Repl_Agmt *)arg;
  2151. PR_ASSERT(NULL != ra);
  2152. if (NULL != ra)
  2153. {
  2154. PRBool reapActive = PR_FALSE;
  2155. Slapi_DN *replarea_sdn = NULL;
  2156. Object *repl_obj = NULL;
  2157. replarea_sdn = agmt_get_replarea(ra);
  2158. repl_obj = replica_get_replica_from_dn(replarea_sdn);
  2159. slapi_sdn_free(&replarea_sdn);
  2160. if (repl_obj) {
  2161. Replica *replica = (Replica*)object_get_data (repl_obj);
  2162. reapActive = replica_get_tombstone_reap_active(replica);
  2163. object_release(repl_obj);
  2164. }
  2165. slapi_entry_attr_set_int(e, "nsds5replicaReapActive", (int)reapActive);
  2166. /* these values persist in the dse.ldif file, so we delete them
  2167. here to avoid multi valued attributes */
  2168. slapi_entry_attr_delete(e, "nsds5replicaLastUpdateStart");
  2169. slapi_entry_attr_delete(e, "nsds5replicaLastUpdateEnd");
  2170. slapi_entry_attr_delete(e, "nsds5replicaChangesSentSinceStartup");
  2171. slapi_entry_attr_delete(e, "nsds5replicaLastUpdateStatus");
  2172. slapi_entry_attr_delete(e, "nsds5replicaUpdateInProgress");
  2173. slapi_entry_attr_delete(e, "nsds5replicaLastInitStart");
  2174. slapi_entry_attr_delete(e, "nsds5replicaLastInitStatus");
  2175. slapi_entry_attr_delete(e, "nsds5replicaLastInitEnd");
  2176. /* now, add the real values (singly) */
  2177. if (ra->last_update_start_time == 0)
  2178. {
  2179. slapi_entry_add_string(e, "nsds5replicaLastUpdateStart", "0");
  2180. }
  2181. else
  2182. {
  2183. time_tmp = format_genTime(ra->last_update_start_time);
  2184. slapi_entry_add_string(e, "nsds5replicaLastUpdateStart", time_tmp);
  2185. slapi_ch_free((void **)&time_tmp);
  2186. }
  2187. if (ra->last_update_end_time == 0)
  2188. {
  2189. slapi_entry_add_string(e, "nsds5replicaLastUpdateEnd", "0");
  2190. }
  2191. else
  2192. {
  2193. time_tmp = format_genTime(ra->last_update_end_time);
  2194. slapi_entry_add_string(e, "nsds5replicaLastUpdateEnd", time_tmp);
  2195. slapi_ch_free((void **)&time_tmp);
  2196. }
  2197. agmt_get_changecount_string (ra, changecount_string, sizeof (changecount_string) );
  2198. slapi_entry_add_string(e, "nsds5replicaChangesSentSinceStartup", changecount_string);
  2199. if (ra->last_update_status[0] == '\0')
  2200. {
  2201. slapi_entry_add_string(e, "nsds5replicaLastUpdateStatus", "0 No replication sessions started since server startup");
  2202. }
  2203. else
  2204. {
  2205. slapi_entry_add_string(e, "nsds5replicaLastUpdateStatus", ra->last_update_status);
  2206. }
  2207. slapi_entry_add_string(e, "nsds5replicaUpdateInProgress", ra->update_in_progress ? "TRUE" : "FALSE");
  2208. if (ra->last_init_start_time == 0)
  2209. {
  2210. slapi_entry_add_string(e, "nsds5replicaLastInitStart", "0");
  2211. }
  2212. else
  2213. {
  2214. time_tmp = format_genTime(ra->last_init_start_time);
  2215. slapi_entry_add_string(e, "nsds5replicaLastInitStart", time_tmp);
  2216. slapi_ch_free((void **)&time_tmp);
  2217. }
  2218. if (ra->last_init_end_time == 0)
  2219. {
  2220. slapi_entry_add_string(e, "nsds5replicaLastInitEnd", "0");
  2221. }
  2222. else
  2223. {
  2224. time_tmp = format_genTime(ra->last_init_end_time);
  2225. slapi_entry_add_string(e, "nsds5replicaLastInitEnd", time_tmp);
  2226. slapi_ch_free((void **)&time_tmp);
  2227. }
  2228. if (ra->last_init_status[0] != '\0')
  2229. {
  2230. slapi_entry_add_string(e, "nsds5replicaLastInitStatus", ra->last_init_status);
  2231. }
  2232. }
  2233. return SLAPI_DSE_CALLBACK_OK;
  2234. }
  2235. static void
  2236. update_window_state_change_callback (void *arg, PRBool opened)
  2237. {
  2238. Repl_Agmt *agmt = (Repl_Agmt*)arg;
  2239. PR_ASSERT (agmt);
  2240. if (opened)
  2241. {
  2242. prot_notify_window_opened (agmt->protocol);
  2243. }
  2244. else
  2245. {
  2246. prot_notify_window_closed (agmt->protocol);
  2247. }
  2248. }
  2249. ReplicaId
  2250. agmt_get_consumer_rid ( Repl_Agmt *agmt, void *conn )
  2251. {
  2252. if ( agmt->consumerRID <= 0 || agmt->tmpConsumerRID) {
  2253. char *mapping_tree_node = NULL;
  2254. struct berval **bvals = NULL;
  2255. /* This function converts the old style DN to the new one. */
  2256. mapping_tree_node =
  2257. slapi_create_dn_string("cn=replica,cn=\"%s\",cn=mapping tree,cn=config",
  2258. slapi_sdn_get_dn (agmt->replarea) );
  2259. if (NULL == mapping_tree_node) {
  2260. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2261. "agmt_get_consumer_rid: failed to normalize "
  2262. "replica dn for %s\n",
  2263. slapi_sdn_get_dn (agmt->replarea));
  2264. agmt->consumerRID = 0;
  2265. }
  2266. conn_read_entry_attribute ( conn, mapping_tree_node, "nsDS5ReplicaID", &bvals );
  2267. if ( NULL != bvals && NULL != bvals[0] ) {
  2268. char *ridstr = slapi_ch_malloc( bvals[0]->bv_len + 1 );
  2269. memcpy ( ridstr, bvals[0]->bv_val, bvals[0]->bv_len );
  2270. ridstr[bvals[0]->bv_len] = '\0';
  2271. agmt->consumerRID = atoi (ridstr);
  2272. slapi_ch_free ( (void**) &ridstr );
  2273. ber_bvecfree ( bvals );
  2274. }
  2275. slapi_ch_free_string(&mapping_tree_node);
  2276. }
  2277. agmt->tmpConsumerRID = 0;
  2278. return agmt->consumerRID;
  2279. }
  2280. int
  2281. get_agmt_agreement_type( Repl_Agmt *agmt)
  2282. {
  2283. PR_ASSERT (agmt);
  2284. return agmt->agreement_type;
  2285. }
  2286. void* agmt_get_priv (const Repl_Agmt *agmt)
  2287. {
  2288. PR_ASSERT (agmt);
  2289. return agmt->priv;
  2290. }
  2291. void agmt_set_priv (Repl_Agmt *agmt, void* priv)
  2292. {
  2293. PR_ASSERT (agmt);
  2294. agmt->priv = priv;
  2295. }
  2296. ReplicaId agmt_get_consumerRID(Repl_Agmt *ra)
  2297. {
  2298. return ra->consumerRID;
  2299. }
  2300. void* agmt_get_connection(Repl_Agmt *ra)
  2301. {
  2302. if(ra->protocol){
  2303. return (void *)prot_get_connection(ra->protocol);
  2304. } else {
  2305. return NULL;
  2306. }
  2307. }
  2308. Repl_Protocol *
  2309. agmt_get_protocol(Repl_Agmt *ra)
  2310. {
  2311. if(ra){
  2312. return ra->protocol;
  2313. } else {
  2314. return NULL;
  2315. }
  2316. }
  2317. int
  2318. agmt_has_protocol(Repl_Agmt *agmt)
  2319. {
  2320. if (agmt) {
  2321. return NULL != agmt->protocol;
  2322. }
  2323. return 0;
  2324. }
  2325. PRBool
  2326. agmt_is_enabled(Repl_Agmt *ra)
  2327. {
  2328. PRBool state;
  2329. PR_Lock(ra->lock);
  2330. state = ra->is_enabled;
  2331. PR_Unlock(ra->lock);
  2332. return state;
  2333. }
  2334. int
  2335. agmt_set_enabled_from_entry(Repl_Agmt *ra, Slapi_Entry *e, char *returntext){
  2336. char *attr_val = NULL;
  2337. int rc = 0;
  2338. if(ra == NULL){
  2339. return -1;
  2340. }
  2341. PR_Lock(ra->lock);
  2342. attr_val = slapi_entry_attr_get_charptr(e, type_nsds5ReplicaEnabled);
  2343. if(attr_val){
  2344. PRBool is_enabled = PR_TRUE;
  2345. if(strcasecmp(attr_val,"off") == 0){
  2346. is_enabled = PR_FALSE;
  2347. } else if(strcasecmp(attr_val,"on") == 0){
  2348. is_enabled = PR_TRUE;
  2349. } else {
  2350. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "agmt_set_enabled_from_entry: invalid "
  2351. "value for nsds5ReplicaEnabled (%s), the value must be \"on\" or \"off\".\n", attr_val);
  2352. PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Invalid value for nsds5ReplicaEnabled, "
  2353. "the value must be \"on\" or \"off\".\n");
  2354. slapi_ch_free_string(&attr_val);
  2355. PR_Unlock(ra->lock);
  2356. return -1;
  2357. }
  2358. slapi_ch_free_string(&attr_val);
  2359. if(is_enabled){
  2360. if(!ra->is_enabled){
  2361. ra->is_enabled = PR_TRUE;
  2362. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmt_set_enabled_from_entry: "
  2363. "agreement is now enabled (%s)\n",ra->long_name);
  2364. PR_Unlock(ra->lock);
  2365. agmt_start(ra);
  2366. return rc;
  2367. }
  2368. } else {
  2369. if(ra->is_enabled){
  2370. ra->is_enabled = PR_FALSE;
  2371. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmt_set_enabled_from_entry: "
  2372. "agreement is now disabled (%s)\n",ra->long_name);
  2373. PR_Unlock(ra->lock);
  2374. agmt_stop(ra);
  2375. agmt_update_consumer_ruv(ra);
  2376. agmt_set_last_update_status(ra,0,0,"agreement disabled");
  2377. return rc;
  2378. }
  2379. }
  2380. } else {
  2381. rc = -1;
  2382. }
  2383. PR_Unlock(ra->lock);
  2384. return rc;
  2385. }
  2386. char **
  2387. agmt_get_attrs_to_strip(Repl_Agmt *ra)
  2388. {
  2389. if(ra){
  2390. return ra->attrs_to_strip;
  2391. } else {
  2392. return NULL;
  2393. }
  2394. }
  2395. int
  2396. agmt_set_attrs_to_strip(Repl_Agmt *ra, Slapi_Entry *e)
  2397. {
  2398. char *tmpstr = NULL;
  2399. PR_Lock(ra->lock);
  2400. tmpstr = slapi_entry_attr_get_charptr(e, type_nsds5ReplicaStripAttrs);
  2401. if (NULL != tmpstr){
  2402. if(ra->attrs_to_strip){
  2403. slapi_ch_array_free(ra->attrs_to_strip);
  2404. }
  2405. ra->attrs_to_strip = slapi_str2charray_ext(tmpstr, " ", 0);
  2406. PR_Unlock(ra->lock);
  2407. prot_notify_agmt_changed(ra->protocol, ra->long_name);
  2408. slapi_ch_free_string(&tmpstr);
  2409. return 0;
  2410. }
  2411. PR_Unlock(ra->lock);
  2412. return -1;
  2413. }
  2414. /* this is called whenever an update (total/incremental)
  2415. is completed */
  2416. void
  2417. agmt_update_done(Repl_Agmt *agmt, int is_total)
  2418. {
  2419. /* we could do a lot of stuff here - consolidate all of the other stuff that gets
  2420. done at the end of an update - setting status, times, etc.
  2421. but for now, all we want to do is "flush" any pending changes made
  2422. during the update into the proper structures so they are in place for the
  2423. next run
  2424. */
  2425. if(get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
  2426. windows_update_done(agmt, is_total);
  2427. }
  2428. }
  2429. PRUint64
  2430. agmt_get_protocol_timeout(Repl_Agmt *agmt)
  2431. {
  2432. if(agmt){
  2433. return slapi_counter_get_value(agmt->protocol_timeout);
  2434. } else {
  2435. return 0;
  2436. }
  2437. }
  2438. void
  2439. agmt_set_protocol_timeout(Repl_Agmt *agmt, PRUint64 timeout)
  2440. {
  2441. if(agmt){
  2442. slapi_counter_set_value(agmt->protocol_timeout, timeout);
  2443. }
  2444. }
  2445. /*
  2446. * Check if all the mods are being removed by fractional/stripped attributes
  2447. */
  2448. void
  2449. agmt_update_maxcsn(Replica *r, Slapi_DN *sdn, int op, LDAPMod **mods, CSN *csn)
  2450. {
  2451. Object *agmt_obj;
  2452. Repl_Agmt *agmt;
  2453. ReplicaId rid = replica_get_rid(r);
  2454. int mod_count = 0, excluded_count = 0;
  2455. agmt_obj = agmtlist_get_first_agreement_for_replica (r);
  2456. if(agmt_obj == NULL){ /* no agreements */
  2457. return;
  2458. }
  2459. while (agmt_obj){
  2460. agmt = (Repl_Agmt*)object_get_data (agmt_obj);
  2461. if(!agmt_is_enabled(agmt) ||
  2462. !slapi_sdn_issuffix(sdn, agmt->replarea) ||
  2463. get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS)
  2464. {
  2465. agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
  2466. continue;
  2467. }
  2468. if(op == SLAPI_OPERATION_MODIFY)
  2469. {
  2470. slapi_rwlock_rdlock(agmt->attr_lock);
  2471. for ( excluded_count = 0, mod_count = 0; NULL != mods[ mod_count ]; mod_count++){
  2472. if(charray_inlist(agmt->frac_attrs, mods[mod_count]->mod_type)){
  2473. excluded_count++;
  2474. } else if(charray_inlist(agmt->attrs_to_strip, mods[mod_count]->mod_type)){
  2475. excluded_count++;
  2476. }
  2477. }
  2478. slapi_rwlock_unlock(agmt->attr_lock);
  2479. }
  2480. if(excluded_count == 0 || excluded_count != mod_count){
  2481. /*
  2482. * This update has not been completely stripped down, update
  2483. * the agmt maxcsn - if the update did not originate from the consumer.
  2484. */
  2485. char maxcsn[CSN_STRSIZE];
  2486. ReplicaId oprid = csn_get_replicaid(csn);
  2487. csn_as_string(csn, PR_FALSE, maxcsn);
  2488. PR_Lock(agmt->lock);
  2489. if(!agmt->consumerRID){
  2490. /*
  2491. * If the RID is 0, that means this is the first update since the
  2492. * agmt was created. Since we have not contacted the consumer yet,
  2493. * we don't know what its rid is. The consumerRID will be set once
  2494. * this update is sent, but until then we don't know it. So for now
  2495. * temporarily mark it as "unavailable".
  2496. */
  2497. slapi_ch_free_string(&agmt->maxcsn);
  2498. agmt->maxcsn = slapi_ch_smprintf("%s;%s;%s;%d;unavailable", slapi_sdn_get_dn(agmt->replarea),
  2499. slapi_rdn_get_value_by_ref(slapi_rdn_get_rdn(agmt->rdn)), agmt->hostname, agmt->port);
  2500. } else if(rid == oprid){
  2501. slapi_ch_free_string(&agmt->maxcsn);
  2502. agmt->maxcsn = slapi_ch_smprintf("%s;%s;%s;%d;%d;%s", slapi_sdn_get_dn(agmt->replarea),
  2503. slapi_rdn_get_value_by_ref(slapi_rdn_get_rdn(agmt->rdn)), agmt->hostname,
  2504. agmt->port, agmt->consumerRID, maxcsn);
  2505. }
  2506. PR_Unlock(agmt->lock);
  2507. }
  2508. agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
  2509. }
  2510. }
  2511. /*
  2512. * Returns the in-memory agmt maxcsn's
  2513. */
  2514. void
  2515. add_agmt_maxcsns(Slapi_Entry *e, Replica *r)
  2516. {
  2517. Object *agmt_obj;
  2518. Repl_Agmt *agmt;
  2519. agmt_obj = agmtlist_get_first_agreement_for_replica (r);
  2520. if(agmt_obj == NULL){ /* no agreements */
  2521. return;
  2522. }
  2523. while (agmt_obj){
  2524. agmt = (Repl_Agmt*)object_get_data (agmt_obj);
  2525. if(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
  2526. agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
  2527. continue;
  2528. }
  2529. PR_Lock(agmt->lock);
  2530. if(agmt->maxcsn){
  2531. slapi_entry_add_string(e, type_agmtMaxCSN, agmt->maxcsn);
  2532. }
  2533. PR_Unlock(agmt->lock);
  2534. agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
  2535. }
  2536. }
  2537. /*
  2538. * Create a smod of all the agmt maxcsns to add to the tombstone entry.
  2539. * Regardless if there is an error, smod always needs to be freed by the caller.
  2540. */
  2541. int
  2542. agmt_maxcsn_to_smod (Replica *r, Slapi_Mod *smod)
  2543. {
  2544. Object *agmt_obj;
  2545. Repl_Agmt *agmt;
  2546. int rc = 1;
  2547. slapi_mod_init (smod, replica_get_agmt_count(r) + 1);
  2548. slapi_mod_set_type (smod, type_agmtMaxCSN);
  2549. slapi_mod_set_operation (smod, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
  2550. agmt_obj = agmtlist_get_first_agreement_for_replica (r);
  2551. if(agmt_obj == NULL){ /* no agreements */
  2552. return rc;
  2553. }
  2554. while (agmt_obj){
  2555. struct berval val;
  2556. agmt = (Repl_Agmt*)object_get_data (agmt_obj);
  2557. if(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
  2558. agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
  2559. continue;
  2560. }
  2561. PR_Lock(agmt->lock);
  2562. if(agmt->maxcsn == NULL){
  2563. PR_Unlock(agmt->lock);
  2564. agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
  2565. continue;
  2566. }
  2567. val.bv_val = agmt->maxcsn;
  2568. val.bv_len = strlen(val.bv_val);
  2569. slapi_mod_add_value(smod, &val);
  2570. PR_Unlock(agmt->lock);
  2571. rc = 0;
  2572. agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
  2573. }
  2574. return rc;
  2575. }
  2576. /*
  2577. * Called when we start a repl agmt
  2578. */
  2579. void
  2580. agmt_set_maxcsn(Repl_Agmt *ra)
  2581. {
  2582. Slapi_PBlock *pb = NULL;
  2583. Slapi_Entry **entries = NULL;
  2584. Replica *r = NULL;
  2585. Object *repl_obj;
  2586. const Slapi_DN *tombstone_sdn = NULL;
  2587. char *attrs[2];
  2588. int rc;
  2589. /* read ruv state from the ruv tombstone entry */
  2590. pb = slapi_pblock_new();
  2591. if (!pb) {
  2592. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "agmt_set_maxcsn: Out of memory\n");
  2593. goto done;
  2594. }
  2595. repl_obj = prot_get_replica_object(ra->protocol);
  2596. if(repl_obj){
  2597. r = (Replica *)object_get_data(repl_obj);
  2598. tombstone_sdn = replica_get_root(r);
  2599. }
  2600. ra->maxcsn = NULL;
  2601. attrs[0] = (char*)type_agmtMaxCSN;
  2602. attrs[1] = NULL;
  2603. slapi_search_internal_set_pb_ext(
  2604. pb,
  2605. (Slapi_DN *)tombstone_sdn,
  2606. LDAP_SCOPE_BASE,
  2607. "objectclass=*",
  2608. attrs,
  2609. 0, /* attrsonly */
  2610. NULL, /* controls */
  2611. RUV_STORAGE_ENTRY_UNIQUEID,
  2612. repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION),
  2613. OP_FLAG_REPLICATED); /* flags */
  2614. slapi_search_internal_pb (pb);
  2615. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  2616. if (rc == LDAP_SUCCESS){
  2617. Replica *r;
  2618. Object *repl_obj;
  2619. char **maxcsns;
  2620. int i;
  2621. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  2622. if (NULL == entries || NULL == entries[0]){
  2623. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2624. "agmt_set_maxcsn: replica ruv tombstone entry for "
  2625. "replica %s not found\n",
  2626. slapi_sdn_get_dn(ra->replarea));
  2627. goto done;
  2628. }
  2629. maxcsns = slapi_entry_attr_get_charray(entries[0], type_agmtMaxCSN);
  2630. repl_obj = prot_get_replica_object(ra->protocol);
  2631. if(repl_obj && maxcsns){
  2632. r = (Replica *)object_get_data(repl_obj);
  2633. if(r){
  2634. /*
  2635. * Loop over all the agmt maxcsns and find ours
  2636. */
  2637. for(i = 0; maxcsns[i]; i++){
  2638. char buf[BUFSIZ];
  2639. char unavail_buf[BUFSIZ];
  2640. PR_snprintf(buf,BUFSIZ,"%s;%s;%s;%d;",slapi_sdn_get_dn(ra->replarea),
  2641. slapi_rdn_get_value_by_ref(slapi_rdn_get_rdn(ra->rdn)),
  2642. ra->hostname, ra->port);
  2643. PR_snprintf(unavail_buf, BUFSIZ,"%s;%s;%s;%d;unavailable", slapi_sdn_get_dn(ra->replarea),
  2644. slapi_rdn_get_value_by_ref(slapi_rdn_get_rdn(ra->rdn)),
  2645. ra->hostname, ra->port);
  2646. if(strstr(maxcsns[i], buf) || strstr(maxcsns[i], unavail_buf)){
  2647. slapi_ch_free_string(&ra->maxcsn);
  2648. ra->maxcsn = slapi_ch_strdup(maxcsns[i]);
  2649. ra->consumerRID = agmt_maxcsn_get_rid(maxcsns[i]);
  2650. ra->tmpConsumerRID = 1;
  2651. break;
  2652. }
  2653. }
  2654. }
  2655. }
  2656. slapi_ch_array_free(maxcsns);
  2657. }
  2658. done:
  2659. if (NULL != pb){
  2660. slapi_free_search_results_internal(pb);
  2661. slapi_pblock_destroy (pb);
  2662. }
  2663. }
  2664. /*
  2665. * Parse out the consumer replicaID from the agmt maxcsn
  2666. *
  2667. * "repl area;agmt_rdn;hostname;port;consumer_rid;maxcsn"
  2668. */
  2669. static ReplicaId
  2670. agmt_maxcsn_get_rid(char *maxcsn)
  2671. {
  2672. ReplicaId rid = 0;
  2673. char *token = NULL;
  2674. char *iter = NULL;
  2675. char *value = slapi_ch_strdup(maxcsn);
  2676. token = ldap_utf8strtok_r(value, ";", &iter); /* repl area */
  2677. token = ldap_utf8strtok_r(iter, ";", &iter); /* agmt rdn */
  2678. token = ldap_utf8strtok_r(iter, ";", &iter); /* host */
  2679. token = ldap_utf8strtok_r(iter, ";", &iter); /* port */
  2680. token = ldap_utf8strtok_r(iter, ";", &iter); /* rid */
  2681. if(token && strcmp(token, "Unavailable")){
  2682. rid = atoi(token);
  2683. }
  2684. slapi_ch_free_string(&value);
  2685. return rid;
  2686. }
  2687. /*
  2688. * Agmt being deleted, remove the agmt maxcsn from the local ruv.
  2689. */
  2690. void
  2691. agmt_remove_maxcsn(Repl_Agmt *ra)
  2692. {
  2693. Slapi_PBlock *pb = NULL;
  2694. Slapi_PBlock *modpb = NULL;
  2695. Slapi_Entry **entries = NULL;
  2696. Replica *r = NULL;
  2697. Object *repl_obj;
  2698. const Slapi_DN *tombstone_sdn = NULL;
  2699. char *attrs[2];
  2700. int rc;
  2701. pb = slapi_pblock_new();
  2702. if (!pb) {
  2703. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "agmt_set_maxcsn: Out of memory\n");
  2704. goto done;
  2705. }
  2706. repl_obj = prot_get_replica_object(ra->protocol);
  2707. if(repl_obj){
  2708. r = (Replica *)object_get_data(repl_obj);
  2709. tombstone_sdn = replica_get_root(r);
  2710. } else {
  2711. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "agmt_set_maxcsn: Failed to get repl object.\n");
  2712. goto done;
  2713. }
  2714. slapi_ch_free_string(&ra->maxcsn);
  2715. attrs[0] = (char*)type_agmtMaxCSN;
  2716. attrs[1] = NULL;
  2717. slapi_search_internal_set_pb_ext(
  2718. pb,
  2719. (Slapi_DN *)tombstone_sdn,
  2720. LDAP_SCOPE_BASE,
  2721. "objectclass=*",
  2722. attrs,
  2723. 0, /* attrsonly */
  2724. NULL, /* controls */
  2725. RUV_STORAGE_ENTRY_UNIQUEID,
  2726. repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION),
  2727. OP_FLAG_REPLICATED); /* flags */
  2728. slapi_search_internal_pb (pb);
  2729. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  2730. if (rc == LDAP_SUCCESS){
  2731. /*
  2732. * Ok we have the db tombstone entry, start looking through the agmt maxcsns
  2733. * for a match to this replica agmt.
  2734. */
  2735. Slapi_Mod smod;
  2736. LDAPMod *mods[2];
  2737. char **maxcsns = NULL;
  2738. int i;
  2739. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  2740. if (NULL == entries || NULL == entries[0]){
  2741. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  2742. "agmt_set_maxcsn: replica ruv tombstone entry for "
  2743. "replica %s not found\n", slapi_sdn_get_dn(ra->replarea));
  2744. goto done;
  2745. }
  2746. maxcsns = slapi_entry_attr_get_charray(entries[0], type_agmtMaxCSN);
  2747. repl_obj = prot_get_replica_object(ra->protocol);
  2748. if(repl_obj && maxcsns){
  2749. r = (Replica *)object_get_data(repl_obj);
  2750. if(r){
  2751. /*
  2752. * Loop over all the agmt maxcsns and find ours...
  2753. */
  2754. for(i = 0; maxcsns[i]; i++){
  2755. char buf[BUFSIZ];
  2756. char unavail_buf[BUFSIZ];
  2757. struct berval val;
  2758. PR_snprintf(buf, BUFSIZ,"%s;%s;%s;%d;",slapi_sdn_get_dn(ra->replarea),
  2759. slapi_rdn_get_value_by_ref(slapi_rdn_get_rdn(ra->rdn)),
  2760. ra->hostname, ra->port);
  2761. PR_snprintf(unavail_buf, BUFSIZ, "%s;%s;%s;%d;unavailable",
  2762. slapi_sdn_get_dn(ra->replarea),
  2763. slapi_rdn_get_value_by_ref(slapi_rdn_get_rdn(ra->rdn)),
  2764. ra->hostname, ra->port);
  2765. if(strstr(maxcsns[i], buf) || strstr(maxcsns[i], unavail_buf)){
  2766. /*
  2767. * We found the matching agmt maxcsn, now remove agmt maxcsn
  2768. * from the tombstone entry.
  2769. */
  2770. val.bv_val = maxcsns[i];
  2771. val.bv_len = strlen(maxcsns[i]);
  2772. slapi_mod_init (&smod, 2);
  2773. slapi_mod_set_type (&smod, type_agmtMaxCSN);
  2774. slapi_mod_set_operation (&smod, LDAP_MOD_DELETE | LDAP_MOD_BVALUES);
  2775. slapi_mod_add_value(&smod, &val);
  2776. mods [0] = smod.mod;
  2777. mods [1] = NULL;
  2778. modpb = slapi_pblock_new();
  2779. slapi_modify_internal_set_pb_ext(
  2780. modpb,
  2781. tombstone_sdn,
  2782. mods,
  2783. NULL, /* controls */
  2784. RUV_STORAGE_ENTRY_UNIQUEID,
  2785. repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION),
  2786. /* Add OP_FLAG_TOMBSTONE_ENTRY so that this doesn't get logged in the Retro ChangeLog */
  2787. OP_FLAG_REPLICATED | OP_FLAG_REPL_FIXUP | OP_FLAG_TOMBSTONE_ENTRY |
  2788. OP_FLAG_REPL_RUV );
  2789. slapi_modify_internal_pb(modpb);
  2790. slapi_pblock_get(modpb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  2791. if (rc != LDAP_SUCCESS){
  2792. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  2793. "agmt_set_maxcsn: failed to remove agmt maxcsn (%s), error(%d)\n",maxcsns[i], rc);
  2794. }
  2795. slapi_mod_done(&smod);
  2796. slapi_pblock_destroy(modpb);
  2797. break;
  2798. }
  2799. }
  2800. }
  2801. }
  2802. slapi_ch_array_free(maxcsns);
  2803. }
  2804. done:
  2805. if (NULL != pb){
  2806. slapi_free_search_results_internal(pb);
  2807. slapi_pblock_destroy (pb);
  2808. }
  2809. }