1 /* $NetBSD: syncprov.c,v 1.1.1.8 2019/08/08 13:31:39 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* syncprov.c - syncrepl provider */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2004-2019 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18 /* ACKNOWLEDGEMENTS: 19 * This work was initially developed by Howard Chu for inclusion in 20 * OpenLDAP Software. 21 */ 22 23 #include <sys/cdefs.h> 24 __RCSID("$NetBSD: syncprov.c,v 1.1.1.8 2019/08/08 13:31:39 christos Exp $"); 25 26 #include "portable.h" 27 28 #ifdef SLAPD_OVER_SYNCPROV 29 30 #include <ac/string.h> 31 #include "lutil.h" 32 #include "slap.h" 33 #include "config.h" 34 #include "ldap_rq.h" 35 36 #ifdef LDAP_DEVEL 37 #define CHECK_CSN 1 38 #endif 39 40 /* A modify request on a particular entry */ 41 typedef struct modinst { 42 struct modinst *mi_next; 43 Operation *mi_op; 44 } modinst; 45 46 typedef struct modtarget { 47 struct modinst *mt_mods; 48 struct modinst *mt_tail; 49 struct berval mt_dn; 50 ldap_pvt_thread_mutex_t mt_mutex; 51 } modtarget; 52 53 /* All the info of a psearch result that's shared between 54 * multiple queues 55 */ 56 typedef struct resinfo { 57 struct syncres *ri_list; 58 Entry *ri_e; 59 struct berval ri_dn; 60 struct berval ri_ndn; 61 struct berval ri_uuid; 62 struct berval ri_csn; 63 struct berval ri_cookie; 64 char ri_isref; 65 ldap_pvt_thread_mutex_t ri_mutex; 66 } resinfo; 67 68 /* A queued result of a persistent search */ 69 typedef struct syncres { 70 struct syncres *s_next; /* list of results on this psearch queue */ 71 struct syncres *s_rilist; /* list of psearches using this result */ 72 resinfo *s_info; 73 char s_mode; 74 } syncres; 75 76 /* Record of a persistent search */ 77 typedef struct syncops { 78 struct syncops *s_next; 79 struct syncprov_info_t *s_si; 80 struct berval s_base; /* ndn of search base */ 81 ID s_eid; /* entryID of search base */ 82 Operation *s_op; /* search op */ 83 int s_rid; 84 int s_sid; 85 struct berval s_filterstr; 86 int s_flags; /* search status */ 87 #define PS_IS_REFRESHING 0x01 88 #define PS_IS_DETACHED 0x02 89 #define PS_WROTE_BASE 0x04 90 #define PS_FIND_BASE 0x08 91 #define PS_FIX_FILTER 0x10 92 #define PS_TASK_QUEUED 0x20 93 94 int s_inuse; /* reference count */ 95 struct syncres *s_res; 96 struct syncres *s_restail; 97 ldap_pvt_thread_mutex_t s_mutex; 98 } syncops; 99 100 /* A received sync control */ 101 typedef struct sync_control { 102 struct sync_cookie sr_state; 103 int sr_rhint; 104 } sync_control; 105 106 #if 0 /* moved back to slap.h */ 107 #define o_sync o_ctrlflag[slap_cids.sc_LDAPsync] 108 #endif 109 /* o_sync_mode uses data bits of o_sync */ 110 #define o_sync_mode o_ctrlflag[slap_cids.sc_LDAPsync] 111 112 #define SLAP_SYNC_NONE (LDAP_SYNC_NONE<<SLAP_CONTROL_SHIFT) 113 #define SLAP_SYNC_REFRESH (LDAP_SYNC_REFRESH_ONLY<<SLAP_CONTROL_SHIFT) 114 #define SLAP_SYNC_PERSIST (LDAP_SYNC_RESERVED<<SLAP_CONTROL_SHIFT) 115 #define SLAP_SYNC_REFRESH_AND_PERSIST (LDAP_SYNC_REFRESH_AND_PERSIST<<SLAP_CONTROL_SHIFT) 116 117 /* Record of which searches matched at premodify step */ 118 typedef struct syncmatches { 119 struct syncmatches *sm_next; 120 syncops *sm_op; 121 } syncmatches; 122 123 /* Session log data */ 124 typedef struct slog_entry { 125 struct slog_entry *se_next; 126 struct berval se_uuid; 127 struct berval se_csn; 128 int se_sid; 129 ber_tag_t se_tag; 130 } slog_entry; 131 132 typedef struct sessionlog { 133 BerVarray sl_mincsn; 134 int *sl_sids; 135 int sl_numcsns; 136 int sl_num; 137 int sl_size; 138 int sl_playing; 139 slog_entry *sl_head; 140 slog_entry *sl_tail; 141 ldap_pvt_thread_mutex_t sl_mutex; 142 } sessionlog; 143 144 /* The main state for this overlay */ 145 typedef struct syncprov_info_t { 146 syncops *si_ops; 147 struct berval si_contextdn; 148 BerVarray si_ctxcsn; /* ldapsync context */ 149 int *si_sids; 150 int si_numcsns; 151 int si_chkops; /* checkpointing info */ 152 int si_chktime; 153 int si_numops; /* number of ops since last checkpoint */ 154 int si_nopres; /* Skip present phase */ 155 int si_usehint; /* use reload hint */ 156 int si_active; /* True if there are active mods */ 157 int si_dirty; /* True if the context is dirty, i.e changes 158 * have been made without updating the csn. */ 159 time_t si_chklast; /* time of last checkpoint */ 160 Avlnode *si_mods; /* entries being modified */ 161 sessionlog *si_logs; 162 ldap_pvt_thread_rdwr_t si_csn_rwlock; 163 ldap_pvt_thread_mutex_t si_ops_mutex; 164 ldap_pvt_thread_mutex_t si_mods_mutex; 165 ldap_pvt_thread_mutex_t si_resp_mutex; 166 } syncprov_info_t; 167 168 typedef struct opcookie { 169 slap_overinst *son; 170 syncmatches *smatches; 171 modtarget *smt; 172 Entry *se; 173 struct berval sdn; /* DN of entry, for deletes */ 174 struct berval sndn; 175 struct berval suuid; /* UUID of entry */ 176 struct berval sctxcsn; 177 short osid; /* sid of op csn */ 178 short rsid; /* sid of relay */ 179 short sreference; /* Is the entry a reference? */ 180 syncres ssres; 181 } opcookie; 182 183 typedef struct fbase_cookie { 184 struct berval *fdn; /* DN of a modified entry, for scope testing */ 185 syncops *fss; /* persistent search we're testing against */ 186 int fbase; /* if TRUE we found the search base and it's still valid */ 187 int fscope; /* if TRUE then fdn is within the psearch scope */ 188 } fbase_cookie; 189 190 static AttributeName csn_anlist[3]; 191 static AttributeName uuid_anlist[2]; 192 193 /* Build a LDAPsync intermediate state control */ 194 static int 195 syncprov_state_ctrl( 196 Operation *op, 197 SlapReply *rs, 198 Entry *e, 199 int entry_sync_state, 200 LDAPControl **ctrls, 201 int num_ctrls, 202 int send_cookie, 203 struct berval *cookie ) 204 { 205 Attribute* a; 206 int ret; 207 208 BerElementBuffer berbuf; 209 BerElement *ber = (BerElement *)&berbuf; 210 LDAPControl *cp; 211 struct berval bv; 212 struct berval entryuuid_bv = BER_BVNULL; 213 214 ber_init2( ber, 0, LBER_USE_DER ); 215 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); 216 217 for ( a = e->e_attrs; a != NULL; a = a->a_next ) { 218 AttributeDescription *desc = a->a_desc; 219 if ( desc == slap_schema.si_ad_entryUUID ) { 220 entryuuid_bv = a->a_nvals[0]; 221 break; 222 } 223 } 224 225 /* FIXME: what if entryuuid is NULL or empty ? */ 226 227 if ( send_cookie && cookie ) { 228 ber_printf( ber, "{eOON}", 229 entry_sync_state, &entryuuid_bv, cookie ); 230 } else { 231 ber_printf( ber, "{eON}", 232 entry_sync_state, &entryuuid_bv ); 233 } 234 235 ret = ber_flatten2( ber, &bv, 0 ); 236 if ( ret == 0 ) { 237 cp = op->o_tmpalloc( sizeof( LDAPControl ) + bv.bv_len, op->o_tmpmemctx ); 238 cp->ldctl_oid = LDAP_CONTROL_SYNC_STATE; 239 cp->ldctl_iscritical = (op->o_sync == SLAP_CONTROL_CRITICAL); 240 cp->ldctl_value.bv_val = (char *)&cp[1]; 241 cp->ldctl_value.bv_len = bv.bv_len; 242 AC_MEMCPY( cp->ldctl_value.bv_val, bv.bv_val, bv.bv_len ); 243 ctrls[num_ctrls] = cp; 244 } 245 ber_free_buf( ber ); 246 247 if ( ret < 0 ) { 248 Debug( LDAP_DEBUG_TRACE, 249 "slap_build_sync_ctrl: ber_flatten2 failed (%d)\n", 250 ret, 0, 0 ); 251 send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); 252 return LDAP_OTHER; 253 } 254 255 return LDAP_SUCCESS; 256 } 257 258 /* Build a LDAPsync final state control */ 259 static int 260 syncprov_done_ctrl( 261 Operation *op, 262 SlapReply *rs, 263 LDAPControl **ctrls, 264 int num_ctrls, 265 int send_cookie, 266 struct berval *cookie, 267 int refreshDeletes ) 268 { 269 int ret; 270 BerElementBuffer berbuf; 271 BerElement *ber = (BerElement *)&berbuf; 272 LDAPControl *cp; 273 struct berval bv; 274 275 ber_init2( ber, NULL, LBER_USE_DER ); 276 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); 277 278 ber_printf( ber, "{" ); 279 if ( send_cookie && cookie ) { 280 ber_printf( ber, "O", cookie ); 281 } 282 if ( refreshDeletes == LDAP_SYNC_REFRESH_DELETES ) { 283 ber_printf( ber, "b", refreshDeletes ); 284 } 285 ber_printf( ber, "N}" ); 286 287 ret = ber_flatten2( ber, &bv, 0 ); 288 if ( ret == 0 ) { 289 cp = op->o_tmpalloc( sizeof( LDAPControl ) + bv.bv_len, op->o_tmpmemctx ); 290 cp->ldctl_oid = LDAP_CONTROL_SYNC_DONE; 291 cp->ldctl_iscritical = (op->o_sync == SLAP_CONTROL_CRITICAL); 292 cp->ldctl_value.bv_val = (char *)&cp[1]; 293 cp->ldctl_value.bv_len = bv.bv_len; 294 AC_MEMCPY( cp->ldctl_value.bv_val, bv.bv_val, bv.bv_len ); 295 ctrls[num_ctrls] = cp; 296 } 297 298 ber_free_buf( ber ); 299 300 if ( ret < 0 ) { 301 Debug( LDAP_DEBUG_TRACE, 302 "syncprov_done_ctrl: ber_flatten2 failed (%d)\n", 303 ret, 0, 0 ); 304 send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); 305 return LDAP_OTHER; 306 } 307 308 return LDAP_SUCCESS; 309 } 310 311 static int 312 syncprov_sendinfo( 313 Operation *op, 314 SlapReply *rs, 315 int type, 316 struct berval *cookie, 317 int refreshDone, 318 BerVarray syncUUIDs, 319 int refreshDeletes ) 320 { 321 BerElementBuffer berbuf; 322 BerElement *ber = (BerElement *)&berbuf; 323 struct berval rspdata; 324 325 int ret; 326 327 ber_init2( ber, NULL, LBER_USE_DER ); 328 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); 329 330 if ( type ) { 331 switch ( type ) { 332 case LDAP_TAG_SYNC_NEW_COOKIE: 333 ber_printf( ber, "tO", type, cookie ); 334 break; 335 case LDAP_TAG_SYNC_REFRESH_DELETE: 336 case LDAP_TAG_SYNC_REFRESH_PRESENT: 337 ber_printf( ber, "t{", type ); 338 if ( cookie ) { 339 ber_printf( ber, "O", cookie ); 340 } 341 if ( refreshDone == 0 ) { 342 ber_printf( ber, "b", refreshDone ); 343 } 344 ber_printf( ber, "N}" ); 345 break; 346 case LDAP_TAG_SYNC_ID_SET: 347 ber_printf( ber, "t{", type ); 348 if ( cookie ) { 349 ber_printf( ber, "O", cookie ); 350 } 351 if ( refreshDeletes == 1 ) { 352 ber_printf( ber, "b", refreshDeletes ); 353 } 354 ber_printf( ber, "[W]", syncUUIDs ); 355 ber_printf( ber, "N}" ); 356 break; 357 default: 358 Debug( LDAP_DEBUG_TRACE, 359 "syncprov_sendinfo: invalid syncinfo type (%d)\n", 360 type, 0, 0 ); 361 return LDAP_OTHER; 362 } 363 } 364 365 ret = ber_flatten2( ber, &rspdata, 0 ); 366 367 if ( ret < 0 ) { 368 Debug( LDAP_DEBUG_TRACE, 369 "syncprov_sendinfo: ber_flatten2 failed (%d)\n", 370 ret, 0, 0 ); 371 send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); 372 return LDAP_OTHER; 373 } 374 375 rs->sr_rspoid = LDAP_SYNC_INFO; 376 rs->sr_rspdata = &rspdata; 377 send_ldap_intermediate( op, rs ); 378 rs->sr_rspdata = NULL; 379 ber_free_buf( ber ); 380 381 return LDAP_SUCCESS; 382 } 383 384 /* Find a modtarget in an AVL tree */ 385 static int 386 sp_avl_cmp( const void *c1, const void *c2 ) 387 { 388 const modtarget *m1, *m2; 389 int rc; 390 391 m1 = c1; m2 = c2; 392 rc = m1->mt_dn.bv_len - m2->mt_dn.bv_len; 393 394 if ( rc ) return rc; 395 return ber_bvcmp( &m1->mt_dn, &m2->mt_dn ); 396 } 397 398 /* syncprov_findbase: 399 * finds the true DN of the base of a search (with alias dereferencing) and 400 * checks to make sure the base entry doesn't get replaced with a different 401 * entry (e.g., swapping trees via ModDN, or retargeting an alias). If a 402 * change is detected, any persistent search on this base must be terminated / 403 * reloaded. 404 * On the first call, we just save the DN and entryID. On subsequent calls 405 * we compare the DN and entryID with the saved values. 406 */ 407 static int 408 findbase_cb( Operation *op, SlapReply *rs ) 409 { 410 slap_callback *sc = op->o_callback; 411 412 if ( rs->sr_type == REP_SEARCH && rs->sr_err == LDAP_SUCCESS ) { 413 fbase_cookie *fc = sc->sc_private; 414 415 /* If no entryID, we're looking for the first time. 416 * Just store whatever we got. 417 */ 418 if ( fc->fss->s_eid == NOID ) { 419 fc->fbase = 2; 420 fc->fss->s_eid = rs->sr_entry->e_id; 421 ber_dupbv( &fc->fss->s_base, &rs->sr_entry->e_nname ); 422 423 } else if ( rs->sr_entry->e_id == fc->fss->s_eid && 424 dn_match( &rs->sr_entry->e_nname, &fc->fss->s_base )) { 425 426 /* OK, the DN is the same and the entryID is the same. */ 427 fc->fbase = 1; 428 } 429 } 430 if ( rs->sr_err != LDAP_SUCCESS ) { 431 Debug( LDAP_DEBUG_ANY, "findbase failed! %d\n", rs->sr_err,0,0 ); 432 } 433 return LDAP_SUCCESS; 434 } 435 436 static Filter generic_filter = { LDAP_FILTER_PRESENT, { 0 }, NULL }; 437 static struct berval generic_filterstr = BER_BVC("(objectclass=*)"); 438 439 static int 440 syncprov_findbase( Operation *op, fbase_cookie *fc ) 441 { 442 /* Use basic parameters from syncrepl search, but use 443 * current op's threadctx / tmpmemctx 444 */ 445 ldap_pvt_thread_mutex_lock( &fc->fss->s_mutex ); 446 if ( fc->fss->s_flags & PS_FIND_BASE ) { 447 slap_callback cb = {0}; 448 Operation fop; 449 SlapReply frs = { REP_RESULT }; 450 int rc; 451 452 fc->fss->s_flags ^= PS_FIND_BASE; 453 ldap_pvt_thread_mutex_unlock( &fc->fss->s_mutex ); 454 455 fop = *fc->fss->s_op; 456 457 fop.o_bd = fop.o_bd->bd_self; 458 fop.o_hdr = op->o_hdr; 459 fop.o_time = op->o_time; 460 fop.o_tincr = op->o_tincr; 461 fop.o_extra = op->o_extra; 462 463 cb.sc_response = findbase_cb; 464 cb.sc_private = fc; 465 466 fop.o_sync_mode = 0; /* turn off sync mode */ 467 fop.o_managedsait = SLAP_CONTROL_CRITICAL; 468 fop.o_callback = &cb; 469 fop.o_tag = LDAP_REQ_SEARCH; 470 fop.ors_scope = LDAP_SCOPE_BASE; 471 fop.ors_limit = NULL; 472 fop.ors_slimit = 1; 473 fop.ors_tlimit = SLAP_NO_LIMIT; 474 fop.ors_attrs = slap_anlist_no_attrs; 475 fop.ors_attrsonly = 1; 476 fop.ors_filter = &generic_filter; 477 fop.ors_filterstr = generic_filterstr; 478 479 rc = fop.o_bd->be_search( &fop, &frs ); 480 } else { 481 ldap_pvt_thread_mutex_unlock( &fc->fss->s_mutex ); 482 fc->fbase = 1; 483 } 484 485 /* After the first call, see if the fdn resides in the scope */ 486 if ( fc->fbase == 1 ) { 487 switch ( fc->fss->s_op->ors_scope ) { 488 case LDAP_SCOPE_BASE: 489 fc->fscope = dn_match( fc->fdn, &fc->fss->s_base ); 490 break; 491 case LDAP_SCOPE_ONELEVEL: { 492 struct berval pdn; 493 dnParent( fc->fdn, &pdn ); 494 fc->fscope = dn_match( &pdn, &fc->fss->s_base ); 495 break; } 496 case LDAP_SCOPE_SUBTREE: 497 fc->fscope = dnIsSuffix( fc->fdn, &fc->fss->s_base ); 498 break; 499 case LDAP_SCOPE_SUBORDINATE: 500 fc->fscope = dnIsSuffix( fc->fdn, &fc->fss->s_base ) && 501 !dn_match( fc->fdn, &fc->fss->s_base ); 502 break; 503 } 504 } 505 506 if ( fc->fbase ) 507 return LDAP_SUCCESS; 508 509 /* If entryID has changed, then the base of this search has 510 * changed. Invalidate the psearch. 511 */ 512 return LDAP_NO_SUCH_OBJECT; 513 } 514 515 /* syncprov_findcsn: 516 * This function has three different purposes, but they all use a search 517 * that filters on entryCSN so they're combined here. 518 * 1: at startup time, after a contextCSN has been read from the database, 519 * we search for all entries with CSN >= contextCSN in case the contextCSN 520 * was not checkpointed at the previous shutdown. 521 * 522 * 2: when the current contextCSN is known and we have a sync cookie, we search 523 * for one entry with CSN = the cookie CSN. If not found, try <= cookie CSN. 524 * If an entry is found, the cookie CSN is valid, otherwise it is stale. 525 * 526 * 3: during a refresh phase, we search for all entries with CSN <= the cookie 527 * CSN, and generate Present records for them. We always collect this result 528 * in SyncID sets, even if there's only one match. 529 */ 530 typedef enum find_csn_t { 531 FIND_MAXCSN = 1, 532 FIND_CSN = 2, 533 FIND_PRESENT = 3 534 } find_csn_t; 535 536 static int 537 findmax_cb( Operation *op, SlapReply *rs ) 538 { 539 if ( rs->sr_type == REP_SEARCH && rs->sr_err == LDAP_SUCCESS ) { 540 struct berval *maxcsn = op->o_callback->sc_private; 541 Attribute *a = attr_find( rs->sr_entry->e_attrs, 542 slap_schema.si_ad_entryCSN ); 543 544 if ( a && ber_bvcmp( &a->a_vals[0], maxcsn ) > 0 && 545 slap_parse_csn_sid( &a->a_vals[0] ) == slap_serverID ) { 546 maxcsn->bv_len = a->a_vals[0].bv_len; 547 strcpy( maxcsn->bv_val, a->a_vals[0].bv_val ); 548 } 549 } 550 return LDAP_SUCCESS; 551 } 552 553 static int 554 findcsn_cb( Operation *op, SlapReply *rs ) 555 { 556 slap_callback *sc = op->o_callback; 557 558 /* We just want to know that at least one exists, so it's OK if 559 * we exceed the unchecked limit. 560 */ 561 if ( rs->sr_err == LDAP_ADMINLIMIT_EXCEEDED || 562 (rs->sr_type == REP_SEARCH && rs->sr_err == LDAP_SUCCESS )) { 563 sc->sc_private = (void *)1; 564 } 565 return LDAP_SUCCESS; 566 } 567 568 /* Build a list of entryUUIDs for sending in a SyncID set */ 569 570 #define UUID_LEN 16 571 572 typedef struct fpres_cookie { 573 int num; 574 BerVarray uuids; 575 char *last; 576 } fpres_cookie; 577 578 static int 579 findpres_cb( Operation *op, SlapReply *rs ) 580 { 581 slap_callback *sc = op->o_callback; 582 fpres_cookie *pc = sc->sc_private; 583 Attribute *a; 584 int ret = SLAP_CB_CONTINUE; 585 586 switch ( rs->sr_type ) { 587 case REP_SEARCH: 588 a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID ); 589 if ( a ) { 590 pc->uuids[pc->num].bv_val = pc->last; 591 AC_MEMCPY( pc->uuids[pc->num].bv_val, a->a_nvals[0].bv_val, 592 pc->uuids[pc->num].bv_len ); 593 pc->num++; 594 pc->last = pc->uuids[pc->num].bv_val; 595 pc->uuids[pc->num].bv_val = NULL; 596 } 597 ret = LDAP_SUCCESS; 598 if ( pc->num != SLAP_SYNCUUID_SET_SIZE ) 599 break; 600 /* FALLTHRU */ 601 case REP_RESULT: 602 ret = rs->sr_err; 603 if ( pc->num ) { 604 ret = syncprov_sendinfo( op, rs, LDAP_TAG_SYNC_ID_SET, NULL, 605 0, pc->uuids, 0 ); 606 pc->uuids[pc->num].bv_val = pc->last; 607 pc->num = 0; 608 pc->last = pc->uuids[0].bv_val; 609 } 610 break; 611 default: 612 break; 613 } 614 return ret; 615 } 616 617 static int 618 syncprov_findcsn( Operation *op, find_csn_t mode, struct berval *csn ) 619 { 620 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 621 syncprov_info_t *si = on->on_bi.bi_private; 622 623 slap_callback cb = {0}; 624 Operation fop; 625 SlapReply frs = { REP_RESULT }; 626 char buf[LDAP_PVT_CSNSTR_BUFSIZE + STRLENOF("(entryCSN<=)")]; 627 char cbuf[LDAP_PVT_CSNSTR_BUFSIZE]; 628 struct berval maxcsn; 629 Filter cf; 630 AttributeAssertion eq = ATTRIBUTEASSERTION_INIT; 631 fpres_cookie pcookie; 632 sync_control *srs = NULL; 633 struct slap_limits_set fc_limits; 634 int i, rc = LDAP_SUCCESS, findcsn_retry = 1; 635 int maxid; 636 637 if ( mode != FIND_MAXCSN ) { 638 srs = op->o_controls[slap_cids.sc_LDAPsync]; 639 } 640 641 fop = *op; 642 fop.o_sync_mode &= SLAP_CONTROL_MASK; /* turn off sync_mode */ 643 /* We want pure entries, not referrals */ 644 fop.o_managedsait = SLAP_CONTROL_CRITICAL; 645 646 cf.f_ava = &eq; 647 cf.f_av_desc = slap_schema.si_ad_entryCSN; 648 BER_BVZERO( &cf.f_av_value ); 649 cf.f_next = NULL; 650 651 fop.o_callback = &cb; 652 fop.ors_limit = NULL; 653 fop.ors_tlimit = SLAP_NO_LIMIT; 654 fop.ors_filter = &cf; 655 fop.ors_filterstr.bv_val = buf; 656 657 again: 658 switch( mode ) { 659 case FIND_MAXCSN: 660 cf.f_choice = LDAP_FILTER_GE; 661 /* If there are multiple CSNs, use the one with our serverID */ 662 for ( i=0; i<si->si_numcsns; i++) { 663 if ( slap_serverID == si->si_sids[i] ) { 664 maxid = i; 665 break; 666 } 667 } 668 if ( i == si->si_numcsns ) { 669 /* No match: this is multimaster, and none of the content in the DB 670 * originated locally. Treat like no CSN. 671 */ 672 return LDAP_NO_SUCH_OBJECT; 673 } 674 cf.f_av_value = si->si_ctxcsn[maxid]; 675 fop.ors_filterstr.bv_len = snprintf( buf, sizeof( buf ), 676 "(entryCSN>=%s)", cf.f_av_value.bv_val ); 677 if ( fop.ors_filterstr.bv_len >= sizeof( buf ) ) { 678 return LDAP_OTHER; 679 } 680 fop.ors_attrsonly = 0; 681 fop.ors_attrs = csn_anlist; 682 fop.ors_slimit = SLAP_NO_LIMIT; 683 cb.sc_private = &maxcsn; 684 cb.sc_response = findmax_cb; 685 strcpy( cbuf, cf.f_av_value.bv_val ); 686 maxcsn.bv_val = cbuf; 687 maxcsn.bv_len = cf.f_av_value.bv_len; 688 break; 689 case FIND_CSN: 690 if ( BER_BVISEMPTY( &cf.f_av_value )) { 691 cf.f_av_value = *csn; 692 } 693 fop.o_dn = op->o_bd->be_rootdn; 694 fop.o_ndn = op->o_bd->be_rootndn; 695 fop.o_req_dn = op->o_bd->be_suffix[0]; 696 fop.o_req_ndn = op->o_bd->be_nsuffix[0]; 697 /* Look for exact match the first time */ 698 if ( findcsn_retry ) { 699 cf.f_choice = LDAP_FILTER_EQUALITY; 700 fop.ors_filterstr.bv_len = snprintf( buf, sizeof( buf ), 701 "(entryCSN=%s)", cf.f_av_value.bv_val ); 702 /* On retry, look for <= */ 703 } else { 704 cf.f_choice = LDAP_FILTER_LE; 705 fop.ors_limit = &fc_limits; 706 memset( &fc_limits, 0, sizeof( fc_limits )); 707 fc_limits.lms_s_unchecked = 1; 708 fop.ors_filterstr.bv_len = snprintf( buf, sizeof( buf ), 709 "(entryCSN<=%s)", cf.f_av_value.bv_val ); 710 } 711 if ( fop.ors_filterstr.bv_len >= sizeof( buf ) ) { 712 return LDAP_OTHER; 713 } 714 fop.ors_attrsonly = 1; 715 fop.ors_attrs = slap_anlist_no_attrs; 716 fop.ors_slimit = 1; 717 cb.sc_private = NULL; 718 cb.sc_response = findcsn_cb; 719 break; 720 case FIND_PRESENT: 721 fop.ors_filter = op->ors_filter; 722 fop.ors_filterstr = op->ors_filterstr; 723 fop.ors_attrsonly = 0; 724 fop.ors_attrs = uuid_anlist; 725 fop.ors_slimit = SLAP_NO_LIMIT; 726 cb.sc_private = &pcookie; 727 cb.sc_response = findpres_cb; 728 pcookie.num = 0; 729 730 /* preallocate storage for a full set */ 731 pcookie.uuids = op->o_tmpalloc( (SLAP_SYNCUUID_SET_SIZE+1) * 732 sizeof(struct berval) + SLAP_SYNCUUID_SET_SIZE * UUID_LEN, 733 op->o_tmpmemctx ); 734 pcookie.last = (char *)(pcookie.uuids + SLAP_SYNCUUID_SET_SIZE+1); 735 pcookie.uuids[0].bv_val = pcookie.last; 736 pcookie.uuids[0].bv_len = UUID_LEN; 737 for (i=1; i<SLAP_SYNCUUID_SET_SIZE; i++) { 738 pcookie.uuids[i].bv_val = pcookie.uuids[i-1].bv_val + UUID_LEN; 739 pcookie.uuids[i].bv_len = UUID_LEN; 740 } 741 break; 742 } 743 744 fop.o_bd->bd_info = (BackendInfo *)on->on_info; 745 fop.o_bd->be_search( &fop, &frs ); 746 fop.o_bd->bd_info = (BackendInfo *)on; 747 748 switch( mode ) { 749 case FIND_MAXCSN: 750 if ( ber_bvcmp( &si->si_ctxcsn[maxid], &maxcsn )) { 751 #ifdef CHECK_CSN 752 Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax; 753 assert( !syn->ssyn_validate( syn, &maxcsn )); 754 #endif 755 ber_bvreplace( &si->si_ctxcsn[maxid], &maxcsn ); 756 si->si_numops++; /* ensure a checkpoint */ 757 } 758 break; 759 case FIND_CSN: 760 /* If matching CSN was not found, invalidate the context. */ 761 if ( !cb.sc_private ) { 762 /* If we didn't find an exact match, then try for <= */ 763 if ( findcsn_retry ) { 764 findcsn_retry = 0; 765 rs_reinit( &frs, REP_RESULT ); 766 goto again; 767 } 768 rc = LDAP_NO_SUCH_OBJECT; 769 } 770 break; 771 case FIND_PRESENT: 772 op->o_tmpfree( pcookie.uuids, op->o_tmpmemctx ); 773 break; 774 } 775 776 return rc; 777 } 778 779 static void free_resinfo( syncres *sr ) 780 { 781 syncres **st; 782 int freeit = 0; 783 ldap_pvt_thread_mutex_lock( &sr->s_info->ri_mutex ); 784 for (st = &sr->s_info->ri_list; *st; st = &(*st)->s_rilist) { 785 if (*st == sr) { 786 *st = sr->s_rilist; 787 break; 788 } 789 } 790 if ( !sr->s_info->ri_list ) 791 freeit = 1; 792 ldap_pvt_thread_mutex_unlock( &sr->s_info->ri_mutex ); 793 if ( freeit ) { 794 ldap_pvt_thread_mutex_destroy( &sr->s_info->ri_mutex ); 795 if ( sr->s_info->ri_e ) 796 entry_free( sr->s_info->ri_e ); 797 if ( !BER_BVISNULL( &sr->s_info->ri_cookie )) 798 ch_free( sr->s_info->ri_cookie.bv_val ); 799 ch_free( sr->s_info ); 800 } 801 } 802 803 static int 804 syncprov_free_syncop( syncops *so, int unlink ) 805 { 806 syncres *sr, *srnext; 807 GroupAssertion *ga, *gnext; 808 809 ldap_pvt_thread_mutex_lock( &so->s_mutex ); 810 /* already being freed, or still in use */ 811 if ( !so->s_inuse || --so->s_inuse > 0 ) { 812 ldap_pvt_thread_mutex_unlock( &so->s_mutex ); 813 return 0; 814 } 815 ldap_pvt_thread_mutex_unlock( &so->s_mutex ); 816 if ( unlink ) { 817 syncops **sop; 818 ldap_pvt_thread_mutex_lock( &so->s_si->si_ops_mutex ); 819 for ( sop = &so->s_si->si_ops; *sop; sop = &(*sop)->s_next ) { 820 if ( *sop == so ) { 821 *sop = so->s_next; 822 break; 823 } 824 } 825 ldap_pvt_thread_mutex_unlock( &so->s_si->si_ops_mutex ); 826 } 827 if ( so->s_flags & PS_IS_DETACHED ) { 828 filter_free( so->s_op->ors_filter ); 829 for ( ga = so->s_op->o_groups; ga; ga=gnext ) { 830 gnext = ga->ga_next; 831 ch_free( ga ); 832 } 833 ch_free( so->s_op ); 834 } 835 ch_free( so->s_base.bv_val ); 836 for ( sr=so->s_res; sr; sr=srnext ) { 837 srnext = sr->s_next; 838 free_resinfo( sr ); 839 ch_free( sr ); 840 } 841 ldap_pvt_thread_mutex_destroy( &so->s_mutex ); 842 ch_free( so ); 843 return 1; 844 } 845 846 /* Send a persistent search response */ 847 static int 848 syncprov_sendresp( Operation *op, resinfo *ri, syncops *so, int mode ) 849 { 850 SlapReply rs = { REP_SEARCH }; 851 struct berval cookie, csns[2]; 852 Entry e_uuid = {0}; 853 Attribute a_uuid = {0}; 854 855 if ( so->s_op->o_abandon ) 856 return SLAPD_ABANDON; 857 858 rs.sr_ctrls = op->o_tmpalloc( sizeof(LDAPControl *)*2, op->o_tmpmemctx ); 859 rs.sr_ctrls[1] = NULL; 860 rs.sr_flags = REP_CTRLS_MUSTBEFREED; 861 csns[0] = ri->ri_csn; 862 BER_BVZERO( &csns[1] ); 863 slap_compose_sync_cookie( op, &cookie, csns, so->s_rid, slap_serverID ? slap_serverID : -1 ); 864 865 #ifdef LDAP_DEBUG 866 if ( so->s_sid > 0 ) { 867 Debug( LDAP_DEBUG_SYNC, "syncprov_sendresp: to=%03x, cookie=%s\n", 868 so->s_sid, cookie.bv_val, 0 ); 869 } else { 870 Debug( LDAP_DEBUG_SYNC, "syncprov_sendresp: cookie=%s\n", 871 cookie.bv_val, 0, 0 ); 872 } 873 #endif 874 875 e_uuid.e_attrs = &a_uuid; 876 a_uuid.a_desc = slap_schema.si_ad_entryUUID; 877 a_uuid.a_nvals = &ri->ri_uuid; 878 rs.sr_err = syncprov_state_ctrl( op, &rs, &e_uuid, 879 mode, rs.sr_ctrls, 0, 1, &cookie ); 880 op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx ); 881 882 rs.sr_entry = &e_uuid; 883 if ( mode == LDAP_SYNC_ADD || mode == LDAP_SYNC_MODIFY ) { 884 e_uuid = *ri->ri_e; 885 e_uuid.e_private = NULL; 886 } 887 888 switch( mode ) { 889 case LDAP_SYNC_ADD: 890 if ( ri->ri_isref && so->s_op->o_managedsait <= SLAP_CONTROL_IGNORED ) { 891 rs.sr_ref = get_entry_referrals( op, rs.sr_entry ); 892 rs.sr_err = send_search_reference( op, &rs ); 893 ber_bvarray_free( rs.sr_ref ); 894 break; 895 } 896 /* fallthru */ 897 case LDAP_SYNC_MODIFY: 898 rs.sr_attrs = op->ors_attrs; 899 rs.sr_err = send_search_entry( op, &rs ); 900 break; 901 case LDAP_SYNC_DELETE: 902 e_uuid.e_attrs = NULL; 903 e_uuid.e_name = ri->ri_dn; 904 e_uuid.e_nname = ri->ri_ndn; 905 if ( ri->ri_isref && so->s_op->o_managedsait <= SLAP_CONTROL_IGNORED ) { 906 struct berval bv = BER_BVNULL; 907 rs.sr_ref = &bv; 908 rs.sr_err = send_search_reference( op, &rs ); 909 } else { 910 rs.sr_err = send_search_entry( op, &rs ); 911 } 912 break; 913 default: 914 assert(0); 915 } 916 return rs.sr_err; 917 } 918 919 static void 920 syncprov_qstart( syncops *so ); 921 922 /* Play back queued responses */ 923 static int 924 syncprov_qplay( Operation *op, syncops *so ) 925 { 926 syncres *sr; 927 int rc = 0; 928 929 do { 930 ldap_pvt_thread_mutex_lock( &so->s_mutex ); 931 sr = so->s_res; 932 /* Exit loop with mutex held */ 933 if ( !sr ) 934 break; 935 so->s_res = sr->s_next; 936 if ( !so->s_res ) 937 so->s_restail = NULL; 938 ldap_pvt_thread_mutex_unlock( &so->s_mutex ); 939 940 if ( !so->s_op->o_abandon ) { 941 942 if ( sr->s_mode == LDAP_SYNC_NEW_COOKIE ) { 943 SlapReply rs = { REP_INTERMEDIATE }; 944 945 rc = syncprov_sendinfo( op, &rs, LDAP_TAG_SYNC_NEW_COOKIE, 946 &sr->s_info->ri_cookie, 0, NULL, 0 ); 947 } else { 948 rc = syncprov_sendresp( op, sr->s_info, so, sr->s_mode ); 949 } 950 } 951 952 free_resinfo( sr ); 953 ch_free( sr ); 954 955 if ( so->s_op->o_abandon ) 956 continue; 957 958 /* Exit loop with mutex held */ 959 ldap_pvt_thread_mutex_lock( &so->s_mutex ); 960 break; 961 962 } while (1); 963 964 /* We now only send one change at a time, to prevent one 965 * psearch from hogging all the CPU. Resubmit this task if 966 * there are more responses queued and no errors occurred. 967 */ 968 969 if ( rc == 0 && so->s_res ) { 970 syncprov_qstart( so ); 971 } else { 972 so->s_flags ^= PS_TASK_QUEUED; 973 } 974 975 ldap_pvt_thread_mutex_unlock( &so->s_mutex ); 976 return rc; 977 } 978 979 /* task for playing back queued responses */ 980 static void * 981 syncprov_qtask( void *ctx, void *arg ) 982 { 983 syncops *so = arg; 984 OperationBuffer opbuf; 985 Operation *op; 986 BackendDB be; 987 int rc; 988 989 op = &opbuf.ob_op; 990 *op = *so->s_op; 991 op->o_hdr = &opbuf.ob_hdr; 992 op->o_controls = opbuf.ob_controls; 993 memset( op->o_controls, 0, sizeof(opbuf.ob_controls) ); 994 op->o_sync = SLAP_CONTROL_IGNORED; 995 996 *op->o_hdr = *so->s_op->o_hdr; 997 998 op->o_tmpmemctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 1); 999 op->o_tmpmfuncs = &slap_sl_mfuncs; 1000 op->o_threadctx = ctx; 1001 1002 /* syncprov_qplay expects a fake db */ 1003 be = *so->s_op->o_bd; 1004 be.be_flags |= SLAP_DBFLAG_OVERLAY; 1005 op->o_bd = &be; 1006 LDAP_SLIST_FIRST(&op->o_extra) = NULL; 1007 op->o_callback = NULL; 1008 1009 rc = syncprov_qplay( op, so ); 1010 1011 /* decrement use count... */ 1012 syncprov_free_syncop( so, 1 ); 1013 1014 return NULL; 1015 } 1016 1017 /* Start the task to play back queued psearch responses */ 1018 static void 1019 syncprov_qstart( syncops *so ) 1020 { 1021 so->s_flags |= PS_TASK_QUEUED; 1022 so->s_inuse++; 1023 ldap_pvt_thread_pool_submit( &connection_pool, 1024 syncprov_qtask, so ); 1025 } 1026 1027 /* Queue a persistent search response */ 1028 static int 1029 syncprov_qresp( opcookie *opc, syncops *so, int mode ) 1030 { 1031 syncres *sr; 1032 resinfo *ri; 1033 int srsize; 1034 struct berval csn = opc->sctxcsn; 1035 1036 sr = ch_malloc( sizeof( syncres )); 1037 sr->s_next = NULL; 1038 sr->s_mode = mode; 1039 if ( !opc->ssres.s_info ) { 1040 1041 srsize = sizeof( resinfo ); 1042 if ( csn.bv_len ) 1043 srsize += csn.bv_len + 1; 1044 1045 if ( opc->se ) { 1046 Attribute *a; 1047 ri = ch_malloc( srsize ); 1048 ri->ri_dn = opc->se->e_name; 1049 ri->ri_ndn = opc->se->e_nname; 1050 a = attr_find( opc->se->e_attrs, slap_schema.si_ad_entryUUID ); 1051 if ( a ) 1052 ri->ri_uuid = a->a_nvals[0]; 1053 else 1054 ri->ri_uuid.bv_len = 0; 1055 if ( csn.bv_len ) { 1056 ri->ri_csn.bv_val = (char *)(ri + 1); 1057 ri->ri_csn.bv_len = csn.bv_len; 1058 memcpy( ri->ri_csn.bv_val, csn.bv_val, csn.bv_len ); 1059 ri->ri_csn.bv_val[csn.bv_len] = '\0'; 1060 } else { 1061 ri->ri_csn.bv_val = NULL; 1062 } 1063 } else { 1064 srsize += opc->suuid.bv_len + 1065 opc->sdn.bv_len + 1 + opc->sndn.bv_len + 1; 1066 ri = ch_malloc( srsize ); 1067 ri->ri_dn.bv_val = (char *)(ri + 1); 1068 ri->ri_dn.bv_len = opc->sdn.bv_len; 1069 ri->ri_ndn.bv_val = lutil_strcopy( ri->ri_dn.bv_val, 1070 opc->sdn.bv_val ) + 1; 1071 ri->ri_ndn.bv_len = opc->sndn.bv_len; 1072 ri->ri_uuid.bv_val = lutil_strcopy( ri->ri_ndn.bv_val, 1073 opc->sndn.bv_val ) + 1; 1074 ri->ri_uuid.bv_len = opc->suuid.bv_len; 1075 AC_MEMCPY( ri->ri_uuid.bv_val, opc->suuid.bv_val, opc->suuid.bv_len ); 1076 if ( csn.bv_len ) { 1077 ri->ri_csn.bv_val = ri->ri_uuid.bv_val + ri->ri_uuid.bv_len; 1078 memcpy( ri->ri_csn.bv_val, csn.bv_val, csn.bv_len ); 1079 ri->ri_csn.bv_val[csn.bv_len] = '\0'; 1080 } else { 1081 ri->ri_csn.bv_val = NULL; 1082 } 1083 } 1084 ri->ri_list = &opc->ssres; 1085 ri->ri_e = opc->se; 1086 ri->ri_csn.bv_len = csn.bv_len; 1087 ri->ri_isref = opc->sreference; 1088 BER_BVZERO( &ri->ri_cookie ); 1089 ldap_pvt_thread_mutex_init( &ri->ri_mutex ); 1090 opc->se = NULL; 1091 opc->ssres.s_info = ri; 1092 } 1093 ri = opc->ssres.s_info; 1094 sr->s_info = ri; 1095 ldap_pvt_thread_mutex_lock( &ri->ri_mutex ); 1096 sr->s_rilist = ri->ri_list; 1097 ri->ri_list = sr; 1098 if ( mode == LDAP_SYNC_NEW_COOKIE && BER_BVISNULL( &ri->ri_cookie )) { 1099 syncprov_info_t *si = opc->son->on_bi.bi_private; 1100 1101 slap_compose_sync_cookie( NULL, &ri->ri_cookie, si->si_ctxcsn, 1102 so->s_rid, slap_serverID ? slap_serverID : -1); 1103 } 1104 ldap_pvt_thread_mutex_unlock( &ri->ri_mutex ); 1105 1106 ldap_pvt_thread_mutex_lock( &so->s_mutex ); 1107 if ( !so->s_res ) { 1108 so->s_res = sr; 1109 } else { 1110 so->s_restail->s_next = sr; 1111 } 1112 so->s_restail = sr; 1113 1114 /* If the base of the psearch was modified, check it next time round */ 1115 if ( so->s_flags & PS_WROTE_BASE ) { 1116 so->s_flags ^= PS_WROTE_BASE; 1117 so->s_flags |= PS_FIND_BASE; 1118 } 1119 if (( so->s_flags & (PS_IS_DETACHED|PS_TASK_QUEUED)) == PS_IS_DETACHED ) { 1120 syncprov_qstart( so ); 1121 } 1122 ldap_pvt_thread_mutex_unlock( &so->s_mutex ); 1123 return LDAP_SUCCESS; 1124 } 1125 1126 static int 1127 syncprov_drop_psearch( syncops *so, int lock ) 1128 { 1129 if ( so->s_flags & PS_IS_DETACHED ) { 1130 if ( lock ) 1131 ldap_pvt_thread_mutex_lock( &so->s_op->o_conn->c_mutex ); 1132 so->s_op->o_conn->c_n_ops_executing--; 1133 so->s_op->o_conn->c_n_ops_completed++; 1134 LDAP_STAILQ_REMOVE( &so->s_op->o_conn->c_ops, so->s_op, Operation, 1135 o_next ); 1136 if ( lock ) 1137 ldap_pvt_thread_mutex_unlock( &so->s_op->o_conn->c_mutex ); 1138 } 1139 return syncprov_free_syncop( so, 0 ); 1140 } 1141 1142 static int 1143 syncprov_ab_cleanup( Operation *op, SlapReply *rs ) 1144 { 1145 slap_callback *sc = op->o_callback; 1146 op->o_callback = sc->sc_next; 1147 syncprov_drop_psearch( sc->sc_private, 0 ); 1148 op->o_tmpfree( sc, op->o_tmpmemctx ); 1149 return 0; 1150 } 1151 1152 static int 1153 syncprov_op_abandon( Operation *op, SlapReply *rs ) 1154 { 1155 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1156 syncprov_info_t *si = on->on_bi.bi_private; 1157 syncops *so, **sop; 1158 1159 ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); 1160 for ( sop=&si->si_ops; (so = *sop); sop = &(*sop)->s_next ) { 1161 if ( so->s_op->o_connid == op->o_connid && 1162 so->s_op->o_msgid == op->orn_msgid ) { 1163 so->s_op->o_abandon = 1; 1164 *sop = so->s_next; 1165 break; 1166 } 1167 } 1168 ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); 1169 if ( so ) { 1170 /* Is this really a Cancel exop? */ 1171 if ( op->o_tag != LDAP_REQ_ABANDON ) { 1172 so->s_op->o_cancel = SLAP_CANCEL_ACK; 1173 rs->sr_err = LDAP_CANCELLED; 1174 send_ldap_result( so->s_op, rs ); 1175 if ( so->s_flags & PS_IS_DETACHED ) { 1176 slap_callback *cb; 1177 cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx ); 1178 cb->sc_cleanup = syncprov_ab_cleanup; 1179 cb->sc_next = op->o_callback; 1180 cb->sc_private = so; 1181 op->o_callback = cb; 1182 return SLAP_CB_CONTINUE; 1183 } 1184 } 1185 syncprov_drop_psearch( so, 0 ); 1186 } 1187 return SLAP_CB_CONTINUE; 1188 } 1189 1190 /* Find which persistent searches are affected by this operation */ 1191 static void 1192 syncprov_matchops( Operation *op, opcookie *opc, int saveit ) 1193 { 1194 slap_overinst *on = opc->son; 1195 syncprov_info_t *si = on->on_bi.bi_private; 1196 1197 fbase_cookie fc; 1198 syncops **pss; 1199 Entry *e = NULL; 1200 Attribute *a; 1201 int rc, gonext; 1202 struct berval newdn; 1203 int freefdn = 0; 1204 BackendDB *b0 = op->o_bd, db; 1205 1206 fc.fdn = &op->o_req_ndn; 1207 /* compute new DN */ 1208 if ( op->o_tag == LDAP_REQ_MODRDN && !saveit ) { 1209 struct berval pdn; 1210 if ( op->orr_nnewSup ) pdn = *op->orr_nnewSup; 1211 else dnParent( fc.fdn, &pdn ); 1212 build_new_dn( &newdn, &pdn, &op->orr_nnewrdn, op->o_tmpmemctx ); 1213 fc.fdn = &newdn; 1214 freefdn = 1; 1215 } 1216 if ( op->o_tag != LDAP_REQ_ADD ) { 1217 if ( !SLAP_ISOVERLAY( op->o_bd )) { 1218 db = *op->o_bd; 1219 op->o_bd = &db; 1220 } 1221 rc = overlay_entry_get_ov( op, fc.fdn, NULL, NULL, 0, &e, on ); 1222 /* If we're sending responses now, make a copy and unlock the DB */ 1223 if ( e && !saveit ) { 1224 if ( !opc->se ) 1225 opc->se = entry_dup( e ); 1226 overlay_entry_release_ov( op, e, 0, on ); 1227 e = opc->se; 1228 } 1229 if ( rc ) { 1230 op->o_bd = b0; 1231 return; 1232 } 1233 } else { 1234 e = op->ora_e; 1235 if ( !saveit ) { 1236 if ( !opc->se ) 1237 opc->se = entry_dup( e ); 1238 e = opc->se; 1239 } 1240 } 1241 1242 if ( saveit || op->o_tag == LDAP_REQ_ADD ) { 1243 ber_dupbv_x( &opc->sdn, &e->e_name, op->o_tmpmemctx ); 1244 ber_dupbv_x( &opc->sndn, &e->e_nname, op->o_tmpmemctx ); 1245 opc->sreference = is_entry_referral( e ); 1246 a = attr_find( e->e_attrs, slap_schema.si_ad_entryUUID ); 1247 if ( a ) 1248 ber_dupbv_x( &opc->suuid, &a->a_nvals[0], op->o_tmpmemctx ); 1249 } else if ( op->o_tag == LDAP_REQ_MODRDN && !saveit ) { 1250 op->o_tmpfree( opc->sndn.bv_val, op->o_tmpmemctx ); 1251 op->o_tmpfree( opc->sdn.bv_val, op->o_tmpmemctx ); 1252 ber_dupbv_x( &opc->sdn, &e->e_name, op->o_tmpmemctx ); 1253 ber_dupbv_x( &opc->sndn, &e->e_nname, op->o_tmpmemctx ); 1254 } 1255 1256 ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); 1257 for (pss = &si->si_ops; *pss; pss = gonext ? &(*pss)->s_next : pss) 1258 { 1259 Operation op2; 1260 Opheader oh; 1261 syncmatches *sm; 1262 int found = 0; 1263 syncops *snext, *ss = *pss; 1264 1265 gonext = 1; 1266 if ( ss->s_op->o_abandon ) 1267 continue; 1268 1269 /* Don't send ops back to the originator */ 1270 if ( opc->osid > 0 && opc->osid == ss->s_sid ) { 1271 Debug( LDAP_DEBUG_SYNC, "syncprov_matchops: skipping original sid %03x\n", 1272 opc->osid, 0, 0 ); 1273 continue; 1274 } 1275 1276 /* Don't send ops back to the messenger */ 1277 if ( opc->rsid > 0 && opc->rsid == ss->s_sid ) { 1278 Debug( LDAP_DEBUG_SYNC, "syncprov_matchops: skipping relayed sid %03x\n", 1279 opc->rsid, 0, 0 ); 1280 continue; 1281 } 1282 1283 /* validate base */ 1284 fc.fss = ss; 1285 fc.fbase = 0; 1286 fc.fscope = 0; 1287 1288 /* If the base of the search is missing, signal a refresh */ 1289 rc = syncprov_findbase( op, &fc ); 1290 if ( rc != LDAP_SUCCESS ) { 1291 SlapReply rs = {REP_RESULT}; 1292 send_ldap_error( ss->s_op, &rs, LDAP_SYNC_REFRESH_REQUIRED, 1293 "search base has changed" ); 1294 snext = ss->s_next; 1295 if ( syncprov_drop_psearch( ss, 1 ) ) 1296 *pss = snext; 1297 gonext = 0; 1298 continue; 1299 } 1300 1301 /* If we're sending results now, look for this op in old matches */ 1302 if ( !saveit ) { 1303 syncmatches *old; 1304 1305 /* Did we modify the search base? */ 1306 if ( dn_match( &op->o_req_ndn, &ss->s_base )) { 1307 ldap_pvt_thread_mutex_lock( &ss->s_mutex ); 1308 ss->s_flags |= PS_WROTE_BASE; 1309 ldap_pvt_thread_mutex_unlock( &ss->s_mutex ); 1310 } 1311 1312 for ( sm=opc->smatches, old=(syncmatches *)&opc->smatches; sm; 1313 old=sm, sm=sm->sm_next ) { 1314 if ( sm->sm_op == ss ) { 1315 found = 1; 1316 old->sm_next = sm->sm_next; 1317 op->o_tmpfree( sm, op->o_tmpmemctx ); 1318 break; 1319 } 1320 } 1321 } 1322 1323 if ( fc.fscope ) { 1324 ldap_pvt_thread_mutex_lock( &ss->s_mutex ); 1325 op2 = *ss->s_op; 1326 oh = *op->o_hdr; 1327 oh.oh_conn = ss->s_op->o_conn; 1328 oh.oh_connid = ss->s_op->o_connid; 1329 op2.o_bd = op->o_bd->bd_self; 1330 op2.o_hdr = &oh; 1331 op2.o_extra = op->o_extra; 1332 op2.o_callback = NULL; 1333 if (ss->s_flags & PS_FIX_FILTER) { 1334 /* Skip the AND/GE clause that we stuck on in front. We 1335 would lose deletes/mods that happen during the refresh 1336 phase otherwise (ITS#6555) */ 1337 op2.ors_filter = ss->s_op->ors_filter->f_and->f_next; 1338 } 1339 rc = test_filter( &op2, e, op2.ors_filter ); 1340 ldap_pvt_thread_mutex_unlock( &ss->s_mutex ); 1341 } 1342 1343 Debug( LDAP_DEBUG_TRACE, "syncprov_matchops: sid %03x fscope %d rc %d\n", 1344 ss->s_sid, fc.fscope, rc ); 1345 1346 /* check if current o_req_dn is in scope and matches filter */ 1347 if ( fc.fscope && rc == LDAP_COMPARE_TRUE ) { 1348 if ( saveit ) { 1349 sm = op->o_tmpalloc( sizeof(syncmatches), op->o_tmpmemctx ); 1350 sm->sm_next = opc->smatches; 1351 sm->sm_op = ss; 1352 ldap_pvt_thread_mutex_lock( &ss->s_mutex ); 1353 ++ss->s_inuse; 1354 ldap_pvt_thread_mutex_unlock( &ss->s_mutex ); 1355 opc->smatches = sm; 1356 } else { 1357 /* if found send UPDATE else send ADD */ 1358 syncprov_qresp( opc, ss, 1359 found ? LDAP_SYNC_MODIFY : LDAP_SYNC_ADD ); 1360 } 1361 } else if ( !saveit && found ) { 1362 /* send DELETE */ 1363 syncprov_qresp( opc, ss, LDAP_SYNC_DELETE ); 1364 } else if ( !saveit ) { 1365 syncprov_qresp( opc, ss, LDAP_SYNC_NEW_COOKIE ); 1366 } 1367 if ( !saveit && found ) { 1368 /* Decrement s_inuse, was incremented when called 1369 * with saveit == TRUE 1370 */ 1371 snext = ss->s_next; 1372 if ( syncprov_free_syncop( ss, 0 ) ) { 1373 *pss = snext; 1374 gonext = 0; 1375 } 1376 } 1377 } 1378 ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); 1379 1380 if ( op->o_tag != LDAP_REQ_ADD && e ) { 1381 if ( !SLAP_ISOVERLAY( op->o_bd )) { 1382 op->o_bd = &db; 1383 } 1384 if ( saveit ) 1385 overlay_entry_release_ov( op, e, 0, on ); 1386 op->o_bd = b0; 1387 } 1388 if ( !saveit ) { 1389 if ( opc->ssres.s_info ) 1390 free_resinfo( &opc->ssres ); 1391 else if ( opc->se ) 1392 entry_free( opc->se ); 1393 } 1394 if ( freefdn ) { 1395 op->o_tmpfree( fc.fdn->bv_val, op->o_tmpmemctx ); 1396 } 1397 op->o_bd = b0; 1398 } 1399 1400 static int 1401 syncprov_op_cleanup( Operation *op, SlapReply *rs ) 1402 { 1403 slap_callback *cb = op->o_callback; 1404 opcookie *opc = cb->sc_private; 1405 slap_overinst *on = opc->son; 1406 syncprov_info_t *si = on->on_bi.bi_private; 1407 syncmatches *sm, *snext; 1408 modtarget *mt; 1409 1410 ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); 1411 if ( si->si_active ) 1412 si->si_active--; 1413 ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); 1414 1415 for (sm = opc->smatches; sm; sm=snext) { 1416 snext = sm->sm_next; 1417 syncprov_free_syncop( sm->sm_op, 1 ); 1418 op->o_tmpfree( sm, op->o_tmpmemctx ); 1419 } 1420 1421 /* Remove op from lock table */ 1422 mt = opc->smt; 1423 if ( mt ) { 1424 modinst *mi = (modinst *)(opc+1), **m2; 1425 ldap_pvt_thread_mutex_lock( &mt->mt_mutex ); 1426 for (m2 = &mt->mt_mods; ; m2 = &(*m2)->mi_next) { 1427 if ( *m2 == mi ) { 1428 *m2 = mi->mi_next; 1429 if ( mt->mt_tail == mi ) 1430 mt->mt_tail = ( m2 == &mt->mt_mods ) ? NULL : (modinst *)m2; 1431 break; 1432 } 1433 } 1434 /* If there are more, promote the next one */ 1435 if ( mt->mt_mods ) { 1436 ldap_pvt_thread_mutex_unlock( &mt->mt_mutex ); 1437 } else { 1438 ldap_pvt_thread_mutex_unlock( &mt->mt_mutex ); 1439 ldap_pvt_thread_mutex_lock( &si->si_mods_mutex ); 1440 avl_delete( &si->si_mods, mt, sp_avl_cmp ); 1441 ldap_pvt_thread_mutex_unlock( &si->si_mods_mutex ); 1442 ldap_pvt_thread_mutex_destroy( &mt->mt_mutex ); 1443 ch_free( mt->mt_dn.bv_val ); 1444 ch_free( mt ); 1445 } 1446 } 1447 if ( !BER_BVISNULL( &opc->suuid )) 1448 op->o_tmpfree( opc->suuid.bv_val, op->o_tmpmemctx ); 1449 if ( !BER_BVISNULL( &opc->sndn )) 1450 op->o_tmpfree( opc->sndn.bv_val, op->o_tmpmemctx ); 1451 if ( !BER_BVISNULL( &opc->sdn )) 1452 op->o_tmpfree( opc->sdn.bv_val, op->o_tmpmemctx ); 1453 op->o_callback = cb->sc_next; 1454 op->o_tmpfree(cb, op->o_tmpmemctx); 1455 1456 return 0; 1457 } 1458 1459 static void 1460 syncprov_checkpoint( Operation *op, slap_overinst *on ) 1461 { 1462 syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private; 1463 Modifications mod; 1464 Operation opm; 1465 SlapReply rsm = {REP_RESULT}; 1466 slap_callback cb = {0}; 1467 BackendDB be; 1468 BackendInfo *bi; 1469 1470 #ifdef CHECK_CSN 1471 Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax; 1472 1473 int i; 1474 for ( i=0; i<si->si_numcsns; i++ ) { 1475 assert( !syn->ssyn_validate( syn, si->si_ctxcsn+i )); 1476 } 1477 #endif 1478 mod.sml_numvals = si->si_numcsns; 1479 mod.sml_values = si->si_ctxcsn; 1480 mod.sml_nvalues = NULL; 1481 mod.sml_desc = slap_schema.si_ad_contextCSN; 1482 mod.sml_op = LDAP_MOD_REPLACE; 1483 mod.sml_flags = SLAP_MOD_INTERNAL; 1484 mod.sml_next = NULL; 1485 1486 cb.sc_response = slap_null_cb; 1487 opm = *op; 1488 opm.o_tag = LDAP_REQ_MODIFY; 1489 opm.o_callback = &cb; 1490 opm.orm_modlist = &mod; 1491 opm.orm_no_opattrs = 1; 1492 if ( SLAP_GLUE_SUBORDINATE( op->o_bd )) { 1493 be = *on->on_info->oi_origdb; 1494 opm.o_bd = &be; 1495 } 1496 opm.o_req_dn = si->si_contextdn; 1497 opm.o_req_ndn = si->si_contextdn; 1498 bi = opm.o_bd->bd_info; 1499 opm.o_bd->bd_info = on->on_info->oi_orig; 1500 opm.o_managedsait = SLAP_CONTROL_NONCRITICAL; 1501 opm.o_no_schema_check = 1; 1502 opm.o_dont_replicate = 1; 1503 opm.o_opid = -1; 1504 opm.o_bd->be_modify( &opm, &rsm ); 1505 1506 if ( rsm.sr_err == LDAP_NO_SUCH_OBJECT && 1507 SLAP_SYNC_SUBENTRY( opm.o_bd )) { 1508 const char *text; 1509 char txtbuf[SLAP_TEXT_BUFLEN]; 1510 size_t textlen = sizeof txtbuf; 1511 Entry *e = slap_create_context_csn_entry( opm.o_bd, NULL ); 1512 rs_reinit( &rsm, REP_RESULT ); 1513 slap_mods2entry( &mod, &e, 0, 1, &text, txtbuf, textlen); 1514 opm.ora_e = e; 1515 opm.o_bd->be_add( &opm, &rsm ); 1516 if ( e == opm.ora_e ) 1517 be_entry_release_w( &opm, opm.ora_e ); 1518 } 1519 opm.o_bd->bd_info = bi; 1520 1521 if ( mod.sml_next != NULL ) { 1522 slap_mods_free( mod.sml_next, 1 ); 1523 } 1524 #ifdef CHECK_CSN 1525 for ( i=0; i<si->si_numcsns; i++ ) { 1526 assert( !syn->ssyn_validate( syn, si->si_ctxcsn+i )); 1527 } 1528 #endif 1529 } 1530 1531 static void 1532 syncprov_add_slog( Operation *op ) 1533 { 1534 opcookie *opc = op->o_callback->sc_private; 1535 slap_overinst *on = opc->son; 1536 syncprov_info_t *si = on->on_bi.bi_private; 1537 sessionlog *sl; 1538 slog_entry *se; 1539 1540 sl = si->si_logs; 1541 { 1542 if ( BER_BVISEMPTY( &op->o_csn ) ) { 1543 /* During the syncrepl refresh phase we can receive operations 1544 * without a csn. We cannot reliably determine the consumers 1545 * state with respect to such operations, so we ignore them and 1546 * wipe out anything in the log if we see them. 1547 */ 1548 ldap_pvt_thread_mutex_lock( &sl->sl_mutex ); 1549 /* can only do this if no one else is reading the log at the moment */ 1550 if (!sl->sl_playing) { 1551 while ( se = sl->sl_head ) { 1552 sl->sl_head = se->se_next; 1553 ch_free( se ); 1554 } 1555 sl->sl_tail = NULL; 1556 sl->sl_num = 0; 1557 } 1558 ldap_pvt_thread_mutex_unlock( &sl->sl_mutex ); 1559 return; 1560 } 1561 1562 /* Allocate a record. UUIDs are not NUL-terminated. */ 1563 se = ch_malloc( sizeof( slog_entry ) + opc->suuid.bv_len + 1564 op->o_csn.bv_len + 1 ); 1565 se->se_next = NULL; 1566 se->se_tag = op->o_tag; 1567 1568 se->se_uuid.bv_val = (char *)(&se[1]); 1569 AC_MEMCPY( se->se_uuid.bv_val, opc->suuid.bv_val, opc->suuid.bv_len ); 1570 se->se_uuid.bv_len = opc->suuid.bv_len; 1571 1572 se->se_csn.bv_val = se->se_uuid.bv_val + opc->suuid.bv_len; 1573 AC_MEMCPY( se->se_csn.bv_val, op->o_csn.bv_val, op->o_csn.bv_len ); 1574 se->se_csn.bv_val[op->o_csn.bv_len] = '\0'; 1575 se->se_csn.bv_len = op->o_csn.bv_len; 1576 se->se_sid = slap_parse_csn_sid( &se->se_csn ); 1577 1578 ldap_pvt_thread_mutex_lock( &sl->sl_mutex ); 1579 if ( sl->sl_head ) { 1580 /* Keep the list in csn order. */ 1581 if ( ber_bvcmp( &sl->sl_tail->se_csn, &se->se_csn ) <= 0 ) { 1582 sl->sl_tail->se_next = se; 1583 sl->sl_tail = se; 1584 } else { 1585 slog_entry **sep; 1586 1587 for ( sep = &sl->sl_head; *sep; sep = &(*sep)->se_next ) { 1588 if ( ber_bvcmp( &se->se_csn, &(*sep)->se_csn ) < 0 ) { 1589 se->se_next = *sep; 1590 *sep = se; 1591 break; 1592 } 1593 } 1594 } 1595 } else { 1596 sl->sl_head = se; 1597 sl->sl_tail = se; 1598 if ( !sl->sl_mincsn ) { 1599 sl->sl_numcsns = 1; 1600 sl->sl_mincsn = ch_malloc( 2*sizeof( struct berval )); 1601 sl->sl_sids = ch_malloc( sizeof( int )); 1602 sl->sl_sids[0] = se->se_sid; 1603 ber_dupbv( sl->sl_mincsn, &se->se_csn ); 1604 BER_BVZERO( &sl->sl_mincsn[1] ); 1605 } 1606 } 1607 sl->sl_num++; 1608 if (!sl->sl_playing) { 1609 while ( sl->sl_num > sl->sl_size ) { 1610 int i; 1611 se = sl->sl_head; 1612 sl->sl_head = se->se_next; 1613 for ( i=0; i<sl->sl_numcsns; i++ ) 1614 if ( sl->sl_sids[i] >= se->se_sid ) 1615 break; 1616 if ( i == sl->sl_numcsns || sl->sl_sids[i] != se->se_sid ) { 1617 slap_insert_csn_sids( (struct sync_cookie *)sl, 1618 i, se->se_sid, &se->se_csn ); 1619 } else { 1620 ber_bvreplace( &sl->sl_mincsn[i], &se->se_csn ); 1621 } 1622 ch_free( se ); 1623 sl->sl_num--; 1624 } 1625 } 1626 ldap_pvt_thread_mutex_unlock( &sl->sl_mutex ); 1627 } 1628 } 1629 1630 /* Just set a flag if we found the matching entry */ 1631 static int 1632 playlog_cb( Operation *op, SlapReply *rs ) 1633 { 1634 if ( rs->sr_type == REP_SEARCH ) { 1635 op->o_callback->sc_private = (void *)1; 1636 } 1637 return rs->sr_err; 1638 } 1639 1640 /* enter with sl->sl_mutex locked, release before returning */ 1641 static void 1642 syncprov_playlog( Operation *op, SlapReply *rs, sessionlog *sl, 1643 sync_control *srs, BerVarray ctxcsn, int numcsns, int *sids ) 1644 { 1645 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 1646 slog_entry *se; 1647 int i, j, ndel, num, nmods, mmods; 1648 char cbuf[LDAP_PVT_CSNSTR_BUFSIZE]; 1649 BerVarray uuids; 1650 struct berval delcsn[2]; 1651 1652 if ( !sl->sl_num ) { 1653 ldap_pvt_thread_mutex_unlock( &sl->sl_mutex ); 1654 return; 1655 } 1656 1657 num = sl->sl_num; 1658 i = 0; 1659 nmods = 0; 1660 sl->sl_playing++; 1661 ldap_pvt_thread_mutex_unlock( &sl->sl_mutex ); 1662 1663 uuids = op->o_tmpalloc( (num+1) * sizeof( struct berval ) + 1664 num * UUID_LEN, op->o_tmpmemctx ); 1665 uuids[0].bv_val = (char *)(uuids + num + 1); 1666 1667 delcsn[0].bv_len = 0; 1668 delcsn[0].bv_val = cbuf; 1669 BER_BVZERO(&delcsn[1]); 1670 1671 /* Make a copy of the relevant UUIDs. Put the Deletes up front 1672 * and everything else at the end. Do this first so we can 1673 * unlock the list mutex. 1674 */ 1675 Debug( LDAP_DEBUG_SYNC, "srs csn %s\n", 1676 srs->sr_state.ctxcsn[0].bv_val, 0, 0 ); 1677 for ( se=sl->sl_head; se; se=se->se_next ) { 1678 int k; 1679 Debug( LDAP_DEBUG_SYNC, "log csn %s\n", se->se_csn.bv_val, 0, 0 ); 1680 ndel = 1; 1681 for ( k=0; k<srs->sr_state.numcsns; k++ ) { 1682 if ( se->se_sid == srs->sr_state.sids[k] ) { 1683 ndel = ber_bvcmp( &se->se_csn, &srs->sr_state.ctxcsn[k] ); 1684 break; 1685 } 1686 } 1687 if ( ndel <= 0 ) { 1688 Debug( LDAP_DEBUG_SYNC, "cmp %d, too old\n", ndel, 0, 0 ); 1689 continue; 1690 } 1691 ndel = 0; 1692 for ( k=0; k<numcsns; k++ ) { 1693 if ( se->se_sid == sids[k] ) { 1694 ndel = ber_bvcmp( &se->se_csn, &ctxcsn[k] ); 1695 break; 1696 } 1697 } 1698 if ( ndel > 0 ) { 1699 Debug( LDAP_DEBUG_SYNC, "cmp %d, too new\n", ndel, 0, 0 ); 1700 break; 1701 } 1702 if ( se->se_tag == LDAP_REQ_DELETE ) { 1703 j = i; 1704 i++; 1705 AC_MEMCPY( cbuf, se->se_csn.bv_val, se->se_csn.bv_len ); 1706 delcsn[0].bv_len = se->se_csn.bv_len; 1707 delcsn[0].bv_val[delcsn[0].bv_len] = '\0'; 1708 } else { 1709 if ( se->se_tag == LDAP_REQ_ADD ) 1710 continue; 1711 nmods++; 1712 j = num - nmods; 1713 } 1714 uuids[j].bv_val = uuids[0].bv_val + (j * UUID_LEN); 1715 AC_MEMCPY(uuids[j].bv_val, se->se_uuid.bv_val, UUID_LEN); 1716 uuids[j].bv_len = UUID_LEN; 1717 } 1718 ldap_pvt_thread_mutex_lock( &sl->sl_mutex ); 1719 sl->sl_playing--; 1720 ldap_pvt_thread_mutex_unlock( &sl->sl_mutex ); 1721 1722 ndel = i; 1723 1724 /* Zero out unused slots */ 1725 for ( i=ndel; i < num - nmods; i++ ) 1726 uuids[i].bv_len = 0; 1727 1728 /* Mods must be validated to see if they belong in this delete set. 1729 */ 1730 1731 mmods = nmods; 1732 /* Strip any duplicates */ 1733 for ( i=0; i<nmods; i++ ) { 1734 for ( j=0; j<ndel; j++ ) { 1735 if ( bvmatch( &uuids[j], &uuids[num - 1 - i] )) { 1736 uuids[num - 1 - i].bv_len = 0; 1737 mmods --; 1738 break; 1739 } 1740 } 1741 if ( uuids[num - 1 - i].bv_len == 0 ) continue; 1742 for ( j=0; j<i; j++ ) { 1743 if ( bvmatch( &uuids[num - 1 - j], &uuids[num - 1 - i] )) { 1744 uuids[num - 1 - i].bv_len = 0; 1745 mmods --; 1746 break; 1747 } 1748 } 1749 } 1750 1751 if ( mmods ) { 1752 Operation fop; 1753 int rc; 1754 Filter mf, af; 1755 AttributeAssertion eq = ATTRIBUTEASSERTION_INIT; 1756 slap_callback cb = {0}; 1757 1758 fop = *op; 1759 1760 fop.o_sync_mode = 0; 1761 fop.o_callback = &cb; 1762 fop.ors_limit = NULL; 1763 fop.ors_tlimit = SLAP_NO_LIMIT; 1764 fop.ors_attrs = slap_anlist_all_attributes; 1765 fop.ors_attrsonly = 0; 1766 fop.o_managedsait = SLAP_CONTROL_CRITICAL; 1767 1768 af.f_choice = LDAP_FILTER_AND; 1769 af.f_next = NULL; 1770 af.f_and = &mf; 1771 mf.f_choice = LDAP_FILTER_EQUALITY; 1772 mf.f_ava = &eq; 1773 mf.f_av_desc = slap_schema.si_ad_entryUUID; 1774 mf.f_next = fop.ors_filter; 1775 1776 fop.ors_filter = ⁡ 1777 1778 cb.sc_response = playlog_cb; 1779 fop.o_bd->bd_info = (BackendInfo *)on->on_info; 1780 1781 for ( i=ndel; i<num; i++ ) { 1782 if ( uuids[i].bv_len != 0 ) { 1783 SlapReply frs = { REP_RESULT }; 1784 1785 mf.f_av_value = uuids[i]; 1786 cb.sc_private = NULL; 1787 fop.ors_slimit = 1; 1788 rc = fop.o_bd->be_search( &fop, &frs ); 1789 1790 /* If entry was not found, add to delete list */ 1791 if ( !cb.sc_private ) { 1792 uuids[ndel++] = uuids[i]; 1793 } 1794 } 1795 } 1796 fop.o_bd->bd_info = (BackendInfo *)on; 1797 } 1798 if ( ndel ) { 1799 struct berval cookie; 1800 1801 if ( delcsn[0].bv_len ) { 1802 slap_compose_sync_cookie( op, &cookie, delcsn, srs->sr_state.rid, 1803 slap_serverID ? slap_serverID : -1 ); 1804 1805 Debug( LDAP_DEBUG_SYNC, "syncprov_playlog: cookie=%s\n", cookie.bv_val, 0, 0 ); 1806 } 1807 1808 uuids[ndel].bv_val = NULL; 1809 syncprov_sendinfo( op, rs, LDAP_TAG_SYNC_ID_SET, 1810 delcsn[0].bv_len ? &cookie : NULL, 0, uuids, 1 ); 1811 if ( delcsn[0].bv_len ) { 1812 op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx ); 1813 } 1814 } 1815 op->o_tmpfree( uuids, op->o_tmpmemctx ); 1816 } 1817 1818 static int 1819 syncprov_new_ctxcsn( opcookie *opc, syncprov_info_t *si, int csn_changed, int numvals, BerVarray vals ) 1820 { 1821 unsigned i; 1822 int j, sid; 1823 1824 for ( i=0; i<numvals; i++ ) { 1825 sid = slap_parse_csn_sid( &vals[i] ); 1826 for ( j=0; j<si->si_numcsns; j++ ) { 1827 if ( sid < si->si_sids[j] ) 1828 break; 1829 if ( sid == si->si_sids[j] ) { 1830 if ( ber_bvcmp( &vals[i], &si->si_ctxcsn[j] ) > 0 ) { 1831 ber_bvreplace( &si->si_ctxcsn[j], &vals[i] ); 1832 csn_changed = 1; 1833 } 1834 break; 1835 } 1836 } 1837 1838 if ( j == si->si_numcsns || sid != si->si_sids[j] ) { 1839 slap_insert_csn_sids( (struct sync_cookie *)&si->si_ctxcsn, 1840 j, sid, &vals[i] ); 1841 csn_changed = 1; 1842 } 1843 } 1844 if ( csn_changed ) 1845 si->si_dirty = 0; 1846 ldap_pvt_thread_rdwr_wunlock( &si->si_csn_rwlock ); 1847 1848 if ( csn_changed ) { 1849 syncops *ss; 1850 ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); 1851 for ( ss = si->si_ops; ss; ss = ss->s_next ) { 1852 if ( ss->s_op->o_abandon ) 1853 continue; 1854 /* Send the updated csn to all syncrepl consumers, 1855 * including the server from which it originated. 1856 * The syncrepl consumer and syncprov provider on 1857 * the originating server may be configured to store 1858 * their csn values in different entries. 1859 */ 1860 syncprov_qresp( opc, ss, LDAP_SYNC_NEW_COOKIE ); 1861 } 1862 ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); 1863 } 1864 return csn_changed; 1865 } 1866 1867 static int 1868 syncprov_op_response( Operation *op, SlapReply *rs ) 1869 { 1870 opcookie *opc = op->o_callback->sc_private; 1871 slap_overinst *on = opc->son; 1872 syncprov_info_t *si = on->on_bi.bi_private; 1873 syncmatches *sm; 1874 1875 if ( rs->sr_err == LDAP_SUCCESS ) 1876 { 1877 struct berval maxcsn; 1878 char cbuf[LDAP_PVT_CSNSTR_BUFSIZE]; 1879 int do_check = 0, have_psearches, foundit, csn_changed = 0; 1880 1881 ldap_pvt_thread_mutex_lock( &si->si_resp_mutex ); 1882 1883 /* Update our context CSN */ 1884 cbuf[0] = '\0'; 1885 maxcsn.bv_val = cbuf; 1886 maxcsn.bv_len = sizeof(cbuf); 1887 ldap_pvt_thread_rdwr_wlock( &si->si_csn_rwlock ); 1888 1889 slap_get_commit_csn( op, &maxcsn, &foundit ); 1890 if ( BER_BVISEMPTY( &maxcsn ) && SLAP_GLUE_SUBORDINATE( op->o_bd )) { 1891 /* syncrepl queues the CSN values in the db where 1892 * it is configured , not where the changes are made. 1893 * So look for a value in the glue db if we didn't 1894 * find any in this db. 1895 */ 1896 BackendDB *be = op->o_bd; 1897 op->o_bd = select_backend( &be->be_nsuffix[0], 1); 1898 maxcsn.bv_val = cbuf; 1899 maxcsn.bv_len = sizeof(cbuf); 1900 slap_get_commit_csn( op, &maxcsn, &foundit ); 1901 op->o_bd = be; 1902 } 1903 if ( !BER_BVISEMPTY( &maxcsn ) ) { 1904 int i, sid; 1905 #ifdef CHECK_CSN 1906 Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax; 1907 assert( !syn->ssyn_validate( syn, &maxcsn )); 1908 #endif 1909 sid = slap_parse_csn_sid( &maxcsn ); 1910 for ( i=0; i<si->si_numcsns; i++ ) { 1911 if ( sid < si->si_sids[i] ) 1912 break; 1913 if ( sid == si->si_sids[i] ) { 1914 if ( ber_bvcmp( &maxcsn, &si->si_ctxcsn[i] ) > 0 ) { 1915 ber_bvreplace( &si->si_ctxcsn[i], &maxcsn ); 1916 csn_changed = 1; 1917 } 1918 break; 1919 } 1920 } 1921 /* It's a new SID for us */ 1922 if ( i == si->si_numcsns || sid != si->si_sids[i] ) { 1923 slap_insert_csn_sids((struct sync_cookie *)&(si->si_ctxcsn), 1924 i, sid, &maxcsn ); 1925 csn_changed = 1; 1926 } 1927 } 1928 1929 /* Don't do any processing for consumer contextCSN updates */ 1930 if ( SLAPD_SYNC_IS_SYNCCONN( op->o_connid ) && 1931 op->o_tag == LDAP_REQ_MODIFY && 1932 op->orm_modlist && 1933 op->orm_modlist->sml_op == LDAP_MOD_REPLACE && 1934 op->orm_modlist->sml_desc == slap_schema.si_ad_contextCSN ) { 1935 /* Catch contextCSN updates from syncrepl. We have to look at 1936 * all the attribute values, as there may be more than one csn 1937 * that changed, and only one can be passed in the csn queue. 1938 */ 1939 csn_changed = syncprov_new_ctxcsn( opc, si, csn_changed, 1940 op->orm_modlist->sml_numvals, op->orm_modlist->sml_values ); 1941 if ( csn_changed ) 1942 si->si_numops++; 1943 goto leave; 1944 } 1945 if ( op->o_dont_replicate ) { 1946 if ( csn_changed ) 1947 si->si_numops++; 1948 ldap_pvt_thread_rdwr_wunlock( &si->si_csn_rwlock ); 1949 goto leave; 1950 } 1951 1952 /* If we're adding the context entry, parse all of its contextCSNs */ 1953 if ( op->o_tag == LDAP_REQ_ADD && 1954 dn_match( &op->o_req_ndn, &si->si_contextdn )) { 1955 Attribute *a = attr_find( op->ora_e->e_attrs, slap_schema.si_ad_contextCSN ); 1956 if ( a ) { 1957 csn_changed = syncprov_new_ctxcsn( opc, si, csn_changed, a->a_numvals, a->a_vals ); 1958 if ( csn_changed ) 1959 si->si_numops++; 1960 goto added; 1961 } 1962 } 1963 1964 if ( csn_changed ) 1965 si->si_numops++; 1966 if ( si->si_chkops || si->si_chktime ) { 1967 /* Never checkpoint adding the context entry, 1968 * it will deadlock 1969 */ 1970 if ( op->o_tag != LDAP_REQ_ADD || 1971 !dn_match( &op->o_req_ndn, &si->si_contextdn )) { 1972 if ( si->si_chkops && si->si_numops >= si->si_chkops ) { 1973 do_check = 1; 1974 si->si_numops = 0; 1975 } 1976 if ( si->si_chktime && 1977 (op->o_time - si->si_chklast >= si->si_chktime )) { 1978 if ( si->si_chklast ) { 1979 do_check = 1; 1980 si->si_chklast = op->o_time; 1981 } else { 1982 si->si_chklast = 1; 1983 } 1984 } 1985 } 1986 } 1987 si->si_dirty = !csn_changed; 1988 ldap_pvt_thread_rdwr_wunlock( &si->si_csn_rwlock ); 1989 1990 added: 1991 if ( do_check ) { 1992 ldap_pvt_thread_rdwr_rlock( &si->si_csn_rwlock ); 1993 syncprov_checkpoint( op, on ); 1994 ldap_pvt_thread_rdwr_runlock( &si->si_csn_rwlock ); 1995 } 1996 1997 /* only update consumer ctx if this is a newer csn */ 1998 if ( csn_changed ) { 1999 opc->sctxcsn = maxcsn; 2000 } 2001 2002 /* Handle any persistent searches */ 2003 ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); 2004 have_psearches = ( si->si_ops != NULL ); 2005 ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); 2006 if ( have_psearches ) { 2007 switch(op->o_tag) { 2008 case LDAP_REQ_ADD: 2009 case LDAP_REQ_MODIFY: 2010 case LDAP_REQ_MODRDN: 2011 case LDAP_REQ_EXTENDED: 2012 syncprov_matchops( op, opc, 0 ); 2013 break; 2014 case LDAP_REQ_DELETE: 2015 /* for each match in opc->smatches: 2016 * send DELETE msg 2017 */ 2018 for ( sm = opc->smatches; sm; sm=sm->sm_next ) { 2019 if ( sm->sm_op->s_op->o_abandon ) 2020 continue; 2021 syncprov_qresp( opc, sm->sm_op, LDAP_SYNC_DELETE ); 2022 } 2023 if ( opc->ssres.s_info ) 2024 free_resinfo( &opc->ssres ); 2025 break; 2026 } 2027 } 2028 2029 /* Add any log records */ 2030 if ( si->si_logs ) { 2031 syncprov_add_slog( op ); 2032 } 2033 leave: ldap_pvt_thread_mutex_unlock( &si->si_resp_mutex ); 2034 } 2035 return SLAP_CB_CONTINUE; 2036 } 2037 2038 /* We don't use a subentry to store the context CSN any more. 2039 * We expose the current context CSN as an operational attribute 2040 * of the suffix entry. 2041 */ 2042 static int 2043 syncprov_op_compare( Operation *op, SlapReply *rs ) 2044 { 2045 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 2046 syncprov_info_t *si = on->on_bi.bi_private; 2047 int rc = SLAP_CB_CONTINUE; 2048 2049 if ( dn_match( &op->o_req_ndn, &si->si_contextdn ) && 2050 op->oq_compare.rs_ava->aa_desc == slap_schema.si_ad_contextCSN ) 2051 { 2052 Entry e = {0}; 2053 Attribute a = {0}; 2054 2055 e.e_name = si->si_contextdn; 2056 e.e_nname = si->si_contextdn; 2057 e.e_attrs = &a; 2058 2059 a.a_desc = slap_schema.si_ad_contextCSN; 2060 2061 ldap_pvt_thread_rdwr_rlock( &si->si_csn_rwlock ); 2062 2063 a.a_vals = si->si_ctxcsn; 2064 a.a_nvals = a.a_vals; 2065 a.a_numvals = si->si_numcsns; 2066 2067 rs->sr_err = access_allowed( op, &e, op->oq_compare.rs_ava->aa_desc, 2068 &op->oq_compare.rs_ava->aa_value, ACL_COMPARE, NULL ); 2069 if ( ! rs->sr_err ) { 2070 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 2071 goto return_results; 2072 } 2073 2074 if ( get_assert( op ) && 2075 ( test_filter( op, &e, get_assertion( op ) ) != LDAP_COMPARE_TRUE ) ) 2076 { 2077 rs->sr_err = LDAP_ASSERTION_FAILED; 2078 goto return_results; 2079 } 2080 2081 2082 rs->sr_err = LDAP_COMPARE_FALSE; 2083 2084 if ( attr_valfind( &a, 2085 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | 2086 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, 2087 &op->oq_compare.rs_ava->aa_value, NULL, op->o_tmpmemctx ) == 0 ) 2088 { 2089 rs->sr_err = LDAP_COMPARE_TRUE; 2090 } 2091 2092 return_results:; 2093 2094 ldap_pvt_thread_rdwr_runlock( &si->si_csn_rwlock ); 2095 2096 send_ldap_result( op, rs ); 2097 2098 if( rs->sr_err == LDAP_COMPARE_FALSE || rs->sr_err == LDAP_COMPARE_TRUE ) { 2099 rs->sr_err = LDAP_SUCCESS; 2100 } 2101 rc = rs->sr_err; 2102 } 2103 2104 return rc; 2105 } 2106 2107 static int 2108 syncprov_op_mod( Operation *op, SlapReply *rs ) 2109 { 2110 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 2111 syncprov_info_t *si = on->on_bi.bi_private; 2112 slap_callback *cb; 2113 opcookie *opc; 2114 int have_psearches, cbsize; 2115 2116 ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); 2117 have_psearches = ( si->si_ops != NULL ); 2118 si->si_active++; 2119 ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); 2120 2121 cbsize = sizeof(slap_callback) + sizeof(opcookie) + 2122 (have_psearches ? sizeof(modinst) : 0 ); 2123 2124 cb = op->o_tmpcalloc(1, cbsize, op->o_tmpmemctx); 2125 opc = (opcookie *)(cb+1); 2126 opc->son = on; 2127 cb->sc_response = syncprov_op_response; 2128 cb->sc_cleanup = syncprov_op_cleanup; 2129 cb->sc_private = opc; 2130 cb->sc_next = op->o_callback; 2131 op->o_callback = cb; 2132 2133 opc->osid = -1; 2134 opc->rsid = -1; 2135 if ( op->o_csn.bv_val ) { 2136 opc->osid = slap_parse_csn_sid( &op->o_csn ); 2137 } 2138 if ( op->o_controls ) { 2139 struct sync_cookie *scook = 2140 op->o_controls[slap_cids.sc_LDAPsync]; 2141 if ( scook ) 2142 opc->rsid = scook->sid; 2143 } 2144 2145 if ( op->o_dont_replicate ) 2146 return SLAP_CB_CONTINUE; 2147 2148 /* If there are active persistent searches, lock this operation. 2149 * See seqmod.c for the locking logic on its own. 2150 */ 2151 if ( have_psearches ) { 2152 modtarget *mt, mtdummy; 2153 modinst *mi; 2154 2155 mi = (modinst *)(opc+1); 2156 mi->mi_op = op; 2157 2158 /* See if we're already modifying this entry... */ 2159 mtdummy.mt_dn = op->o_req_ndn; 2160 retry: 2161 ldap_pvt_thread_mutex_lock( &si->si_mods_mutex ); 2162 mt = avl_find( si->si_mods, &mtdummy, sp_avl_cmp ); 2163 if ( mt ) { 2164 ldap_pvt_thread_mutex_lock( &mt->mt_mutex ); 2165 if ( mt->mt_mods == NULL ) { 2166 /* Cannot reuse this mt, as another thread is about 2167 * to release it in syncprov_op_cleanup. Wait for them 2168 * to finish; our own insert is required to succeed. 2169 */ 2170 ldap_pvt_thread_mutex_unlock( &mt->mt_mutex ); 2171 ldap_pvt_thread_mutex_unlock( &si->si_mods_mutex ); 2172 ldap_pvt_thread_yield(); 2173 goto retry; 2174 } 2175 } 2176 if ( mt ) { 2177 mt->mt_tail->mi_next = mi; 2178 mt->mt_tail = mi; 2179 ldap_pvt_thread_mutex_unlock( &si->si_mods_mutex ); 2180 /* wait for this op to get to head of list */ 2181 while ( mt->mt_mods != mi ) { 2182 modinst *m2; 2183 /* don't wait on other mods from the same thread */ 2184 for ( m2 = mt->mt_mods; m2; m2 = m2->mi_next ) { 2185 if ( m2->mi_op->o_threadctx == op->o_threadctx ) { 2186 break; 2187 } 2188 } 2189 if ( m2 ) 2190 break; 2191 2192 ldap_pvt_thread_mutex_unlock( &mt->mt_mutex ); 2193 /* FIXME: if dynamic config can delete overlays or 2194 * databases we'll have to check for cleanup here. 2195 * Currently it's not an issue because there are 2196 * no dynamic config deletes... 2197 */ 2198 if ( slapd_shutdown ) 2199 return SLAPD_ABANDON; 2200 2201 if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool )) 2202 ldap_pvt_thread_yield(); 2203 ldap_pvt_thread_mutex_lock( &mt->mt_mutex ); 2204 2205 /* clean up if the caller is giving up */ 2206 if ( op->o_abandon ) { 2207 modinst **m2; 2208 slap_callback **sc; 2209 for (m2 = &mt->mt_mods; ; m2 = &(*m2)->mi_next) { 2210 if ( *m2 == mi ) { 2211 *m2 = mi->mi_next; 2212 if ( mt->mt_tail == mi ) 2213 mt->mt_tail = ( m2 == &mt->mt_mods ) ? NULL : (modinst *)m2; 2214 break; 2215 } 2216 } 2217 for (sc = &op->o_callback; ; sc = &(*sc)->sc_next) { 2218 if ( *sc == cb ) { 2219 *sc = cb->sc_next; 2220 break; 2221 } 2222 } 2223 op->o_tmpfree( cb, op->o_tmpmemctx ); 2224 ldap_pvt_thread_mutex_unlock( &mt->mt_mutex ); 2225 return SLAPD_ABANDON; 2226 } 2227 } 2228 ldap_pvt_thread_mutex_unlock( &mt->mt_mutex ); 2229 } else { 2230 /* Record that we're modifying this entry now */ 2231 mt = ch_malloc( sizeof(modtarget) ); 2232 mt->mt_mods = mi; 2233 mt->mt_tail = mi; 2234 ber_dupbv( &mt->mt_dn, &mi->mi_op->o_req_ndn ); 2235 ldap_pvt_thread_mutex_init( &mt->mt_mutex ); 2236 avl_insert( &si->si_mods, mt, sp_avl_cmp, avl_dup_error ); 2237 ldap_pvt_thread_mutex_unlock( &si->si_mods_mutex ); 2238 } 2239 opc->smt = mt; 2240 } 2241 2242 if (( have_psearches || si->si_logs ) && op->o_tag != LDAP_REQ_ADD ) 2243 syncprov_matchops( op, opc, 1 ); 2244 2245 return SLAP_CB_CONTINUE; 2246 } 2247 2248 static int 2249 syncprov_op_extended( Operation *op, SlapReply *rs ) 2250 { 2251 if ( exop_is_write( op )) 2252 return syncprov_op_mod( op, rs ); 2253 2254 return SLAP_CB_CONTINUE; 2255 } 2256 2257 typedef struct searchstate { 2258 slap_overinst *ss_on; 2259 syncops *ss_so; 2260 BerVarray ss_ctxcsn; 2261 int *ss_sids; 2262 int ss_numcsns; 2263 #define SS_PRESENT 0x01 2264 #define SS_CHANGED 0x02 2265 int ss_flags; 2266 } searchstate; 2267 2268 typedef struct SyncOperationBuffer { 2269 Operation sob_op; 2270 Opheader sob_hdr; 2271 OpExtra sob_oe; 2272 AttributeName sob_extra; /* not always present */ 2273 /* Further data allocated here */ 2274 } SyncOperationBuffer; 2275 2276 static void 2277 syncprov_detach_op( Operation *op, syncops *so, slap_overinst *on ) 2278 { 2279 SyncOperationBuffer *sopbuf2; 2280 Operation *op2; 2281 int i, alen = 0; 2282 size_t size; 2283 char *ptr; 2284 GroupAssertion *g1, *g2; 2285 2286 /* count the search attrs */ 2287 for (i=0; op->ors_attrs && !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++) { 2288 alen += op->ors_attrs[i].an_name.bv_len + 1; 2289 } 2290 /* Make a new copy of the operation */ 2291 size = offsetof( SyncOperationBuffer, sob_extra ) + 2292 (i ? ( (i+1) * sizeof(AttributeName) + alen) : 0) + 2293 op->o_req_dn.bv_len + 1 + 2294 op->o_req_ndn.bv_len + 1 + 2295 op->o_ndn.bv_len + 1 + 2296 so->s_filterstr.bv_len + 1; 2297 sopbuf2 = ch_calloc( 1, size ); 2298 op2 = &sopbuf2->sob_op; 2299 op2->o_hdr = &sopbuf2->sob_hdr; 2300 LDAP_SLIST_FIRST(&op2->o_extra) = &sopbuf2->sob_oe; 2301 2302 /* Copy the fields we care about explicitly, leave the rest alone */ 2303 *op2->o_hdr = *op->o_hdr; 2304 op2->o_tag = op->o_tag; 2305 op2->o_time = op->o_time; 2306 op2->o_bd = on->on_info->oi_origdb; 2307 op2->o_request = op->o_request; 2308 op2->o_managedsait = op->o_managedsait; 2309 LDAP_SLIST_FIRST(&op2->o_extra)->oe_key = on; 2310 LDAP_SLIST_NEXT(LDAP_SLIST_FIRST(&op2->o_extra), oe_next) = NULL; 2311 2312 ptr = (char *) sopbuf2 + offsetof( SyncOperationBuffer, sob_extra ); 2313 if ( i ) { 2314 op2->ors_attrs = (AttributeName *) ptr; 2315 ptr = (char *) &op2->ors_attrs[i+1]; 2316 for (i=0; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++) { 2317 op2->ors_attrs[i] = op->ors_attrs[i]; 2318 op2->ors_attrs[i].an_name.bv_val = ptr; 2319 ptr = lutil_strcopy( ptr, op->ors_attrs[i].an_name.bv_val ) + 1; 2320 } 2321 BER_BVZERO( &op2->ors_attrs[i].an_name ); 2322 } 2323 2324 op2->o_authz = op->o_authz; 2325 op2->o_ndn.bv_val = ptr; 2326 ptr = lutil_strcopy(ptr, op->o_ndn.bv_val) + 1; 2327 op2->o_dn = op2->o_ndn; 2328 op2->o_req_dn.bv_len = op->o_req_dn.bv_len; 2329 op2->o_req_dn.bv_val = ptr; 2330 ptr = lutil_strcopy(ptr, op->o_req_dn.bv_val) + 1; 2331 op2->o_req_ndn.bv_len = op->o_req_ndn.bv_len; 2332 op2->o_req_ndn.bv_val = ptr; 2333 ptr = lutil_strcopy(ptr, op->o_req_ndn.bv_val) + 1; 2334 op2->ors_filterstr.bv_val = ptr; 2335 strcpy( ptr, so->s_filterstr.bv_val ); 2336 op2->ors_filterstr.bv_len = so->s_filterstr.bv_len; 2337 2338 /* Skip the AND/GE clause that we stuck on in front */ 2339 if ( so->s_flags & PS_FIX_FILTER ) { 2340 op2->ors_filter = op->ors_filter->f_and->f_next; 2341 so->s_flags ^= PS_FIX_FILTER; 2342 } else { 2343 op2->ors_filter = op->ors_filter; 2344 } 2345 op2->ors_filter = filter_dup( op2->ors_filter, NULL ); 2346 so->s_op = op2; 2347 2348 /* Copy any cached group ACLs individually */ 2349 op2->o_groups = NULL; 2350 for ( g1=op->o_groups; g1; g1=g1->ga_next ) { 2351 g2 = ch_malloc( sizeof(GroupAssertion) + g1->ga_len ); 2352 *g2 = *g1; 2353 strcpy( g2->ga_ndn, g1->ga_ndn ); 2354 g2->ga_next = op2->o_groups; 2355 op2->o_groups = g2; 2356 } 2357 /* Don't allow any further group caching */ 2358 op2->o_do_not_cache = 1; 2359 2360 /* Add op2 to conn so abandon will find us */ 2361 op->o_conn->c_n_ops_executing++; 2362 op->o_conn->c_n_ops_completed--; 2363 LDAP_STAILQ_INSERT_TAIL( &op->o_conn->c_ops, op2, o_next ); 2364 so->s_flags |= PS_IS_DETACHED; 2365 2366 /* Prevent anyone else from trying to send a result for this op */ 2367 op->o_abandon = 1; 2368 } 2369 2370 static int 2371 syncprov_search_response( Operation *op, SlapReply *rs ) 2372 { 2373 searchstate *ss = op->o_callback->sc_private; 2374 slap_overinst *on = ss->ss_on; 2375 syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private; 2376 sync_control *srs = op->o_controls[slap_cids.sc_LDAPsync]; 2377 2378 if ( rs->sr_type == REP_SEARCH || rs->sr_type == REP_SEARCHREF ) { 2379 Attribute *a; 2380 /* If we got a referral without a referral object, there's 2381 * something missing that we cannot replicate. Just ignore it. 2382 * The consumer will abort because we didn't send the expected 2383 * control. 2384 */ 2385 if ( !rs->sr_entry ) { 2386 assert( rs->sr_entry != NULL ); 2387 Debug( LDAP_DEBUG_ANY, "bogus referral in context\n",0,0,0 ); 2388 return SLAP_CB_CONTINUE; 2389 } 2390 a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryCSN ); 2391 if ( a == NULL && rs->sr_operational_attrs != NULL ) { 2392 a = attr_find( rs->sr_operational_attrs, slap_schema.si_ad_entryCSN ); 2393 } 2394 if ( a ) { 2395 int i, sid; 2396 sid = slap_parse_csn_sid( &a->a_nvals[0] ); 2397 2398 /* If not a persistent search */ 2399 if ( !ss->ss_so ) { 2400 /* Make sure entry is less than the snapshot'd contextCSN */ 2401 for ( i=0; i<ss->ss_numcsns; i++ ) { 2402 if ( sid == ss->ss_sids[i] && ber_bvcmp( &a->a_nvals[0], 2403 &ss->ss_ctxcsn[i] ) > 0 ) { 2404 Debug( LDAP_DEBUG_SYNC, 2405 "Entry %s CSN %s greater than snapshot %s\n", 2406 rs->sr_entry->e_name.bv_val, 2407 a->a_nvals[0].bv_val, 2408 ss->ss_ctxcsn[i].bv_val ); 2409 return LDAP_SUCCESS; 2410 } 2411 } 2412 } 2413 2414 /* Don't send old entries twice */ 2415 if ( srs->sr_state.ctxcsn ) { 2416 for ( i=0; i<srs->sr_state.numcsns; i++ ) { 2417 if ( sid == srs->sr_state.sids[i] && 2418 ber_bvcmp( &a->a_nvals[0], 2419 &srs->sr_state.ctxcsn[i] )<= 0 ) { 2420 Debug( LDAP_DEBUG_SYNC, 2421 "Entry %s CSN %s older or equal to ctx %s\n", 2422 rs->sr_entry->e_name.bv_val, 2423 a->a_nvals[0].bv_val, 2424 srs->sr_state.ctxcsn[i].bv_val ); 2425 return LDAP_SUCCESS; 2426 } 2427 } 2428 } 2429 } 2430 rs->sr_ctrls = op->o_tmpalloc( sizeof(LDAPControl *)*2, 2431 op->o_tmpmemctx ); 2432 rs->sr_ctrls[1] = NULL; 2433 rs->sr_flags |= REP_CTRLS_MUSTBEFREED; 2434 /* If we're in delta-sync mode, always send a cookie */ 2435 if ( si->si_nopres && si->si_usehint && a ) { 2436 struct berval cookie; 2437 slap_compose_sync_cookie( op, &cookie, a->a_nvals, srs->sr_state.rid, slap_serverID ? slap_serverID : -1 ); 2438 rs->sr_err = syncprov_state_ctrl( op, rs, rs->sr_entry, 2439 LDAP_SYNC_ADD, rs->sr_ctrls, 0, 1, &cookie ); 2440 op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx ); 2441 } else { 2442 rs->sr_err = syncprov_state_ctrl( op, rs, rs->sr_entry, 2443 LDAP_SYNC_ADD, rs->sr_ctrls, 0, 0, NULL ); 2444 } 2445 } else if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS ) { 2446 struct berval cookie = BER_BVNULL; 2447 2448 if ( ( ss->ss_flags & SS_CHANGED ) && 2449 ss->ss_ctxcsn && !BER_BVISNULL( &ss->ss_ctxcsn[0] )) { 2450 slap_compose_sync_cookie( op, &cookie, ss->ss_ctxcsn, 2451 srs->sr_state.rid, slap_serverID ? slap_serverID : -1 ); 2452 2453 Debug( LDAP_DEBUG_SYNC, "syncprov_search_response: cookie=%s\n", cookie.bv_val, 0, 0 ); 2454 } 2455 2456 /* Is this a regular refresh? 2457 * Note: refresh never gets here if there were no changes 2458 */ 2459 if ( !ss->ss_so ) { 2460 rs->sr_ctrls = op->o_tmpalloc( sizeof(LDAPControl *)*2, 2461 op->o_tmpmemctx ); 2462 rs->sr_ctrls[1] = NULL; 2463 rs->sr_flags |= REP_CTRLS_MUSTBEFREED; 2464 rs->sr_err = syncprov_done_ctrl( op, rs, rs->sr_ctrls, 2465 0, 1, &cookie, ( ss->ss_flags & SS_PRESENT ) ? LDAP_SYNC_REFRESH_PRESENTS : 2466 LDAP_SYNC_REFRESH_DELETES ); 2467 op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx ); 2468 } else { 2469 /* It's RefreshAndPersist, transition to Persist phase */ 2470 syncprov_sendinfo( op, rs, ( ss->ss_flags & SS_PRESENT ) ? 2471 LDAP_TAG_SYNC_REFRESH_PRESENT : LDAP_TAG_SYNC_REFRESH_DELETE, 2472 ( ss->ss_flags & SS_CHANGED ) ? &cookie : NULL, 2473 1, NULL, 0 ); 2474 if ( !BER_BVISNULL( &cookie )) 2475 op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx ); 2476 2477 /* Detach this Op from frontend control */ 2478 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); 2479 2480 /* But not if this connection was closed along the way */ 2481 if ( op->o_abandon ) { 2482 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); 2483 /* syncprov_ab_cleanup will free this syncop */ 2484 return SLAPD_ABANDON; 2485 2486 } else { 2487 ldap_pvt_thread_mutex_lock( &ss->ss_so->s_mutex ); 2488 /* Turn off the refreshing flag */ 2489 ss->ss_so->s_flags ^= PS_IS_REFRESHING; 2490 2491 syncprov_detach_op( op, ss->ss_so, on ); 2492 2493 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); 2494 2495 /* If there are queued responses, fire them off */ 2496 if ( ss->ss_so->s_res ) 2497 syncprov_qstart( ss->ss_so ); 2498 ldap_pvt_thread_mutex_unlock( &ss->ss_so->s_mutex ); 2499 } 2500 2501 return LDAP_SUCCESS; 2502 } 2503 } 2504 2505 return SLAP_CB_CONTINUE; 2506 } 2507 2508 static int 2509 syncprov_op_search( Operation *op, SlapReply *rs ) 2510 { 2511 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 2512 syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private; 2513 slap_callback *cb; 2514 int gotstate = 0, changed = 0, do_present = 0; 2515 syncops *sop = NULL; 2516 searchstate *ss; 2517 sync_control *srs; 2518 BerVarray ctxcsn; 2519 int i, *sids, numcsns; 2520 struct berval mincsn, maxcsn; 2521 int minsid, maxsid; 2522 int dirty = 0; 2523 2524 if ( !(op->o_sync_mode & SLAP_SYNC_REFRESH) ) return SLAP_CB_CONTINUE; 2525 2526 if ( op->ors_deref & LDAP_DEREF_SEARCHING ) { 2527 send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, "illegal value for derefAliases" ); 2528 return rs->sr_err; 2529 } 2530 2531 srs = op->o_controls[slap_cids.sc_LDAPsync]; 2532 2533 /* If this is a persistent search, set it up right away */ 2534 if ( op->o_sync_mode & SLAP_SYNC_PERSIST ) { 2535 syncops so = {0}; 2536 fbase_cookie fc; 2537 opcookie opc; 2538 slap_callback sc = {0}; 2539 2540 fc.fss = &so; 2541 fc.fbase = 0; 2542 so.s_eid = NOID; 2543 so.s_op = op; 2544 so.s_flags = PS_IS_REFRESHING | PS_FIND_BASE; 2545 /* syncprov_findbase expects to be called as a callback... */ 2546 sc.sc_private = &opc; 2547 opc.son = on; 2548 ldap_pvt_thread_mutex_init( &so.s_mutex ); 2549 cb = op->o_callback; 2550 op->o_callback = ≻ 2551 rs->sr_err = syncprov_findbase( op, &fc ); 2552 op->o_callback = cb; 2553 ldap_pvt_thread_mutex_destroy( &so.s_mutex ); 2554 2555 if ( rs->sr_err != LDAP_SUCCESS ) { 2556 send_ldap_result( op, rs ); 2557 return rs->sr_err; 2558 } 2559 sop = ch_malloc( sizeof( syncops )); 2560 *sop = so; 2561 sop->s_rid = srs->sr_state.rid; 2562 sop->s_sid = srs->sr_state.sid; 2563 /* set refcount=2 to prevent being freed out from under us 2564 * by abandons that occur while we're running here 2565 */ 2566 sop->s_inuse = 2; 2567 2568 ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); 2569 while ( si->si_active ) { 2570 /* Wait for active mods to finish before proceeding, as they 2571 * may already have inspected the si_ops list looking for 2572 * consumers to replicate the change to. Using the log 2573 * doesn't help, as we may finish playing it before the 2574 * active mods gets added to it. 2575 */ 2576 ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); 2577 if ( slapd_shutdown ) { 2578 ch_free( sop ); 2579 return SLAPD_ABANDON; 2580 } 2581 if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool )) 2582 ldap_pvt_thread_yield(); 2583 ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); 2584 } 2585 if ( op->o_abandon ) { 2586 ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); 2587 ch_free( sop ); 2588 return SLAPD_ABANDON; 2589 } 2590 ldap_pvt_thread_mutex_init( &sop->s_mutex ); 2591 sop->s_next = si->si_ops; 2592 sop->s_si = si; 2593 si->si_ops = sop; 2594 ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); 2595 } 2596 2597 /* snapshot the ctxcsn 2598 * Note: this must not be done before the psearch setup. (ITS#8365) 2599 */ 2600 ldap_pvt_thread_rdwr_rlock( &si->si_csn_rwlock ); 2601 numcsns = si->si_numcsns; 2602 if ( numcsns ) { 2603 ber_bvarray_dup_x( &ctxcsn, si->si_ctxcsn, op->o_tmpmemctx ); 2604 sids = op->o_tmpalloc( numcsns * sizeof(int), op->o_tmpmemctx ); 2605 for ( i=0; i<numcsns; i++ ) 2606 sids[i] = si->si_sids[i]; 2607 } else { 2608 ctxcsn = NULL; 2609 sids = NULL; 2610 } 2611 dirty = si->si_dirty; 2612 ldap_pvt_thread_rdwr_runlock( &si->si_csn_rwlock ); 2613 2614 /* If we have a cookie, handle the PRESENT lookups */ 2615 if ( srs->sr_state.ctxcsn ) { 2616 sessionlog *sl; 2617 int i, j; 2618 2619 /* If we don't have any CSN of our own yet, bail out. 2620 */ 2621 if ( !numcsns ) { 2622 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 2623 rs->sr_text = "consumer has state info but provider doesn't!"; 2624 goto bailout; 2625 } 2626 2627 if ( !si->si_nopres ) 2628 do_present = SS_PRESENT; 2629 2630 /* If there are SIDs we don't recognize in the cookie, drop them */ 2631 for (i=0; i<srs->sr_state.numcsns; ) { 2632 for (j=i; j<numcsns; j++) { 2633 if ( srs->sr_state.sids[i] <= sids[j] ) { 2634 break; 2635 } 2636 } 2637 /* not found */ 2638 if ( j == numcsns || srs->sr_state.sids[i] != sids[j] ) { 2639 char *tmp = srs->sr_state.ctxcsn[i].bv_val; 2640 srs->sr_state.numcsns--; 2641 for ( j=i; j<srs->sr_state.numcsns; j++ ) { 2642 srs->sr_state.ctxcsn[j] = srs->sr_state.ctxcsn[j+1]; 2643 srs->sr_state.sids[j] = srs->sr_state.sids[j+1]; 2644 } 2645 srs->sr_state.ctxcsn[j].bv_val = tmp; 2646 srs->sr_state.ctxcsn[j].bv_len = 0; 2647 continue; 2648 } 2649 i++; 2650 } 2651 2652 if (srs->sr_state.numcsns != numcsns) { 2653 /* consumer doesn't have the right number of CSNs */ 2654 changed = SS_CHANGED; 2655 if ( srs->sr_state.ctxcsn ) { 2656 ber_bvarray_free_x( srs->sr_state.ctxcsn, op->o_tmpmemctx ); 2657 srs->sr_state.ctxcsn = NULL; 2658 } 2659 if ( srs->sr_state.sids ) { 2660 slap_sl_free( srs->sr_state.sids, op->o_tmpmemctx ); 2661 srs->sr_state.sids = NULL; 2662 } 2663 srs->sr_state.numcsns = 0; 2664 goto shortcut; 2665 } 2666 2667 /* Find the smallest CSN which differs from contextCSN */ 2668 mincsn.bv_len = 0; 2669 maxcsn.bv_len = 0; 2670 for ( i=0,j=0; i<srs->sr_state.numcsns; i++ ) { 2671 int newer; 2672 while ( srs->sr_state.sids[i] != sids[j] ) j++; 2673 if ( BER_BVISEMPTY( &maxcsn ) || ber_bvcmp( &maxcsn, 2674 &srs->sr_state.ctxcsn[i] ) < 0 ) { 2675 maxcsn = srs->sr_state.ctxcsn[i]; 2676 maxsid = sids[j]; 2677 } 2678 newer = ber_bvcmp( &srs->sr_state.ctxcsn[i], &ctxcsn[j] ); 2679 /* If our state is newer, tell consumer about changes */ 2680 if ( newer < 0) { 2681 changed = SS_CHANGED; 2682 if ( BER_BVISEMPTY( &mincsn ) || ber_bvcmp( &mincsn, 2683 &srs->sr_state.ctxcsn[i] ) > 0 ) { 2684 mincsn = srs->sr_state.ctxcsn[i]; 2685 minsid = sids[j]; 2686 } 2687 } else if ( newer > 0 && sids[j] == slap_serverID ) { 2688 /* our state is older, complain to consumer */ 2689 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 2690 rs->sr_text = "consumer state is newer than provider!"; 2691 bailout: 2692 if ( sop ) { 2693 syncops **sp = &si->si_ops; 2694 2695 ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); 2696 while ( *sp != sop ) 2697 sp = &(*sp)->s_next; 2698 *sp = sop->s_next; 2699 ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); 2700 ch_free( sop ); 2701 } 2702 rs->sr_ctrls = NULL; 2703 send_ldap_result( op, rs ); 2704 return rs->sr_err; 2705 } 2706 } 2707 if ( BER_BVISEMPTY( &mincsn )) { 2708 mincsn = maxcsn; 2709 minsid = maxsid; 2710 } 2711 2712 /* If nothing has changed, shortcut it */ 2713 if ( !changed && !dirty ) { 2714 do_present = 0; 2715 no_change: if ( !(op->o_sync_mode & SLAP_SYNC_PERSIST) ) { 2716 LDAPControl *ctrls[2]; 2717 2718 ctrls[0] = NULL; 2719 ctrls[1] = NULL; 2720 syncprov_done_ctrl( op, rs, ctrls, 0, 0, 2721 NULL, LDAP_SYNC_REFRESH_DELETES ); 2722 rs->sr_ctrls = ctrls; 2723 rs->sr_err = LDAP_SUCCESS; 2724 send_ldap_result( op, rs ); 2725 rs->sr_ctrls = NULL; 2726 return rs->sr_err; 2727 } 2728 goto shortcut; 2729 } 2730 2731 /* Do we have a sessionlog for this search? */ 2732 sl=si->si_logs; 2733 if ( sl ) { 2734 int do_play = 0; 2735 ldap_pvt_thread_mutex_lock( &sl->sl_mutex ); 2736 /* Are there any log entries, and is the consumer state 2737 * present in the session log? 2738 */ 2739 if ( sl->sl_num > 0 ) { 2740 int i; 2741 for ( i=0; i<sl->sl_numcsns; i++ ) { 2742 /* SID not present == new enough */ 2743 if ( minsid < sl->sl_sids[i] ) { 2744 do_play = 1; 2745 break; 2746 } 2747 /* SID present */ 2748 if ( minsid == sl->sl_sids[i] ) { 2749 /* new enough? */ 2750 if ( ber_bvcmp( &mincsn, &sl->sl_mincsn[i] ) >= 0 ) 2751 do_play = 1; 2752 break; 2753 } 2754 } 2755 /* SID not present == new enough */ 2756 if ( i == sl->sl_numcsns ) 2757 do_play = 1; 2758 } 2759 if ( do_play ) { 2760 do_present = 0; 2761 /* mutex is unlocked in playlog */ 2762 syncprov_playlog( op, rs, sl, srs, ctxcsn, numcsns, sids ); 2763 } else { 2764 ldap_pvt_thread_mutex_unlock( &sl->sl_mutex ); 2765 } 2766 } 2767 /* Is the CSN still present in the database? */ 2768 if ( syncprov_findcsn( op, FIND_CSN, &mincsn ) != LDAP_SUCCESS ) { 2769 /* No, so a reload is required */ 2770 /* the 2.2 consumer doesn't send this hint */ 2771 if ( si->si_usehint && srs->sr_rhint == 0 ) { 2772 if ( ctxcsn ) 2773 ber_bvarray_free_x( ctxcsn, op->o_tmpmemctx ); 2774 if ( sids ) 2775 op->o_tmpfree( sids, op->o_tmpmemctx ); 2776 rs->sr_err = LDAP_SYNC_REFRESH_REQUIRED; 2777 rs->sr_text = "sync cookie is stale"; 2778 goto bailout; 2779 } 2780 if ( srs->sr_state.ctxcsn ) { 2781 ber_bvarray_free_x( srs->sr_state.ctxcsn, op->o_tmpmemctx ); 2782 srs->sr_state.ctxcsn = NULL; 2783 } 2784 if ( srs->sr_state.sids ) { 2785 slap_sl_free( srs->sr_state.sids, op->o_tmpmemctx ); 2786 srs->sr_state.sids = NULL; 2787 } 2788 srs->sr_state.numcsns = 0; 2789 } else { 2790 gotstate = 1; 2791 /* If changed and doing Present lookup, send Present UUIDs */ 2792 if ( do_present && syncprov_findcsn( op, FIND_PRESENT, 0 ) != 2793 LDAP_SUCCESS ) { 2794 if ( ctxcsn ) 2795 ber_bvarray_free_x( ctxcsn, op->o_tmpmemctx ); 2796 if ( sids ) 2797 op->o_tmpfree( sids, op->o_tmpmemctx ); 2798 goto bailout; 2799 } 2800 } 2801 } else { 2802 /* The consumer knows nothing, we know nothing. OK. */ 2803 if (!numcsns) 2804 goto no_change; 2805 /* No consumer state, assume something has changed */ 2806 changed = SS_CHANGED; 2807 } 2808 2809 shortcut: 2810 /* Append CSN range to search filter, save original filter 2811 * for persistent search evaluation 2812 */ 2813 if ( sop ) { 2814 ldap_pvt_thread_mutex_lock( &sop->s_mutex ); 2815 sop->s_filterstr = op->ors_filterstr; 2816 /* correct the refcount that was set to 2 before */ 2817 sop->s_inuse--; 2818 } 2819 2820 /* If something changed, find the changes */ 2821 if ( gotstate && ( changed || dirty ) ) { 2822 Filter *fand, *fava; 2823 2824 fand = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx ); 2825 fand->f_choice = LDAP_FILTER_AND; 2826 fand->f_next = NULL; 2827 fava = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx ); 2828 fand->f_and = fava; 2829 fava->f_choice = LDAP_FILTER_GE; 2830 fava->f_ava = op->o_tmpalloc( sizeof(AttributeAssertion), op->o_tmpmemctx ); 2831 fava->f_ava->aa_desc = slap_schema.si_ad_entryCSN; 2832 #ifdef LDAP_COMP_MATCH 2833 fava->f_ava->aa_cf = NULL; 2834 #endif 2835 ber_dupbv_x( &fava->f_ava->aa_value, &mincsn, op->o_tmpmemctx ); 2836 fava->f_next = op->ors_filter; 2837 op->ors_filter = fand; 2838 filter2bv_x( op, op->ors_filter, &op->ors_filterstr ); 2839 if ( sop ) { 2840 sop->s_flags |= PS_FIX_FILTER; 2841 } 2842 } 2843 if ( sop ) { 2844 ldap_pvt_thread_mutex_unlock( &sop->s_mutex ); 2845 } 2846 2847 /* Let our callback add needed info to returned entries */ 2848 cb = op->o_tmpcalloc(1, sizeof(slap_callback)+sizeof(searchstate), op->o_tmpmemctx); 2849 ss = (searchstate *)(cb+1); 2850 ss->ss_on = on; 2851 ss->ss_so = sop; 2852 ss->ss_flags = do_present | changed; 2853 ss->ss_ctxcsn = ctxcsn; 2854 ss->ss_numcsns = numcsns; 2855 ss->ss_sids = sids; 2856 cb->sc_response = syncprov_search_response; 2857 cb->sc_private = ss; 2858 cb->sc_next = op->o_callback; 2859 op->o_callback = cb; 2860 2861 /* If this is a persistent search and no changes were reported during 2862 * the refresh phase, just invoke the response callback to transition 2863 * us into persist phase 2864 */ 2865 if ( !changed && !dirty ) { 2866 rs->sr_err = LDAP_SUCCESS; 2867 rs->sr_nentries = 0; 2868 send_ldap_result( op, rs ); 2869 return rs->sr_err; 2870 } 2871 return SLAP_CB_CONTINUE; 2872 } 2873 2874 static int 2875 syncprov_operational( 2876 Operation *op, 2877 SlapReply *rs ) 2878 { 2879 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 2880 syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private; 2881 2882 /* This prevents generating unnecessarily; frontend will strip 2883 * any statically stored copy. 2884 */ 2885 if ( op->o_sync != SLAP_CONTROL_NONE ) 2886 return SLAP_CB_CONTINUE; 2887 2888 if ( rs->sr_entry && 2889 dn_match( &rs->sr_entry->e_nname, &si->si_contextdn )) { 2890 2891 if ( SLAP_OPATTRS( rs->sr_attr_flags ) || 2892 ad_inlist( slap_schema.si_ad_contextCSN, rs->sr_attrs )) { 2893 Attribute *a, **ap = NULL; 2894 2895 for ( a=rs->sr_entry->e_attrs; a; a=a->a_next ) { 2896 if ( a->a_desc == slap_schema.si_ad_contextCSN ) 2897 break; 2898 } 2899 2900 ldap_pvt_thread_rdwr_rlock( &si->si_csn_rwlock ); 2901 if ( si->si_ctxcsn ) { 2902 if ( !a ) { 2903 for ( ap = &rs->sr_operational_attrs; *ap; 2904 ap=&(*ap)->a_next ); 2905 2906 a = attr_alloc( slap_schema.si_ad_contextCSN ); 2907 *ap = a; 2908 } 2909 2910 if ( !ap ) { 2911 if ( rs_entry2modifiable( op, rs, on )) { 2912 a = attr_find( rs->sr_entry->e_attrs, 2913 slap_schema.si_ad_contextCSN ); 2914 } 2915 if ( a->a_nvals != a->a_vals ) { 2916 ber_bvarray_free( a->a_nvals ); 2917 } 2918 a->a_nvals = NULL; 2919 ber_bvarray_free( a->a_vals ); 2920 a->a_vals = NULL; 2921 a->a_numvals = 0; 2922 } 2923 attr_valadd( a, si->si_ctxcsn, si->si_ctxcsn, si->si_numcsns ); 2924 } 2925 ldap_pvt_thread_rdwr_runlock( &si->si_csn_rwlock ); 2926 } 2927 } 2928 return SLAP_CB_CONTINUE; 2929 } 2930 2931 enum { 2932 SP_CHKPT = 1, 2933 SP_SESSL, 2934 SP_NOPRES, 2935 SP_USEHINT 2936 }; 2937 2938 static ConfigDriver sp_cf_gen; 2939 2940 static ConfigTable spcfg[] = { 2941 { "syncprov-checkpoint", "ops> <minutes", 3, 3, 0, ARG_MAGIC|SP_CHKPT, 2942 sp_cf_gen, "( OLcfgOvAt:1.1 NAME 'olcSpCheckpoint' " 2943 "DESC 'ContextCSN checkpoint interval in ops and minutes' " 2944 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, 2945 { "syncprov-sessionlog", "ops", 2, 2, 0, ARG_INT|ARG_MAGIC|SP_SESSL, 2946 sp_cf_gen, "( OLcfgOvAt:1.2 NAME 'olcSpSessionlog' " 2947 "DESC 'Session log size in ops' " 2948 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, 2949 { "syncprov-nopresent", NULL, 2, 2, 0, ARG_ON_OFF|ARG_MAGIC|SP_NOPRES, 2950 sp_cf_gen, "( OLcfgOvAt:1.3 NAME 'olcSpNoPresent' " 2951 "DESC 'Omit Present phase processing' " 2952 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 2953 { "syncprov-reloadhint", NULL, 2, 2, 0, ARG_ON_OFF|ARG_MAGIC|SP_USEHINT, 2954 sp_cf_gen, "( OLcfgOvAt:1.4 NAME 'olcSpReloadHint' " 2955 "DESC 'Observe Reload Hint in Request control' " 2956 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 2957 { NULL, NULL, 0, 0, 0, ARG_IGNORED } 2958 }; 2959 2960 static ConfigOCs spocs[] = { 2961 { "( OLcfgOvOc:1.1 " 2962 "NAME 'olcSyncProvConfig' " 2963 "DESC 'SyncRepl Provider configuration' " 2964 "SUP olcOverlayConfig " 2965 "MAY ( olcSpCheckpoint " 2966 "$ olcSpSessionlog " 2967 "$ olcSpNoPresent " 2968 "$ olcSpReloadHint " 2969 ") )", 2970 Cft_Overlay, spcfg }, 2971 { NULL, 0, NULL } 2972 }; 2973 2974 static int 2975 sp_cf_gen(ConfigArgs *c) 2976 { 2977 slap_overinst *on = (slap_overinst *)c->bi; 2978 syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private; 2979 int rc = 0; 2980 2981 if ( c->op == SLAP_CONFIG_EMIT ) { 2982 switch ( c->type ) { 2983 case SP_CHKPT: 2984 if ( si->si_chkops || si->si_chktime ) { 2985 struct berval bv; 2986 /* we assume si_chktime is a multiple of 60 2987 * because the parsed value was originally 2988 * multiplied by 60 */ 2989 bv.bv_len = snprintf( c->cr_msg, sizeof( c->cr_msg ), 2990 "%d %d", si->si_chkops, si->si_chktime/60 ); 2991 if ( bv.bv_len >= sizeof( c->cr_msg ) ) { 2992 rc = 1; 2993 } else { 2994 bv.bv_val = c->cr_msg; 2995 value_add_one( &c->rvalue_vals, &bv ); 2996 } 2997 } else { 2998 rc = 1; 2999 } 3000 break; 3001 case SP_SESSL: 3002 if ( si->si_logs ) { 3003 c->value_int = si->si_logs->sl_size; 3004 } else { 3005 rc = 1; 3006 } 3007 break; 3008 case SP_NOPRES: 3009 if ( si->si_nopres ) { 3010 c->value_int = 1; 3011 } else { 3012 rc = 1; 3013 } 3014 break; 3015 case SP_USEHINT: 3016 if ( si->si_usehint ) { 3017 c->value_int = 1; 3018 } else { 3019 rc = 1; 3020 } 3021 break; 3022 } 3023 return rc; 3024 } else if ( c->op == LDAP_MOD_DELETE ) { 3025 switch ( c->type ) { 3026 case SP_CHKPT: 3027 si->si_chkops = 0; 3028 si->si_chktime = 0; 3029 break; 3030 case SP_SESSL: 3031 si->si_logs->sl_size = 0; 3032 break; 3033 case SP_NOPRES: 3034 si->si_nopres = 0; 3035 break; 3036 case SP_USEHINT: 3037 si->si_usehint = 0; 3038 break; 3039 } 3040 return rc; 3041 } 3042 switch ( c->type ) { 3043 case SP_CHKPT: 3044 if ( lutil_atoi( &si->si_chkops, c->argv[1] ) != 0 ) { 3045 snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s unable to parse checkpoint ops # \"%s\"", 3046 c->argv[0], c->argv[1] ); 3047 Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, 3048 "%s: %s\n", c->log, c->cr_msg, 0 ); 3049 return ARG_BAD_CONF; 3050 } 3051 if ( si->si_chkops <= 0 ) { 3052 snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s invalid checkpoint ops # \"%d\"", 3053 c->argv[0], si->si_chkops ); 3054 Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, 3055 "%s: %s\n", c->log, c->cr_msg, 0 ); 3056 return ARG_BAD_CONF; 3057 } 3058 if ( lutil_atoi( &si->si_chktime, c->argv[2] ) != 0 ) { 3059 snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s unable to parse checkpoint time \"%s\"", 3060 c->argv[0], c->argv[1] ); 3061 Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, 3062 "%s: %s\n", c->log, c->cr_msg, 0 ); 3063 return ARG_BAD_CONF; 3064 } 3065 if ( si->si_chktime <= 0 ) { 3066 snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s invalid checkpoint time \"%d\"", 3067 c->argv[0], si->si_chkops ); 3068 Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, 3069 "%s: %s\n", c->log, c->cr_msg, 0 ); 3070 return ARG_BAD_CONF; 3071 } 3072 si->si_chktime *= 60; 3073 break; 3074 case SP_SESSL: { 3075 sessionlog *sl; 3076 int size = c->value_int; 3077 3078 if ( size < 0 ) { 3079 snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s size %d is negative", 3080 c->argv[0], size ); 3081 Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, 3082 "%s: %s\n", c->log, c->cr_msg, 0 ); 3083 return ARG_BAD_CONF; 3084 } 3085 sl = si->si_logs; 3086 if ( !sl ) { 3087 sl = ch_malloc( sizeof( sessionlog )); 3088 sl->sl_mincsn = NULL; 3089 sl->sl_sids = NULL; 3090 sl->sl_num = 0; 3091 sl->sl_numcsns = 0; 3092 sl->sl_head = sl->sl_tail = NULL; 3093 ldap_pvt_thread_mutex_init( &sl->sl_mutex ); 3094 si->si_logs = sl; 3095 } 3096 sl->sl_size = size; 3097 } 3098 break; 3099 case SP_NOPRES: 3100 si->si_nopres = c->value_int; 3101 break; 3102 case SP_USEHINT: 3103 si->si_usehint = c->value_int; 3104 break; 3105 } 3106 return rc; 3107 } 3108 3109 /* ITS#3456 we cannot run this search on the main thread, must use a 3110 * child thread in order to insure we have a big enough stack. 3111 */ 3112 static void * 3113 syncprov_db_otask( 3114 void *ptr 3115 ) 3116 { 3117 syncprov_findcsn( ptr, FIND_MAXCSN, 0 ); 3118 return NULL; 3119 } 3120 3121 3122 /* Read any existing contextCSN from the underlying db. 3123 * Then search for any entries newer than that. If no value exists, 3124 * just generate it. Cache whatever result. 3125 */ 3126 static int 3127 syncprov_db_open( 3128 BackendDB *be, 3129 ConfigReply *cr 3130 ) 3131 { 3132 slap_overinst *on = (slap_overinst *) be->bd_info; 3133 syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private; 3134 3135 Connection conn = { 0 }; 3136 OperationBuffer opbuf; 3137 Operation *op; 3138 Entry *e = NULL; 3139 Attribute *a; 3140 int rc; 3141 void *thrctx = NULL; 3142 3143 if ( !SLAP_LASTMOD( be )) { 3144 Debug( LDAP_DEBUG_ANY, 3145 "syncprov_db_open: invalid config, lastmod must be enabled\n", 0, 0, 0 ); 3146 return -1; 3147 } 3148 3149 if ( slapMode & SLAP_TOOL_MODE ) { 3150 return 0; 3151 } 3152 3153 rc = overlay_register_control( be, LDAP_CONTROL_SYNC ); 3154 if ( rc ) { 3155 return rc; 3156 } 3157 3158 thrctx = ldap_pvt_thread_pool_context(); 3159 connection_fake_init2( &conn, &opbuf, thrctx, 0 ); 3160 op = &opbuf.ob_op; 3161 op->o_bd = be; 3162 op->o_dn = be->be_rootdn; 3163 op->o_ndn = be->be_rootndn; 3164 3165 if ( SLAP_SYNC_SUBENTRY( be )) { 3166 build_new_dn( &si->si_contextdn, be->be_nsuffix, 3167 (struct berval *)&slap_ldapsync_cn_bv, NULL ); 3168 } else { 3169 si->si_contextdn = be->be_nsuffix[0]; 3170 } 3171 rc = overlay_entry_get_ov( op, &si->si_contextdn, NULL, 3172 slap_schema.si_ad_contextCSN, 0, &e, on ); 3173 3174 if ( e ) { 3175 ldap_pvt_thread_t tid; 3176 3177 a = attr_find( e->e_attrs, slap_schema.si_ad_contextCSN ); 3178 if ( a ) { 3179 ber_bvarray_dup_x( &si->si_ctxcsn, a->a_vals, NULL ); 3180 si->si_numcsns = a->a_numvals; 3181 si->si_sids = slap_parse_csn_sids( si->si_ctxcsn, a->a_numvals, NULL ); 3182 slap_sort_csn_sids( si->si_ctxcsn, si->si_sids, si->si_numcsns, NULL ); 3183 } 3184 overlay_entry_release_ov( op, e, 0, on ); 3185 if ( si->si_ctxcsn && !SLAP_DBCLEAN( be )) { 3186 op->o_tag = LDAP_REQ_SEARCH; 3187 op->o_req_dn = be->be_suffix[0]; 3188 op->o_req_ndn = be->be_nsuffix[0]; 3189 op->ors_scope = LDAP_SCOPE_SUBTREE; 3190 ldap_pvt_thread_create( &tid, 0, syncprov_db_otask, op ); 3191 ldap_pvt_thread_join( tid, NULL ); 3192 } 3193 } 3194 3195 /* Didn't find a contextCSN, should we generate one? */ 3196 if ( !si->si_ctxcsn ) { 3197 char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ]; 3198 struct berval csn; 3199 3200 if ( SLAP_SINGLE_SHADOW( op->o_bd ) ) { 3201 /* Not in charge of this serverID, don't generate anything. */ 3202 goto out; 3203 } 3204 if ( !SLAP_SYNC_SUBENTRY( be ) && rc != LDAP_SUCCESS 3205 && rc != LDAP_NO_SUCH_ATTRIBUTE ) { 3206 /* If the DB is genuinely empty, don't generate one either. */ 3207 goto out; 3208 } 3209 csn.bv_val = csnbuf; 3210 csn.bv_len = sizeof( csnbuf ); 3211 slap_get_csn( op, &csn, 0 ); 3212 value_add_one( &si->si_ctxcsn, &csn ); 3213 si->si_numcsns = 1; 3214 si->si_sids = ch_malloc( sizeof(int) ); 3215 si->si_sids[0] = slap_serverID; 3216 3217 /* make sure we do a checkpoint on close */ 3218 si->si_numops++; 3219 } 3220 3221 /* Initialize the sessionlog mincsn */ 3222 if ( si->si_logs && si->si_numcsns ) { 3223 sessionlog *sl = si->si_logs; 3224 int i; 3225 ber_bvarray_dup_x( &sl->sl_mincsn, si->si_ctxcsn, NULL ); 3226 sl->sl_numcsns = si->si_numcsns; 3227 sl->sl_sids = ch_malloc( si->si_numcsns * sizeof(int) ); 3228 for ( i=0; i < si->si_numcsns; i++ ) 3229 sl->sl_sids[i] = si->si_sids[i]; 3230 } 3231 3232 out: 3233 op->o_bd->bd_info = (BackendInfo *)on; 3234 return 0; 3235 } 3236 3237 /* Write the current contextCSN into the underlying db. 3238 */ 3239 static int 3240 syncprov_db_close( 3241 BackendDB *be, 3242 ConfigReply *cr 3243 ) 3244 { 3245 slap_overinst *on = (slap_overinst *) be->bd_info; 3246 syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private; 3247 #ifdef SLAP_CONFIG_DELETE 3248 syncops *so, *sonext; 3249 #endif /* SLAP_CONFIG_DELETE */ 3250 3251 if ( slapMode & SLAP_TOOL_MODE ) { 3252 return 0; 3253 } 3254 if ( si->si_numops ) { 3255 Connection conn = {0}; 3256 OperationBuffer opbuf; 3257 Operation *op; 3258 void *thrctx; 3259 3260 thrctx = ldap_pvt_thread_pool_context(); 3261 connection_fake_init2( &conn, &opbuf, thrctx, 0 ); 3262 op = &opbuf.ob_op; 3263 op->o_bd = be; 3264 op->o_dn = be->be_rootdn; 3265 op->o_ndn = be->be_rootndn; 3266 syncprov_checkpoint( op, on ); 3267 } 3268 3269 #ifdef SLAP_CONFIG_DELETE 3270 if ( !slapd_shutdown ) { 3271 ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); 3272 for ( so=si->si_ops, sonext=so; so; so=sonext ) { 3273 SlapReply rs = {REP_RESULT}; 3274 rs.sr_err = LDAP_UNAVAILABLE; 3275 send_ldap_result( so->s_op, &rs ); 3276 sonext=so->s_next; 3277 syncprov_drop_psearch( so, 0); 3278 } 3279 si->si_ops=NULL; 3280 ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); 3281 } 3282 overlay_unregister_control( be, LDAP_CONTROL_SYNC ); 3283 #endif /* SLAP_CONFIG_DELETE */ 3284 3285 return 0; 3286 } 3287 3288 static int 3289 syncprov_db_init( 3290 BackendDB *be, 3291 ConfigReply *cr 3292 ) 3293 { 3294 slap_overinst *on = (slap_overinst *)be->bd_info; 3295 syncprov_info_t *si; 3296 3297 if ( SLAP_ISGLOBALOVERLAY( be ) ) { 3298 Debug( LDAP_DEBUG_ANY, 3299 "syncprov must be instantiated within a database.\n", 3300 0, 0, 0 ); 3301 return 1; 3302 } 3303 3304 si = ch_calloc(1, sizeof(syncprov_info_t)); 3305 on->on_bi.bi_private = si; 3306 ldap_pvt_thread_rdwr_init( &si->si_csn_rwlock ); 3307 ldap_pvt_thread_mutex_init( &si->si_ops_mutex ); 3308 ldap_pvt_thread_mutex_init( &si->si_mods_mutex ); 3309 ldap_pvt_thread_mutex_init( &si->si_resp_mutex ); 3310 3311 csn_anlist[0].an_desc = slap_schema.si_ad_entryCSN; 3312 csn_anlist[0].an_name = slap_schema.si_ad_entryCSN->ad_cname; 3313 csn_anlist[1].an_desc = slap_schema.si_ad_entryUUID; 3314 csn_anlist[1].an_name = slap_schema.si_ad_entryUUID->ad_cname; 3315 3316 uuid_anlist[0].an_desc = slap_schema.si_ad_entryUUID; 3317 uuid_anlist[0].an_name = slap_schema.si_ad_entryUUID->ad_cname; 3318 3319 return 0; 3320 } 3321 3322 static int 3323 syncprov_db_destroy( 3324 BackendDB *be, 3325 ConfigReply *cr 3326 ) 3327 { 3328 slap_overinst *on = (slap_overinst *)be->bd_info; 3329 syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private; 3330 3331 if ( si ) { 3332 if ( si->si_logs ) { 3333 sessionlog *sl = si->si_logs; 3334 slog_entry *se = sl->sl_head; 3335 3336 while ( se ) { 3337 slog_entry *se_next = se->se_next; 3338 ch_free( se ); 3339 se = se_next; 3340 } 3341 if ( sl->sl_mincsn ) 3342 ber_bvarray_free( sl->sl_mincsn ); 3343 if ( sl->sl_sids ) 3344 ch_free( sl->sl_sids ); 3345 3346 ldap_pvt_thread_mutex_destroy(&si->si_logs->sl_mutex); 3347 ch_free( si->si_logs ); 3348 } 3349 if ( si->si_ctxcsn ) 3350 ber_bvarray_free( si->si_ctxcsn ); 3351 if ( si->si_sids ) 3352 ch_free( si->si_sids ); 3353 ldap_pvt_thread_mutex_destroy( &si->si_resp_mutex ); 3354 ldap_pvt_thread_mutex_destroy( &si->si_mods_mutex ); 3355 ldap_pvt_thread_mutex_destroy( &si->si_ops_mutex ); 3356 ldap_pvt_thread_rdwr_destroy( &si->si_csn_rwlock ); 3357 ch_free( si ); 3358 } 3359 3360 return 0; 3361 } 3362 3363 static int syncprov_parseCtrl ( 3364 Operation *op, 3365 SlapReply *rs, 3366 LDAPControl *ctrl ) 3367 { 3368 ber_tag_t tag; 3369 BerElementBuffer berbuf; 3370 BerElement *ber = (BerElement *)&berbuf; 3371 ber_int_t mode; 3372 ber_len_t len; 3373 struct berval cookie = BER_BVNULL; 3374 sync_control *sr; 3375 int rhint = 0; 3376 3377 if ( op->o_sync != SLAP_CONTROL_NONE ) { 3378 rs->sr_text = "Sync control specified multiple times"; 3379 return LDAP_PROTOCOL_ERROR; 3380 } 3381 3382 if ( op->o_pagedresults != SLAP_CONTROL_NONE ) { 3383 rs->sr_text = "Sync control specified with pagedResults control"; 3384 return LDAP_PROTOCOL_ERROR; 3385 } 3386 3387 if ( BER_BVISNULL( &ctrl->ldctl_value ) ) { 3388 rs->sr_text = "Sync control value is absent"; 3389 return LDAP_PROTOCOL_ERROR; 3390 } 3391 3392 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) { 3393 rs->sr_text = "Sync control value is empty"; 3394 return LDAP_PROTOCOL_ERROR; 3395 } 3396 3397 /* Parse the control value 3398 * syncRequestValue ::= SEQUENCE { 3399 * mode ENUMERATED { 3400 * -- 0 unused 3401 * refreshOnly (1), 3402 * -- 2 reserved 3403 * refreshAndPersist (3) 3404 * }, 3405 * cookie syncCookie OPTIONAL 3406 * } 3407 */ 3408 3409 ber_init2( ber, &ctrl->ldctl_value, 0 ); 3410 3411 if ( (tag = ber_scanf( ber, "{i" /*}*/, &mode )) == LBER_ERROR ) { 3412 rs->sr_text = "Sync control : mode decoding error"; 3413 return LDAP_PROTOCOL_ERROR; 3414 } 3415 3416 switch( mode ) { 3417 case LDAP_SYNC_REFRESH_ONLY: 3418 mode = SLAP_SYNC_REFRESH; 3419 break; 3420 case LDAP_SYNC_REFRESH_AND_PERSIST: 3421 mode = SLAP_SYNC_REFRESH_AND_PERSIST; 3422 break; 3423 default: 3424 rs->sr_text = "Sync control : unknown update mode"; 3425 return LDAP_PROTOCOL_ERROR; 3426 } 3427 3428 tag = ber_peek_tag( ber, &len ); 3429 3430 if ( tag == LDAP_TAG_SYNC_COOKIE ) { 3431 if (( ber_scanf( ber, /*{*/ "m", &cookie )) == LBER_ERROR ) { 3432 rs->sr_text = "Sync control : cookie decoding error"; 3433 return LDAP_PROTOCOL_ERROR; 3434 } 3435 tag = ber_peek_tag( ber, &len ); 3436 } 3437 if ( tag == LDAP_TAG_RELOAD_HINT ) { 3438 if (( ber_scanf( ber, /*{*/ "b", &rhint )) == LBER_ERROR ) { 3439 rs->sr_text = "Sync control : rhint decoding error"; 3440 return LDAP_PROTOCOL_ERROR; 3441 } 3442 } 3443 if (( ber_scanf( ber, /*{*/ "}")) == LBER_ERROR ) { 3444 rs->sr_text = "Sync control : decoding error"; 3445 return LDAP_PROTOCOL_ERROR; 3446 } 3447 sr = op->o_tmpcalloc( 1, sizeof(struct sync_control), op->o_tmpmemctx ); 3448 sr->sr_rhint = rhint; 3449 if (!BER_BVISNULL(&cookie)) { 3450 ber_dupbv_x( &sr->sr_state.octet_str, &cookie, op->o_tmpmemctx ); 3451 /* If parse fails, pretend no cookie was sent */ 3452 if ( slap_parse_sync_cookie( &sr->sr_state, op->o_tmpmemctx ) || 3453 sr->sr_state.rid == -1 ) { 3454 if ( sr->sr_state.ctxcsn ) { 3455 ber_bvarray_free_x( sr->sr_state.ctxcsn, op->o_tmpmemctx ); 3456 sr->sr_state.ctxcsn = NULL; 3457 } 3458 sr->sr_state.numcsns = 0; 3459 } 3460 } 3461 3462 op->o_controls[slap_cids.sc_LDAPsync] = sr; 3463 3464 op->o_sync = ctrl->ldctl_iscritical 3465 ? SLAP_CONTROL_CRITICAL 3466 : SLAP_CONTROL_NONCRITICAL; 3467 3468 op->o_sync_mode |= mode; /* o_sync_mode shares o_sync */ 3469 3470 return LDAP_SUCCESS; 3471 } 3472 3473 /* This overlay is set up for dynamic loading via moduleload. For static 3474 * configuration, you'll need to arrange for the slap_overinst to be 3475 * initialized and registered by some other function inside slapd. 3476 */ 3477 3478 static slap_overinst syncprov; 3479 3480 int 3481 syncprov_initialize() 3482 { 3483 int rc; 3484 3485 rc = register_supported_control( LDAP_CONTROL_SYNC, 3486 SLAP_CTRL_SEARCH, NULL, 3487 syncprov_parseCtrl, &slap_cids.sc_LDAPsync ); 3488 if ( rc != LDAP_SUCCESS ) { 3489 Debug( LDAP_DEBUG_ANY, 3490 "syncprov_init: Failed to register control %d\n", rc, 0, 0 ); 3491 return rc; 3492 } 3493 3494 syncprov.on_bi.bi_type = "syncprov"; 3495 syncprov.on_bi.bi_db_init = syncprov_db_init; 3496 syncprov.on_bi.bi_db_destroy = syncprov_db_destroy; 3497 syncprov.on_bi.bi_db_open = syncprov_db_open; 3498 syncprov.on_bi.bi_db_close = syncprov_db_close; 3499 3500 syncprov.on_bi.bi_op_abandon = syncprov_op_abandon; 3501 syncprov.on_bi.bi_op_cancel = syncprov_op_abandon; 3502 3503 syncprov.on_bi.bi_op_add = syncprov_op_mod; 3504 syncprov.on_bi.bi_op_compare = syncprov_op_compare; 3505 syncprov.on_bi.bi_op_delete = syncprov_op_mod; 3506 syncprov.on_bi.bi_op_modify = syncprov_op_mod; 3507 syncprov.on_bi.bi_op_modrdn = syncprov_op_mod; 3508 syncprov.on_bi.bi_op_search = syncprov_op_search; 3509 syncprov.on_bi.bi_extended = syncprov_op_extended; 3510 syncprov.on_bi.bi_operational = syncprov_operational; 3511 3512 syncprov.on_bi.bi_cf_ocs = spocs; 3513 3514 generic_filter.f_desc = slap_schema.si_ad_objectClass; 3515 3516 rc = config_register_schema( spcfg, spocs ); 3517 if ( rc ) return rc; 3518 3519 return overlay_register( &syncprov ); 3520 } 3521 3522 #if SLAPD_OVER_SYNCPROV == SLAPD_MOD_DYNAMIC 3523 int 3524 init_module( int argc, char *argv[] ) 3525 { 3526 return syncprov_initialize(); 3527 } 3528 #endif /* SLAPD_OVER_SYNCPROV == SLAPD_MOD_DYNAMIC */ 3529 3530 #endif /* defined(SLAPD_OVER_SYNCPROV) */ 3531