sync_refresh.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771
  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) 2013 Red Hat, Inc.
  35. * All rights reserved.
  36. * END COPYRIGHT BLOCK **/
  37. #include "sync.h"
  38. static SyncOpInfo *new_SyncOpInfo(int flag, PRThread *tid, Sync_Cookie *cookie);
  39. static int sync_extension_type;
  40. static int sync_extension_handle;
  41. static SyncOpInfo *sync_get_operation_extension(Slapi_PBlock *pb);
  42. static void sync_set_operation_extension(Slapi_PBlock *pb, SyncOpInfo *spec);
  43. static int sync_find_ref_by_uuid(Sync_UpdateNode *updates, int stop, char *uniqueid);
  44. static void sync_free_update_nodes (Sync_UpdateNode **updates, int count);
  45. Slapi_Entry *sync_deleted_entry_from_changelog(Slapi_Entry *cl_entry);
  46. static int sync_feature_allowed (Slapi_PBlock *pb);
  47. static int sync_feature_allowed (Slapi_PBlock *pb)
  48. {
  49. int isroot = 0;
  50. int ldapcode = LDAP_SUCCESS;
  51. slapi_pblock_get(pb, SLAPI_REQUESTOR_ISROOT, &isroot);
  52. if ( !isroot) {
  53. char *dn;
  54. Slapi_Entry *feature = NULL;
  55. /* Fetch the feature entry and see if the requestor is allowed access. */
  56. dn = slapi_ch_smprintf("dn: oid=%s,cn=features,cn=config", LDAP_CONTROL_SYNC);
  57. if ((feature = slapi_str2entry(dn,0)) != NULL) {
  58. char *dummy_attr = "1.1";
  59. ldapcode = slapi_access_allowed(pb, feature, dummy_attr, NULL, SLAPI_ACL_READ);
  60. }
  61. /* If the feature entry does not exist, deny use of the control. Only
  62. * the root DN will be allowed to use the control in this case. */
  63. if ((feature == NULL) || (ldapcode != LDAP_SUCCESS)) {
  64. ldapcode = LDAP_INSUFFICIENT_ACCESS;
  65. }
  66. slapi_ch_free((void **)&dn);
  67. slapi_entry_free(feature);
  68. }
  69. return(ldapcode);
  70. }
  71. int sync_srch_refresh_pre_search(Slapi_PBlock *pb)
  72. {
  73. LDAPControl **requestcontrols;
  74. struct berval *psbvp;
  75. Sync_Cookie *client_cookie = NULL;
  76. Sync_Cookie *session_cookie = NULL;
  77. int rc = 0;
  78. int sync_persist = 0;
  79. PRThread *tid = NULL;
  80. int entries_sent = 0;
  81. slapi_pblock_get (pb, SLAPI_REQCONTROLS, &requestcontrols);
  82. if ( slapi_control_present( requestcontrols, LDAP_CONTROL_SYNC, &psbvp, NULL )){
  83. char *cookie = NULL;
  84. int mode = 1;
  85. int refresh = 0;
  86. if ( sync_parse_control_value( psbvp, &mode,
  87. &refresh, &cookie ) != LDAP_SUCCESS )
  88. {
  89. rc = 1;
  90. goto error_return;
  91. } else {
  92. /* control is valid, check if usere is allowed to perform sync searches */
  93. rc = sync_feature_allowed(pb);
  94. if (rc) {
  95. sync_result_err(pb,rc,NULL);
  96. goto error_return;
  97. }
  98. }
  99. if ( mode == 1 || mode == 3 )
  100. {
  101. /* we need to return a cookie in the result message
  102. * indicating a state to be used in future sessions
  103. * as starting point - create it now
  104. */
  105. session_cookie = sync_cookie_create(pb);
  106. /*
  107. * if mode is persist we need to setup the persit handler
  108. * to catch the mods while the refresh is done
  109. */
  110. if ( mode == 3 )
  111. {
  112. tid = sync_persist_add(pb);
  113. if ( tid )
  114. sync_persist = 1;
  115. else {
  116. rc = LDAP_UNWILLING_TO_PERFORM;
  117. sync_result_err(pb,rc,"Too many active synchronization sessions");
  118. goto error_return;
  119. }
  120. }
  121. /*
  122. * now handl the refresh request
  123. * there are two scenarios
  124. * 1. no cookie is provided this means send all entries matching the search request
  125. * 2. a cookie is provided: send all entries changed since the cookie was issued
  126. * -- return an error if the cookie is invalid
  127. * -- return e-syncRefreshRequired if the data referenced in the cookie are no
  128. * longer in the history
  129. */
  130. if (cookie &&
  131. ( client_cookie = sync_cookie_parse (cookie))) {
  132. if (sync_cookie_isvalid(client_cookie, session_cookie)) {
  133. rc = sync_refresh_update_content(pb, client_cookie, session_cookie);
  134. if (rc == 0)
  135. entries_sent = 1;
  136. if (sync_persist)
  137. rc = sync_intermediate_msg(pb, LDAP_TAG_SYNC_REFRESH_DELETE, session_cookie, NULL);
  138. else
  139. rc = sync_result_msg(pb, session_cookie);
  140. } else {
  141. rc = E_SYNC_REFRESH_REQUIRED;
  142. sync_result_err(pb,rc, "Invalid session cookie");
  143. }
  144. } else {
  145. rc = sync_refresh_initial_content (pb, sync_persist, tid, session_cookie);
  146. if (rc == 0 && !sync_persist)
  147. /* maintained in postop code */
  148. session_cookie = NULL;
  149. /* if persis it will be handed over to persist code */
  150. }
  151. if ( rc ) {
  152. if (sync_persist)
  153. sync_persist_terminate (tid);
  154. goto error_return;
  155. } else if (sync_persist){
  156. Slapi_Operation *operation;
  157. slapi_pblock_get(pb, SLAPI_OPERATION, &operation);
  158. if (client_cookie) {
  159. rc = sync_persist_startup(tid, session_cookie);
  160. }
  161. if (rc == 0) {
  162. session_cookie = NULL; /* maintained in persist code */
  163. slapi_operation_set_flag(operation, OP_FLAG_SYNC_PERSIST);
  164. }
  165. }
  166. } else {
  167. /* unknown mode, return an error */
  168. rc = 1;
  169. }
  170. error_return:
  171. sync_cookie_free(&client_cookie);
  172. sync_cookie_free(&session_cookie);
  173. slapi_ch_free((void **)&cookie);
  174. }
  175. /* if we sent the entries
  176. * return "error" to abort normal search
  177. */
  178. if ( entries_sent > 0 ) {
  179. return(1);
  180. } else {
  181. return(rc);
  182. }
  183. }
  184. int sync_srch_refresh_post_search(Slapi_PBlock *pb)
  185. {
  186. int rc = 0;
  187. SyncOpInfo *info = sync_get_operation_extension(pb);
  188. if (!info) {
  189. return (0); /* nothing to do */
  190. }
  191. if (info->send_flag & SYNC_FLAG_SEND_INTERMEDIATE) {
  192. rc = sync_intermediate_msg(pb, LDAP_TAG_SYNC_REFRESH_DELETE, info->cookie, NULL);
  193. /* the refresh phase is over, now the post op
  194. * plugins will create the state control
  195. * depending on the operation type, reset flag
  196. */
  197. info->send_flag &= ~SYNC_FLAG_ADD_STATE_CTRL;
  198. /* activate the persistent phase thread*/
  199. sync_persist_startup(info->tid, info->cookie);
  200. }
  201. if (info->send_flag & SYNC_FLAG_ADD_DONE_CTRL) {
  202. LDAPControl **ctrl = (LDAPControl **)slapi_ch_calloc(2, sizeof (LDAPControl *));
  203. char *cookiestr = sync_cookie2str(info->cookie);
  204. sync_create_sync_done_control( &ctrl[0], 0, cookiestr);
  205. slapi_pblock_set(pb, SLAPI_RESCONTROLS, ctrl);
  206. slapi_ch_free((void **)&cookiestr);
  207. }
  208. return(rc);
  209. }
  210. int sync_srch_refresh_pre_entry(Slapi_PBlock *pb)
  211. {
  212. int rc = 0;
  213. SyncOpInfo *info = sync_get_operation_extension(pb);
  214. if (!info) {
  215. rc = 0; /* nothing to do */
  216. } else if (info->send_flag & SYNC_FLAG_ADD_STATE_CTRL) {
  217. Slapi_Entry *e;
  218. slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_ENTRY, &e);
  219. LDAPControl **ctrl = (LDAPControl **)slapi_ch_calloc(2, sizeof (LDAPControl *));
  220. sync_create_state_control(e, &ctrl[0], LDAP_SYNC_ADD, NULL);
  221. slapi_pblock_set(pb, SLAPI_SEARCH_CTRLS, ctrl);
  222. }
  223. return(rc);
  224. }
  225. int sync_srch_refresh_pre_result(Slapi_PBlock *pb)
  226. {
  227. SyncOpInfo *info = sync_get_operation_extension(pb);
  228. if (!info) {
  229. return 0; /* nothing to do */
  230. }
  231. if (info->send_flag & SYNC_FLAG_NO_RESULT ) {
  232. return(1);
  233. } else {
  234. return(0);
  235. }
  236. }
  237. static void
  238. sync_free_update_nodes (Sync_UpdateNode **updates, int count)
  239. {
  240. int i;
  241. for (i=0; i<count;i++) {
  242. if ((*updates)[i].upd_uuid)
  243. slapi_ch_free((void **)&((*updates)[i].upd_uuid));
  244. if ((*updates)[i].upd_e)
  245. slapi_entry_free((*updates)[i].upd_e);
  246. }
  247. slapi_ch_free((void **)updates);
  248. }
  249. int
  250. sync_refresh_update_content(Slapi_PBlock *pb, Sync_Cookie *client_cookie, Sync_Cookie *server_cookie)
  251. {
  252. Slapi_PBlock *seq_pb;
  253. char *filter;
  254. Sync_CallBackData cb_data;
  255. int rc;
  256. int chg_count = server_cookie->cookie_change_info -
  257. client_cookie->cookie_change_info + 1;
  258. cb_data.cb_updates = (Sync_UpdateNode *)slapi_ch_calloc(chg_count, sizeof(Sync_UpdateNode));
  259. seq_pb = slapi_pblock_new();
  260. slapi_pblock_init(seq_pb);
  261. cb_data.orig_pb = pb;
  262. cb_data.change_start = client_cookie->cookie_change_info;
  263. filter = slapi_ch_smprintf("(&(changenumber>=%lu)(changenumber<=%lu))",
  264. client_cookie->cookie_change_info,
  265. server_cookie->cookie_change_info);
  266. slapi_search_internal_set_pb(
  267. seq_pb,
  268. CL_SRCH_BASE,
  269. LDAP_SCOPE_ONE,
  270. filter,
  271. NULL,
  272. 0,
  273. NULL, NULL,
  274. plugin_get_default_component_id(),
  275. 0);
  276. rc = slapi_search_internal_callback_pb (
  277. seq_pb, &cb_data, NULL, sync_read_entry_from_changelog, NULL);
  278. slapi_pblock_destroy(seq_pb);
  279. /* Now send the deleted entries in a sync info message
  280. * and the modified entries as single entries
  281. */
  282. sync_send_deleted_entries(pb, cb_data.cb_updates, chg_count, server_cookie);
  283. sync_send_modified_entries(pb, cb_data.cb_updates, chg_count);
  284. sync_free_update_nodes(&cb_data.cb_updates, chg_count);
  285. slapi_ch_free((void **)&filter);
  286. return (rc);
  287. }
  288. int
  289. sync_refresh_initial_content(Slapi_PBlock *pb, int sync_persist, PRThread *tid, Sync_Cookie *sc)
  290. {
  291. /* the entries will be sent in the normal search process, but
  292. * - a control has to be sent with each entry
  293. * if sync persist:
  294. * - an intermediate response has to be sent
  295. * - no result message must be sent
  296. *
  297. * else
  298. * - a result message with a sync done control has to be sent
  299. *
  300. * setup on operation extension to take care of in
  301. * pre_entry, pre_result and post_search plugins
  302. */
  303. SyncOpInfo *info;
  304. if (sync_persist) {
  305. info = new_SyncOpInfo
  306. (SYNC_FLAG_ADD_STATE_CTRL |
  307. SYNC_FLAG_SEND_INTERMEDIATE |
  308. SYNC_FLAG_NO_RESULT,
  309. tid,
  310. sc);
  311. } else {
  312. info = new_SyncOpInfo
  313. (SYNC_FLAG_ADD_STATE_CTRL |
  314. SYNC_FLAG_ADD_DONE_CTRL,
  315. tid,
  316. sc);
  317. }
  318. sync_set_operation_extension(pb, info);
  319. return(0);
  320. }
  321. static int
  322. sync_str2chgreq(char *chgtype)
  323. {
  324. if (chgtype == NULL) {
  325. return(-1);
  326. }
  327. if (strcasecmp(chgtype,"add") == 0) {
  328. return(LDAP_REQ_ADD);
  329. } else if (strcasecmp(chgtype,"modify") == 0) {
  330. return(LDAP_REQ_MODIFY);
  331. } else if (strcasecmp(chgtype,"modrdn") == 0) {
  332. return(LDAP_REQ_MODRDN);
  333. } else if (strcasecmp(chgtype,"delete") == 0) {
  334. return(LDAP_REQ_DELETE);
  335. } else {
  336. return(-1);
  337. }
  338. }
  339. static char*
  340. sync_get_attr_value_from_entry( Slapi_Entry *cl_entry, char *attrtype)
  341. {
  342. Slapi_Value *sval=NULL;
  343. const struct berval *value;
  344. char *strvalue = NULL;
  345. if ( NULL != cl_entry ) {
  346. Slapi_Attr *chattr = NULL;
  347. sval = NULL;
  348. value = NULL;
  349. if ( slapi_entry_attr_find( cl_entry, attrtype, &chattr ) == 0 ) {
  350. slapi_attr_first_value( chattr,&sval );
  351. if ( NULL != sval ) {
  352. value = slapi_value_get_berval ( sval );
  353. if( NULL != value && NULL != value->bv_val &&
  354. '\0' != value->bv_val[0]) {
  355. strvalue = slapi_ch_strdup( value->bv_val);
  356. }
  357. }
  358. }
  359. }
  360. return (strvalue);
  361. }
  362. static int
  363. sync_find_ref_by_uuid(Sync_UpdateNode *updates, int stop, char *uniqueid)
  364. {
  365. int rc = -1;
  366. int i;
  367. for (i=0; i<stop; i++) {
  368. if ( updates[i].upd_uuid && (0 == strcmp(uniqueid, updates[i].upd_uuid))) {
  369. rc = i;
  370. break;
  371. }
  372. }
  373. return (rc);
  374. }
  375. static int
  376. sync_is_entry_in_scope(Slapi_PBlock *pb, Slapi_Entry *db_entry)
  377. {
  378. Slapi_Filter *origfilter;
  379. slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &origfilter );
  380. if (db_entry &&
  381. sync_is_active(db_entry, pb) &&
  382. (slapi_vattr_filter_test( pb, db_entry, origfilter, 1) == 0)) {
  383. return(1);
  384. } else {
  385. return(0);
  386. }
  387. }
  388. Slapi_Entry *
  389. sync_deleted_entry_from_changelog(Slapi_Entry *cl_entry)
  390. {
  391. Slapi_Entry *db_entry = NULL;
  392. char *entrydn = NULL;
  393. char *uniqueid = NULL;
  394. entrydn = sync_get_attr_value_from_entry (cl_entry, CL_ATTR_ENTRYDN);
  395. uniqueid = sync_get_attr_value_from_entry (cl_entry, CL_ATTR_UNIQUEID);
  396. /* when the Retro CL can provide the deleted entry
  397. * the entry will be taken from th RCL.
  398. * For now. just create an entry to holde the nsuniqueid
  399. */
  400. db_entry = slapi_entry_alloc();
  401. slapi_entry_init(db_entry, entrydn, NULL);
  402. slapi_entry_add_string(db_entry, "nsuniqueid", uniqueid);
  403. slapi_ch_free((void**)&uniqueid);
  404. return(db_entry);
  405. }
  406. int
  407. sync_read_entry_from_changelog( Slapi_Entry *cl_entry, void *cb_data)
  408. {
  409. char *uniqueid = NULL;
  410. char *chgtype = NULL;
  411. char *chgnr = NULL;
  412. int chg_req;
  413. int prev = 0;
  414. int index = 0;
  415. unsigned long chgnum = 0;
  416. Sync_CallBackData *cb = (Sync_CallBackData *) cb_data;
  417. if (cb == NULL) {
  418. return(1);
  419. }
  420. uniqueid = sync_get_attr_value_from_entry (cl_entry, CL_ATTR_UNIQUEID);
  421. if (uniqueid == NULL) {
  422. slapi_log_error (SLAPI_LOG_FATAL, SYNC_PLUGIN_SUBSYSTEM,
  423. "Retro Changelog does not provied nsuniquedid."
  424. "Check RCL plugin configuration.\n" );
  425. return(1);
  426. }
  427. chgnr = sync_get_attr_value_from_entry (cl_entry, CL_ATTR_CHANGENUMBER);
  428. chgnum = sync_number2ulong(chgnr);
  429. if (SYNC_INVALID_CHANGENUM == chgnum) {
  430. slapi_log_error (SLAPI_LOG_FATAL, SYNC_PLUGIN_SUBSYSTEM,
  431. "Change number provided by Retro Changelog is invalid: %s\n", chgnr);
  432. slapi_ch_free_string(&chgnr);
  433. slapi_ch_free_string(&uniqueid);
  434. return(1);
  435. }
  436. if (chgnum < cb->change_start) {
  437. slapi_log_error (SLAPI_LOG_FATAL, SYNC_PLUGIN_SUBSYSTEM,
  438. "Change number provided by Retro Changelog %s is less than the initial number %lu\n",
  439. chgnr, cb->change_start);
  440. slapi_ch_free_string(&chgnr);
  441. slapi_ch_free_string(&uniqueid);
  442. return(1);
  443. }
  444. index = chgnum - cb->change_start;
  445. chgtype = sync_get_attr_value_from_entry (cl_entry, CL_ATTR_CHGTYPE);
  446. chg_req = sync_str2chgreq(chgtype);
  447. switch (chg_req){
  448. case LDAP_REQ_ADD:
  449. /* nsuniqueid cannot exist, just add reference */
  450. cb->cb_updates[index].upd_chgtype = LDAP_REQ_ADD;
  451. cb->cb_updates[index].upd_uuid = uniqueid;
  452. break;
  453. case LDAP_REQ_MODIFY:
  454. /* check if we have seen this uuid already */
  455. prev = sync_find_ref_by_uuid(cb->cb_updates, index, uniqueid);
  456. if (prev == -1) {
  457. cb->cb_updates[index].upd_chgtype = LDAP_REQ_MODIFY;
  458. cb->cb_updates[index].upd_uuid = uniqueid;
  459. } else {
  460. /* was add or mod, keep it */
  461. cb->cb_updates[index].upd_uuid = 0;
  462. cb->cb_updates[index].upd_chgtype = 0;
  463. slapi_ch_free_string(&uniqueid);
  464. }
  465. break;
  466. case LDAP_REQ_MODRDN:
  467. {
  468. /* if it is a modrdn, we finally need to decide if this will
  469. * trigger a present or delete state, keep the info that
  470. * the entry was subject to a modrdn
  471. */
  472. int new_scope = 0;
  473. int old_scope = 0;
  474. Slapi_DN *original_dn;
  475. char *newsuperior = sync_get_attr_value_from_entry (cl_entry, CL_ATTR_NEWSUPERIOR);
  476. char *entrydn = sync_get_attr_value_from_entry (cl_entry, CL_ATTR_ENTRYDN);
  477. /* if newsuperior is set we need to checkif the entry has been moved into
  478. * or moved out of the scope of the synchronization request
  479. */
  480. original_dn = slapi_sdn_new_dn_byref(entrydn);
  481. old_scope = sync_is_active_scope(original_dn,cb->orig_pb);
  482. slapi_sdn_free(&original_dn);
  483. slapi_ch_free_string(&entrydn);
  484. if (newsuperior) {
  485. Slapi_DN *newbase;
  486. newbase = slapi_sdn_new_dn_byref(newsuperior);
  487. new_scope = sync_is_active_scope(newbase, cb->orig_pb);
  488. slapi_ch_free_string(&newsuperior);
  489. slapi_sdn_free(&newbase);
  490. } else {
  491. /* scope didn't change */
  492. new_scope = old_scope;
  493. }
  494. prev = sync_find_ref_by_uuid(cb->cb_updates, index, uniqueid);
  495. if ( old_scope && new_scope ) {
  496. /* nothing changed, it's just a MOD */
  497. if (prev == -1) {
  498. cb->cb_updates[index].upd_chgtype = LDAP_REQ_MODIFY;
  499. cb->cb_updates[index].upd_uuid = uniqueid;
  500. } else {
  501. cb->cb_updates[index].upd_uuid = 0;
  502. cb->cb_updates[index].upd_chgtype = 0;
  503. slapi_ch_free_string(&uniqueid);
  504. }
  505. } else if ( old_scope ) {
  506. /* it was moved out of scope, handle as DEL */
  507. if (prev == -1) {
  508. cb->cb_updates[index].upd_chgtype = LDAP_REQ_DELETE;
  509. cb->cb_updates[index].upd_uuid = uniqueid;
  510. cb->cb_updates[index].upd_e = sync_deleted_entry_from_changelog(cl_entry);
  511. } else {
  512. cb->cb_updates[prev].upd_chgtype = LDAP_REQ_DELETE;
  513. cb->cb_updates[prev].upd_e = sync_deleted_entry_from_changelog(cl_entry);
  514. slapi_ch_free_string(&uniqueid);
  515. }
  516. } else if ( new_scope ) {
  517. /* moved into scope, handle as ADD */
  518. cb->cb_updates[index].upd_chgtype = LDAP_REQ_ADD;
  519. cb->cb_updates[index].upd_uuid = uniqueid;
  520. } else {
  521. /* nothing to do */
  522. slapi_ch_free_string(&uniqueid);
  523. }
  524. slapi_sdn_free(&original_dn);
  525. break;
  526. }
  527. case LDAP_REQ_DELETE:
  528. /* check if we have seen this uuid already */
  529. prev = sync_find_ref_by_uuid(cb->cb_updates, index, uniqueid);
  530. if (prev == -1) {
  531. cb->cb_updates[index].upd_chgtype = LDAP_REQ_DELETE;
  532. cb->cb_updates[index].upd_uuid = uniqueid;
  533. cb->cb_updates[index].upd_e = sync_deleted_entry_from_changelog(cl_entry);
  534. } else {
  535. /* if it was added since last cookie state, we
  536. * can ignoere it */
  537. if (cb->cb_updates[prev].upd_chgtype == LDAP_REQ_ADD) {
  538. slapi_ch_free_string(&(cb->cb_updates[prev].upd_uuid));
  539. cb->cb_updates[prev].upd_uuid = NULL;
  540. cb->cb_updates[index].upd_uuid = NULL;
  541. } else {
  542. /* ignore previous mod */
  543. cb->cb_updates[index].upd_uuid = NULL;
  544. cb->cb_updates[prev].upd_chgtype = LDAP_REQ_DELETE;
  545. cb->cb_updates[prev].upd_e = sync_deleted_entry_from_changelog(cl_entry);
  546. }
  547. slapi_ch_free_string(&uniqueid);
  548. }
  549. break;
  550. default:
  551. slapi_ch_free_string(&uniqueid);
  552. }
  553. slapi_ch_free_string(&chgtype);
  554. slapi_ch_free_string(&chgnr);
  555. return (0);
  556. }
  557. #define SYNC_MAX_DELETED_UUID_BATCH 50
  558. void
  559. sync_send_deleted_entries(Slapi_PBlock *pb, Sync_UpdateNode *upd, int chg_count, Sync_Cookie *cookie)
  560. {
  561. char *syncUUIDs[SYNC_MAX_DELETED_UUID_BATCH + 1];
  562. int uuid_index = 0;
  563. int index, i;
  564. syncUUIDs[0] = NULL;
  565. for (index=0; index < chg_count; index++) {
  566. if (upd[index].upd_chgtype == LDAP_REQ_DELETE &&
  567. upd[index].upd_uuid ) {
  568. if (uuid_index < SYNC_MAX_DELETED_UUID_BATCH) {
  569. syncUUIDs[uuid_index++] = sync_nsuniqueid2uuid(upd[index].upd_uuid);
  570. } else {
  571. /* max number of uuids to be sent in one sync info message */
  572. syncUUIDs[uuid_index] = NULL;
  573. sync_intermediate_msg (pb, LDAP_TAG_SYNC_ID_SET, cookie, &syncUUIDs[0]);
  574. for (i=0; i<uuid_index;i++) {
  575. slapi_ch_free((void **)&syncUUIDs[i]);
  576. syncUUIDs[i] = NULL;
  577. }
  578. uuid_index = 0;
  579. }
  580. }
  581. }
  582. if (uuid_index > 0 && syncUUIDs[uuid_index-1]) {
  583. /* more entries to send */
  584. syncUUIDs[uuid_index] = NULL;
  585. sync_intermediate_msg (pb, LDAP_TAG_SYNC_ID_SET, cookie, &syncUUIDs[0]);
  586. for (i=0; i<uuid_index;i++) {
  587. slapi_ch_free((void **)&syncUUIDs[i]);
  588. syncUUIDs[i] = NULL;
  589. }
  590. }
  591. }
  592. void
  593. sync_send_modified_entries(Slapi_PBlock *pb, Sync_UpdateNode *upd, int chg_count)
  594. {
  595. int index;
  596. for (index=0; index < chg_count; index++) {
  597. if (upd[index].upd_chgtype != LDAP_REQ_DELETE &&
  598. upd[index].upd_uuid )
  599. sync_send_entry_from_changelog(pb, upd[index].upd_chgtype, upd[index].upd_uuid);
  600. }
  601. }
  602. int
  603. sync_send_entry_from_changelog(Slapi_PBlock *pb,int chg_req, char *uniqueid)
  604. {
  605. Slapi_Entry *db_entry = NULL;
  606. int chg_type = LDAP_SYNC_ADD;
  607. int rv;
  608. Slapi_PBlock *search_pb = NULL;
  609. Slapi_Entry **entries = NULL;
  610. char *origbase;
  611. char *filter = slapi_ch_smprintf("(nsuniqueid=%s)",uniqueid);
  612. slapi_pblock_get( pb, SLAPI_ORIGINAL_TARGET_DN, &origbase );
  613. search_pb = slapi_pblock_new();
  614. slapi_search_internal_set_pb(search_pb, origbase,
  615. LDAP_SCOPE_SUBTREE, filter,
  616. NULL, 0, NULL, NULL, plugin_get_default_component_id(), 0);
  617. slapi_search_internal_pb(search_pb);
  618. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &rv);
  619. if ( rv == LDAP_SUCCESS) {
  620. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  621. if (entries)
  622. db_entry = *entries; /* there can only be one */
  623. }
  624. if (db_entry && sync_is_entry_in_scope(pb, db_entry)) {
  625. LDAPControl **ctrl = (LDAPControl **)slapi_ch_calloc(2, sizeof (LDAPControl *));
  626. sync_create_state_control(db_entry, &ctrl[0], chg_type, NULL);
  627. slapi_send_ldap_search_entry (pb, db_entry, ctrl, NULL, 0);
  628. ldap_controls_free(ctrl);
  629. }
  630. slapi_free_search_results_internal(search_pb);
  631. slapi_pblock_destroy(search_pb);
  632. slapi_ch_free((void **)&filter);
  633. return (0);
  634. }
  635. static SyncOpInfo*
  636. new_SyncOpInfo(int flag, PRThread *tid, Sync_Cookie *cookie) {
  637. SyncOpInfo *spec = (SyncOpInfo *)slapi_ch_calloc(1, sizeof(SyncOpInfo));
  638. spec->send_flag = flag;
  639. spec->cookie = cookie;
  640. spec->tid = tid;
  641. return spec;
  642. }
  643. /* consumer operation extension constructor */
  644. static void *
  645. sync_operation_extension_ctor(void *object, void *parent)
  646. {
  647. /* we only set the extension value explicitly if the
  648. client requested the control - see deref_pre_search */
  649. return NULL; /* we don't set anything in the ctor */
  650. }
  651. /* consumer operation extension destructor */
  652. static void
  653. sync_delete_SyncOpInfo(SyncOpInfo **info)
  654. {
  655. if (info && *info) {
  656. sync_cookie_free(&((*info)->cookie));
  657. slapi_ch_free((void **)info);
  658. }
  659. }
  660. static void
  661. sync_operation_extension_dtor(void *ext, void *object, void *parent)
  662. {
  663. SyncOpInfo *spec = (SyncOpInfo *)ext;
  664. sync_delete_SyncOpInfo(&spec);
  665. }
  666. static SyncOpInfo *
  667. sync_get_operation_extension(Slapi_PBlock *pb)
  668. {
  669. Slapi_Operation *op;
  670. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  671. return (SyncOpInfo *)slapi_get_object_extension(sync_extension_type,
  672. op, sync_extension_handle);
  673. }
  674. static void
  675. sync_set_operation_extension(Slapi_PBlock *pb, SyncOpInfo *spec)
  676. {
  677. Slapi_Operation *op;
  678. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  679. slapi_set_object_extension(sync_extension_type, op,
  680. sync_extension_handle, (void *)spec);
  681. }
  682. int
  683. sync_register_operation_extension(void)
  684. {
  685. return slapi_register_object_extension(SYNC_PLUGIN_SUBSYSTEM,
  686. SLAPI_EXT_OPERATION,
  687. sync_operation_extension_ctor,
  688. sync_operation_extension_dtor,
  689. &sync_extension_type,
  690. &sync_extension_handle);
  691. }
  692. int
  693. sync_unregister_operation_entension(void)
  694. {
  695. int rc = slapi_unregister_object_extension(SYNC_PLUGIN_SUBSYSTEM,
  696. SLAPI_EXT_OPERATION,
  697. &sync_extension_type,
  698. &sync_extension_handle);
  699. return rc;
  700. }