sync_refresh.c 21 KB

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