repl_extop.c 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright 2001 Sun Microsystems, Inc.
  3. * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
  4. * All rights reserved.
  5. * END COPYRIGHT BLOCK **/
  6. #include "slapi-plugin.h"
  7. #include "repl.h"
  8. #include "repl5.h"
  9. #include "repl5_prot_private.h"
  10. #include "cl5_api.h"
  11. /*
  12. * repl_extop.c - there are two types of functions in this file:
  13. * - Code that implements an extended operation plugin.
  14. * The replication DLL arranges for this code to
  15. * be called when a StartNSDS50ReplicationRequest
  16. * or an EndNSDS50ReplicationRequest extended operation
  17. * is received.
  18. * - Code that sends extended operations on an already-
  19. * established client connection.
  20. *
  21. * The requestValue portion of the StartNSDS50ReplicationRequest
  22. * looks like this:
  23. *
  24. * requestValue ::= SEQUENCE {
  25. * replProtocolOID LDAPOID,
  26. * replicatedTree LDAPDN,
  27. supplierRUV OCTET STRING
  28. * referralURLs SET of LDAPURL OPTIONAL
  29. * csn OCTET STRING OPTIONAL
  30. * }
  31. *
  32. */
  33. static int check_replica_id_uniqueness(Replica *replica, RUV *supplier_ruv);
  34. static int
  35. encode_ruv (BerElement *ber, const RUV *ruv)
  36. {
  37. int rc = LDAP_SUCCESS;
  38. struct berval **bvals = NULL;
  39. PR_ASSERT (ber);
  40. PR_ASSERT (ruv);
  41. if (ruv_to_bervals(ruv, &bvals) != 0)
  42. {
  43. rc = LDAP_OPERATIONS_ERROR;
  44. goto done;
  45. }
  46. if (ber_printf(ber, "[V]", bvals) == -1)
  47. {
  48. rc = LDAP_ENCODING_ERROR;
  49. goto done;
  50. }
  51. rc = LDAP_SUCCESS;
  52. done:
  53. if (bvals)
  54. ber_bvecfree (bvals);
  55. return rc;
  56. }
  57. static struct berval *
  58. create_NSDS50ReplicationExtopPayload(const char *protocol_oid,
  59. const char *repl_root, char **extra_referrals, CSN *csn,
  60. int send_end)
  61. {
  62. struct berval *req_data = NULL;
  63. BerElement *tmp_bere = NULL;
  64. int rc = 0;
  65. const char *csnstr = NULL;
  66. Object *repl_obj, *ruv_obj = NULL;
  67. Replica *repl;
  68. RUV *ruv;
  69. Slapi_DN *sdn;
  70. PR_ASSERT(protocol_oid != NULL || send_end);
  71. PR_ASSERT(repl_root != NULL);
  72. /* Create the request data */
  73. if ((tmp_bere = der_alloc()) == NULL)
  74. {
  75. rc = LDAP_ENCODING_ERROR;
  76. goto loser;
  77. }
  78. if (!send_end)
  79. {
  80. if (ber_printf(tmp_bere, "{ss", protocol_oid, repl_root) == -1)
  81. {
  82. rc = LDAP_ENCODING_ERROR;
  83. goto loser;
  84. }
  85. }
  86. else
  87. {
  88. if (ber_printf(tmp_bere, "{s", repl_root) == -1)
  89. {
  90. rc = LDAP_ENCODING_ERROR;
  91. goto loser;
  92. }
  93. }
  94. sdn = slapi_sdn_new_dn_byref(repl_root);
  95. repl_obj = replica_get_replica_from_dn (sdn);
  96. if (repl_obj == NULL)
  97. {
  98. rc = LDAP_OPERATIONS_ERROR;
  99. goto loser;
  100. }
  101. repl = (Replica*)object_get_data (repl_obj);
  102. PR_ASSERT (repl);
  103. ruv_obj = replica_get_ruv (repl);
  104. if (ruv_obj == NULL)
  105. {
  106. rc = LDAP_OPERATIONS_ERROR;
  107. goto loser;
  108. }
  109. ruv = object_get_data(ruv_obj);
  110. PR_ASSERT(ruv);
  111. /* send supplier's ruv so that consumer can build its own referrals.
  112. In case of total protocol, it is also used as consumer's ruv once
  113. protocol successfully completes */
  114. /* We need to encode and send each time the local ruv in case we have changed it */
  115. rc = encode_ruv (tmp_bere, ruv);
  116. if (rc != 0)
  117. {
  118. goto loser;
  119. }
  120. if (!send_end)
  121. {
  122. char s[CSN_STRSIZE];
  123. ReplicaId rid;
  124. char *local_replica_referral[2] = {0};
  125. char **referrals_to_send = NULL;
  126. /* Add the referral URL(s), if present */
  127. rid = replica_get_rid(repl);
  128. if (!ruv_contains_replica(ruv, rid))
  129. {
  130. /*
  131. * In the event that there is no RUV component for this replica (e.g.
  132. * if the database was just loaded from LDIF and no local CSNs have been
  133. * generated), then we need to explicitly add this server to the list
  134. * of referrals, since it wouldn't have been sent with the RUV.
  135. */
  136. local_replica_referral[0] = (char *)multimaster_get_local_purl(); /* XXXggood had to cast away const */
  137. }
  138. charray_merge(&referrals_to_send, extra_referrals, 0);
  139. charray_merge(&referrals_to_send, local_replica_referral, 0);
  140. if (NULL != referrals_to_send)
  141. {
  142. if (ber_printf(tmp_bere, "[v]", referrals_to_send) == -1)
  143. {
  144. rc = LDAP_ENCODING_ERROR;
  145. goto loser;
  146. }
  147. slapi_ch_free((void **)&referrals_to_send);
  148. }
  149. /* Add the CSN */
  150. PR_ASSERT(NULL != csn);
  151. if (ber_printf(tmp_bere, "s", csnstr = csn_as_string(csn,PR_FALSE,s)) == -1)
  152. {
  153. rc = LDAP_ENCODING_ERROR;
  154. goto loser;
  155. }
  156. }
  157. if (ber_printf(tmp_bere, "}") == -1)
  158. {
  159. rc = LDAP_ENCODING_ERROR;
  160. goto loser;
  161. }
  162. if (ber_flatten(tmp_bere, &req_data) == -1)
  163. {
  164. rc = LDAP_LOCAL_ERROR;
  165. goto loser;
  166. }
  167. /* Success */
  168. goto done;
  169. loser:
  170. /* Free stuff we allocated */
  171. if (NULL != req_data)
  172. {
  173. ber_bvfree(req_data); req_data = NULL;
  174. }
  175. done:
  176. if (NULL != tmp_bere)
  177. {
  178. ber_free(tmp_bere, 1); tmp_bere = NULL;
  179. }
  180. if (NULL != sdn)
  181. {
  182. slapi_sdn_free (&sdn); /* Put on stack instead of allocating? */
  183. }
  184. if (NULL != repl_obj)
  185. {
  186. object_release (repl_obj);
  187. }
  188. if (NULL != ruv_obj)
  189. {
  190. object_release (ruv_obj);
  191. }
  192. return req_data;
  193. }
  194. struct berval *
  195. NSDS50StartReplicationRequest_new(const char *protocol_oid,
  196. const char *repl_root, char **extra_referrals, CSN *csn)
  197. {
  198. return(create_NSDS50ReplicationExtopPayload(protocol_oid,
  199. repl_root, extra_referrals, csn, 0));
  200. }
  201. struct berval *
  202. NSDS50EndReplicationRequest_new(char *repl_root)
  203. {
  204. return(create_NSDS50ReplicationExtopPayload(NULL, repl_root, NULL, NULL, 1));
  205. }
  206. static int
  207. decode_ruv (BerElement *ber, RUV **ruv)
  208. {
  209. int rc = -1;
  210. struct berval **bvals = NULL;
  211. PR_ASSERT (ber && ruv);
  212. if (ber_scanf(ber, "[V]", &bvals) == -1)
  213. {
  214. goto done;
  215. }
  216. if (ruv_init_from_bervals(bvals, ruv) != 0)
  217. {
  218. goto done;
  219. }
  220. rc = 0;
  221. done:
  222. if (bvals)
  223. ber_bvecfree (bvals);
  224. return rc;
  225. }
  226. /*
  227. * Decode an NSDS50 Start Replication Request extended
  228. * operation. Returns 0 on success, -1 on decoding error.
  229. * The caller is responsible for freeing protocol_oid,
  230. * repl_root, referrals, and csn.
  231. */
  232. static int
  233. decode_startrepl_extop(Slapi_PBlock *pb, char **protocol_oid, char **repl_root,
  234. RUV **supplier_ruv, char ***extra_referrals, char **csnstr)
  235. {
  236. char *extop_oid = NULL;
  237. struct berval *extop_value = NULL;
  238. BerElement *tmp_bere = NULL;
  239. unsigned long len;
  240. int rc = 0;
  241. PR_ASSERT (pb && protocol_oid && repl_root && supplier_ruv && extra_referrals && csnstr);
  242. *protocol_oid = NULL;
  243. *repl_root = NULL;
  244. *supplier_ruv = NULL;
  245. *extra_referrals = NULL;
  246. *csnstr = NULL;
  247. slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid);
  248. slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
  249. if (NULL == extop_oid ||
  250. strcmp(extop_oid, REPL_START_NSDS50_REPLICATION_REQUEST_OID) != 0 ||
  251. NULL == extop_value)
  252. {
  253. /* bogus */
  254. rc = -1;
  255. goto free_and_return;
  256. }
  257. if ((tmp_bere = ber_init(extop_value)) == NULL)
  258. {
  259. rc = -1;
  260. goto free_and_return;
  261. }
  262. if (ber_scanf(tmp_bere, "{") == -1)
  263. {
  264. rc = -1;
  265. goto free_and_return;
  266. }
  267. /* Get the required protocol OID and root of replicated subtree */
  268. if (ber_get_stringa(tmp_bere, protocol_oid) == -1)
  269. {
  270. rc = -1;
  271. goto free_and_return;
  272. }
  273. if (ber_get_stringa(tmp_bere, repl_root) == -1)
  274. {
  275. rc = -1;
  276. goto free_and_return;
  277. }
  278. /* get supplier's ruv */
  279. if (decode_ruv (tmp_bere, supplier_ruv) == -1)
  280. {
  281. rc = -1;
  282. goto free_and_return;
  283. }
  284. /* Get the optional set of referral URLs */
  285. if (ber_peek_tag(tmp_bere, &len) == LBER_SET)
  286. {
  287. if (ber_scanf(tmp_bere, "[v]", extra_referrals) == -1)
  288. {
  289. rc = -1;
  290. goto free_and_return;
  291. }
  292. }
  293. /* Get the optional CSN */
  294. if (ber_peek_tag(tmp_bere, &len) == LBER_OCTETSTRING)
  295. {
  296. if (ber_get_stringa(tmp_bere, csnstr) == -1)
  297. {
  298. rc = -1;
  299. goto free_and_return;
  300. }
  301. }
  302. if (ber_scanf(tmp_bere, "}") == -1)
  303. {
  304. rc = -1;
  305. goto free_and_return;
  306. }
  307. free_and_return:
  308. if (-1 == rc)
  309. {
  310. /* Free everything when error encountered */
  311. /* slapi_ch_free accepts NULL pointer */
  312. slapi_ch_free ((void**)protocol_oid);
  313. slapi_ch_free ((void**)repl_root);
  314. slapi_ch_free ((void **)extra_referrals);
  315. slapi_ch_free ((void**)csnstr);
  316. if (*supplier_ruv)
  317. {
  318. ruv_destroy (supplier_ruv);
  319. }
  320. }
  321. if (NULL != tmp_bere)
  322. {
  323. ber_free(tmp_bere, 1);
  324. tmp_bere = NULL;
  325. }
  326. return rc;
  327. }
  328. /*
  329. * Decode an NSDS50 End Replication Request extended
  330. * operation. Returns 0 on success, -1 on decoding error.
  331. * The caller is responsible for freeing repl_root.
  332. */
  333. static int
  334. decode_endrepl_extop(Slapi_PBlock *pb, char **repl_root)
  335. {
  336. char *extop_oid = NULL;
  337. struct berval *extop_value = NULL;
  338. BerElement *tmp_bere = NULL;
  339. int rc = 0;
  340. slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid);
  341. slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
  342. if (NULL == extop_oid ||
  343. strcmp(extop_oid, REPL_END_NSDS50_REPLICATION_REQUEST_OID) != 0 ||
  344. NULL == extop_value)
  345. {
  346. /* bogus */
  347. rc = -1;
  348. goto free_and_return;
  349. }
  350. if ((tmp_bere = ber_init(extop_value)) == NULL)
  351. {
  352. rc = -1;
  353. goto free_and_return;
  354. }
  355. if (ber_scanf(tmp_bere, "{") == -1)
  356. {
  357. rc = -1;
  358. goto free_and_return;
  359. }
  360. /* Get the required root of replicated subtree */
  361. if (ber_get_stringa(tmp_bere, repl_root) == -1)
  362. {
  363. rc = -1;
  364. goto free_and_return;
  365. }
  366. if (ber_scanf(tmp_bere, "}") == -1)
  367. {
  368. rc = -1;
  369. goto free_and_return;
  370. }
  371. free_and_return:
  372. if (NULL != tmp_bere)
  373. {
  374. ber_free(tmp_bere, 1);
  375. tmp_bere = NULL;
  376. }
  377. return rc;
  378. }
  379. /*
  380. * Decode an NSDS50ReplicationResponse extended response.
  381. * The extended response just contains a sequence that contains:
  382. * 1) An integer response code
  383. * 2) An optional array of bervals representing the consumer
  384. * replica's update vector
  385. * Returns 0 on success, or -1 if the response could not be parsed.
  386. */
  387. int
  388. decode_repl_ext_response(struct berval *data, int *response_code,
  389. struct berval ***ruv_bervals)
  390. {
  391. BerElement *tmp_bere = NULL;
  392. int return_value = 0;
  393. PR_ASSERT(NULL != response_code);
  394. PR_ASSERT(NULL != ruv_bervals);
  395. if (NULL == data || NULL == response_code || NULL == ruv_bervals)
  396. {
  397. return_value = -1;
  398. }
  399. else
  400. {
  401. unsigned long len, tag = 0;
  402. long temp_response_code = 0;
  403. *ruv_bervals = NULL;
  404. if ((tmp_bere = ber_init(data)) == NULL)
  405. {
  406. return_value = -1;
  407. }
  408. else if (ber_scanf(tmp_bere, "{e", &temp_response_code) == -1)
  409. {
  410. return_value = -1;
  411. }
  412. else if ((tag = ber_peek_tag(tmp_bere, &len)) == LBER_SEQUENCE)
  413. {
  414. if (ber_scanf(tmp_bere, "{V}}", ruv_bervals) == -1)
  415. {
  416. return_value = -1;
  417. }
  418. } else if (ber_scanf(tmp_bere, "}") == -1)
  419. {
  420. return_value = -1;
  421. }
  422. *response_code = (int)temp_response_code;
  423. }
  424. if (0 != return_value)
  425. {
  426. if (NULL != *ruv_bervals)
  427. {
  428. ber_bvecfree(*ruv_bervals);
  429. }
  430. }
  431. if (NULL != tmp_bere)
  432. {
  433. ber_free(tmp_bere, 1); tmp_bere = NULL;
  434. }
  435. return return_value;
  436. }
  437. /*
  438. * This plugin entry point is called whenever a
  439. * StartNSDS50ReplicationRequest is received.
  440. */
  441. int
  442. multimaster_extop_StartNSDS50ReplicationRequest(Slapi_PBlock *pb)
  443. {
  444. int return_value = SLAPI_PLUGIN_EXTENDED_NOT_HANDLED;
  445. int response = 0;
  446. int rc = 0;
  447. BerElement *resp_bere = NULL;
  448. struct berval *resp_bval = NULL;
  449. char *protocol_oid = NULL;
  450. char *repl_root = NULL;
  451. Slapi_DN *repl_root_sdn = NULL;
  452. char **referrals = NULL;
  453. Object *replica_object = NULL;
  454. Replica *replica = NULL;
  455. void *conn;
  456. consumer_connection_extension *connext = NULL;
  457. CSN *mycsn = NULL;
  458. char *replicacsnstr = NULL;
  459. CSN *replicacsn = NULL;
  460. int zero = 0;
  461. int one = 1;
  462. RUV *ruv = NULL;
  463. struct berval **ruv_bervals = NULL;
  464. CSNGen *gen = NULL;
  465. Object *gen_obj = NULL;
  466. Slapi_DN *bind_sdn = NULL;
  467. char *bind_dn = NULL;
  468. Object *ruv_object = NULL;
  469. RUV *supplier_ruv = NULL;
  470. int connid, opid;
  471. PRBool isInc = PR_FALSE; /* true if incremental update */
  472. char *locking_purl = NULL; /* the supplier contacting us */
  473. char *current_purl = NULL; /* the supplier which already has exclusive access */
  474. char locking_session[24];
  475. /* Decode the extended operation */
  476. if (decode_startrepl_extop(pb, &protocol_oid, &repl_root, &supplier_ruv,
  477. &referrals, &replicacsnstr) == -1)
  478. {
  479. response = NSDS50_REPL_DECODING_ERROR;
  480. goto send_response;
  481. }
  482. if (NULL == protocol_oid || NULL == repl_root || NULL == replicacsnstr)
  483. {
  484. response = NSDS50_REPL_DECODING_ERROR;
  485. goto send_response;
  486. }
  487. connid = 0;
  488. slapi_pblock_get(pb, SLAPI_CONN_ID, &connid);
  489. opid = 0;
  490. slapi_pblock_get(pb, SLAPI_OPERATION_ID, &opid);
  491. /*
  492. * Get a hold of the connection extension object and
  493. * make sure it's there.
  494. */
  495. slapi_pblock_get(pb, SLAPI_CONNECTION, &conn);
  496. connext = (consumer_connection_extension *)repl_con_get_ext(
  497. REPL_CON_EXT_CONN, conn);
  498. if (NULL == connext)
  499. {
  500. /* Something bad happened. Don't go any further */
  501. response = NSDS50_REPL_INTERNAL_ERROR;
  502. goto send_response;
  503. }
  504. /* Verify that we know about this replication protocol OID */
  505. if (strcmp(protocol_oid, REPL_NSDS50_INCREMENTAL_PROTOCOL_OID) == 0)
  506. {
  507. /* Stash info that this is an incremental update session */
  508. connext->repl_protocol_version = REPL_PROTOCOL_50_INCREMENTAL;
  509. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  510. "conn=%d op=%d repl=\"%s\": Begin incremental protocol\n",
  511. connid, opid, repl_root);
  512. isInc = PR_TRUE;
  513. }
  514. else if (strcmp(protocol_oid, REPL_NSDS50_TOTAL_PROTOCOL_OID) == 0)
  515. {
  516. /* Stash info that this is a total update session */
  517. if (NULL != connext)
  518. {
  519. connext->repl_protocol_version = REPL_PROTOCOL_50_TOTALUPDATE;
  520. }
  521. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  522. "conn=%d op=%d repl=\"%s\": Begin total protocol\n",
  523. connid, opid, repl_root);
  524. isInc = PR_FALSE;
  525. }
  526. else
  527. {
  528. /* Unknown replication protocol */
  529. response = NSDS50_REPL_UNKNOWN_UPDATE_PROTOCOL;
  530. goto send_response;
  531. }
  532. /* Verify that repl_root names a valid replicated area */
  533. if ((repl_root_sdn = slapi_sdn_new_dn_byval(repl_root)) == NULL)
  534. {
  535. response = NSDS50_REPL_INTERNAL_ERROR;
  536. goto send_response;
  537. }
  538. /* see if this replica is being configured and wait for it */
  539. if (replica_is_being_configured(repl_root))
  540. {
  541. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  542. "conn=%d op=%d replica=\"%s\": "
  543. "Replica is being configured: try again later\n",
  544. connid, opid, repl_root);
  545. response = NSDS50_REPL_REPLICA_BUSY;
  546. goto send_response;
  547. }
  548. replica_object = replica_get_replica_from_dn(repl_root_sdn);
  549. if (NULL != replica_object)
  550. {
  551. replica = object_get_data(replica_object);
  552. }
  553. if (NULL == replica)
  554. {
  555. response = NSDS50_REPL_NO_SUCH_REPLICA;
  556. goto send_response;
  557. }
  558. /* check that this replica is not a 4.0 consumer */
  559. if (replica_is_legacy_consumer (replica))
  560. {
  561. response = NSDS50_REPL_LEGACY_CONSUMER;
  562. goto send_response;
  563. }
  564. /* Check that bind dn is authorized to supply replication updates */
  565. slapi_pblock_get(pb, SLAPI_CONN_DN, &bind_dn); /* bind_dn is allocated */
  566. bind_sdn = slapi_sdn_new_dn_passin(bind_dn);
  567. if (replica_is_updatedn(replica, bind_sdn) == PR_FALSE)
  568. {
  569. response = NSDS50_REPL_PERMISSION_DENIED;
  570. goto send_response;
  571. }
  572. /* Check received CSN for clock skew */
  573. gen_obj = replica_get_csngen(replica);
  574. if (NULL != gen_obj)
  575. {
  576. gen = object_get_data(gen_obj);
  577. if (NULL != gen)
  578. {
  579. if (csngen_new_csn(gen, &mycsn, PR_FALSE /* notify */) == CSN_SUCCESS)
  580. {
  581. replicacsn = csn_new_by_string(replicacsnstr);
  582. if (NULL != replicacsn)
  583. {
  584. /* ONREPL - we used to manage clock skew here. However, csn generator
  585. code already does it. The csngen also manages local skew caused by
  586. system clock reset, so to keep it consistent, I removed code from here */
  587. time_t diff = 0L;
  588. diff = csn_time_difference(mycsn, replicacsn);
  589. if (diff > 0)
  590. {
  591. /* update the state of the csn generator */
  592. rc = csngen_adjust_time (gen, replicacsn);
  593. if (rc == CSN_LIMIT_EXCEEDED) /* too much skew */
  594. {
  595. response = NSDS50_REPL_EXCESSIVE_CLOCK_SKEW;
  596. goto send_response;
  597. }
  598. }
  599. else if (diff <= 0)
  600. {
  601. /* Supplier's clock is behind ours */
  602. /* XXXggood check if CSN smaller than purge point */
  603. /* response = NSDS50_REPL_BELOW_PURGEPOINT; */
  604. /* goto send_response; */
  605. }
  606. }
  607. else
  608. {
  609. /* Oops, csnstr couldn't be converted */
  610. response = NSDS50_REPL_INTERNAL_ERROR;
  611. goto send_response;
  612. }
  613. }
  614. else
  615. {
  616. /* Oops, csn generator failed */
  617. response = NSDS50_REPL_INTERNAL_ERROR;
  618. goto send_response;
  619. }
  620. /* update csn generator's state from the supplier's ruv */
  621. rc = replica_update_csngen_state (replica, supplier_ruv); /* too much skew */
  622. if (rc != 0)
  623. {
  624. response = NSDS50_REPL_EXCESSIVE_CLOCK_SKEW;
  625. goto send_response;
  626. }
  627. }
  628. else
  629. {
  630. /* Oops, no csn generator */
  631. response = NSDS50_REPL_INTERNAL_ERROR;
  632. goto send_response;
  633. }
  634. }
  635. else
  636. {
  637. /* Oops, no csn generator object */
  638. response = NSDS50_REPL_INTERNAL_ERROR;
  639. goto send_response;
  640. }
  641. if (check_replica_id_uniqueness(replica, supplier_ruv) != 0){
  642. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  643. "conn=%d op=%d repl=\"%s\": "
  644. "Replica has same replicaID %d as supplier\n",
  645. connid, opid, repl_root, replica_get_rid(replica));
  646. response = NSDS50_REPL_REPLICAID_ERROR;
  647. goto send_response;
  648. }
  649. /* Attempt to acquire exclusive access to the replicated area */
  650. /* Since partial URL is always the master, this locking_purl does not
  651. * help us to know the true locker when it is a hub. Change to use
  652. * the session's conn id and op id to identify the the supplier.
  653. */
  654. /* junkrc = ruv_get_first_id_and_purl(supplier_ruv, &junkrid, &locking_purl); */
  655. sprintf(locking_session, "conn=%d id=%d", connid, opid);
  656. locking_purl = &locking_session[0];
  657. if (replica_get_exclusive_access(replica, &isInc, connid, opid,
  658. locking_purl,
  659. &current_purl) == PR_FALSE)
  660. {
  661. locking_purl = NULL; /* no dangling pointers */
  662. response = NSDS50_REPL_REPLICA_BUSY;
  663. goto send_response;
  664. }
  665. else
  666. {
  667. locking_purl = NULL; /* no dangling pointers */
  668. /* Stick the replica object pointer in the connection extension */
  669. connext->replica_acquired = (void *)replica_object;
  670. replica_object = NULL;
  671. }
  672. /* If this is incremental protocol get replica's ruv to return to the supplier */
  673. if (connext->repl_protocol_version == REPL_PROTOCOL_50_INCREMENTAL)
  674. {
  675. ruv_object = replica_get_ruv(replica);
  676. if (NULL != ruv_object)
  677. {
  678. ruv = object_get_data(ruv_object);
  679. (void)ruv_to_bervals(ruv, &ruv_bervals);
  680. object_release(ruv_object);
  681. }
  682. }
  683. /*
  684. * Save the supplier ruv in the connection extension so it can
  685. * either (a) be installed upon successful initialization (if this
  686. * is a total update session) or used to update referral information
  687. * for new replicas that show up in the supplier's RUV.
  688. */
  689. /*
  690. * the supplier_ruv may have been set before, so free it here
  691. * (in ruv_copy_and_destroy)
  692. */
  693. ruv_copy_and_destroy(&supplier_ruv, (RUV **)&connext->supplier_ruv);
  694. if (connext->repl_protocol_version == REPL_PROTOCOL_50_INCREMENTAL)
  695. {
  696. /* The supplier ruv may have changed, so let's update the referrals */
  697. consumer5_set_mapping_tree_state_for_replica(replica, connext->supplier_ruv);
  698. }
  699. else /* full protocol */
  700. {
  701. char *mtnstate = slapi_mtn_get_state(repl_root_sdn);
  702. char **mtnreferral = slapi_mtn_get_referral(repl_root_sdn);
  703. /* richm 20041118 - we do not want to reap tombstones while there is
  704. a total update in progress, so shut it down */
  705. replica_set_tombstone_reap_stop(replica, PR_TRUE);
  706. /* richm 20010831 - set the mapping tree to the referral state *before*
  707. we invoke slapi_start_bulk_import - see bug 556992 -
  708. slapi_start_bulk_import sets the database offline, if an operation comes
  709. in while the database is offline but the mapping tree is not referring yet,
  710. the server gets confused
  711. */
  712. /* During a total update we refer *all* operations */
  713. repl_set_mtn_state_and_referrals(repl_root_sdn, STATE_REFERRAL,
  714. connext->supplier_ruv, NULL, referrals);
  715. /* LPREPL - check the return code.
  716. * But what do we do if mapping tree could not be updated ? */
  717. /* start the bulk import */
  718. slapi_pblock_set (pb, SLAPI_TARGET_DN, repl_root);
  719. rc = slapi_start_bulk_import (pb);
  720. if (rc != LDAP_SUCCESS)
  721. {
  722. response = NSDS50_REPL_INTERNAL_ERROR;
  723. /* reset the mapping tree state to what it was before
  724. we tried to do the bulk import */
  725. repl_set_mtn_state_and_referrals(repl_root_sdn, mtnstate,
  726. NULL, NULL, mtnreferral);
  727. slapi_ch_free_string(&mtnstate);
  728. charray_free(mtnreferral);
  729. mtnreferral = NULL;
  730. goto send_response;
  731. }
  732. slapi_ch_free_string(&mtnstate);
  733. charray_free(mtnreferral);
  734. mtnreferral = NULL;
  735. }
  736. response = NSDS50_REPL_REPLICA_READY;
  737. /* Set the "is replication session" flag in the connection extension */
  738. slapi_pblock_set( pb, SLAPI_CONN_IS_REPLICATION_SESSION, &one );
  739. connext->isreplicationsession = 1;
  740. /* Save away the connection */
  741. slapi_pblock_get(pb, SLAPI_CONNECTION, &connext->connection);
  742. send_response:
  743. if (response != NSDS50_REPL_REPLICA_READY)
  744. {
  745. int resp_log_level = SLAPI_LOG_FATAL;
  746. char purlstr[1024] = {0};
  747. if (current_purl)
  748. sprintf(purlstr, " locked by %s for %s update", current_purl,
  749. isInc ? "incremental" : "total");
  750. /* Don't log replica busy as errors - these are almost always not
  751. errors - use the replication monitoring tools to determine if
  752. a replica is not converging, then look for pathological replica
  753. busy errors by turning on the replication log level */
  754. if (response == NSDS50_REPL_REPLICA_BUSY) {
  755. resp_log_level = SLAPI_LOG_REPL;
  756. }
  757. slapi_log_error (resp_log_level, repl_plugin_name,
  758. "conn=%d op=%d replica=\"%s\": "
  759. "Unable to acquire replica: error: %s%s\n",
  760. connid, opid,
  761. (replica ? slapi_sdn_get_dn(replica_get_root(replica)) : "unknown"),
  762. protocol_response2string (response), purlstr);
  763. /* enable tombstone reap again since the total update failed */
  764. replica_set_tombstone_reap_stop(replica, PR_FALSE);
  765. }
  766. /* Send the response */
  767. if ((resp_bere = der_alloc()) == NULL)
  768. {
  769. /* ONREPL - not sure what we suppose to do here */
  770. }
  771. ber_printf(resp_bere, "{e", response);
  772. if (NULL != ruv_bervals)
  773. {
  774. ber_printf(resp_bere, "{V}", ruv_bervals);
  775. }
  776. ber_printf(resp_bere, "}");
  777. ber_flatten(resp_bere, &resp_bval);
  778. slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, REPL_NSDS50_REPLICATION_RESPONSE_OID);
  779. slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, resp_bval);
  780. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  781. "conn=%d op=%d repl=\"%s\": "
  782. "StartNSDS50ReplicationRequest: response=%d rc=%d\n",
  783. connid, opid, repl_root,
  784. response, rc);
  785. slapi_send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
  786. return_value = SLAPI_PLUGIN_EXTENDED_SENT_RESULT;
  787. slapi_ch_free_string(&current_purl);
  788. /* protocol_oid */
  789. /* slapi_ch_free accepts NULL pointer */
  790. slapi_ch_free((void **)&protocol_oid);
  791. /* repl_root */
  792. slapi_ch_free((void **)&repl_root);
  793. /* supplier's ruv */
  794. if (supplier_ruv)
  795. {
  796. ruv_destroy (&supplier_ruv);
  797. }
  798. /* referrals */
  799. slapi_ch_free((void **)&referrals);
  800. /* replicacsnstr */
  801. slapi_ch_free((void **)&replicacsnstr);
  802. /* repl_root_sdn */
  803. if (NULL != repl_root_sdn)
  804. {
  805. slapi_sdn_free(&repl_root_sdn);
  806. }
  807. if (NSDS50_REPL_REPLICA_READY != response)
  808. {
  809. /*
  810. * Something went wrong, and we never told the other end that the
  811. * replica had been acquired, so we'd better release it.
  812. */
  813. if (NULL != connext && NULL != connext->replica_acquired)
  814. {
  815. Object *r_obj = (Object*)connext->replica_acquired;
  816. replica_relinquish_exclusive_access((Replica*)object_get_data (r_obj),
  817. connid, opid);
  818. }
  819. /* Remove any flags that would indicate repl session in progress */
  820. if (NULL != connext)
  821. {
  822. connext->repl_protocol_version = REPL_PROTOCOL_UNKNOWN;
  823. connext->isreplicationsession = 0;
  824. }
  825. slapi_pblock_set( pb, SLAPI_CONN_IS_REPLICATION_SESSION, &zero );
  826. }
  827. /* Release reference to replica_object */
  828. if (NULL != replica_object)
  829. {
  830. object_release(replica_object);
  831. }
  832. /* bind_sdn */
  833. if (NULL != bind_sdn)
  834. {
  835. slapi_sdn_free(&bind_sdn);
  836. }
  837. /* Release reference to gen_obj */
  838. if (NULL != gen_obj)
  839. {
  840. object_release(gen_obj);
  841. }
  842. /* mycsn */
  843. if (NULL != mycsn)
  844. {
  845. csn_free(&mycsn);
  846. }
  847. /* replicacsn */
  848. if (NULL != replicacsn)
  849. {
  850. csn_free(&replicacsn);
  851. }
  852. /* resp_bere */
  853. if (NULL != resp_bere)
  854. {
  855. ber_free(resp_bere, 1);
  856. }
  857. /* resp_bval */
  858. if (NULL != resp_bval)
  859. {
  860. ber_bvfree(resp_bval);
  861. }
  862. /* ruv_bervals */
  863. if (NULL != ruv_bervals)
  864. {
  865. ber_bvecfree(ruv_bervals);
  866. }
  867. return return_value;
  868. }
  869. /*
  870. * This plugin entry point is called whenever an
  871. * EndNSDS50ReplicationRequest is received.
  872. * XXXggood this code is not finished.
  873. */
  874. int
  875. multimaster_extop_EndNSDS50ReplicationRequest(Slapi_PBlock *pb)
  876. {
  877. int return_value = SLAPI_PLUGIN_EXTENDED_NOT_HANDLED;
  878. char *repl_root = NULL;
  879. BerElement *resp_bere = NULL;
  880. struct berval *resp_bval = NULL;
  881. int response;
  882. void *conn;
  883. consumer_connection_extension *connext = NULL;
  884. int rc;
  885. int connid=-1, opid=-1;
  886. /* Decode the extended operation */
  887. if (decode_endrepl_extop(pb, &repl_root) == -1)
  888. {
  889. response = NSDS50_REPL_DECODING_ERROR;
  890. }
  891. else
  892. {
  893. /* First, verify that the current connection is a replication session */
  894. /* XXXggood - do we need to wait around for any pending updates to complete?
  895. I suppose it's possible that the end request may arrive asynchronously, before
  896. we're really done processing all the updates.
  897. */
  898. /* Get a hold of the connection extension object */
  899. slapi_pblock_get(pb, SLAPI_CONNECTION, &conn);
  900. connext = (consumer_connection_extension *)repl_con_get_ext(
  901. REPL_CON_EXT_CONN, conn);
  902. if (NULL != connext && NULL != connext->replica_acquired)
  903. {
  904. int zero= 0;
  905. Replica *r = (Replica*)object_get_data ((Object*)connext->replica_acquired);
  906. /* if this is total protocol we need to install suppliers ruv for the replica */
  907. if (connext->repl_protocol_version == REPL_PROTOCOL_50_TOTALUPDATE)
  908. {
  909. /* We no longer need to refer all operations...
  910. * and update the referrals on the mapping tree node
  911. */
  912. consumer5_set_mapping_tree_state_for_replica(r, NULL);
  913. /* LPREPL - First we clear the total in progress flag
  914. Like this we know it's a normal termination of import. This is required by
  915. the replication function that responds to backend state change.
  916. If the flag is not clear, the callback knows that replication should not be
  917. enabled again */
  918. replica_set_state_flag(r, REPLICA_TOTAL_IN_PROGRESS, PR_TRUE /* clear flag */);
  919. slapi_pblock_set (pb, SLAPI_TARGET_DN, repl_root);
  920. slapi_stop_bulk_import (pb);
  921. /* ONREPL - this is a bit of a hack. Once bulk import is finished,
  922. the replication function that responds to backend state change
  923. will be called. That function normally do all ruv and changelog
  924. processing. However, in the case of replica initalization, it
  925. will not do the right thing because supplier does not send its
  926. ruv tombstone to the consumer. So that's why we need to do the
  927. second processing here.
  928. The supplier does not send its RUV entry because it could be
  929. more up to date then the data send to the consumer.
  930. The best solution I think, would be to "fake" on the supplier
  931. an entry that corresponds to the ruv sent to the consumer and then
  932. send it as part of the data */
  933. if (cl5GetState () == CL5_STATE_OPEN)
  934. {
  935. rc = cl5DeleteDBSync (connext->replica_acquired);
  936. }
  937. replica_set_ruv (r, connext->supplier_ruv);
  938. connext->supplier_ruv = NULL;
  939. /* if changelog is enabled, we need to log a dummy change for the
  940. smallest csn in the new ruv, so that this replica ca supply
  941. other servers.
  942. */
  943. if (cl5GetState () == CL5_STATE_OPEN)
  944. {
  945. replica_log_ruv_elements (r);
  946. }
  947. /* ONREPL code that dealt with new RUV, etc was moved into the code
  948. that enables replication when a backend comes back online. This
  949. code is called once the bulk import is finished */
  950. /* allow reaping again */
  951. replica_set_tombstone_reap_stop(r, PR_FALSE);
  952. }
  953. else if (connext->repl_protocol_version == REPL_PROTOCOL_50_INCREMENTAL)
  954. {
  955. /* The ruv from the supplier may have changed. Report the change on the
  956. consumer side */
  957. replica_update_ruv_consumer(r, connext->supplier_ruv);
  958. }
  959. /* Relinquish control of the replica */
  960. slapi_pblock_get (pb, SLAPI_OPERATION_ID, &opid);
  961. if (opid) slapi_pblock_get (pb, SLAPI_CONN_ID, &connid);
  962. replica_relinquish_exclusive_access(r, connid, opid);
  963. object_release ((Object*)connext->replica_acquired);
  964. connext->replica_acquired = NULL;
  965. connext->isreplicationsession= 0;
  966. slapi_pblock_set( pb, SLAPI_CONN_IS_REPLICATION_SESSION, &zero );
  967. response = NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED;
  968. /* Outbound replication agreements need to all be restarted now */
  969. /* XXXGGOOD RESTART REEPL AGREEMENTS */
  970. }
  971. }
  972. /* Send the response code */
  973. if ((resp_bere = der_alloc()) == NULL)
  974. {
  975. rc = LDAP_ENCODING_ERROR;
  976. goto free_and_return;
  977. }
  978. ber_printf(resp_bere, "{e}", response);
  979. ber_flatten(resp_bere, &resp_bval);
  980. slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, REPL_NSDS50_REPLICATION_RESPONSE_OID);
  981. slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, resp_bval);
  982. slapi_send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
  983. return_value = SLAPI_PLUGIN_EXTENDED_SENT_RESULT;
  984. free_and_return:
  985. /* repl_root */
  986. slapi_ch_free((void **)&repl_root);
  987. /* BerElement */
  988. if (NULL != resp_bere)
  989. {
  990. ber_free(resp_bere, 1);
  991. }
  992. /* response */
  993. if (NULL != resp_bval)
  994. {
  995. ber_bvfree(resp_bval);
  996. }
  997. return return_value;
  998. }
  999. /*
  1000. * This plugin entry point is a noop entry
  1001. * point. It's used when registering extops that
  1002. * are only used as responses. We'll never receive
  1003. * one of those, unsolicited, but we still want to
  1004. * register them so they appear in the
  1005. * supportedextension attribute in the root DSE.
  1006. */
  1007. int
  1008. extop_noop(Slapi_PBlock *pb)
  1009. {
  1010. return SLAPI_PLUGIN_EXTENDED_NOT_HANDLED;
  1011. }
  1012. static int
  1013. check_replica_id_uniqueness(Replica *replica, RUV *supplier_ruv)
  1014. {
  1015. ReplicaId local_rid = replica_get_rid(replica);
  1016. ReplicaId sup_rid = 0;
  1017. char *sup_purl = NULL;
  1018. if (ruv_get_first_id_and_purl(supplier_ruv, &sup_rid, &sup_purl) == RUV_SUCCESS) {
  1019. /* ReplicaID Uniqueness is checked only on Masters */
  1020. if ((replica_get_type(replica) == REPLICA_TYPE_UPDATABLE) &&
  1021. (sup_rid == local_rid)) {
  1022. return 1;
  1023. }
  1024. }
  1025. return 0;
  1026. }