1 /* $NetBSD: syncrepl.c,v 1.3 2021/08/14 16:14:58 christos Exp $ */ 2 3 /* syncrepl.c -- Replication Engine which uses the LDAP Sync protocol */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2003-2021 The OpenLDAP Foundation. 8 * Portions Copyright 2003 by IBM Corporation. 9 * Portions Copyright 2003-2008 by Howard Chu, Symas Corporation. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted only as authorized by the OpenLDAP 14 * Public License. 15 * 16 * A copy of this license is available in the file LICENSE in the 17 * top-level directory of the distribution or, alternatively, at 18 * <http://www.OpenLDAP.org/license.html>. 19 */ 20 21 #include <sys/cdefs.h> 22 __RCSID("$NetBSD: syncrepl.c,v 1.3 2021/08/14 16:14:58 christos Exp $"); 23 24 #include "portable.h" 25 26 #include <stdio.h> 27 28 #include <ac/string.h> 29 #include <ac/socket.h> 30 31 #include "lutil.h" 32 #include "slap.h" 33 #include "lutil_ldap.h" 34 35 #include "slap-config.h" 36 37 #include "ldap_rq.h" 38 39 #include "rewrite.h" 40 41 #include "back-monitor/back-monitor.h" 42 43 #define SUFFIXM_CTX "<suffix massage>" 44 45 #ifdef LDAP_CONTROL_X_DIRSYNC 46 #define MSAD_DIRSYNC 0x04 47 #define MSAD_DIRSYNC_MODIFY 0x10 48 49 static AttributeDescription *sy_ad_objectGUID; 50 static AttributeDescription *sy_ad_instanceType; 51 static AttributeDescription *sy_ad_isDeleted; 52 static AttributeDescription *sy_ad_whenCreated; 53 static AttributeDescription *sy_ad_dirSyncCookie; 54 55 static struct berval msad_addval = BER_BVC("range=1-1"); 56 static struct berval msad_delval = BER_BVC("range=0-0"); 57 #endif 58 59 static AttributeDescription *sy_ad_nsUniqueId; 60 static AttributeDescription *sy_ad_dseeLastChange; 61 62 #define DSEE_SYNC_ADD 0x20 63 64 #define UUIDLEN 16 65 66 struct nonpresent_entry { 67 struct berval *npe_name; 68 struct berval *npe_nname; 69 LDAP_LIST_ENTRY(nonpresent_entry) npe_link; 70 }; 71 72 typedef struct cookie_vals { 73 struct berval *cv_vals; 74 int *cv_sids; 75 int cv_num; 76 } cookie_vals; 77 78 typedef struct cookie_state { 79 ldap_pvt_thread_mutex_t cs_mutex; 80 ldap_pvt_thread_cond_t cs_cond; 81 struct berval *cs_vals; 82 int *cs_sids; 83 int cs_num; 84 int cs_age; 85 int cs_ref; 86 int cs_updating; 87 88 /* pending changes, not yet committed */ 89 ldap_pvt_thread_mutex_t cs_pmutex; 90 struct berval *cs_pvals; 91 int *cs_psids; 92 int cs_pnum; 93 } cookie_state; 94 95 #define SYNCDATA_DEFAULT 0 /* entries are plain LDAP entries */ 96 #define SYNCDATA_ACCESSLOG 1 /* entries are accesslog format */ 97 #define SYNCDATA_CHANGELOG 2 /* entries are changelog format */ 98 99 #define SYNCLOG_LOGGING 0 /* doing a log-based update */ 100 #define SYNCLOG_FALLBACK 1 /* doing a full refresh */ 101 102 #define RETRYNUM_FOREVER (-1) /* retry forever */ 103 #define RETRYNUM_TAIL (-2) /* end of retrynum array */ 104 #define RETRYNUM_VALID(n) ((n) >= RETRYNUM_FOREVER) /* valid retrynum */ 105 #define RETRYNUM_FINITE(n) ((n) > RETRYNUM_FOREVER) /* not forever */ 106 107 typedef struct syncinfo_s { 108 struct syncinfo_s *si_next; 109 BackendDB *si_be; 110 BackendDB *si_wbe; 111 struct re_s *si_re; 112 int si_rid; 113 char si_ridtxt[ STRLENOF("rid=999") + 1 ]; 114 slap_bindconf si_bindconf; 115 struct berval si_base; 116 struct berval si_logbase; 117 struct berval si_filterstr; 118 struct berval si_logfilterstr; 119 Filter *si_filter; 120 Filter *si_logfilter; 121 struct berval si_contextdn; 122 int si_scope; 123 int si_attrsonly; 124 char *si_anfile; 125 AttributeName *si_anlist; 126 AttributeName *si_exanlist; 127 char **si_attrs; 128 char **si_exattrs; 129 int si_allattrs; 130 int si_allopattrs; 131 int si_schemachecking; 132 int si_type; /* the active type */ 133 int si_ctype; /* the configured type */ 134 time_t si_interval; 135 time_t *si_retryinterval; 136 int *si_retrynum_init; 137 int *si_retrynum; 138 struct sync_cookie si_syncCookie; 139 cookie_state *si_cookieState; 140 int si_cookieAge; 141 int si_manageDSAit; 142 int si_slimit; 143 int si_tlimit; 144 int si_refreshDelete; 145 int si_refreshPresent; 146 int si_refreshDone; 147 int si_syncdata; 148 int si_logstate; 149 int si_lazyCommit; 150 int si_got; 151 int si_strict_refresh; /* stop listening during fallback refresh */ 152 int si_too_old; 153 int si_is_configdb; 154 ber_int_t si_msgid; 155 Avlnode *si_presentlist; 156 LDAP *si_ld; 157 Connection *si_conn; 158 LDAP_LIST_HEAD(np, nonpresent_entry) si_nonpresentlist; 159 struct rewrite_info *si_rewrite; 160 struct berval si_suffixm; 161 #ifdef LDAP_CONTROL_X_DIRSYNC 162 struct berval si_dirSyncCookie; 163 #endif 164 unsigned long si_prevchange; 165 unsigned long si_lastchange; 166 167 /* monitor info */ 168 int si_monitorInited; 169 time_t si_lastconnect; 170 time_t si_lastcontact; 171 struct berval si_connaddr; 172 struct berval si_lastCookieRcvd; 173 struct berval si_lastCookieSent; 174 struct berval si_monitor_ndn; 175 char si_connaddrbuf[LDAP_IPADDRLEN]; 176 177 ldap_pvt_thread_mutex_t si_monitor_mutex; 178 ldap_pvt_thread_mutex_t si_mutex; 179 } syncinfo_t; 180 181 static int syncuuid_cmp( const void *, const void * ); 182 static int presentlist_insert( syncinfo_t* si, struct berval *syncUUID ); 183 static void presentlist_delete( Avlnode **av, struct berval *syncUUID ); 184 static char *presentlist_find( Avlnode *av, struct berval *syncUUID ); 185 static int presentlist_free( Avlnode *av ); 186 static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct sync_cookie *, int ); 187 static int syncrepl_message_to_op( 188 syncinfo_t *, Operation *, LDAPMessage *, int ); 189 static int syncrepl_message_to_entry( 190 syncinfo_t *, Operation *, LDAPMessage *, 191 Modifications **, Entry **, int, struct berval* ); 192 static int syncrepl_entry( 193 syncinfo_t *, Operation*, Entry*, 194 Modifications**,int, struct berval*, 195 struct berval *cookieCSN ); 196 static int syncrepl_updateCookie( 197 syncinfo_t *, Operation *, 198 struct sync_cookie *, int save ); 199 static struct berval * slap_uuidstr_from_normalized( 200 struct berval *, struct berval *, void * ); 201 static int syncrepl_add_glue_ancestors( 202 Operation* op, Entry *e ); 203 204 #ifdef LDAP_CONTROL_X_DIRSYNC 205 static int syncrepl_dirsync_message( 206 syncinfo_t *, Operation *, LDAPMessage *, 207 Modifications **, Entry **, int *, struct berval* ); 208 static int syncrepl_dirsync_cookie( 209 syncinfo_t *, Operation *, LDAPControl ** ); 210 #endif 211 212 static int syncrepl_dsee_update( syncinfo_t *si, Operation *op ) ; 213 214 /* delta-mpr overlay handler */ 215 static int syncrepl_op_modify( Operation *op, SlapReply *rs ); 216 217 /* callback functions */ 218 static int dn_callback( Operation *, SlapReply * ); 219 static int nonpresent_callback( Operation *, SlapReply * ); 220 221 static AttributeDescription *sync_descs[4]; 222 223 static AttributeDescription *dsee_descs[7]; 224 225 /* delta-mpr */ 226 static AttributeDescription *ad_reqMod, *ad_reqDN; 227 228 typedef struct logschema { 229 struct berval ls_dn; 230 struct berval ls_req; 231 struct berval ls_mod; 232 struct berval ls_newRdn; 233 struct berval ls_delRdn; 234 struct berval ls_newSup; 235 struct berval ls_controls; 236 struct berval ls_uuid; 237 struct berval ls_changenum; 238 } logschema; 239 240 static logschema changelog_sc = { 241 BER_BVC("targetDN"), 242 BER_BVC("changeType"), 243 BER_BVC("changes"), 244 BER_BVC("newRDN"), 245 BER_BVC("deleteOldRDN"), 246 BER_BVC("newSuperior"), 247 BER_BVNULL, 248 BER_BVC("targetUniqueId"), 249 BER_BVC("changeNumber") 250 }; 251 252 static logschema accesslog_sc = { 253 BER_BVC("reqDN"), 254 BER_BVC("reqType"), 255 BER_BVC("reqMod"), 256 BER_BVC("reqNewRDN"), 257 BER_BVC("reqDeleteOldRDN"), 258 BER_BVC("reqNewSuperior"), 259 BER_BVC("reqControls") 260 }; 261 262 static const char * 263 syncrepl_state2str( int state ) 264 { 265 switch ( state ) { 266 case LDAP_SYNC_PRESENT: 267 return "PRESENT"; 268 269 case LDAP_SYNC_ADD: 270 return "ADD"; 271 272 case LDAP_SYNC_MODIFY: 273 return "MODIFY"; 274 275 case LDAP_SYNC_DELETE: 276 return "DELETE"; 277 #ifdef LDAP_CONTROL_X_DIRSYNC 278 case MSAD_DIRSYNC_MODIFY: 279 return "DIRSYNC_MOD"; 280 #endif 281 case DSEE_SYNC_ADD: 282 return "DSEE_ADD"; 283 } 284 285 return "UNKNOWN"; 286 } 287 288 static slap_overinst syncrepl_ov; 289 290 static void 291 init_syncrepl(syncinfo_t *si) 292 { 293 int i, j, k, l, n; 294 char **attrs, **exattrs; 295 296 if ( !syncrepl_ov.on_bi.bi_type ) { 297 syncrepl_ov.on_bi.bi_type = "syncrepl"; 298 syncrepl_ov.on_bi.bi_op_modify = syncrepl_op_modify; 299 overlay_register( &syncrepl_ov ); 300 } 301 302 /* delta-MPR needs the overlay, nothing else does. 303 * This must happen before accesslog overlay is configured. 304 */ 305 if ( si->si_syncdata && 306 !overlay_is_inst( si->si_be, syncrepl_ov.on_bi.bi_type )) { 307 overlay_config( si->si_be, syncrepl_ov.on_bi.bi_type, -1, NULL, NULL ); 308 if ( !ad_reqMod ) { 309 const char *text; 310 logschema *ls = &accesslog_sc; 311 312 slap_bv2ad( &ls->ls_mod, &ad_reqMod, &text ); 313 slap_bv2ad( &ls->ls_dn, &ad_reqDN, &text ); 314 } 315 } 316 317 if ( !sync_descs[0] ) { 318 sync_descs[0] = slap_schema.si_ad_objectClass; 319 sync_descs[1] = slap_schema.si_ad_structuralObjectClass; 320 sync_descs[2] = slap_schema.si_ad_entryCSN; 321 sync_descs[3] = NULL; 322 } 323 324 if ( si->si_syncdata == SYNCDATA_CHANGELOG ) { 325 /* DSEE doesn't support allopattrs */ 326 si->si_allopattrs = 0; 327 if ( !dsee_descs[0] ) { 328 dsee_descs[0] = slap_schema.si_ad_objectClass; 329 dsee_descs[1] = slap_schema.si_ad_creatorsName; 330 dsee_descs[2] = slap_schema.si_ad_createTimestamp; 331 dsee_descs[3] = slap_schema.si_ad_modifiersName; 332 dsee_descs[4] = slap_schema.si_ad_modifyTimestamp; 333 dsee_descs[5] = sy_ad_nsUniqueId; 334 dsee_descs[6] = NULL; 335 } 336 } 337 338 if ( si->si_allattrs && si->si_allopattrs ) 339 attrs = NULL; 340 else 341 attrs = anlist2attrs( si->si_anlist ); 342 343 if ( attrs ) { 344 if ( si->si_allattrs ) { 345 i = 0; 346 while ( attrs[i] ) { 347 if ( !is_at_operational( at_find( attrs[i] ) ) ) { 348 for ( j = i; attrs[j] != NULL; j++ ) { 349 if ( j == i ) 350 ch_free( attrs[i] ); 351 attrs[j] = attrs[j+1]; 352 } 353 } else { 354 i++; 355 } 356 } 357 attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) ); 358 attrs[i] = ch_strdup("*"); 359 attrs[i + 1] = NULL; 360 361 } else if ( si->si_allopattrs ) { 362 i = 0; 363 while ( attrs[i] ) { 364 if ( is_at_operational( at_find( attrs[i] ) ) ) { 365 for ( j = i; attrs[j] != NULL; j++ ) { 366 if ( j == i ) 367 ch_free( attrs[i] ); 368 attrs[j] = attrs[j+1]; 369 } 370 } else { 371 i++; 372 } 373 } 374 attrs = ( char ** ) ch_realloc( attrs, (i + 2)*sizeof( char * ) ); 375 attrs[i] = ch_strdup("+"); 376 attrs[i + 1] = NULL; 377 } 378 379 for ( i = 0; sync_descs[i] != NULL; i++ ) { 380 j = 0; 381 while ( attrs[j] ) { 382 if ( !strcmp( attrs[j], sync_descs[i]->ad_cname.bv_val ) ) { 383 for ( k = j; attrs[k] != NULL; k++ ) { 384 if ( k == j ) 385 ch_free( attrs[k] ); 386 attrs[k] = attrs[k+1]; 387 } 388 } else { 389 j++; 390 } 391 } 392 } 393 394 for ( n = 0; attrs[ n ] != NULL; n++ ) /* empty */; 395 396 if ( si->si_allopattrs ) { 397 attrs = ( char ** ) ch_realloc( attrs, (n + 2)*sizeof( char * ) ); 398 } else { 399 attrs = ( char ** ) ch_realloc( attrs, (n + 4)*sizeof( char * ) ); 400 } 401 402 /* Add Attributes */ 403 if ( si->si_allopattrs ) { 404 attrs[n++] = ch_strdup( sync_descs[0]->ad_cname.bv_val ); 405 } else { 406 if ( si->si_syncdata != SYNCDATA_CHANGELOG ) { 407 for ( i = 0; sync_descs[ i ] != NULL; i++ ) { 408 attrs[ n++ ] = ch_strdup ( sync_descs[i]->ad_cname.bv_val ); 409 } 410 } 411 } 412 attrs[ n ] = NULL; 413 414 } else { 415 416 i = 0; 417 if ( si->si_allattrs == si->si_allopattrs ) { 418 attrs = (char**) ch_malloc( 3 * sizeof(char*) ); 419 attrs[i++] = ch_strdup( "*" ); 420 attrs[i++] = ch_strdup( "+" ); 421 si->si_allattrs = si->si_allopattrs = 1; 422 } else if ( si->si_allattrs && !si->si_allopattrs ) { 423 for ( n = 0; sync_descs[ n ] != NULL; n++ ) ; 424 attrs = (char**) ch_malloc( (n+1)* sizeof(char*) ); 425 attrs[i++] = ch_strdup( "*" ); 426 for ( j = 1; sync_descs[ j ] != NULL; j++ ) { 427 attrs[i++] = ch_strdup ( sync_descs[j]->ad_cname.bv_val ); 428 } 429 } else if ( !si->si_allattrs && si->si_allopattrs ) { 430 attrs = (char**) ch_malloc( 3 * sizeof(char*) ); 431 attrs[i++] = ch_strdup( "+" ); 432 attrs[i++] = ch_strdup( sync_descs[0]->ad_cname.bv_val ); 433 } 434 attrs[i] = NULL; 435 } 436 437 if ( si->si_syncdata == SYNCDATA_CHANGELOG ) { 438 for ( n = 0; attrs[ n ] != NULL; n++ ) /* empty */; 439 attrs = ( char ** ) ch_realloc( attrs, (n + 6)*sizeof( char * ) ); 440 for ( i = 0; dsee_descs[ i ] != NULL; i++ ) { 441 attrs[ n++ ] = ch_strdup ( dsee_descs[i]->ad_cname.bv_val ); 442 } 443 attrs[n] = NULL; 444 } 445 446 si->si_attrs = attrs; 447 448 exattrs = anlist2attrs( si->si_exanlist ); 449 450 if ( exattrs ) { 451 for ( n = 0; exattrs[n] != NULL; n++ ) ; 452 453 for ( i = 0; sync_descs[i] != NULL; i++ ) { 454 j = 0; 455 while ( exattrs[j] != NULL ) { 456 if ( !strcmp( exattrs[j], sync_descs[i]->ad_cname.bv_val ) ) { 457 ch_free( exattrs[j] ); 458 for ( k = j; exattrs[k] != NULL; k++ ) { 459 exattrs[k] = exattrs[k+1]; 460 } 461 } else { 462 j++; 463 } 464 } 465 } 466 467 for ( i = 0; exattrs[i] != NULL; i++ ) { 468 for ( j = 0; si->si_anlist[j].an_name.bv_val; j++ ) { 469 ObjectClass *oc; 470 if ( ( oc = si->si_anlist[j].an_oc ) ) { 471 k = 0; 472 while ( oc->soc_required[k] ) { 473 if ( !strcmp( exattrs[i], 474 oc->soc_required[k]->sat_cname.bv_val ) ) { 475 ch_free( exattrs[i] ); 476 for ( l = i; exattrs[l]; l++ ) { 477 exattrs[l] = exattrs[l+1]; 478 } 479 } else { 480 k++; 481 } 482 } 483 } 484 } 485 } 486 487 for ( i = 0; exattrs[i] != NULL; i++ ) ; 488 489 if ( i != n ) 490 exattrs = (char **) ch_realloc( exattrs, (i + 1)*sizeof(char *) ); 491 } 492 493 si->si_exattrs = exattrs; 494 } 495 496 static struct berval generic_filterstr = BER_BVC("(objectclass=*)"); 497 498 static int 499 ldap_sync_search( 500 syncinfo_t *si, 501 void *ctx ) 502 { 503 BerElementBuffer berbuf; 504 BerElement *ber = (BerElement *)&berbuf; 505 LDAPControl c[3], *ctrls[4]; 506 int rc; 507 int rhint; 508 char *base; 509 char **attrs, *lattrs[9]; 510 char *filter; 511 int attrsonly; 512 int scope; 513 char filterbuf[sizeof("(changeNumber>=18446744073709551615)")]; 514 515 /* setup LDAP SYNC control */ 516 ber_init2( ber, NULL, LBER_USE_DER ); 517 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &ctx ); 518 519 /* If we're using a log but we have no state, then fallback to 520 * normal mode for a full refresh. 521 */ 522 if ( si->si_syncdata ) { 523 if ( si->si_syncdata == SYNCDATA_CHANGELOG ) { 524 LDAPMessage *res, *msg; 525 unsigned long first = 0, last = 0; 526 int gotfirst = 0, gotlast = 0; 527 /* See if we're new enough for the remote server */ 528 lattrs[0] = "firstchangenumber"; 529 lattrs[1] = "lastchangenumber"; 530 lattrs[2] = NULL; 531 rc = ldap_search_ext_s( si->si_ld, "", LDAP_SCOPE_BASE, generic_filterstr.bv_val, lattrs, 0, 532 NULL, NULL, NULL, si->si_slimit, &res ); 533 if ( rc ) 534 return rc; 535 msg = ldap_first_message( si->si_ld, res ); 536 if ( msg && ldap_msgtype( msg ) == LDAP_RES_SEARCH_ENTRY ) { 537 BerElement *ber = NULL; 538 struct berval bv, *bvals, **bvp = &bvals;; 539 rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bv ); 540 for ( rc = ldap_get_attribute_ber( si->si_ld, msg, ber, &bv, bvp ); 541 rc == LDAP_SUCCESS; 542 rc = ldap_get_attribute_ber( si->si_ld, msg, ber, &bv, bvp ) ) { 543 if ( bv.bv_val == NULL ) 544 break; 545 if ( !strcasecmp( bv.bv_val, "firstchangenumber" )) { 546 first = strtoul( bvals[0].bv_val, NULL, 0 ); 547 gotfirst = 1; 548 } else if ( !strcasecmp( bv.bv_val, "lastchangenumber" )) { 549 last = strtoul( bvals[0].bv_val, NULL, 0 ); 550 gotlast = 1; 551 } 552 } 553 } 554 ldap_msgfree( res ); 555 if ( gotfirst && gotlast ) { 556 if ( si->si_lastchange < first || (!si->si_lastchange && !si->si_refreshDone )) 557 si->si_logstate = SYNCLOG_FALLBACK; 558 /* if we're in logging mode, it will update si_lastchange itself */ 559 if ( si->si_logstate == SYNCLOG_FALLBACK ) 560 si->si_lastchange = last; 561 } else { 562 /* should be an error; changelog plugin not enabled on provider */ 563 si->si_logstate = SYNCLOG_FALLBACK; 564 } 565 } else 566 if ( si->si_logstate == SYNCLOG_LOGGING && !si->si_syncCookie.numcsns && 567 !si->si_refreshDone ) { 568 si->si_logstate = SYNCLOG_FALLBACK; 569 } 570 } 571 572 /* Use the log parameters if we're in log mode */ 573 if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) { 574 logschema *ls; 575 if ( si->si_syncdata == SYNCDATA_ACCESSLOG ) 576 ls = &accesslog_sc; 577 else 578 ls = &changelog_sc; 579 lattrs[0] = ls->ls_dn.bv_val; 580 lattrs[1] = ls->ls_req.bv_val; 581 lattrs[2] = ls->ls_mod.bv_val; 582 lattrs[3] = ls->ls_newRdn.bv_val; 583 lattrs[4] = ls->ls_delRdn.bv_val; 584 lattrs[5] = ls->ls_newSup.bv_val; 585 if ( si->si_syncdata == SYNCDATA_ACCESSLOG ) { 586 lattrs[6] = ls->ls_controls.bv_val; 587 lattrs[7] = slap_schema.si_ad_entryCSN->ad_cname.bv_val; 588 lattrs[8] = NULL; 589 filter = si->si_logfilterstr.bv_val; 590 scope = LDAP_SCOPE_SUBTREE; 591 } else { 592 lattrs[6] = ls->ls_uuid.bv_val; 593 lattrs[7] = ls->ls_changenum.bv_val; 594 lattrs[8] = NULL; 595 sprintf( filterbuf, "(changeNumber>=%lu)", si->si_lastchange+1 ); 596 filter = filterbuf; 597 scope = LDAP_SCOPE_ONELEVEL; 598 } 599 600 rhint = 0; 601 base = si->si_logbase.bv_val; 602 attrs = lattrs; 603 attrsonly = 0; 604 } else { 605 rhint = 1; 606 base = si->si_base.bv_val; 607 filter = si->si_filterstr.bv_val; 608 attrs = si->si_attrs; 609 attrsonly = si->si_attrsonly; 610 scope = si->si_scope; 611 } 612 if ( si->si_syncdata && si->si_logstate == SYNCLOG_FALLBACK ) { 613 si->si_type = LDAP_SYNC_REFRESH_ONLY; 614 } else { 615 si->si_type = si->si_ctype; 616 } 617 618 #ifdef LDAP_CONTROL_X_DIRSYNC 619 if ( si->si_ctype == MSAD_DIRSYNC ) { 620 ber_printf( ber, "{iiO}", LDAP_CONTROL_X_DIRSYNC_INCREMENTAL_VALUES, 0, &si->si_dirSyncCookie ); 621 622 if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == -1 ) { 623 ber_free_buf( ber ); 624 return rc; 625 } 626 c[0].ldctl_oid = LDAP_CONTROL_X_DIRSYNC; 627 c[0].ldctl_iscritical = 1; 628 ctrls[0] = &c[0]; 629 630 if ( !BER_BVISEMPTY( &si->si_dirSyncCookie )) { 631 c[1].ldctl_oid = LDAP_CONTROL_X_SHOW_DELETED; 632 BER_BVZERO( &c[1].ldctl_value ); 633 c[1].ldctl_iscritical = 1; 634 ctrls[1] = &c[1]; 635 ctrls[2] = NULL; 636 } else { 637 ctrls[1] = NULL; 638 } 639 } else 640 #endif 641 if ( si->si_syncdata == SYNCDATA_CHANGELOG ) { 642 if ( si->si_logstate == SYNCLOG_LOGGING && si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ) { 643 c[0].ldctl_oid = LDAP_CONTROL_PERSIST_REQUEST; 644 c[0].ldctl_iscritical = 0; 645 rc = ldap_create_persistentsearch_control_value( si->si_ld, LDAP_CONTROL_PERSIST_ENTRY_CHANGE_ADD, 646 0, 1, &c[0].ldctl_value ); 647 ctrls[0] = &c[0]; 648 ctrls[1] = NULL; 649 } else { 650 ctrls[0] = NULL; 651 } 652 } else 653 { 654 if ( !BER_BVISNULL( &si->si_syncCookie.octet_str ) ) 655 { 656 ber_printf( ber, "{eOb}", 657 abs(si->si_type), &si->si_syncCookie.octet_str, rhint ); 658 } else { 659 ber_printf( ber, "{eb}", 660 abs(si->si_type), rhint ); 661 } 662 663 if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == -1 ) { 664 ber_free_buf( ber ); 665 return rc; 666 } 667 668 c[0].ldctl_oid = LDAP_CONTROL_SYNC; 669 c[0].ldctl_iscritical = si->si_type < 0; 670 ctrls[0] = &c[0]; 671 672 c[1].ldctl_oid = LDAP_CONTROL_MANAGEDSAIT; 673 BER_BVZERO( &c[1].ldctl_value ); 674 c[1].ldctl_iscritical = 1; 675 ctrls[1] = &c[1]; 676 677 if ( !BER_BVISNULL( &si->si_bindconf.sb_authzId ) ) { 678 c[2].ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ; 679 c[2].ldctl_value = si->si_bindconf.sb_authzId; 680 c[2].ldctl_iscritical = 1; 681 ctrls[2] = &c[2]; 682 ctrls[3] = NULL; 683 } else { 684 ctrls[2] = NULL; 685 } 686 } 687 688 rc = ldap_search_ext( si->si_ld, base, scope, filter, attrs, attrsonly, 689 ctrls, NULL, NULL, si->si_slimit, &si->si_msgid ); 690 ber_free_buf( ber ); 691 return rc; 692 } 693 694 /* #define DEBUG_MERGE_STATE 1 */ 695 696 static int 697 merge_state( syncinfo_t *si, struct sync_cookie *sc1, struct sync_cookie *sc2 ) 698 { 699 int i, j, k, changed = 0; 700 int ei, ej; 701 int *newsids; 702 struct berval *newcsns; 703 704 ei = sc1->numcsns; 705 ej = sc2->numcsns; 706 #ifdef DEBUG_MERGE_STATE 707 for ( i=0; i<ei; i++ ) { 708 fprintf(stderr, "merge_state: %s si_syncCookie [%d] %d %s\n", 709 si->si_ridtxt, i, sc1->sids[i], sc1->ctxcsn[i].bv_val ); 710 } 711 for ( i=0; i<ej; i++ ) { 712 fprintf(stderr, "merge_state: %s si_cookieState [%d] %d %s\n", 713 si->si_ridtxt, i, sc2->sids[i], sc2->ctxcsn[i].bv_val ); 714 } 715 #endif 716 /* see if they cover the same SIDs */ 717 if ( ei == ej ) { 718 for ( i = 0; i < ei; i++ ) { 719 if ( sc1->sids[i] != sc2->sids[i] ) { 720 changed = 1; 721 break; 722 } 723 } 724 /* SIDs are the same, take fast path */ 725 if ( !changed ) { 726 for ( i = 0; i < ei; i++ ) { 727 if ( ber_bvcmp( &sc1->ctxcsn[i], &sc2->ctxcsn[i] ) < 0 ) { 728 ber_bvreplace( &sc1->ctxcsn[i], &sc2->ctxcsn[i] ); 729 changed = 1; 730 } 731 } 732 return changed; 733 } 734 changed = 0; 735 } 736 737 i = ei + ej; 738 newsids = ch_malloc( sizeof(int) * i ); 739 newcsns = ch_malloc( sizeof(struct berval) * ( i + 1 )); 740 741 for ( i=0, j=0, k=0; i < ei || j < ej ; ) { 742 if ( i < ei && sc1->sids[i] == -1 ) { 743 i++; 744 continue; 745 } 746 if ( j >= ej || (i < ei && sc1->sids[i] < sc2->sids[j] )) { 747 newsids[k] = sc1->sids[i]; 748 ber_dupbv( &newcsns[k], &sc1->ctxcsn[i] ); 749 i++; k++; 750 continue; 751 } 752 if ( i < ei && sc1->sids[i] == sc2->sids[j] ) { 753 newsids[k] = sc1->sids[i]; 754 if ( ber_bvcmp( &sc1->ctxcsn[i], &sc2->ctxcsn[j] ) < 0 ) { 755 changed = 1; 756 ber_dupbv( &newcsns[k], &sc2->ctxcsn[j] ); 757 } else { 758 ber_dupbv( &newcsns[k], &sc1->ctxcsn[i] ); 759 } 760 i++; j++; k++; 761 continue; 762 } 763 if ( j < ej ) { 764 if ( sc2->sids[j] == -1 ) { 765 j++; 766 continue; 767 } 768 newsids[k] = sc2->sids[j]; 769 ber_dupbv( &newcsns[k], &sc2->ctxcsn[j] ); 770 changed = 1; 771 j++; k++; 772 } 773 } 774 775 ber_bvarray_free( sc1->ctxcsn ); 776 ch_free( sc1->sids ); 777 sc1->numcsns = k; 778 sc1->sids = ch_realloc( newsids, sizeof(int) * k ); 779 sc1->ctxcsn = ch_realloc( newcsns, sizeof(struct berval) * (k+1) ); 780 BER_BVZERO( &sc1->ctxcsn[k] ); 781 #ifdef DEBUG_MERGE_STATE 782 for ( i=0; i<sc1->numcsns; i++ ) { 783 fprintf(stderr, "merge_state: %s si_syncCookie2 [%d] %d %s\n", 784 si->si_ridtxt, i, sc1->sids[i], sc1->ctxcsn[i].bv_val ); 785 } 786 #endif 787 788 return changed; 789 } 790 791 #ifdef DEBUG_MERGE_STATE 792 static void 793 merge_test( syncinfo_t *si ) { 794 struct sync_cookie sc1, sc2; 795 int ret; 796 797 sc1.numcsns = 4; 798 sc1.sids = malloc( sizeof( int ) * sc1.numcsns ); 799 sc1.ctxcsn = malloc( sizeof( struct berval ) * ( sc1.numcsns + 1 )); 800 sc1.sids[0] = 1; 801 sc1.sids[1] = 3; 802 sc1.sids[2] = 4; 803 sc1.sids[3] = 5; 804 { struct berval bv = BER_BVC("20200101000000.100000Z#sc1#001#000000"); /* unique */ 805 ber_dupbv( &sc1.ctxcsn[0], &bv ); } 806 { struct berval bv = BER_BVC("20200101000000.100000Z#sc1#003#000000"); /* lower */ 807 ber_dupbv( &sc1.ctxcsn[1], &bv ); } 808 { struct berval bv = BER_BVC("20201231000000.100000Z#sc1#004#000000"); /* higher */ 809 ber_dupbv( &sc1.ctxcsn[2], &bv ); } 810 { struct berval bv = BER_BVC("20200228000000.100000Z#sc1#005#000000"); /* unique */ 811 ber_dupbv( &sc1.ctxcsn[3], &bv ); } 812 BER_BVZERO( &sc1.ctxcsn[sc1.numcsns] ); 813 814 sc2.numcsns = 4; 815 sc2.sids = malloc( sizeof( int ) * sc2.numcsns ); 816 sc2.ctxcsn = malloc( sizeof( struct berval ) * ( sc2.numcsns + 1 )); 817 sc2.sids[0] = 2; 818 sc2.sids[1] = 3; 819 sc2.sids[2] = 4; 820 sc2.sids[3] = 6; 821 { struct berval bv = BER_BVC("20200101000000.100000Z#sc2#002#000000"); /* unique */ 822 ber_dupbv( &sc2.ctxcsn[0], &bv ); } 823 { struct berval bv = BER_BVC("20200331000000.100000Z#sc2#003#000000"); /* higher */ 824 ber_dupbv( &sc2.ctxcsn[1], &bv ); } 825 { struct berval bv = BER_BVC("20200501000000.100000Z#sc2#004#000000"); /* lower */ 826 ber_dupbv( &sc2.ctxcsn[2], &bv ); } 827 { struct berval bv = BER_BVC("20200628000000.100000Z#sc2#006#000000"); /* unique */ 828 ber_dupbv( &sc2.ctxcsn[3], &bv ); } 829 BER_BVZERO( &sc2.ctxcsn[sc2.numcsns] ); 830 831 ret = merge_state( si, &sc1, &sc2 ); 832 } 833 #endif 834 835 static int 836 check_syncprov( 837 Operation *op, 838 syncinfo_t *si ) 839 { 840 AttributeName at[2]; 841 Attribute a = {0}; 842 Entry e = {0}; 843 SlapReply rs = {REP_SEARCH}; 844 int i, j, changed = 0; 845 846 /* Look for contextCSN from syncprov overlay. If 847 * there's no overlay, this will be a no-op. That means 848 * this is a pure consumer, so local changes will not be 849 * allowed, and all changes will already be reflected in 850 * the cookieState. 851 */ 852 a.a_desc = slap_schema.si_ad_contextCSN; 853 e.e_attrs = &a; 854 e.e_name = si->si_contextdn; 855 e.e_nname = si->si_contextdn; 856 at[0].an_name = a.a_desc->ad_cname; 857 at[0].an_desc = a.a_desc; 858 BER_BVZERO( &at[1].an_name ); 859 rs.sr_entry = &e; 860 rs.sr_flags = REP_ENTRY_MODIFIABLE; 861 rs.sr_attrs = at; 862 op->o_req_dn = e.e_name; 863 op->o_req_ndn = e.e_nname; 864 865 ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex ); 866 i = backend_operational( op, &rs ); 867 if ( i == LDAP_SUCCESS && a.a_nvals ) { 868 int num = a.a_numvals; 869 /* check for differences */ 870 if ( num != si->si_cookieState->cs_num ) { 871 changed = 1; 872 } else { 873 for ( i=0; i<num; i++ ) { 874 if ( ber_bvcmp( &a.a_nvals[i], 875 &si->si_cookieState->cs_vals[i] )) { 876 changed = 1; 877 break; 878 } 879 } 880 } 881 if ( changed ) { 882 ber_bvarray_free( si->si_cookieState->cs_vals ); 883 ch_free( si->si_cookieState->cs_sids ); 884 si->si_cookieState->cs_num = num; 885 si->si_cookieState->cs_vals = a.a_nvals; 886 si->si_cookieState->cs_sids = slap_parse_csn_sids( a.a_nvals, 887 num, NULL ); 888 si->si_cookieState->cs_age++; 889 } else { 890 ber_bvarray_free( a.a_nvals ); 891 } 892 ber_bvarray_free( a.a_vals ); 893 } 894 /* See if the cookieState has changed due to anything outside 895 * this particular consumer. That includes other consumers in 896 * the same context, or local changes detected above. 897 */ 898 if ( si->si_cookieState->cs_num > 0 && si->si_cookieAge != 899 si->si_cookieState->cs_age ) { 900 if ( !si->si_syncCookie.numcsns ) { 901 ber_bvarray_free( si->si_syncCookie.ctxcsn ); 902 ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn, 903 si->si_cookieState->cs_vals, NULL ); 904 changed = 1; 905 } else { 906 changed = merge_state( si, &si->si_syncCookie, 907 (struct sync_cookie *)&si->si_cookieState->cs_vals ); 908 } 909 } 910 if ( changed ) { 911 si->si_cookieAge = si->si_cookieState->cs_age; 912 ch_free( si->si_syncCookie.octet_str.bv_val ); 913 slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str, 914 si->si_syncCookie.ctxcsn, si->si_syncCookie.rid, 915 si->si_syncCookie.sid, NULL ); 916 ch_free( si->si_syncCookie.sids ); 917 slap_reparse_sync_cookie( &si->si_syncCookie, op->o_tmpmemctx ); 918 } 919 ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex ); 920 return changed; 921 } 922 923 static int 924 do_syncrep1( 925 Operation *op, 926 syncinfo_t *si ) 927 { 928 int rc; 929 int cmdline_cookie_found = 0; 930 931 struct sync_cookie *sc = NULL; 932 #ifdef HAVE_TLS 933 void *ssl; 934 #endif 935 936 si->si_lastconnect = slap_get_time(); 937 si->si_refreshDone = 0; 938 rc = slap_client_connect( &si->si_ld, &si->si_bindconf ); 939 if ( rc != LDAP_SUCCESS ) { 940 goto done; 941 } 942 op->o_protocol = LDAP_VERSION3; 943 944 /* Set SSF to strongest of TLS, SASL SSFs */ 945 op->o_sasl_ssf = 0; 946 op->o_tls_ssf = 0; 947 op->o_transport_ssf = 0; 948 #ifdef HAVE_TLS 949 if ( ldap_get_option( si->si_ld, LDAP_OPT_X_TLS_SSL_CTX, &ssl ) 950 == LDAP_SUCCESS && ssl != NULL ) 951 { 952 op->o_tls_ssf = ldap_pvt_tls_get_strength( ssl ); 953 } 954 #endif /* HAVE_TLS */ 955 { 956 ber_len_t ssf; /* ITS#5403, 3864 LDAP_OPT_X_SASL_SSF probably ought 957 to use sasl_ssf_t but currently uses ber_len_t */ 958 if ( ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf ) 959 == LDAP_SUCCESS ) 960 op->o_sasl_ssf = ssf; 961 } 962 op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf ) 963 ? op->o_sasl_ssf : op->o_tls_ssf; 964 965 ldap_set_option( si->si_ld, LDAP_OPT_TIMELIMIT, &si->si_tlimit ); 966 967 rc = LDAP_DEREF_NEVER; /* actually could allow DEREF_FINDING */ 968 ldap_set_option( si->si_ld, LDAP_OPT_DEREF, &rc ); 969 970 ldap_set_option( si->si_ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF ); 971 972 si->si_syncCookie.rid = si->si_rid; 973 974 /* whenever there are multiple data sources possible, advertise sid */ 975 si->si_syncCookie.sid = ( SLAP_MULTIPROVIDER( si->si_be ) || si->si_be != si->si_wbe ) ? 976 slap_serverID : -1; 977 978 #ifdef LDAP_CONTROL_X_DIRSYNC 979 if ( si->si_ctype == MSAD_DIRSYNC ) { 980 if ( BER_BVISEMPTY( &si->si_dirSyncCookie )) { 981 BerVarray cookies = NULL; 982 void *ctx = op->o_tmpmemctx; 983 984 op->o_req_ndn = si->si_contextdn; 985 op->o_req_dn = op->o_req_ndn; 986 987 /* try to read stored cookie */ 988 op->o_tmpmemctx = NULL; 989 backend_attribute( op, NULL, &op->o_req_ndn, 990 sy_ad_dirSyncCookie, &cookies, ACL_READ ); 991 op->o_tmpmemctx = ctx; 992 if ( cookies ) 993 si->si_dirSyncCookie = cookies[0]; 994 } 995 } else 996 #endif 997 if ( si->si_syncdata == SYNCDATA_CHANGELOG ) { 998 if ( !si->si_lastchange ) { 999 BerVarray vals = NULL; 1000 1001 op->o_req_ndn = si->si_contextdn; 1002 op->o_req_dn = op->o_req_ndn; 1003 /* try to read last change number */ 1004 backend_attribute( op, NULL, &op->o_req_ndn, 1005 sy_ad_dseeLastChange, &vals, ACL_READ ); 1006 if ( vals ) { 1007 si->si_lastchange = strtoul( vals[0].bv_val, NULL, 0 ); 1008 si->si_prevchange = si->si_lastchange; 1009 } 1010 } 1011 } else 1012 { 1013 1014 /* We've just started up, or the remote server hasn't sent us 1015 * any meaningful state. 1016 */ 1017 if ( !si->si_syncCookie.ctxcsn ) { 1018 int i; 1019 1020 LDAP_STAILQ_FOREACH( sc, &slap_sync_cookie, sc_next ) { 1021 if ( si->si_rid == sc->rid ) { 1022 cmdline_cookie_found = 1; 1023 break; 1024 } 1025 } 1026 1027 if ( cmdline_cookie_found ) { 1028 /* cookie is supplied in the command line */ 1029 1030 LDAP_STAILQ_REMOVE( &slap_sync_cookie, sc, sync_cookie, sc_next ); 1031 1032 slap_sync_cookie_free( &si->si_syncCookie, 0 ); 1033 si->si_syncCookie.octet_str = sc->octet_str; 1034 ch_free( sc ); 1035 /* ctxcsn wasn't parsed yet, do it now */ 1036 slap_parse_sync_cookie( &si->si_syncCookie, NULL ); 1037 } else { 1038 ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex ); 1039 if ( !si->si_cookieState->cs_num ) { 1040 /* get contextCSN shadow replica from database */ 1041 BerVarray csn = NULL; 1042 void *ctx = op->o_tmpmemctx; 1043 1044 op->o_req_ndn = si->si_contextdn; 1045 op->o_req_dn = op->o_req_ndn; 1046 1047 /* try to read stored contextCSN */ 1048 op->o_tmpmemctx = NULL; 1049 backend_attribute( op, NULL, &op->o_req_ndn, 1050 slap_schema.si_ad_contextCSN, &csn, ACL_READ ); 1051 op->o_tmpmemctx = ctx; 1052 if ( csn ) { 1053 si->si_cookieState->cs_vals = csn; 1054 for (i=0; !BER_BVISNULL( &csn[i] ); i++); 1055 si->si_cookieState->cs_num = i; 1056 si->si_cookieState->cs_sids = slap_parse_csn_sids( csn, i, NULL ); 1057 slap_sort_csn_sids( csn, si->si_cookieState->cs_sids, i, NULL ); 1058 } 1059 } 1060 if ( si->si_cookieState->cs_num ) { 1061 ber_bvarray_free( si->si_syncCookie.ctxcsn ); 1062 if ( ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn, 1063 si->si_cookieState->cs_vals, NULL )) { 1064 rc = LDAP_NO_MEMORY; 1065 ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex ); 1066 goto done; 1067 } 1068 si->si_syncCookie.numcsns = si->si_cookieState->cs_num; 1069 si->si_syncCookie.sids = ch_malloc( si->si_cookieState->cs_num * 1070 sizeof(int) ); 1071 for ( i=0; i<si->si_syncCookie.numcsns; i++ ) 1072 si->si_syncCookie.sids[i] = si->si_cookieState->cs_sids[i]; 1073 } 1074 ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex ); 1075 } 1076 } 1077 1078 if ( !cmdline_cookie_found ) { 1079 /* ITS#6367: recreate the cookie so it has our SID, not our peer's */ 1080 ch_free( si->si_syncCookie.octet_str.bv_val ); 1081 BER_BVZERO( &si->si_syncCookie.octet_str ); 1082 /* Look for contextCSN from syncprov overlay. */ 1083 check_syncprov( op, si ); 1084 if ( BER_BVISNULL( &si->si_syncCookie.octet_str )) 1085 slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str, 1086 si->si_syncCookie.ctxcsn, si->si_syncCookie.rid, 1087 si->si_syncCookie.sid, NULL ); 1088 } 1089 } 1090 1091 Debug( LDAP_DEBUG_SYNC, "do_syncrep1: %s starting refresh (sending cookie=%s)\n", 1092 si->si_ridtxt, si->si_syncCookie.octet_str.bv_val ); 1093 1094 ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex ); 1095 ber_bvreplace( &si->si_lastCookieSent, &si->si_syncCookie.octet_str ); 1096 ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex ); 1097 1098 rc = ldap_sync_search( si, op->o_tmpmemctx ); 1099 1100 if( rc != LDAP_SUCCESS ) { 1101 Debug( LDAP_DEBUG_ANY, "do_syncrep1: %s " 1102 "ldap_search_ext: %s (%d)\n", 1103 si->si_ridtxt, ldap_err2string( rc ), rc ); 1104 } 1105 1106 done: 1107 if ( rc ) { 1108 if ( si->si_ld ) { 1109 ldap_unbind_ext( si->si_ld, NULL, NULL ); 1110 si->si_ld = NULL; 1111 } 1112 } 1113 1114 return rc; 1115 } 1116 1117 static int 1118 compare_csns( struct sync_cookie *sc1, struct sync_cookie *sc2, int *which ) 1119 { 1120 int i, j, match = 0; 1121 const char *text; 1122 1123 *which = 0; 1124 1125 if ( sc1->numcsns < sc2->numcsns ) { 1126 *which = sc1->numcsns; 1127 return -1; 1128 } 1129 1130 for (j=0; j<sc2->numcsns; j++) { 1131 for (i=0; i<sc1->numcsns; i++) { 1132 if ( sc1->sids[i] != sc2->sids[j] ) 1133 continue; 1134 value_match( &match, slap_schema.si_ad_entryCSN, 1135 slap_schema.si_ad_entryCSN->ad_type->sat_ordering, 1136 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, 1137 &sc1->ctxcsn[i], &sc2->ctxcsn[j], &text ); 1138 if ( match < 0 ) { 1139 *which = j; 1140 return match; 1141 } 1142 break; 1143 } 1144 if ( i == sc1->numcsns ) { 1145 /* sc2 has a sid sc1 lacks */ 1146 *which = j; 1147 return -1; 1148 } 1149 } 1150 return match; 1151 } 1152 1153 #define CV_CSN_OK 0 1154 #define CV_CSN_OLD 1 1155 #define CV_SID_NEW 2 1156 1157 static int 1158 check_csn_age( 1159 syncinfo_t *si, 1160 struct berval *dn, 1161 struct berval *csn, 1162 int sid, 1163 cookie_vals *cv, 1164 int *slot ) 1165 { 1166 int i, rc = CV_SID_NEW; 1167 1168 for ( i =0; i<cv->cv_num; i++ ) { 1169 #ifdef CHATTY_SYNCLOG 1170 Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN for sid %d: %s\n", 1171 si->si_ridtxt, i, cv->cv_vals[i].bv_val ); 1172 #endif 1173 /* new SID */ 1174 if ( sid < cv->cv_sids[i] ) 1175 break; 1176 if ( cv->cv_sids[i] == sid ) { 1177 if ( ber_bvcmp( csn, &cv->cv_vals[i] ) <= 0 ) { 1178 dn->bv_val[dn->bv_len] = '\0'; 1179 Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s (%s)\n", 1180 si->si_ridtxt, csn->bv_val, dn->bv_val ); 1181 return CV_CSN_OLD; 1182 } 1183 rc = CV_CSN_OK; 1184 break; 1185 } 1186 } 1187 if ( slot ) 1188 *slot = i; 1189 return rc; 1190 } 1191 1192 #define SYNC_TIMEOUT 0 1193 #define SYNC_SHUTDOWN -100 1194 #define SYNC_ERROR -101 1195 #define SYNC_REPOLL -102 1196 #define SYNC_PAUSED -103 1197 1198 static int 1199 get_pmutex( 1200 syncinfo_t *si 1201 ) 1202 { 1203 if ( !si->si_is_configdb ) { 1204 ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_pmutex ); 1205 } else { 1206 /* avoid deadlock when replicating cn=config */ 1207 while ( ldap_pvt_thread_mutex_trylock( &si->si_cookieState->cs_pmutex )) { 1208 if ( slapd_shutdown ) 1209 return SYNC_SHUTDOWN; 1210 if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool )) 1211 ldap_pvt_thread_yield(); 1212 } 1213 } 1214 1215 return 0; 1216 } 1217 1218 static int 1219 do_syncrep2( 1220 Operation *op, 1221 syncinfo_t *si ) 1222 { 1223 BerElementBuffer berbuf; 1224 BerElement *ber = (BerElement *)&berbuf; 1225 1226 LDAPMessage *msg = NULL; 1227 1228 struct sync_cookie syncCookie = { NULL }; 1229 struct sync_cookie syncCookie_req = { NULL }; 1230 1231 int rc, 1232 err = LDAP_SUCCESS; 1233 1234 Modifications *modlist = NULL; 1235 1236 int m; 1237 1238 struct timeval tout = { 0, 0 }; 1239 1240 int refreshDeletes = 0; 1241 char empty[6] = "empty"; 1242 1243 if ( slapd_shutdown ) { 1244 rc = SYNC_SHUTDOWN; 1245 goto done; 1246 } 1247 1248 ber_init2( ber, NULL, LBER_USE_DER ); 1249 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); 1250 1251 Debug( LDAP_DEBUG_TRACE, "=>do_syncrep2 %s\n", si->si_ridtxt ); 1252 1253 slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie ); 1254 1255 if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST && si->si_refreshDone ) { 1256 tout.tv_sec = 0; 1257 } else { 1258 /* Give some time for refresh response to arrive */ 1259 tout.tv_sec = si->si_bindconf.sb_timeout_api; 1260 } 1261 1262 while ( ( rc = ldap_result( si->si_ld, si->si_msgid, LDAP_MSG_ONE, 1263 &tout, &msg ) ) > 0 ) 1264 { 1265 int match, punlock, syncstate; 1266 struct berval *retdata, syncUUID[2], cookie = BER_BVNULL; 1267 char *retoid; 1268 LDAPControl **rctrls = NULL, *rctrlp = NULL; 1269 BerVarray syncUUIDs; 1270 ber_len_t len; 1271 ber_tag_t si_tag; 1272 Entry *entry; 1273 struct berval bdn; 1274 1275 if ( slapd_shutdown ) { 1276 rc = SYNC_SHUTDOWN; 1277 goto done; 1278 } 1279 si->si_lastcontact = slap_get_time(); 1280 switch( ldap_msgtype( msg ) ) { 1281 case LDAP_RES_SEARCH_ENTRY: 1282 #ifdef LDAP_CONTROL_X_DIRSYNC 1283 if ( si->si_ctype == MSAD_DIRSYNC ) { 1284 BER_BVZERO( &syncUUID[0] ); 1285 rc = syncrepl_dirsync_message( si, op, msg, &modlist, &entry, &syncstate, syncUUID ); 1286 if ( rc == 0 ) 1287 rc = syncrepl_entry( si, op, entry, &modlist, syncstate, syncUUID, NULL ); 1288 op->o_tmpfree( syncUUID[0].bv_val, op->o_tmpmemctx ); 1289 if ( modlist ) 1290 slap_mods_free( modlist, 1); 1291 if ( rc ) 1292 goto done; 1293 break; 1294 } 1295 #endif 1296 ldap_get_entry_controls( si->si_ld, msg, &rctrls ); 1297 ldap_get_dn_ber( si->si_ld, msg, NULL, &bdn ); 1298 if (!bdn.bv_len) { 1299 bdn.bv_val = empty; 1300 bdn.bv_len = sizeof(empty)-1; 1301 } 1302 if ( si->si_syncdata == SYNCDATA_CHANGELOG ) { 1303 if ( si->si_logstate == SYNCLOG_LOGGING ) { 1304 rc = syncrepl_message_to_op( si, op, msg, 1 ); 1305 if ( rc ) 1306 goto logerr; 1307 if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST && rctrls ) { 1308 LDAPControl **next = NULL; 1309 /* The notification control is only sent during persist phase */ 1310 rctrlp = ldap_control_find( LDAP_CONTROL_PERSIST_ENTRY_CHANGE_NOTICE, rctrls, &next ); 1311 if ( rctrlp ) { 1312 if ( !si->si_refreshDone ) 1313 si->si_refreshDone = 1; 1314 if ( si->si_refreshDone ) 1315 syncrepl_dsee_update( si, op ); 1316 } 1317 } 1318 1319 } else { 1320 syncstate = DSEE_SYNC_ADD; 1321 rc = syncrepl_message_to_entry( si, op, msg, 1322 &modlist, &entry, syncstate, syncUUID ); 1323 if ( rc == 0 ) 1324 rc = syncrepl_entry( si, op, entry, &modlist, syncstate, syncUUID, NULL ); 1325 op->o_tmpfree( syncUUID[0].bv_val, op->o_tmpmemctx ); 1326 if ( modlist ) 1327 slap_mods_free( modlist, 1); 1328 } 1329 if ( rc ) 1330 goto done; 1331 break; 1332 } 1333 /* we can't work without the control */ 1334 if ( rctrls ) { 1335 LDAPControl **next = NULL; 1336 /* NOTE: make sure we use the right one; 1337 * a better approach would be to run thru 1338 * the whole list and take care of all */ 1339 /* NOTE: since we issue the search request, 1340 * we should know what controls to expect, 1341 * and there should be none apart from the 1342 * sync-related control */ 1343 rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_STATE, rctrls, &next ); 1344 if ( next && ldap_control_find( LDAP_CONTROL_SYNC_STATE, next, NULL ) ) 1345 { 1346 bdn.bv_val[bdn.bv_len] = '\0'; 1347 Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s " 1348 "got search entry with multiple " 1349 "Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val ); 1350 ldap_controls_free( rctrls ); 1351 rc = -1; 1352 goto done; 1353 } 1354 } 1355 if ( rctrlp == NULL ) { 1356 bdn.bv_val[bdn.bv_len] = '\0'; 1357 Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s " 1358 "got search entry without " 1359 "Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val ); 1360 rc = -1; 1361 goto done; 1362 } 1363 ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER ); 1364 if ( ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID[0] ) 1365 == LBER_ERROR ) { 1366 bdn.bv_val[bdn.bv_len] = '\0'; 1367 Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s malformed message (%s)\n", 1368 si->si_ridtxt, bdn.bv_val ); 1369 ldap_controls_free( rctrls ); 1370 rc = -1; 1371 goto done; 1372 } 1373 /* FIXME: what if syncUUID is NULL or empty? 1374 * (happens with back-sql...) */ 1375 if ( syncUUID[0].bv_len != UUIDLEN ) { 1376 bdn.bv_val[bdn.bv_len] = '\0'; 1377 Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s " 1378 "got empty or invalid syncUUID with LDAP_SYNC_%s (%s)\n", 1379 si->si_ridtxt, 1380 syncrepl_state2str( syncstate ), bdn.bv_val ); 1381 ldap_controls_free( rctrls ); 1382 rc = -1; 1383 goto done; 1384 } 1385 punlock = -1; 1386 if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) { 1387 if ( ber_scanf( ber, /*"{"*/ "m}", &cookie ) != LBER_ERROR ) { 1388 1389 Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n", 1390 si->si_ridtxt, 1391 BER_BVISNULL( &cookie ) ? "" : cookie.bv_val ); 1392 1393 if ( !BER_BVISNULL( &cookie ) ) { 1394 ch_free( syncCookie.octet_str.bv_val ); 1395 ber_dupbv( &syncCookie.octet_str, &cookie ); 1396 1397 ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex ); 1398 ber_bvreplace( &si->si_lastCookieRcvd, &cookie ); 1399 ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex ); 1400 } 1401 if ( !BER_BVISNULL( &syncCookie.octet_str ) ) 1402 { 1403 slap_parse_sync_cookie( &syncCookie, NULL ); 1404 if ( syncCookie.ctxcsn ) { 1405 int i, slot, sid = slap_parse_csn_sid( syncCookie.ctxcsn ); 1406 check_syncprov( op, si ); 1407 ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex ); 1408 i = check_csn_age( si, &bdn, syncCookie.ctxcsn, sid, (cookie_vals *)&si->si_cookieState->cs_vals, NULL ); 1409 ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex ); 1410 if ( i == CV_CSN_OLD ) { 1411 si->si_too_old = 1; 1412 ldap_controls_free( rctrls ); 1413 rc = 0; 1414 goto done; 1415 } 1416 si->si_too_old = 0; 1417 1418 /* check pending CSNs too */ 1419 if (( rc = get_pmutex( si ))) 1420 goto done; 1421 1422 i = check_csn_age( si, &bdn, syncCookie.ctxcsn, sid, (cookie_vals *)&si->si_cookieState->cs_pvals, &slot ); 1423 if ( i == CV_CSN_OK ) { 1424 ber_bvreplace( &si->si_cookieState->cs_pvals[slot], 1425 syncCookie.ctxcsn ); 1426 } else if ( i == CV_CSN_OLD ) { 1427 ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex ); 1428 ldap_controls_free( rctrls ); 1429 rc = 0; 1430 goto done; 1431 } else { 1432 /* new SID, add it */ 1433 slap_insert_csn_sids( 1434 (struct sync_cookie *)&si->si_cookieState->cs_pvals, 1435 slot, sid, syncCookie.ctxcsn ); 1436 } 1437 assert( punlock < 0 ); 1438 punlock = slot; 1439 } else if (si->si_too_old) { 1440 bdn.bv_val[bdn.bv_len] = '\0'; 1441 Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring (%s)\n", 1442 si->si_ridtxt, bdn.bv_val ); 1443 ldap_controls_free( rctrls ); 1444 rc = 0; 1445 goto done; 1446 } 1447 op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie; 1448 } 1449 } 1450 } 1451 rc = 0; 1452 if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) { 1453 modlist = NULL; 1454 if ( ( rc = syncrepl_message_to_op( si, op, msg, punlock < 0 ) ) == LDAP_SUCCESS && 1455 syncCookie.ctxcsn ) 1456 { 1457 rc = syncrepl_updateCookie( si, op, &syncCookie, 0 ); 1458 } else 1459 logerr: 1460 switch ( rc ) { 1461 case LDAP_ALREADY_EXISTS: 1462 case LDAP_NO_SUCH_OBJECT: 1463 case LDAP_NO_SUCH_ATTRIBUTE: 1464 case LDAP_TYPE_OR_VALUE_EXISTS: 1465 case LDAP_NOT_ALLOWED_ON_NONLEAF: 1466 rc = LDAP_SYNC_REFRESH_REQUIRED; 1467 si->si_logstate = SYNCLOG_FALLBACK; 1468 ldap_abandon_ext( si->si_ld, si->si_msgid, NULL, NULL ); 1469 bdn.bv_val[bdn.bv_len] = '\0'; 1470 Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s delta-sync lost sync on (%s), switching to REFRESH\n", 1471 si->si_ridtxt, bdn.bv_val ); 1472 if (si->si_strict_refresh) { 1473 slap_suspend_listeners(); 1474 connections_drop(); 1475 } 1476 break; 1477 default: 1478 break; 1479 } 1480 } else if ( ( rc = syncrepl_message_to_entry( si, op, msg, 1481 &modlist, &entry, syncstate, syncUUID ) ) == LDAP_SUCCESS ) 1482 { 1483 if ( punlock < 0 ) { 1484 if (( rc = get_pmutex( si ))) 1485 goto done; 1486 } 1487 if ( ( rc = syncrepl_entry( si, op, entry, &modlist, 1488 syncstate, syncUUID, syncCookie.ctxcsn ) ) == LDAP_SUCCESS && 1489 syncCookie.ctxcsn ) 1490 { 1491 rc = syncrepl_updateCookie( si, op, &syncCookie, 0 ); 1492 } 1493 if ( punlock < 0 ) 1494 ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex ); 1495 } 1496 if ( punlock >= 0 ) { 1497 /* on failure, revert pending CSN */ 1498 if ( rc != LDAP_SUCCESS ) { 1499 int i; 1500 ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex ); 1501 for ( i = 0; i<si->si_cookieState->cs_num; i++ ) { 1502 if ( si->si_cookieState->cs_sids[i] == si->si_cookieState->cs_psids[punlock] ) { 1503 ber_bvreplace( &si->si_cookieState->cs_pvals[punlock], 1504 &si->si_cookieState->cs_vals[i] ); 1505 break; 1506 } 1507 } 1508 if ( i == si->si_cookieState->cs_num ) 1509 si->si_cookieState->cs_pvals[punlock].bv_val[0] = '\0'; 1510 ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex ); 1511 } 1512 ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex ); 1513 } 1514 ldap_controls_free( rctrls ); 1515 if ( modlist ) { 1516 slap_mods_free( modlist, 1 ); 1517 } 1518 if ( rc ) 1519 goto done; 1520 break; 1521 1522 case LDAP_RES_SEARCH_REFERENCE: 1523 Debug( LDAP_DEBUG_ANY, 1524 "do_syncrep2: %s reference received error\n", 1525 si->si_ridtxt ); 1526 break; 1527 1528 case LDAP_RES_SEARCH_RESULT: 1529 Debug( LDAP_DEBUG_SYNC, 1530 "do_syncrep2: %s LDAP_RES_SEARCH_RESULT\n", 1531 si->si_ridtxt ); 1532 err = LDAP_OTHER; /* FIXME check parse result properly */ 1533 ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL, 1534 &rctrls, 0 ); 1535 #ifdef LDAP_X_SYNC_REFRESH_REQUIRED 1536 if ( err == LDAP_X_SYNC_REFRESH_REQUIRED ) { 1537 /* map old result code to registered code */ 1538 err = LDAP_SYNC_REFRESH_REQUIRED; 1539 } 1540 #endif 1541 if ( err == LDAP_SYNC_REFRESH_REQUIRED ) { 1542 if ( si->si_logstate == SYNCLOG_LOGGING ) { 1543 si->si_logstate = SYNCLOG_FALLBACK; 1544 Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s delta-sync lost sync, switching to REFRESH\n", 1545 si->si_ridtxt ); 1546 if (si->si_strict_refresh) { 1547 slap_suspend_listeners(); 1548 connections_drop(); 1549 } 1550 } 1551 rc = err; 1552 goto done; 1553 } 1554 if ( err ) { 1555 Debug( LDAP_DEBUG_ANY, 1556 "do_syncrep2: %s LDAP_RES_SEARCH_RESULT (%d) %s\n", 1557 si->si_ridtxt, err, ldap_err2string( err ) ); 1558 } 1559 if ( si->si_syncdata == SYNCDATA_CHANGELOG && err == LDAP_SUCCESS ) { 1560 rc = syncrepl_dsee_update( si, op ); 1561 if ( rc == LDAP_SUCCESS ) { 1562 if ( si->si_logstate == SYNCLOG_FALLBACK ) { 1563 si->si_logstate = SYNCLOG_LOGGING; 1564 si->si_refreshDone = 1; 1565 rc = LDAP_SYNC_REFRESH_REQUIRED; 1566 } else { 1567 rc = SYNC_REPOLL; 1568 } 1569 } 1570 goto done; 1571 } 1572 if ( rctrls ) { 1573 LDAPControl **next = NULL; 1574 #ifdef LDAP_CONTROL_X_DIRSYNC 1575 if ( si->si_ctype == MSAD_DIRSYNC ) { 1576 rc = syncrepl_dirsync_cookie( si, op, rctrls ); 1577 if ( rc == LDAP_SUCCESS ) 1578 rc = SYNC_REPOLL; /* schedule a re-poll */ 1579 goto done; 1580 } 1581 #endif 1582 /* NOTE: make sure we use the right one; 1583 * a better approach would be to run thru 1584 * the whole list and take care of all */ 1585 /* NOTE: since we issue the search request, 1586 * we should know what controls to expect, 1587 * and there should be none apart from the 1588 * sync-related control */ 1589 rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_DONE, rctrls, &next ); 1590 if ( next && ldap_control_find( LDAP_CONTROL_SYNC_DONE, next, NULL ) ) 1591 { 1592 Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s " 1593 "got search result with multiple " 1594 "Sync State control\n", si->si_ridtxt ); 1595 ldap_controls_free( rctrls ); 1596 rc = SYNC_ERROR; 1597 goto done; 1598 } 1599 } 1600 if ( rctrlp ) { 1601 ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER ); 1602 1603 ber_scanf( ber, "{" /*"}"*/); 1604 if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) { 1605 ber_scanf( ber, "m", &cookie ); 1606 1607 Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n", 1608 si->si_ridtxt, 1609 BER_BVISNULL( &cookie ) ? "" : cookie.bv_val ); 1610 1611 if ( !BER_BVISNULL( &cookie ) ) { 1612 ch_free( syncCookie.octet_str.bv_val ); 1613 ber_dupbv( &syncCookie.octet_str, &cookie); 1614 1615 ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex ); 1616 ber_bvreplace( &si->si_lastCookieRcvd, &cookie ); 1617 ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex ); 1618 } 1619 if ( !BER_BVISNULL( &syncCookie.octet_str ) ) 1620 { 1621 slap_parse_sync_cookie( &syncCookie, NULL ); 1622 op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie; 1623 } 1624 } 1625 if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES ) 1626 { 1627 ber_scanf( ber, "b", &refreshDeletes ); 1628 } 1629 ber_scanf( ber, /*"{"*/ "}" ); 1630 } 1631 if ( SLAP_MULTIPROVIDER( op->o_bd ) && check_syncprov( op, si )) { 1632 slap_sync_cookie_free( &syncCookie_req, 0 ); 1633 slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie ); 1634 } 1635 if ( !syncCookie.ctxcsn ) { 1636 match = 1; 1637 } else if ( !syncCookie_req.ctxcsn ) { 1638 match = -1; 1639 m = 0; 1640 } else { 1641 match = compare_csns( &syncCookie_req, &syncCookie, &m ); 1642 } 1643 if ( rctrls ) { 1644 ldap_controls_free( rctrls ); 1645 } 1646 if (si->si_type != LDAP_SYNC_REFRESH_AND_PERSIST) { 1647 /* FIXME : different error behaviors according to 1648 * 1) err code : LDAP_BUSY ... 1649 * 2) on err policy : stop service, stop sync, retry 1650 */ 1651 if ( refreshDeletes == 0 && match < 0 && err == LDAP_SUCCESS ) 1652 { 1653 syncrepl_del_nonpresent( op, si, NULL, 1654 &syncCookie, m ); 1655 } else if ( si->si_presentlist ) { 1656 presentlist_free( si->si_presentlist ); 1657 si->si_presentlist = NULL; 1658 } 1659 } 1660 if ( syncCookie.ctxcsn && match < 0 && err == LDAP_SUCCESS ) 1661 { 1662 rc = syncrepl_updateCookie( si, op, &syncCookie, 1 ); 1663 } 1664 if ( err == LDAP_SUCCESS 1665 && si->si_logstate == SYNCLOG_FALLBACK ) { 1666 si->si_logstate = SYNCLOG_LOGGING; 1667 si->si_refreshDone = 1; 1668 rc = LDAP_SYNC_REFRESH_REQUIRED; 1669 slap_resume_listeners(); 1670 } else { 1671 /* for persist, we shouldn't get a SearchResult so this is an error */ 1672 if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ) 1673 rc = SYNC_ERROR; 1674 else 1675 rc = SYNC_REPOLL; 1676 } 1677 goto done; 1678 1679 case LDAP_RES_INTERMEDIATE: 1680 retoid = NULL; 1681 retdata = NULL; 1682 rc = ldap_parse_intermediate( si->si_ld, msg, 1683 &retoid, &retdata, NULL, 0 ); 1684 if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) { 1685 ber_init2( ber, retdata, LBER_USE_DER ); 1686 1687 switch ( si_tag = ber_peek_tag( ber, &len ) ) { 1688 ber_tag_t tag; 1689 case LDAP_TAG_SYNC_NEW_COOKIE: 1690 Debug( LDAP_DEBUG_SYNC, 1691 "do_syncrep2: %s %s - %s\n", 1692 si->si_ridtxt, 1693 "LDAP_RES_INTERMEDIATE", 1694 "NEW_COOKIE" ); 1695 ber_scanf( ber, "tm", &tag, &cookie ); 1696 Debug( LDAP_DEBUG_SYNC, 1697 "do_syncrep2: %s NEW_COOKIE: %s\n", 1698 si->si_ridtxt, 1699 cookie.bv_val ); 1700 if ( !BER_BVISNULL( &cookie ) ) { 1701 ch_free( syncCookie.octet_str.bv_val ); 1702 ber_dupbv( &syncCookie.octet_str, &cookie ); 1703 1704 ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex ); 1705 ber_bvreplace( &si->si_lastCookieRcvd, &cookie ); 1706 ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex ); 1707 } 1708 if (!BER_BVISNULL( &syncCookie.octet_str ) ) { 1709 slap_parse_sync_cookie( &syncCookie, NULL ); 1710 op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie; 1711 } 1712 break; 1713 case LDAP_TAG_SYNC_REFRESH_DELETE: 1714 case LDAP_TAG_SYNC_REFRESH_PRESENT: 1715 Debug( LDAP_DEBUG_SYNC, 1716 "do_syncrep2: %s %s - %s\n", 1717 si->si_ridtxt, 1718 "LDAP_RES_INTERMEDIATE", 1719 si_tag == LDAP_TAG_SYNC_REFRESH_PRESENT ? 1720 "REFRESH_PRESENT" : "REFRESH_DELETE" ); 1721 if ( si_tag == LDAP_TAG_SYNC_REFRESH_DELETE ) { 1722 si->si_refreshDelete = 1; 1723 } else { 1724 si->si_refreshPresent = 1; 1725 } 1726 ber_scanf( ber, "t{" /*"}"*/, &tag ); 1727 if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) 1728 { 1729 ber_scanf( ber, "m", &cookie ); 1730 1731 Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n", 1732 si->si_ridtxt, 1733 BER_BVISNULL( &cookie ) ? "" : cookie.bv_val ); 1734 1735 if ( !BER_BVISNULL( &cookie ) ) { 1736 ch_free( syncCookie.octet_str.bv_val ); 1737 ber_dupbv( &syncCookie.octet_str, &cookie ); 1738 1739 ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex ); 1740 ber_bvreplace( &si->si_lastCookieRcvd, &cookie ); 1741 ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex ); 1742 } 1743 if ( !BER_BVISNULL( &syncCookie.octet_str ) ) 1744 { 1745 slap_parse_sync_cookie( &syncCookie, NULL ); 1746 op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie; 1747 } 1748 } 1749 /* Defaults to TRUE */ 1750 if ( ber_peek_tag( ber, &len ) == 1751 LDAP_TAG_REFRESHDONE ) 1752 { 1753 ber_scanf( ber, "b", &si->si_refreshDone ); 1754 } else 1755 { 1756 si->si_refreshDone = 1; 1757 } 1758 ber_scanf( ber, /*"{"*/ "}" ); 1759 if ( si->si_refreshDone ) { 1760 Debug( LDAP_DEBUG_SYNC, "do_syncrep1: %s finished refresh\n", 1761 si->si_ridtxt ); 1762 } 1763 break; 1764 case LDAP_TAG_SYNC_ID_SET: 1765 Debug( LDAP_DEBUG_SYNC, 1766 "do_syncrep2: %s %s - %s\n", 1767 si->si_ridtxt, 1768 "LDAP_RES_INTERMEDIATE", 1769 "SYNC_ID_SET" ); 1770 ber_scanf( ber, "t{" /*"}"*/, &tag ); 1771 if ( ber_peek_tag( ber, &len ) == 1772 LDAP_TAG_SYNC_COOKIE ) 1773 { 1774 ber_scanf( ber, "m", &cookie ); 1775 1776 Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n", 1777 si->si_ridtxt, 1778 BER_BVISNULL( &cookie ) ? "" : cookie.bv_val ); 1779 1780 if ( !BER_BVISNULL( &cookie ) ) { 1781 ch_free( syncCookie.octet_str.bv_val ); 1782 ber_dupbv( &syncCookie.octet_str, &cookie ); 1783 1784 ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex ); 1785 ber_bvreplace( &si->si_lastCookieRcvd, &cookie ); 1786 ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex ); 1787 } 1788 if ( !BER_BVISNULL( &syncCookie.octet_str ) ) 1789 { 1790 slap_parse_sync_cookie( &syncCookie, NULL ); 1791 op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie; 1792 compare_csns( &syncCookie_req, &syncCookie, &m ); 1793 } 1794 } 1795 if ( ber_peek_tag( ber, &len ) == 1796 LDAP_TAG_REFRESHDELETES ) 1797 { 1798 ber_scanf( ber, "b", &refreshDeletes ); 1799 } 1800 syncUUIDs = NULL; 1801 rc = ber_scanf( ber, "[W]", &syncUUIDs ); 1802 ber_scanf( ber, /*"{"*/ "}" ); 1803 if ( rc != LBER_ERROR ) { 1804 if ( refreshDeletes ) { 1805 syncrepl_del_nonpresent( op, si, syncUUIDs, 1806 &syncCookie, m ); 1807 ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx ); 1808 } else { 1809 int i; 1810 for ( i = 0; !BER_BVISNULL( &syncUUIDs[i] ); i++ ) { 1811 (void)presentlist_insert( si, &syncUUIDs[i] ); 1812 slap_sl_free( syncUUIDs[i].bv_val, op->o_tmpmemctx ); 1813 } 1814 slap_sl_free( syncUUIDs, op->o_tmpmemctx ); 1815 } 1816 } 1817 rc = 0; 1818 slap_sync_cookie_free( &syncCookie, 0 ); 1819 break; 1820 default: 1821 Debug( LDAP_DEBUG_ANY, 1822 "do_syncrep2: %s unknown syncinfo tag (%ld)\n", 1823 si->si_ridtxt, (long) si_tag ); 1824 ldap_memfree( retoid ); 1825 ber_bvfree( retdata ); 1826 continue; 1827 } 1828 1829 if ( SLAP_MULTIPROVIDER( op->o_bd ) && check_syncprov( op, si )) { 1830 slap_sync_cookie_free( &syncCookie_req, 0 ); 1831 slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie ); 1832 } 1833 if ( !syncCookie.ctxcsn ) { 1834 match = 1; 1835 } else if ( !syncCookie_req.ctxcsn ) { 1836 match = -1; 1837 m = 0; 1838 } else { 1839 match = compare_csns( &syncCookie_req, &syncCookie, &m ); 1840 } 1841 1842 if ( match < 0 ) { 1843 if ( si->si_refreshPresent == 1 && 1844 si_tag != LDAP_TAG_SYNC_NEW_COOKIE ) { 1845 syncrepl_del_nonpresent( op, si, NULL, 1846 &syncCookie, m ); 1847 } 1848 1849 if ( syncCookie.ctxcsn ) 1850 { 1851 rc = syncrepl_updateCookie( si, op, &syncCookie, 1 ); 1852 } 1853 if ( si->si_presentlist ) { 1854 presentlist_free( si->si_presentlist ); 1855 si->si_presentlist = NULL; 1856 } 1857 } 1858 1859 ldap_memfree( retoid ); 1860 ber_bvfree( retdata ); 1861 1862 if ( rc ) 1863 goto done; 1864 1865 } else { 1866 Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s " 1867 "unknown intermediate response (%d)\n", 1868 si->si_ridtxt, rc ); 1869 ldap_memfree( retoid ); 1870 ber_bvfree( retdata ); 1871 } 1872 break; 1873 1874 default: 1875 Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s " 1876 "unknown message (0x%02lx)\n", 1877 si->si_ridtxt, 1878 (unsigned long)ldap_msgtype( msg ) ); 1879 break; 1880 1881 } 1882 if ( !BER_BVISNULL( &syncCookie.octet_str ) ) { 1883 slap_sync_cookie_free( &syncCookie_req, 0 ); 1884 syncCookie_req = syncCookie; 1885 memset( &syncCookie, 0, sizeof( syncCookie )); 1886 } 1887 ldap_msgfree( msg ); 1888 msg = NULL; 1889 if ( ldap_pvt_thread_pool_pausing( &connection_pool )) { 1890 slap_sync_cookie_free( &syncCookie, 0 ); 1891 slap_sync_cookie_free( &syncCookie_req, 0 ); 1892 return SYNC_PAUSED; 1893 } 1894 } 1895 1896 if ( rc == SYNC_ERROR ) { 1897 rc = LDAP_OTHER; 1898 ldap_get_option( si->si_ld, LDAP_OPT_ERROR_NUMBER, &rc ); 1899 err = rc; 1900 } 1901 1902 done: 1903 if ( err != LDAP_SUCCESS ) { 1904 Debug( LDAP_DEBUG_ANY, 1905 "do_syncrep2: %s (%d) %s\n", 1906 si->si_ridtxt, err, ldap_err2string( err ) ); 1907 } 1908 1909 slap_sync_cookie_free( &syncCookie, 0 ); 1910 slap_sync_cookie_free( &syncCookie_req, 0 ); 1911 1912 if ( msg ) ldap_msgfree( msg ); 1913 1914 if ( rc ) { 1915 if ( rc == LDAP_SYNC_REFRESH_REQUIRED && si->si_logstate == SYNCLOG_LOGGING && si->si_ld ) 1916 return rc; 1917 /* never reuse existing connection */ 1918 if ( si->si_conn ) { 1919 connection_client_stop( si->si_conn ); 1920 si->si_conn = NULL; 1921 } 1922 ldap_unbind_ext( si->si_ld, NULL, NULL ); 1923 si->si_ld = NULL; 1924 } 1925 1926 return rc; 1927 } 1928 1929 static int 1930 syncrepl_monitor_add( syncinfo_t *si ); 1931 1932 static int 1933 syncrepl_monitor_del( syncinfo_t *si ); 1934 1935 static void * 1936 do_syncrepl( 1937 void *ctx, 1938 void *arg ) 1939 { 1940 struct re_s* rtask = arg; 1941 syncinfo_t *si = ( syncinfo_t * ) rtask->arg; 1942 Connection conn = {0}; 1943 OperationBuffer opbuf; 1944 Operation *op; 1945 int rc = LDAP_SUCCESS; 1946 int dostop = 0; 1947 ber_socket_t s; 1948 int i, fail = 0, freeinfo = 0; 1949 Backend *be; 1950 1951 if ( si == NULL ) 1952 return NULL; 1953 if ( slapd_shutdown ) 1954 return NULL; 1955 1956 if ( !si->si_monitorInited ) { 1957 syncrepl_monitor_add( si ); 1958 si->si_monitorInited = 1; 1959 } 1960 1961 Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl %s\n", si->si_ridtxt ); 1962 1963 /* Don't get stuck here while a pause is initiated */ 1964 while ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) { 1965 if ( slapd_shutdown ) 1966 return NULL; 1967 if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool )) 1968 ldap_pvt_thread_yield(); 1969 } 1970 1971 si->si_too_old = 0; 1972 1973 if ( si->si_ctype < 1 ) { 1974 goto deleted; 1975 } 1976 1977 switch( abs( si->si_type ) ) { 1978 case LDAP_SYNC_REFRESH_ONLY: 1979 case LDAP_SYNC_REFRESH_AND_PERSIST: 1980 #ifdef LDAP_CONTROL_X_DIRSYNC 1981 case MSAD_DIRSYNC: 1982 #endif 1983 break; 1984 default: 1985 ldap_pvt_thread_mutex_unlock( &si->si_mutex ); 1986 return NULL; 1987 } 1988 1989 if ( slapd_shutdown ) { 1990 if ( si->si_ld ) { 1991 if ( si->si_conn ) { 1992 connection_client_stop( si->si_conn ); 1993 si->si_conn = NULL; 1994 } 1995 ldap_unbind_ext( si->si_ld, NULL, NULL ); 1996 si->si_ld = NULL; 1997 } 1998 ldap_pvt_thread_mutex_unlock( &si->si_mutex ); 1999 return NULL; 2000 } 2001 2002 connection_fake_init( &conn, &opbuf, ctx ); 2003 op = &opbuf.ob_op; 2004 /* o_connids must be unique for slap_graduate_commit_csn */ 2005 op->o_connid = SLAPD_SYNC_RID2SYNCCONN(si->si_rid); 2006 2007 op->o_managedsait = SLAP_CONTROL_NONCRITICAL; 2008 be = si->si_be; 2009 2010 /* Coordinate contextCSN updates with any syncprov overlays 2011 * in use. This may be complicated by the use of the glue 2012 * overlay. 2013 * 2014 * Typically there is a single syncprov controlling the entire 2015 * glued tree. In that case, our contextCSN updates should 2016 * go to the primary DB. But if there is no syncprov on the 2017 * primary DB, then nothing special is needed here. 2018 * 2019 * Alternatively, there may be individual syncprov overlays 2020 * on each glued branch. In that case, each syncprov only 2021 * knows about changes within its own branch. And so our 2022 * contextCSN updates should only go to the local DB. 2023 */ 2024 if ( !si->si_wbe ) { 2025 if ( SLAP_GLUE_SUBORDINATE( be ) && !overlay_is_inst( be, "syncprov" )) { 2026 BackendDB * top_be = select_backend( &be->be_nsuffix[0], 1 ); 2027 if ( overlay_is_inst( top_be, "syncprov" )) 2028 si->si_wbe = top_be; 2029 else 2030 si->si_wbe = be; 2031 } else { 2032 si->si_wbe = be; 2033 } 2034 if ( SLAP_SYNC_SUBENTRY( si->si_wbe )) { 2035 build_new_dn( &si->si_contextdn, &si->si_wbe->be_nsuffix[0], 2036 (struct berval *)&slap_ldapsync_cn_bv, NULL ); 2037 } else { 2038 si->si_contextdn = si->si_wbe->be_nsuffix[0]; 2039 } 2040 } 2041 if ( !si->si_schemachecking ) 2042 op->o_no_schema_check = 1; 2043 2044 /* Establish session, do search */ 2045 if ( !si->si_ld ) { 2046 si->si_refreshDelete = 0; 2047 si->si_refreshPresent = 0; 2048 2049 if ( si->si_presentlist ) { 2050 presentlist_free( si->si_presentlist ); 2051 si->si_presentlist = NULL; 2052 } 2053 2054 /* use main DB when retrieving contextCSN */ 2055 op->o_bd = si->si_wbe; 2056 op->o_dn = op->o_bd->be_rootdn; 2057 op->o_ndn = op->o_bd->be_rootndn; 2058 rc = do_syncrep1( op, si ); 2059 } 2060 2061 reload: 2062 /* Process results */ 2063 if ( rc == LDAP_SUCCESS ) { 2064 ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s ); 2065 2066 if ( !BER_BVISEMPTY( &si->si_monitor_ndn )) 2067 { 2068 Sockaddr addr; 2069 socklen_t len = sizeof( addr ); 2070 if ( !getsockname( s, &addr.sa_addr, &len )) { 2071 si->si_connaddr.bv_val = si->si_connaddrbuf; 2072 si->si_connaddr.bv_len = sizeof( si->si_connaddrbuf ); 2073 ldap_pvt_sockaddrstr( &addr, &si->si_connaddr ); 2074 } 2075 } 2076 2077 /* use current DB */ 2078 op->o_bd = be; 2079 op->o_dn = op->o_bd->be_rootdn; 2080 op->o_ndn = op->o_bd->be_rootndn; 2081 rc = do_syncrep2( op, si ); 2082 if ( rc == LDAP_SYNC_REFRESH_REQUIRED ) { 2083 if ( si->si_logstate == SYNCLOG_LOGGING ) { 2084 if ( BER_BVISNULL( &si->si_syncCookie.octet_str )) 2085 slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str, 2086 si->si_syncCookie.ctxcsn, si->si_syncCookie.rid, 2087 si->si_syncCookie.sid, NULL ); 2088 rc = ldap_sync_search( si, op->o_tmpmemctx ); 2089 goto reload; 2090 } 2091 /* give up but schedule an immedite retry */ 2092 rc = SYNC_PAUSED; 2093 } 2094 2095 deleted: 2096 /* We got deleted while running on cn=config */ 2097 if ( si->si_ctype < 1 ) { 2098 if ( si->si_ctype == -1 ) { 2099 si->si_ctype = 0; 2100 freeinfo = 1; 2101 } 2102 if ( si->si_conn ) 2103 dostop = 1; 2104 rc = SYNC_SHUTDOWN; 2105 } 2106 2107 if ( rc != SYNC_PAUSED ) { 2108 if ( rc == SYNC_TIMEOUT ) { 2109 /* there was nothing to read, try to listen for more */ 2110 if ( si->si_conn ) { 2111 connection_client_enable( si->si_conn ); 2112 } else { 2113 si->si_conn = connection_client_setup( s, do_syncrepl, arg ); 2114 } 2115 } else if ( si->si_conn ) { 2116 dostop = 1; 2117 } 2118 } 2119 } 2120 2121 /* At this point, we have 5 cases: 2122 * 1) for any hard failure, give up and remove this task 2123 * 2) for ServerDown, reschedule this task to run later 2124 * 3) for threadpool pause, reschedule to run immediately 2125 * 4) for SYNC_REPOLL, reschedule to run later 2126 * 5) for SYNC_TIMEOUT, reschedule to defer 2127 */ 2128 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 2129 2130 if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask ) ) { 2131 ldap_pvt_runqueue_stoptask( &slapd_rq, rtask ); 2132 } 2133 2134 if ( dostop ) { 2135 connection_client_stop( si->si_conn ); 2136 si->si_conn = NULL; 2137 } 2138 2139 if ( rc == SYNC_PAUSED ) { 2140 rtask->interval.tv_sec = 0; 2141 ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 ); 2142 rtask->interval.tv_sec = si->si_interval; 2143 rc = 0; 2144 } else if ( rc == SYNC_TIMEOUT ) { 2145 ldap_pvt_runqueue_resched( &slapd_rq, rtask, 1 ); 2146 } else if ( rc == SYNC_REPOLL ) { 2147 rtask->interval.tv_sec = si->si_interval; 2148 ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 ); 2149 if ( si->si_retrynum ) { 2150 for ( i = 0; si->si_retrynum_init[i] != RETRYNUM_TAIL; i++ ) { 2151 si->si_retrynum[i] = si->si_retrynum_init[i]; 2152 } 2153 si->si_retrynum[i] = RETRYNUM_TAIL; 2154 } 2155 slap_wake_listener(); 2156 rc = 0; 2157 } else { 2158 for ( i = 0; si->si_retrynum && si->si_retrynum[i] <= 0; i++ ) { 2159 if ( si->si_retrynum[i] == RETRYNUM_FOREVER || si->si_retrynum[i] == RETRYNUM_TAIL ) 2160 break; 2161 } 2162 2163 if ( si->si_ctype < 1 || rc == SYNC_SHUTDOWN 2164 || !si->si_retrynum || si->si_retrynum[i] == RETRYNUM_TAIL ) { 2165 if ( si->si_re ) { 2166 ldap_pvt_runqueue_remove( &slapd_rq, rtask ); 2167 si->si_re = NULL; 2168 } 2169 fail = RETRYNUM_TAIL; 2170 } else if ( RETRYNUM_VALID( si->si_retrynum[i] ) ) { 2171 if ( si->si_retrynum[i] > 0 ) 2172 si->si_retrynum[i]--; 2173 fail = si->si_retrynum[i]; 2174 rtask->interval.tv_sec = si->si_retryinterval[i]; 2175 ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 ); 2176 slap_wake_listener(); 2177 } 2178 } 2179 2180 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 2181 ldap_pvt_thread_mutex_unlock( &si->si_mutex ); 2182 2183 if ( rc ) { 2184 if ( fail == RETRYNUM_TAIL ) { 2185 Debug( LDAP_DEBUG_ANY, 2186 "do_syncrepl: %s rc %d quitting\n", 2187 si->si_ridtxt, rc ); 2188 } else if ( fail > 0 ) { 2189 Debug( LDAP_DEBUG_ANY, 2190 "do_syncrepl: %s rc %d retrying (%d retries left)\n", 2191 si->si_ridtxt, rc, fail ); 2192 } else { 2193 Debug( LDAP_DEBUG_ANY, 2194 "do_syncrepl: %s rc %d retrying\n", 2195 si->si_ridtxt, rc ); 2196 } 2197 } 2198 2199 /* Do final delete cleanup */ 2200 if ( freeinfo ) { 2201 syncinfo_free( si, 0 ); 2202 } 2203 return NULL; 2204 } 2205 2206 static int 2207 syncrepl_rewrite_dn( 2208 syncinfo_t *si, 2209 struct berval *dn, 2210 struct berval *sdn ) 2211 { 2212 char nul; 2213 int rc; 2214 2215 nul = dn->bv_val[dn->bv_len]; 2216 dn->bv_val[dn->bv_len] = 0; 2217 rc = rewrite( si->si_rewrite, SUFFIXM_CTX, dn->bv_val, &sdn->bv_val ); 2218 dn->bv_val[dn->bv_len] = nul; 2219 2220 if ( sdn->bv_val == dn->bv_val ) 2221 sdn->bv_val = NULL; 2222 else if ( rc == REWRITE_REGEXEC_OK && sdn->bv_val ) 2223 sdn->bv_len = strlen( sdn->bv_val ); 2224 return rc; 2225 } 2226 #define REWRITE_VAL(si, ad, bv, bv2) \ 2227 BER_BVZERO( &bv2 ); \ 2228 if ( si->si_rewrite && ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName) \ 2229 syncrepl_rewrite_dn( si, &bv, &bv2); \ 2230 if ( BER_BVISNULL( &bv2 )) \ 2231 ber_dupbv( &bv2, &bv ) 2232 #define REWRITE_DN(si, bv, bv2, dn, ndn) \ 2233 BER_BVZERO( &bv2 ); \ 2234 if (si->si_rewrite) \ 2235 syncrepl_rewrite_dn(si, &bv, &bv2); \ 2236 rc = dnPrettyNormal( NULL, bv2.bv_val ? &bv2 : &bv, &dn, &ndn, op->o_tmpmemctx ); \ 2237 ch_free(bv2.bv_val) 2238 2239 static slap_verbmasks modops[] = { 2240 { BER_BVC("add"), LDAP_REQ_ADD }, 2241 { BER_BVC("delete"), LDAP_REQ_DELETE }, 2242 { BER_BVC("modify"), LDAP_REQ_MODIFY }, 2243 { BER_BVC("modrdn"), LDAP_REQ_MODRDN}, 2244 { BER_BVNULL, 0 } 2245 }; 2246 2247 static int 2248 syncrepl_accesslog_mods( 2249 syncinfo_t *si, 2250 struct berval *vals, 2251 struct Modifications **modres 2252 ) 2253 { 2254 char *colon; 2255 const char *text; 2256 AttributeDescription *ad; 2257 struct berval bv, bv2; 2258 short op; 2259 Modifications *mod = NULL, *modlist = NULL, **modtail; 2260 int i, rc = 0; 2261 2262 modtail = &modlist; 2263 2264 for (i=0; !BER_BVISNULL( &vals[i] ); i++) { 2265 ad = NULL; 2266 bv = vals[i]; 2267 2268 colon = ber_bvchr( &bv, ':' ); 2269 if ( !colon ) { 2270 /* Invalid */ 2271 continue; 2272 } else if ( colon == bv.bv_val ) { 2273 /* ITS#6545: An empty attribute signals that a new mod 2274 * is about to start */ 2275 mod = NULL; 2276 continue; 2277 } 2278 2279 bv.bv_len = colon - bv.bv_val; 2280 if ( slap_bv2ad( &bv, &ad, &text ) ) { 2281 /* Invalid */ 2282 Debug( LDAP_DEBUG_ANY, "syncrepl_accesslog_mods: %s " 2283 "Invalid attribute %s, %s\n", 2284 si->si_ridtxt, bv.bv_val, text ); 2285 slap_mods_free( modlist, 1 ); 2286 modlist = NULL; 2287 rc = -1; 2288 break; 2289 } 2290 2291 /* Ignore dynamically generated attrs */ 2292 if ( ad->ad_type->sat_flags & SLAP_AT_DYNAMIC ) { 2293 continue; 2294 } 2295 2296 /* Ignore excluded attrs */ 2297 if ( ldap_charray_inlist( si->si_exattrs, 2298 ad->ad_type->sat_cname.bv_val ) ) 2299 { 2300 continue; 2301 } 2302 2303 switch(colon[1]) { 2304 case '+': op = LDAP_MOD_ADD; break; 2305 case '-': op = LDAP_MOD_DELETE; break; 2306 case '=': op = LDAP_MOD_REPLACE; break; 2307 case '#': op = LDAP_MOD_INCREMENT; break; 2308 default: continue; 2309 } 2310 2311 if ( !mod || ad != mod->sml_desc || op != mod->sml_op ) { 2312 mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); 2313 mod->sml_flags = 0; 2314 mod->sml_op = op; 2315 mod->sml_next = NULL; 2316 mod->sml_desc = ad; 2317 mod->sml_type = ad->ad_cname; 2318 mod->sml_values = NULL; 2319 mod->sml_nvalues = NULL; 2320 mod->sml_numvals = 0; 2321 2322 if ( is_at_single_value( ad->ad_type ) ) { 2323 if ( op == LDAP_MOD_ADD ) { 2324 /* ITS#9295 an ADD might conflict with an existing value */ 2325 mod->sml_op = LDAP_MOD_REPLACE; 2326 } else if ( op == LDAP_MOD_DELETE ) { 2327 /* ITS#9295 the above REPLACE could invalidate subsequent 2328 * DELETEs */ 2329 mod->sml_op = SLAP_MOD_SOFTDEL; 2330 } 2331 } 2332 2333 *modtail = mod; 2334 modtail = &mod->sml_next; 2335 } 2336 if ( colon[2] == ' ' ) { 2337 bv.bv_val = colon + 3; 2338 bv.bv_len = vals[i].bv_len - ( bv.bv_val - vals[i].bv_val ); 2339 REWRITE_VAL( si, ad, bv, bv2 ); 2340 ber_bvarray_add( &mod->sml_values, &bv2 ); 2341 mod->sml_numvals++; 2342 } 2343 } 2344 *modres = modlist; 2345 return rc; 2346 } 2347 2348 static int 2349 syncrepl_dsee_uuid( 2350 struct berval *dseestr, 2351 struct berval *syncUUID, 2352 void *ctx 2353 ) 2354 { 2355 slap_mr_normalize_func *normf; 2356 /* DSEE UUID is of form 12345678-12345678-12345678-12345678 */ 2357 if ( dseestr->bv_len != 35 ) 2358 return -1; 2359 dseestr->bv_len++; 2360 dseestr->bv_val[35] = '-'; 2361 normf = slap_schema.si_ad_entryUUID->ad_type->sat_equality->smr_normalize; 2362 if ( normf( SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, NULL, NULL, 2363 dseestr, &syncUUID[0], ctx )) 2364 return -1; 2365 (void)slap_uuidstr_from_normalized( &syncUUID[1], &syncUUID[0], ctx ); 2366 return LDAP_SUCCESS; 2367 } 2368 2369 static int 2370 syncrepl_changelog_mods( 2371 syncinfo_t *si, 2372 ber_tag_t req, 2373 struct berval *vals, 2374 struct Modifications **modres, 2375 struct berval *uuid, 2376 void *ctx 2377 ) 2378 { 2379 LDIFRecord lr; 2380 struct berval rbuf = vals[0]; 2381 int i, rc; 2382 int lrflags = LDIF_NO_DN; 2383 Modifications *mod = NULL, *modlist = NULL, **modtail = &modlist; 2384 2385 if ( req == LDAP_REQ_ADD ) 2386 lrflags |= LDIF_ENTRIES_ONLY|LDIF_DEFAULT_ADD; 2387 else 2388 lrflags |= LDIF_MODS_ONLY; 2389 2390 rc = ldap_parse_ldif_record_x( &rbuf, 0, &lr, "syncrepl", lrflags, ctx ); 2391 for (i = 0; lr.lrop_mods[i] != NULL; i++) { 2392 AttributeDescription *ad = NULL; 2393 const char *text; 2394 int j; 2395 if ( slap_str2ad( lr.lrop_mods[i]->mod_type, &ad, &text ) ) { 2396 /* Invalid */ 2397 Debug( LDAP_DEBUG_ANY, "syncrepl_changelog_mods: %s " 2398 "Invalid attribute %s, %s\n", 2399 si->si_ridtxt, lr.lrop_mods[i]->mod_type, text ); 2400 slap_mods_free( modlist, 1 ); 2401 modlist = NULL; 2402 rc = -1; 2403 break; 2404 } 2405 mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); 2406 mod->sml_flags = 0; 2407 mod->sml_op = lr.lrop_mods[i]->mod_op ^ LDAP_MOD_BVALUES; 2408 mod->sml_next = NULL; 2409 mod->sml_desc = ad; 2410 mod->sml_type = ad->ad_cname; 2411 mod->sml_values = NULL; 2412 mod->sml_nvalues = NULL; 2413 j = 0; 2414 if ( lr.lrop_mods[i]->mod_bvalues != NULL ) { 2415 for (; lr.lrop_mods[i]->mod_bvalues[j] != NULL; j++ ) { 2416 struct berval bv, bv2; 2417 bv = *(lr.lrop_mods[i]->mod_bvalues[j]); 2418 REWRITE_VAL( si, ad, bv, bv2 ); 2419 ber_bvarray_add( &mod->sml_values, &bv2 ); 2420 } 2421 } 2422 mod->sml_numvals = j; 2423 2424 *modtail = mod; 2425 modtail = &mod->sml_next; 2426 } 2427 ldap_ldif_record_done( &lr ); 2428 2429 if ( req == LDAP_REQ_ADD && !BER_BVISNULL( uuid )) { 2430 struct berval uuids[2]; 2431 if ( !syncrepl_dsee_uuid( uuid, uuids, ctx )) { 2432 mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); 2433 mod->sml_flags = 0; 2434 mod->sml_op = LDAP_MOD_ADD; 2435 mod->sml_next = NULL; 2436 mod->sml_desc = slap_schema.si_ad_entryUUID; 2437 mod->sml_type = slap_schema.si_ad_entryUUID->ad_cname; 2438 mod->sml_values = ch_malloc( 2 * sizeof(struct berval)); 2439 mod->sml_nvalues = NULL; 2440 ber_dupbv( &mod->sml_values[0], &uuids[1] ); 2441 BER_BVZERO( &mod->sml_values[1] ); 2442 slap_sl_free( uuids[0].bv_val, ctx ); 2443 slap_sl_free( uuids[1].bv_val, ctx ); 2444 mod->sml_numvals = 1; 2445 *modtail = mod; 2446 modtail = &mod->sml_next; 2447 } 2448 } 2449 2450 *modres = modlist; 2451 return rc; 2452 } 2453 2454 typedef struct OpExtraSync { 2455 OpExtra oe; 2456 syncinfo_t *oe_si; 2457 } OpExtraSync; 2458 2459 /* Copy the original modlist, split Replace ops into Delete/Add, 2460 * and drop mod opattrs since this modification is in the past. 2461 */ 2462 static Modifications *mods_dup( Operation *op, Modifications *modlist, int match ) 2463 { 2464 Modifications *mod, *modnew = NULL, *modtail = NULL; 2465 int size; 2466 for ( ; modlist; modlist = modlist->sml_next ) { 2467 /* older ops */ 2468 if ( match < 0 ) { 2469 if ( modlist->sml_desc == slap_schema.si_ad_modifiersName || 2470 modlist->sml_desc == slap_schema.si_ad_modifyTimestamp || 2471 modlist->sml_desc == slap_schema.si_ad_entryCSN ) 2472 continue; 2473 if ( modlist->sml_values == NULL && modlist->sml_op == LDAP_MOD_REPLACE ) { 2474 /* ITS#9359 This adds no values, just change to a delete op */ 2475 modlist->sml_op = LDAP_MOD_DELETE; 2476 } else if ( modlist->sml_op == LDAP_MOD_REPLACE ) { 2477 mod = op->o_tmpalloc( sizeof(Modifications), op->o_tmpmemctx ); 2478 mod->sml_desc = modlist->sml_desc; 2479 mod->sml_values = NULL; 2480 mod->sml_nvalues = NULL; 2481 mod->sml_op = LDAP_MOD_DELETE; 2482 mod->sml_numvals = 0; 2483 mod->sml_flags = 0; 2484 if ( !modnew ) 2485 modnew = mod; 2486 if ( modtail ) 2487 modtail->sml_next = mod; 2488 modtail = mod; 2489 } 2490 } 2491 if ( modlist->sml_numvals ) { 2492 size = (modlist->sml_numvals+1) * sizeof(struct berval); 2493 if ( modlist->sml_nvalues ) size *= 2; 2494 } else { 2495 size = 0; 2496 } 2497 size += sizeof(Modifications); 2498 mod = op->o_tmpalloc( size, op->o_tmpmemctx ); 2499 if ( !modnew ) 2500 modnew = mod; 2501 if ( modtail ) 2502 modtail->sml_next = mod; 2503 modtail = mod; 2504 mod->sml_desc = modlist->sml_desc; 2505 mod->sml_numvals = modlist->sml_numvals; 2506 mod->sml_flags = 0; 2507 if ( modlist->sml_numvals ) { 2508 int i; 2509 mod->sml_values = (BerVarray)(mod+1); 2510 for (i=0; i<mod->sml_numvals; i++) 2511 mod->sml_values[i] = modlist->sml_values[i]; 2512 BER_BVZERO(&mod->sml_values[i]); 2513 if ( modlist->sml_nvalues ) { 2514 mod->sml_nvalues = mod->sml_values + mod->sml_numvals + 1; 2515 for (i=0; i<mod->sml_numvals; i++) 2516 mod->sml_nvalues[i] = modlist->sml_nvalues[i]; 2517 BER_BVZERO(&mod->sml_nvalues[i]); 2518 } else { 2519 mod->sml_nvalues = NULL; 2520 } 2521 } else { 2522 mod->sml_values = NULL; 2523 mod->sml_nvalues = NULL; 2524 } 2525 if ( match < 0 && modlist->sml_op == LDAP_MOD_REPLACE ) 2526 mod->sml_op = LDAP_MOD_ADD; 2527 else 2528 mod->sml_op = modlist->sml_op; 2529 mod->sml_next = NULL; 2530 } 2531 return modnew; 2532 } 2533 2534 typedef struct resolve_ctxt { 2535 syncinfo_t *rx_si; 2536 Modifications *rx_mods; 2537 } resolve_ctxt; 2538 2539 static void 2540 compare_vals( Modifications *m1, Modifications *m2 ) 2541 { 2542 int i, j; 2543 struct berval *bv1, *bv2; 2544 2545 if ( m2->sml_nvalues ) { 2546 bv2 = m2->sml_nvalues; 2547 bv1 = m1->sml_nvalues; 2548 } else { 2549 bv2 = m2->sml_values; 2550 bv1 = m1->sml_values; 2551 } 2552 for ( j=0; j<m2->sml_numvals; j++ ) { 2553 for ( i=0; i<m1->sml_numvals; i++ ) { 2554 if ( !ber_bvcmp( &bv1[i], &bv2[j] )) { 2555 int k; 2556 for ( k=i; k<m1->sml_numvals-1; k++ ) { 2557 m1->sml_values[k] = m1->sml_values[k+1]; 2558 if ( m1->sml_nvalues ) 2559 m1->sml_nvalues[k] = m1->sml_nvalues[k+1]; 2560 } 2561 BER_BVZERO(&m1->sml_values[k]); 2562 if ( m1->sml_nvalues ) { 2563 BER_BVZERO(&m1->sml_nvalues[k]); 2564 } 2565 m1->sml_numvals--; 2566 i--; 2567 } 2568 } 2569 } 2570 } 2571 2572 static int 2573 syncrepl_resolve_cb( Operation *op, SlapReply *rs ) 2574 { 2575 if ( rs->sr_type == REP_SEARCH ) { 2576 resolve_ctxt *rx = op->o_callback->sc_private; 2577 Attribute *a = attr_find( rs->sr_entry->e_attrs, ad_reqMod ); 2578 if ( a ) { 2579 Modifications *oldmods, *newmods, *m1, *m2, **prev; 2580 oldmods = rx->rx_mods; 2581 syncrepl_accesslog_mods( rx->rx_si, a->a_vals, &newmods ); 2582 for ( m2 = newmods; m2; m2=m2->sml_next ) { 2583 for ( prev = &oldmods, m1 = *prev; m1; m1 = *prev ) { 2584 if ( m1->sml_desc != m2->sml_desc ) { 2585 prev = &m1->sml_next; 2586 continue; 2587 } 2588 if ( m2->sml_op == LDAP_MOD_DELETE || 2589 m2->sml_op == SLAP_MOD_SOFTDEL || 2590 m2->sml_op == LDAP_MOD_REPLACE ) { 2591 int numvals = m2->sml_numvals; 2592 if ( m2->sml_op == LDAP_MOD_REPLACE ) 2593 numvals = 0; 2594 /* New delete All cancels everything */ 2595 if ( numvals == 0 ) { 2596 drop: 2597 *prev = m1->sml_next; 2598 op->o_tmpfree( m1, op->o_tmpmemctx ); 2599 continue; 2600 } 2601 if ( m1->sml_op == LDAP_MOD_DELETE || 2602 m1->sml_op == SLAP_MOD_SOFTDEL ) { 2603 if ( m1->sml_numvals == 0 ) { 2604 /* turn this to SOFTDEL later */ 2605 m1->sml_flags = SLAP_MOD_INTERNAL; 2606 } else { 2607 compare_vals( m1, m2 ); 2608 if ( !m1->sml_numvals ) 2609 goto drop; 2610 } 2611 } else if ( m1->sml_op == LDAP_MOD_ADD ) { 2612 compare_vals( m1, m2 ); 2613 if ( !m1->sml_numvals ) 2614 goto drop; 2615 } 2616 } 2617 2618 if ( m2->sml_op == LDAP_MOD_ADD || 2619 m2->sml_op == LDAP_MOD_REPLACE ) { 2620 if ( m1->sml_op == LDAP_MOD_DELETE ) { 2621 if ( !m1->sml_numvals ) goto drop; 2622 compare_vals( m1, m2 ); 2623 if ( !m1->sml_numvals ) 2624 goto drop; 2625 } 2626 if ( m2->sml_desc->ad_type->sat_atype.at_single_value ) 2627 goto drop; 2628 compare_vals( m1, m2 ); 2629 if ( !m1->sml_numvals ) 2630 goto drop; 2631 } 2632 prev = &m1->sml_next; 2633 } 2634 } 2635 slap_mods_free( newmods, 1 ); 2636 rx->rx_mods = oldmods; 2637 } 2638 } 2639 return LDAP_SUCCESS; 2640 } 2641 2642 typedef struct modify_ctxt { 2643 Modifications *mx_orig; 2644 Modifications *mx_free; 2645 } modify_ctxt; 2646 2647 static int 2648 syncrepl_modify_cb( Operation *op, SlapReply *rs ) 2649 { 2650 slap_callback *sc = op->o_callback; 2651 modify_ctxt *mx = sc->sc_private; 2652 Modifications *ml; 2653 2654 op->orm_no_opattrs = 0; 2655 op->orm_modlist = mx->mx_orig; 2656 for ( ml = mx->mx_free; ml; ml = mx->mx_free ) { 2657 mx->mx_free = ml->sml_next; 2658 op->o_tmpfree( ml, op->o_tmpmemctx ); 2659 } 2660 op->o_callback = sc->sc_next; 2661 op->o_tmpfree( sc, op->o_tmpmemctx ); 2662 return SLAP_CB_CONTINUE; 2663 } 2664 2665 static int 2666 syncrepl_op_modify( Operation *op, SlapReply *rs ) 2667 { 2668 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 2669 OpExtra *oex; 2670 syncinfo_t *si; 2671 Entry *e; 2672 int rc, match = 0; 2673 Modifications *mod, *newlist; 2674 2675 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { 2676 if ( oex->oe_key == (void *)syncrepl_message_to_op ) 2677 break; 2678 } 2679 if ( !oex ) 2680 return SLAP_CB_CONTINUE; 2681 2682 si = ((OpExtraSync *)oex)->oe_si; 2683 2684 /* Check if entryCSN in modlist is newer than entryCSN in entry. 2685 * We do it here because the op has been serialized by accesslog 2686 * by the time we get here. If the CSN is new enough, just do the 2687 * mod. If not, we need to resolve conflicts. 2688 */ 2689 2690 for ( mod = op->orm_modlist; mod; mod=mod->sml_next ) { 2691 if ( mod->sml_desc == slap_schema.si_ad_entryCSN ) break; 2692 } 2693 /* FIXME: what should we do if entryCSN is missing from the mod? */ 2694 if ( !mod ) 2695 return SLAP_CB_CONTINUE; 2696 2697 { 2698 int sid = slap_parse_csn_sid( &mod->sml_nvalues[0] ); 2699 ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex ); 2700 rc = check_csn_age( si, &op->o_req_dn, &mod->sml_nvalues[0], 2701 sid, (cookie_vals *)&si->si_cookieState->cs_vals, NULL ); 2702 ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex ); 2703 if ( rc == CV_CSN_OLD ) { 2704 slap_graduate_commit_csn( op ); 2705 /* tell accesslog this was a failure */ 2706 rs->sr_err = LDAP_TYPE_OR_VALUE_EXISTS; 2707 return LDAP_SUCCESS; 2708 } 2709 } 2710 2711 rc = overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ); 2712 if ( rc == 0 ) { 2713 Attribute *a; 2714 const char *text; 2715 a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN ); 2716 if ( a ) { 2717 value_match( &match, slap_schema.si_ad_entryCSN, 2718 slap_schema.si_ad_entryCSN->ad_type->sat_ordering, 2719 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, 2720 &mod->sml_nvalues[0], &a->a_nvals[0], &text ); 2721 } else { 2722 /* no entryCSN? shouldn't happen. assume mod is newer. */ 2723 match = 1; 2724 } 2725 overlay_entry_release_ov( op, e, 0, on ); 2726 } else { 2727 return SLAP_CB_CONTINUE; 2728 } 2729 2730 /* equal? Should never happen */ 2731 if ( match == 0 ) { 2732 slap_graduate_commit_csn( op ); 2733 /* tell accesslog this was a failure */ 2734 rs->sr_err = LDAP_TYPE_OR_VALUE_EXISTS; 2735 return LDAP_SUCCESS; 2736 } 2737 2738 /* mod is older: resolve conflicts... 2739 * 1. Save/copy original modlist. Split Replace to Del/Add. 2740 * 2. Find all mods to this reqDN newer than the mod stamp. 2741 * 3. Resolve any mods in this request that affect attributes 2742 * touched by newer mods. 2743 * old new 2744 * delete all delete all drop 2745 * delete all delete X SOFTDEL 2746 * delete X delete all drop 2747 * delete X delete X drop 2748 * delete X delete Y OK 2749 * delete all add X drop 2750 * delete X add X drop 2751 * delete X add Y OK 2752 * add X delete all drop 2753 * add X delete X drop 2754 * add X add X drop 2755 * add X add Y if SV, drop else OK 2756 * 2757 * 4. Swap original modlist back in response callback so 2758 * that accesslog logs the original mod. 2759 * 2760 * Even if the mod is newer, other out-of-order changes may 2761 * have been committed, forcing us to tweak the modlist: 2762 * 1. Save/copy original modlist. 2763 * 2. Change deletes to soft deletes. 2764 * 3. Change Adds of single-valued attrs to Replace. 2765 */ 2766 2767 newlist = mods_dup( op, op->orm_modlist, match ); 2768 2769 /* mod is older */ 2770 if ( match < 0 ) { 2771 Operation op2 = *op; 2772 AttributeName an[2]; 2773 struct berval bv; 2774 int size; 2775 SlapReply rs1 = {0}; 2776 resolve_ctxt rx; 2777 slap_callback cb = { NULL, syncrepl_resolve_cb, NULL, NULL }; 2778 Filter lf[3] = {0}; 2779 AttributeAssertion aa[2] = {0}; 2780 2781 rx.rx_si = si; 2782 rx.rx_mods = newlist; 2783 cb.sc_private = ℞ 2784 2785 op2.o_tag = LDAP_REQ_SEARCH; 2786 op2.ors_scope = LDAP_SCOPE_SUBTREE; 2787 op2.ors_deref = LDAP_DEREF_NEVER; 2788 op2.o_req_dn = si->si_logbase; 2789 op2.o_req_ndn = si->si_logbase; 2790 op2.ors_tlimit = SLAP_NO_LIMIT; 2791 op2.ors_slimit = SLAP_NO_LIMIT; 2792 op2.ors_limit = NULL; 2793 memset( an, 0, sizeof(an)); 2794 an[0].an_desc = ad_reqMod; 2795 an[0].an_name = ad_reqMod->ad_cname; 2796 op2.ors_attrs = an; 2797 op2.ors_attrsonly = 0; 2798 2799 bv = mod->sml_nvalues[0]; 2800 2801 size = sizeof("(&(entryCSN>=)(reqDN=))"); 2802 size += bv.bv_len + op->o_req_ndn.bv_len + si->si_logfilterstr.bv_len; 2803 op2.ors_filterstr.bv_val = op->o_tmpalloc( size, op->o_tmpmemctx ); 2804 op2.ors_filterstr.bv_len = sprintf(op2.ors_filterstr.bv_val, 2805 "(&(entryCSN>=%s)(reqDN=%s)%s)", 2806 bv.bv_val, op->o_req_ndn.bv_val, si->si_logfilterstr.bv_val ); 2807 2808 lf[0].f_choice = LDAP_FILTER_AND; 2809 lf[0].f_and = lf+1; 2810 lf[1].f_choice = LDAP_FILTER_GE; 2811 lf[1].f_ava = aa; 2812 lf[1].f_av_desc = slap_schema.si_ad_entryCSN; 2813 lf[1].f_av_value = bv; 2814 lf[1].f_next = lf+2; 2815 lf[2].f_choice = LDAP_FILTER_EQUALITY; 2816 lf[2].f_ava = aa+1; 2817 lf[2].f_av_desc = ad_reqDN; 2818 lf[2].f_av_value = op->o_req_ndn; 2819 lf[2].f_next = si->si_logfilter; 2820 2821 op2.ors_filter = lf; 2822 2823 op2.o_callback = &cb; 2824 op2.o_bd = select_backend( &op2.o_req_ndn, 1 ); 2825 op2.o_bd->be_search( &op2, &rs1 ); 2826 newlist = rx.rx_mods; 2827 } 2828 2829 { 2830 slap_callback *sc = op->o_tmpalloc( sizeof(slap_callback) + 2831 sizeof(modify_ctxt), op->o_tmpmemctx ); 2832 modify_ctxt *mx = (modify_ctxt *)(sc+1); 2833 Modifications *ml; 2834 2835 sc->sc_response = syncrepl_modify_cb; 2836 sc->sc_private = mx; 2837 sc->sc_next = op->o_callback; 2838 sc->sc_cleanup = NULL; 2839 sc->sc_writewait = NULL; 2840 op->o_callback = sc; 2841 op->orm_no_opattrs = 1; 2842 mx->mx_orig = op->orm_modlist; 2843 mx->mx_free = newlist; 2844 for ( ml = newlist; ml; ml=ml->sml_next ) { 2845 if ( ml->sml_flags == SLAP_MOD_INTERNAL ) { 2846 ml->sml_flags = 0; 2847 ml->sml_op = SLAP_MOD_SOFTDEL; 2848 } 2849 else if ( ml->sml_op == LDAP_MOD_DELETE ) 2850 ml->sml_op = SLAP_MOD_SOFTDEL; 2851 else if ( ml->sml_op == LDAP_MOD_ADD && 2852 ml->sml_desc->ad_type->sat_atype.at_single_value ) 2853 ml->sml_op = LDAP_MOD_REPLACE; 2854 } 2855 op->orm_modlist = newlist; 2856 op->o_csn = mod->sml_nvalues[0]; 2857 } 2858 return SLAP_CB_CONTINUE; 2859 } 2860 2861 static int 2862 syncrepl_null_callback( 2863 Operation *op, 2864 SlapReply *rs ) 2865 { 2866 /* If we're not the last callback in the chain, move to the end */ 2867 if ( op->o_callback->sc_next ) { 2868 slap_callback **sc, *s1; 2869 s1 = op->o_callback; 2870 op->o_callback = op->o_callback->sc_next; 2871 for ( sc = &op->o_callback; *sc; sc = &(*sc)->sc_next ) ; 2872 *sc = s1; 2873 s1->sc_next = NULL; 2874 return SLAP_CB_CONTINUE; 2875 } 2876 if ( rs->sr_err != LDAP_SUCCESS && 2877 rs->sr_err != LDAP_REFERRAL && 2878 rs->sr_err != LDAP_ALREADY_EXISTS && 2879 rs->sr_err != LDAP_NO_SUCH_OBJECT && 2880 rs->sr_err != LDAP_NOT_ALLOWED_ON_NONLEAF ) 2881 { 2882 Debug( LDAP_DEBUG_ANY, 2883 "syncrepl_null_callback : error code 0x%x\n", 2884 rs->sr_err ); 2885 } 2886 return LDAP_SUCCESS; 2887 } 2888 2889 static int 2890 syncrepl_message_to_op( 2891 syncinfo_t *si, 2892 Operation *op, 2893 LDAPMessage *msg, 2894 int do_lock 2895 ) 2896 { 2897 BerElement *ber = NULL; 2898 Modifications *modlist = NULL; 2899 logschema *ls; 2900 SlapReply rs = { REP_RESULT }; 2901 slap_callback cb = { NULL, syncrepl_null_callback, NULL, NULL }; 2902 2903 const char *text; 2904 char txtbuf[SLAP_TEXT_BUFLEN]; 2905 size_t textlen = sizeof txtbuf; 2906 2907 struct berval bdn, dn = BER_BVNULL, ndn; 2908 struct berval bv, bv2, *bvals = NULL; 2909 struct berval rdn = BER_BVNULL, sup = BER_BVNULL, 2910 prdn = BER_BVNULL, nrdn = BER_BVNULL, 2911 psup = BER_BVNULL, nsup = BER_BVNULL; 2912 struct berval dsee_uuid = BER_BVNULL, dsee_mods = BER_BVNULL; 2913 int rc, deleteOldRdn = 0, freeReqDn = 0; 2914 int do_graduate = 0, do_unlock = 0; 2915 unsigned long changenum = 0; 2916 2917 if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) { 2918 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s " 2919 "Message type should be entry (%d)", 2920 si->si_ridtxt, ldap_msgtype( msg ) ); 2921 return -1; 2922 } 2923 2924 if ( si->si_syncdata == SYNCDATA_ACCESSLOG ) 2925 ls = &accesslog_sc; 2926 else 2927 ls = &changelog_sc; 2928 2929 rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn ); 2930 2931 if ( rc != LDAP_SUCCESS ) { 2932 Debug( LDAP_DEBUG_ANY, 2933 "syncrepl_message_to_op: %s dn get failed (%d)", 2934 si->si_ridtxt, rc ); 2935 return rc; 2936 } 2937 2938 op->o_tag = LBER_DEFAULT; 2939 op->o_bd = si->si_wbe; 2940 2941 if ( BER_BVISEMPTY( &bdn )) { 2942 Debug( LDAP_DEBUG_ANY, 2943 "syncrepl_message_to_op: %s got empty dn", 2944 si->si_ridtxt ); 2945 return LDAP_OTHER; 2946 } 2947 2948 while (( rc = ldap_get_attribute_ber( si->si_ld, msg, ber, &bv, &bvals ) ) 2949 == LDAP_SUCCESS ) { 2950 if ( bv.bv_val == NULL ) 2951 break; 2952 2953 if ( !ber_bvstrcasecmp( &bv, &ls->ls_dn ) ) { 2954 bdn = bvals[0]; 2955 REWRITE_DN( si, bdn, bv2, dn, ndn ); 2956 if ( rc != LDAP_SUCCESS ) { 2957 Debug( LDAP_DEBUG_ANY, 2958 "syncrepl_message_to_op: %s " 2959 "dn \"%s\" normalization failed (%d)", 2960 si->si_ridtxt, bdn.bv_val, rc ); 2961 rc = -1; 2962 ch_free( bvals ); 2963 goto done; 2964 } 2965 ber_dupbv( &op->o_req_dn, &dn ); 2966 ber_dupbv( &op->o_req_ndn, &ndn ); 2967 slap_sl_free( ndn.bv_val, op->o_tmpmemctx ); 2968 slap_sl_free( dn.bv_val, op->o_tmpmemctx ); 2969 freeReqDn = 1; 2970 } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_req ) ) { 2971 int i = verb_to_mask( bvals[0].bv_val, modops ); 2972 if ( i < 0 ) { 2973 Debug( LDAP_DEBUG_ANY, 2974 "syncrepl_message_to_op: %s unknown op %s", 2975 si->si_ridtxt, bvals[0].bv_val ); 2976 ch_free( bvals ); 2977 rc = -1; 2978 goto done; 2979 } 2980 op->o_tag = modops[i].mask; 2981 } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_mod ) ) { 2982 /* Parse attribute into modlist */ 2983 if ( si->si_syncdata == SYNCDATA_ACCESSLOG ) { 2984 rc = syncrepl_accesslog_mods( si, bvals, &modlist ); 2985 } else { 2986 dsee_mods = bvals[0]; 2987 } 2988 if ( rc ) goto done; 2989 } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_newRdn ) ) { 2990 rdn = bvals[0]; 2991 } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_delRdn ) ) { 2992 if ( !ber_bvstrcasecmp( &slap_true_bv, bvals ) ) { 2993 deleteOldRdn = 1; 2994 } 2995 } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_newSup ) ) { 2996 sup = bvals[0]; 2997 } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_controls ) ) { 2998 int i; 2999 struct berval rel_ctrl_bv; 3000 3001 (void)ber_str2bv( "{" LDAP_CONTROL_RELAX, 0, 0, &rel_ctrl_bv ); 3002 for ( i = 0; bvals[i].bv_val; i++ ) { 3003 struct berval cbv, tmp; 3004 3005 ber_bvchr_post( &cbv, &bvals[i], '}' ); 3006 ber_bvchr_post( &tmp, &cbv, '{' ); 3007 ber_bvchr_pre( &cbv, &tmp, ' ' ); 3008 if ( cbv.bv_len == tmp.bv_len ) /* control w/o value */ 3009 ber_bvchr_pre( &cbv, &tmp, '}' ); 3010 if ( !ber_bvcmp( &cbv, &rel_ctrl_bv ) ) 3011 op->o_relax = SLAP_CONTROL_CRITICAL; 3012 } 3013 } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_uuid ) ) { 3014 dsee_uuid = bvals[0]; 3015 } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_changenum ) ) { 3016 changenum = strtoul( bvals->bv_val, NULL, 0 ); 3017 } else if ( !ber_bvstrcasecmp( &bv, 3018 &slap_schema.si_ad_entryCSN->ad_cname ) ) 3019 { 3020 slap_queue_csn( op, bvals ); 3021 do_graduate = 1; 3022 } 3023 ch_free( bvals ); 3024 } 3025 3026 /* don't parse mods until we've gotten the uuid */ 3027 if ( si->si_syncdata == SYNCDATA_CHANGELOG && !BER_BVISNULL( &dsee_mods )) { 3028 rc = syncrepl_changelog_mods( si, op->o_tag, 3029 &dsee_mods, &modlist, &dsee_uuid, op->o_tmpmemctx ); 3030 if ( rc ) 3031 goto done; 3032 } 3033 3034 /* If we didn't get a mod type or a target DN, bail out */ 3035 if ( op->o_tag == LBER_DEFAULT || BER_BVISNULL( &dn ) ) { 3036 rc = -1; 3037 goto done; 3038 } 3039 3040 if ( do_lock ) { 3041 if (( rc = get_pmutex( si ))) 3042 goto done; 3043 do_unlock = 1; 3044 } 3045 3046 op->o_callback = &cb; 3047 slap_op_time( &op->o_time, &op->o_tincr ); 3048 3049 Debug( LDAP_DEBUG_SYNC, "syncrepl_message_to_op: %s tid %p\n", 3050 si->si_ridtxt, (void *)op->o_tid ); 3051 3052 switch( op->o_tag ) { 3053 case LDAP_REQ_ADD: 3054 case LDAP_REQ_MODIFY: 3055 /* If we didn't get required data, bail */ 3056 if ( !modlist ) goto done; 3057 3058 rc = slap_mods_check( op, modlist, &text, txtbuf, textlen, NULL ); 3059 3060 if ( rc != LDAP_SUCCESS ) { 3061 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s " 3062 "mods check (%s)\n", 3063 si->si_ridtxt, text ); 3064 goto done; 3065 } 3066 3067 if ( op->o_tag == LDAP_REQ_ADD ) { 3068 Entry *e = entry_alloc(); 3069 op->ora_e = e; 3070 op->ora_e->e_name = op->o_req_dn; 3071 op->ora_e->e_nname = op->o_req_ndn; 3072 freeReqDn = 0; 3073 rc = slap_mods2entry( modlist, &op->ora_e, 1, 0, &text, txtbuf, textlen); 3074 if( rc != LDAP_SUCCESS ) { 3075 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s " 3076 "mods2entry (%s)\n", 3077 si->si_ridtxt, text ); 3078 } else { 3079 rc = op->o_bd->be_add( op, &rs ); 3080 Debug( LDAP_DEBUG_SYNC, 3081 "syncrepl_message_to_op: %s be_add %s (%d)\n", 3082 si->si_ridtxt, op->o_req_dn.bv_val, rc ); 3083 do_graduate = 0; 3084 if ( rc == LDAP_ALREADY_EXISTS ) { 3085 Attribute *a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN ); 3086 struct berval *vals; 3087 if ( a && backend_attribute( op, NULL, &op->o_req_ndn, 3088 slap_schema.si_ad_entryCSN, &vals, ACL_READ ) == LDAP_SUCCESS ) { 3089 if ( ber_bvcmp( &vals[0], &a->a_vals[0] ) >= 0 ) 3090 rc = LDAP_SUCCESS; 3091 ber_bvarray_free_x( vals, op->o_tmpmemctx ); 3092 } 3093 } 3094 } 3095 if ( e == op->ora_e ) 3096 be_entry_release_w( op, op->ora_e ); 3097 } else { 3098 OpExtraSync oes; 3099 op->orm_modlist = modlist; 3100 op->o_bd = si->si_wbe; 3101 /* delta-mpr needs additional checks in syncrepl_op_modify */ 3102 if ( SLAP_MULTIPROVIDER( op->o_bd )) { 3103 oes.oe.oe_key = (void *)syncrepl_message_to_op; 3104 oes.oe_si = si; 3105 LDAP_SLIST_INSERT_HEAD( &op->o_extra, &oes.oe, oe_next ); 3106 } 3107 rc = op->o_bd->be_modify( op, &rs ); 3108 if ( SLAP_MULTIPROVIDER( op->o_bd )) { 3109 LDAP_SLIST_REMOVE( &op->o_extra, &oes.oe, OpExtra, oe_next ); 3110 BER_BVZERO( &op->o_csn ); 3111 } 3112 modlist = op->orm_modlist; 3113 Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC, 3114 "syncrepl_message_to_op: %s be_modify %s (%d)\n", 3115 si->si_ridtxt, op->o_req_dn.bv_val, rc ); 3116 op->o_bd = si->si_be; 3117 do_graduate = 0; 3118 } 3119 break; 3120 case LDAP_REQ_MODRDN: 3121 if ( BER_BVISNULL( &rdn ) ) goto done; 3122 3123 if ( rdnPretty( NULL, &rdn, &prdn, NULL ) ) { 3124 goto done; 3125 } 3126 if ( rdnNormalize( 0, NULL, NULL, &rdn, &nrdn, NULL ) ) { 3127 goto done; 3128 } 3129 if ( !BER_BVISNULL( &sup ) ) { 3130 REWRITE_DN( si, sup, bv2, psup, nsup ); 3131 if ( rc ) 3132 goto done; 3133 op->orr_newSup = &psup; 3134 op->orr_nnewSup = ⊅ 3135 } else { 3136 op->orr_newSup = NULL; 3137 op->orr_nnewSup = NULL; 3138 } 3139 op->orr_newrdn = prdn; 3140 op->orr_nnewrdn = nrdn; 3141 op->orr_deleteoldrdn = deleteOldRdn; 3142 op->orr_modlist = NULL; 3143 if ( slap_modrdn2mods( op, &rs ) ) { 3144 goto done; 3145 } 3146 3147 /* Append modlist for operational attrs */ 3148 { 3149 Modifications *m; 3150 3151 for ( m = op->orr_modlist; m->sml_next; m = m->sml_next ) 3152 ; 3153 m->sml_next = modlist; 3154 modlist = NULL; 3155 } 3156 rc = op->o_bd->be_modrdn( op, &rs ); 3157 slap_mods_free( op->orr_modlist, 1 ); 3158 Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC, 3159 "syncrepl_message_to_op: %s be_modrdn %s (%d)\n", 3160 si->si_ridtxt, op->o_req_dn.bv_val, rc ); 3161 do_graduate = 0; 3162 break; 3163 case LDAP_REQ_DELETE: 3164 rc = op->o_bd->be_delete( op, &rs ); 3165 Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC, 3166 "syncrepl_message_to_op: %s be_delete %s (%d)\n", 3167 si->si_ridtxt, op->o_req_dn.bv_val, rc ); 3168 /* silently ignore this */ 3169 if ( rc == LDAP_NO_SUCH_OBJECT ) 3170 rc = LDAP_SUCCESS; 3171 do_graduate = 0; 3172 break; 3173 } 3174 if ( si->si_syncdata == SYNCDATA_CHANGELOG && !rc ) 3175 si->si_lastchange = changenum; 3176 3177 done: 3178 if ( do_graduate ) 3179 slap_graduate_commit_csn( op ); 3180 if ( do_unlock ) 3181 ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex ); 3182 op->o_bd = si->si_be; 3183 op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx ); 3184 BER_BVZERO( &op->o_csn ); 3185 if ( modlist ) { 3186 slap_mods_free( modlist, op->o_tag != LDAP_REQ_ADD ); 3187 } 3188 if ( !BER_BVISNULL( &rdn ) ) { 3189 if ( !BER_BVISNULL( &nsup ) ) { 3190 ch_free( nsup.bv_val ); 3191 } 3192 if ( !BER_BVISNULL( &psup ) ) { 3193 ch_free( psup.bv_val ); 3194 } 3195 if ( !BER_BVISNULL( &nrdn ) ) { 3196 ch_free( nrdn.bv_val ); 3197 } 3198 if ( !BER_BVISNULL( &prdn ) ) { 3199 ch_free( prdn.bv_val ); 3200 } 3201 } 3202 if ( freeReqDn ) { 3203 ch_free( op->o_req_ndn.bv_val ); 3204 ch_free( op->o_req_dn.bv_val ); 3205 } 3206 ber_free( ber, 0 ); 3207 return rc; 3208 } 3209 3210 static int 3211 syncrepl_message_to_entry( 3212 syncinfo_t *si, 3213 Operation *op, 3214 LDAPMessage *msg, 3215 Modifications **modlist, 3216 Entry **entry, 3217 int syncstate, 3218 struct berval *syncUUID 3219 ) 3220 { 3221 Entry *e = NULL; 3222 BerElement *ber = NULL; 3223 Modifications tmp; 3224 Modifications *mod; 3225 Modifications **modtail = modlist; 3226 3227 const char *text; 3228 char txtbuf[SLAP_TEXT_BUFLEN]; 3229 size_t textlen = sizeof txtbuf; 3230 3231 struct berval bdn = BER_BVNULL, dn, ndn, bv2; 3232 int rc, is_ctx; 3233 3234 *modlist = NULL; 3235 3236 if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) { 3237 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s " 3238 "Message type should be entry (%d)", 3239 si->si_ridtxt, ldap_msgtype( msg ) ); 3240 return -1; 3241 } 3242 3243 op->o_tag = LDAP_REQ_ADD; 3244 3245 rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn ); 3246 if ( rc != LDAP_SUCCESS ) { 3247 Debug( LDAP_DEBUG_ANY, 3248 "syncrepl_message_to_entry: %s dn get failed (%d)", 3249 si->si_ridtxt, rc ); 3250 return rc; 3251 } 3252 3253 if ( BER_BVISEMPTY( &bdn ) && !BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] ) ) { 3254 Debug( LDAP_DEBUG_ANY, 3255 "syncrepl_message_to_entry: %s got empty dn", 3256 si->si_ridtxt ); 3257 return LDAP_OTHER; 3258 } 3259 3260 if ( si->si_syncdata != SYNCDATA_CHANGELOG ) { 3261 /* syncUUID[0] is normalized UUID received over the wire 3262 * syncUUID[1] is denormalized UUID, generated here 3263 */ 3264 (void)slap_uuidstr_from_normalized( &syncUUID[1], &syncUUID[0], op->o_tmpmemctx ); 3265 Debug( LDAP_DEBUG_SYNC, 3266 "syncrepl_message_to_entry: %s DN: %s, UUID: %s\n", 3267 si->si_ridtxt, bdn.bv_val, syncUUID[1].bv_val ); 3268 } 3269 3270 if ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_DELETE ) { 3271 /* NOTE: this could be done even before decoding the DN, 3272 * although encoding errors wouldn't be detected */ 3273 rc = LDAP_SUCCESS; 3274 goto done; 3275 } 3276 3277 if ( entry == NULL ) { 3278 return -1; 3279 } 3280 3281 REWRITE_DN( si, bdn, bv2, dn, ndn ); 3282 if ( rc != LDAP_SUCCESS ) { 3283 /* One of the things that could happen is that the schema 3284 * is not lined-up; this could result in unknown attributes. 3285 * A value non conformant to the syntax should be unlikely, 3286 * except when replicating between different versions 3287 * of the software, or when syntax validation bugs are fixed 3288 */ 3289 Debug( LDAP_DEBUG_ANY, 3290 "syncrepl_message_to_entry: " 3291 "%s dn \"%s\" normalization failed (%d)", 3292 si->si_ridtxt, bdn.bv_val, rc ); 3293 return rc; 3294 } 3295 3296 ber_dupbv( &op->o_req_dn, &dn ); 3297 ber_dupbv( &op->o_req_ndn, &ndn ); 3298 slap_sl_free( ndn.bv_val, op->o_tmpmemctx ); 3299 slap_sl_free( dn.bv_val, op->o_tmpmemctx ); 3300 3301 is_ctx = dn_match( &op->o_req_ndn, &op->o_bd->be_nsuffix[0] ); 3302 3303 e = entry_alloc(); 3304 e->e_name = op->o_req_dn; 3305 e->e_nname = op->o_req_ndn; 3306 3307 while ( ber_remaining( ber ) ) { 3308 if ( (ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values ) == 3309 LBER_ERROR ) || BER_BVISNULL( &tmp.sml_type ) ) 3310 { 3311 break; 3312 } 3313 3314 /* Drop all updates to the contextCSN of the context entry 3315 * (ITS#4622, etc.) 3316 */ 3317 if ( is_ctx && !strcasecmp( tmp.sml_type.bv_val, 3318 slap_schema.si_ad_contextCSN->ad_cname.bv_val )) { 3319 ber_bvarray_free( tmp.sml_values ); 3320 continue; 3321 } 3322 3323 /* map nsUniqueId to entryUUID, drop nsUniqueId */ 3324 if ( si->si_syncdata == SYNCDATA_CHANGELOG && 3325 !strcasecmp( tmp.sml_type.bv_val, sy_ad_nsUniqueId->ad_cname.bv_val )) { 3326 rc = syncrepl_dsee_uuid( &tmp.sml_values[0], syncUUID, op->o_tmpmemctx ); 3327 ber_bvarray_free( tmp.sml_values ); 3328 if ( rc ) 3329 goto done; 3330 continue; 3331 } 3332 3333 mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); 3334 3335 mod->sml_op = LDAP_MOD_REPLACE; 3336 mod->sml_flags = 0; 3337 mod->sml_next = NULL; 3338 mod->sml_desc = NULL; 3339 mod->sml_type = tmp.sml_type; 3340 mod->sml_values = tmp.sml_values; 3341 mod->sml_nvalues = NULL; 3342 mod->sml_numvals = 0; /* slap_mods_check will set this */ 3343 3344 if (si->si_rewrite) { 3345 AttributeDescription *ad = NULL; 3346 slap_bv2ad( &tmp.sml_type, &ad, &text ); 3347 if ( ad ) { 3348 mod->sml_desc = ad; 3349 mod->sml_type = ad->ad_cname; 3350 if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) { 3351 int i; 3352 for ( i = 0; tmp.sml_values[i].bv_val; i++ ) { 3353 syncrepl_rewrite_dn( si, &tmp.sml_values[i], &bv2); 3354 if ( !BER_BVISNULL( &bv2 )) { 3355 ber_memfree( tmp.sml_values[i].bv_val ); 3356 tmp.sml_values[i] = bv2; 3357 } 3358 } 3359 } 3360 } 3361 } 3362 *modtail = mod; 3363 modtail = &mod->sml_next; 3364 } 3365 3366 if ( *modlist == NULL ) { 3367 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s no attributes\n", 3368 si->si_ridtxt ); 3369 rc = -1; 3370 goto done; 3371 } 3372 3373 rc = slap_mods_check( op, *modlist, &text, txtbuf, textlen, NULL ); 3374 3375 if ( rc != LDAP_SUCCESS ) { 3376 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s mods check (%s)\n", 3377 si->si_ridtxt, text ); 3378 goto done; 3379 } 3380 3381 /* Strip out dynamically generated attrs */ 3382 for ( modtail = modlist; *modtail ; ) { 3383 mod = *modtail; 3384 if ( mod->sml_desc->ad_type->sat_flags & SLAP_AT_DYNAMIC ) { 3385 *modtail = mod->sml_next; 3386 slap_mod_free( &mod->sml_mod, 0 ); 3387 ch_free( mod ); 3388 } else { 3389 modtail = &mod->sml_next; 3390 } 3391 } 3392 3393 /* Strip out attrs in exattrs list */ 3394 for ( modtail = modlist; *modtail ; ) { 3395 mod = *modtail; 3396 if ( ldap_charray_inlist( si->si_exattrs, 3397 mod->sml_desc->ad_type->sat_cname.bv_val ) ) 3398 { 3399 *modtail = mod->sml_next; 3400 slap_mod_free( &mod->sml_mod, 0 ); 3401 ch_free( mod ); 3402 } else { 3403 modtail = &mod->sml_next; 3404 } 3405 } 3406 3407 rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen); 3408 if( rc != LDAP_SUCCESS ) { 3409 Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s mods2entry (%s)\n", 3410 si->si_ridtxt, text ); 3411 } 3412 3413 done: 3414 ber_free( ber, 0 ); 3415 if ( rc != LDAP_SUCCESS ) { 3416 if ( e ) { 3417 entry_free( e ); 3418 e = NULL; 3419 } 3420 } 3421 if ( entry ) 3422 *entry = e; 3423 3424 return rc; 3425 } 3426 3427 #ifdef LDAP_CONTROL_X_DIRSYNC 3428 static int 3429 syncrepl_dirsync_message( 3430 syncinfo_t *si, 3431 Operation *op, 3432 LDAPMessage *msg, 3433 Modifications **modlist, 3434 Entry **entry, 3435 int *syncstate, 3436 struct berval *syncUUID 3437 ) 3438 { 3439 Entry *e = NULL; 3440 BerElement *ber = NULL; 3441 Modifications tmp; 3442 Modifications *mod, *rangeMod = NULL; 3443 Modifications **modtail = modlist; 3444 3445 const char *text; 3446 char txtbuf[SLAP_TEXT_BUFLEN]; 3447 size_t textlen = sizeof txtbuf; 3448 3449 struct berval bdn = BER_BVNULL, dn, ndn, bv2; 3450 int rc; 3451 3452 *modlist = NULL; 3453 *syncstate = MSAD_DIRSYNC_MODIFY; 3454 3455 if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) { 3456 Debug( LDAP_DEBUG_ANY, "syncrepl_dirsync_message: %s " 3457 "Message type should be entry (%d)\n", 3458 si->si_ridtxt, ldap_msgtype( msg ) ); 3459 return -1; 3460 } 3461 3462 rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn ); 3463 if ( rc != LDAP_SUCCESS ) { 3464 Debug( LDAP_DEBUG_ANY, 3465 "syncrepl_dirsync_message: %s dn get failed (%d)\n", 3466 si->si_ridtxt, rc ); 3467 return rc; 3468 } 3469 3470 if ( BER_BVISEMPTY( &bdn ) && !BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] ) ) { 3471 Debug( LDAP_DEBUG_ANY, 3472 "syncrepl_dirsync_message: %s got empty dn\n", 3473 si->si_ridtxt ); 3474 return LDAP_OTHER; 3475 } 3476 3477 while ( ber_remaining( ber ) ) { 3478 AttributeDescription *ad = NULL; 3479 3480 if ( (ber_scanf( ber, "{mW}", &tmp.sml_type, &tmp.sml_values ) == 3481 LBER_ERROR ) || BER_BVISNULL( &tmp.sml_type ) ) 3482 { 3483 break; 3484 } 3485 if ( tmp.sml_values == NULL ) 3486 continue; 3487 3488 mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); 3489 3490 mod->sml_op = LDAP_MOD_REPLACE; 3491 mod->sml_flags = 0; 3492 mod->sml_next = NULL; 3493 mod->sml_desc = NULL; 3494 mod->sml_type = tmp.sml_type; 3495 mod->sml_values = tmp.sml_values; 3496 mod->sml_nvalues = NULL; 3497 mod->sml_numvals = 0; /* slap_mods_check will set this */ 3498 3499 rc = slap_bv2ad( &tmp.sml_type, &ad, &text ); 3500 if ( !ad ) { 3501 Debug( LDAP_DEBUG_ANY, 3502 "syncrepl_dirsync_message: %s unknown attributeType %s\n", 3503 si->si_ridtxt, tmp.sml_type.bv_val ); 3504 return rc; 3505 } 3506 mod->sml_desc = ad; 3507 mod->sml_type = ad->ad_cname; 3508 if (( ad->ad_flags & SLAP_DESC_TAG_RANGE ) && rangeMod == NULL) 3509 rangeMod = mod; 3510 if (si->si_rewrite) { 3511 if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) { 3512 int i; 3513 for ( i = 0; tmp.sml_values[i].bv_val; i++ ) { 3514 syncrepl_rewrite_dn( si, &tmp.sml_values[i], &bv2); 3515 if ( !BER_BVISNULL( &bv2 )) { 3516 ber_memfree( tmp.sml_values[i].bv_val ); 3517 tmp.sml_values[i] = bv2; 3518 } 3519 } 3520 } 3521 } 3522 if ( mod->sml_desc == sy_ad_objectGUID ) { 3523 ber_dupbv_x( &syncUUID[0], &tmp.sml_values[0], op->o_tmpmemctx ); 3524 /* syncUUID[0] is normalized UUID received over the wire 3525 * syncUUID[1] is denormalized UUID, generated here 3526 */ 3527 (void)slap_uuidstr_from_normalized( &syncUUID[1], &syncUUID[0], op->o_tmpmemctx ); 3528 Debug( LDAP_DEBUG_SYNC, 3529 "syncrepl_dirsync_message: %s DN: %s, UUID: %s\n", 3530 si->si_ridtxt, bdn.bv_val, syncUUID[1].bv_val ); 3531 } else if ( mod->sml_desc == sy_ad_isDeleted ) { 3532 *syncstate = LDAP_SYNC_DELETE; 3533 } else if ( mod->sml_desc == sy_ad_whenCreated ) { 3534 *syncstate = LDAP_SYNC_ADD; 3535 *modtail = mod; 3536 modtail = &mod->sml_next; 3537 mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); 3538 3539 mod->sml_op = LDAP_MOD_REPLACE; 3540 mod->sml_flags = 0; 3541 mod->sml_next = NULL; 3542 mod->sml_desc = slap_schema.si_ad_createTimestamp; 3543 mod->sml_type = mod->sml_desc->ad_cname; 3544 ber_bvarray_dup_x( &mod->sml_values, tmp.sml_values, NULL ); 3545 mod->sml_nvalues = NULL; 3546 mod->sml_numvals = 0; /* slap_mods_check will set this */ 3547 } /* else is a modify or modrdn */ 3548 3549 *modtail = mod; 3550 modtail = &mod->sml_next; 3551 } 3552 3553 if ( *modlist == NULL ) { 3554 Debug( LDAP_DEBUG_ANY, "syncrepl_dirsync_message: %s no attributes\n", 3555 si->si_ridtxt ); 3556 rc = -1; 3557 goto done; 3558 } 3559 3560 if ( *syncstate == LDAP_SYNC_DELETE ) { 3561 e = NULL; 3562 slap_mods_free( *modlist, 1 ); 3563 *modlist = NULL; 3564 } else { 3565 /* check for incremental multival mods */ 3566 if ( *syncstate == MSAD_DIRSYNC_MODIFY && rangeMod != NULL ) { 3567 for (; rangeMod; rangeMod = rangeMod->sml_next) { 3568 if ( rangeMod->sml_desc->ad_flags & SLAP_DESC_TAG_RANGE ) { 3569 if ( bvmatch( &rangeMod->sml_desc->ad_tags, &msad_addval )) 3570 rangeMod->sml_op = SLAP_MOD_SOFTADD; 3571 else if ( bvmatch( &rangeMod->sml_desc->ad_tags, &msad_delval )) 3572 rangeMod->sml_op = SLAP_MOD_SOFTDEL; 3573 /* turn the tagged attr into a normal one */ 3574 if ( rangeMod->sml_op != LDAP_MOD_REPLACE ) { 3575 AttributeDescription *ad = NULL; 3576 slap_bv2ad( &rangeMod->sml_desc->ad_type->sat_cname, &ad, &text ); 3577 rangeMod->sml_desc = ad; 3578 } 3579 } 3580 } 3581 } 3582 rc = slap_mods_check( op, *modlist, &text, txtbuf, textlen, NULL ); 3583 3584 if ( rc != LDAP_SUCCESS ) { 3585 Debug( LDAP_DEBUG_ANY, "syncrepl_dirsync_message: %s mods check (%s)\n", 3586 si->si_ridtxt, text ); 3587 goto done; 3588 } 3589 3590 REWRITE_DN( si, bdn, bv2, dn, ndn ); 3591 if ( rc != LDAP_SUCCESS ) { 3592 /* One of the things that could happen is that the schema 3593 * is not lined-up; this could result in unknown attributes. 3594 * A value non conformant to the syntax should be unlikely, 3595 * except when replicating between different versions 3596 * of the software, or when syntax validation bugs are fixed 3597 */ 3598 Debug( LDAP_DEBUG_ANY, 3599 "syncrepl_dirsync_message: " 3600 "%s dn \"%s\" normalization failed (%d)", 3601 si->si_ridtxt, bdn.bv_val, rc ); 3602 return rc; 3603 } 3604 3605 ber_dupbv( &op->o_req_dn, &dn ); 3606 ber_dupbv( &op->o_req_ndn, &ndn ); 3607 slap_sl_free( ndn.bv_val, op->o_tmpmemctx ); 3608 slap_sl_free( dn.bv_val, op->o_tmpmemctx ); 3609 3610 e = entry_alloc(); 3611 e->e_name = op->o_req_dn; 3612 e->e_nname = op->o_req_ndn; 3613 3614 /* Strip out redundant attrs */ 3615 if ( *syncstate == MSAD_DIRSYNC_MODIFY ) { 3616 for ( modtail = modlist; *modtail ; ) { 3617 mod = *modtail; 3618 if ( mod->sml_desc == sy_ad_objectGUID || 3619 mod->sml_desc == sy_ad_instanceType ) { 3620 *modtail = mod->sml_next; 3621 slap_mod_free( &mod->sml_mod, 0 ); 3622 ch_free( mod ); 3623 } else { 3624 modtail = &mod->sml_next; 3625 } 3626 } 3627 } 3628 3629 /* Strip out dynamically generated attrs */ 3630 for ( modtail = modlist; *modtail ; ) { 3631 mod = *modtail; 3632 if ( mod->sml_desc->ad_type->sat_flags & SLAP_AT_DYNAMIC ) { 3633 *modtail = mod->sml_next; 3634 slap_mod_free( &mod->sml_mod, 0 ); 3635 ch_free( mod ); 3636 } else { 3637 modtail = &mod->sml_next; 3638 } 3639 } 3640 3641 /* Strip out attrs in exattrs list */ 3642 for ( modtail = modlist; *modtail ; ) { 3643 mod = *modtail; 3644 if ( ldap_charray_inlist( si->si_exattrs, 3645 mod->sml_desc->ad_type->sat_cname.bv_val ) ) 3646 { 3647 *modtail = mod->sml_next; 3648 slap_mod_free( &mod->sml_mod, 0 ); 3649 ch_free( mod ); 3650 } else { 3651 modtail = &mod->sml_next; 3652 } 3653 } 3654 3655 rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen); 3656 if( rc != LDAP_SUCCESS ) { 3657 Debug( LDAP_DEBUG_ANY, "syncrepl_dirsync_message: %s mods2entry (%s)\n", 3658 si->si_ridtxt, text ); 3659 } 3660 } 3661 3662 done: 3663 ber_free( ber, 0 ); 3664 if ( rc != LDAP_SUCCESS ) { 3665 if ( e ) { 3666 entry_free( e ); 3667 e = NULL; 3668 } 3669 } 3670 if ( entry ) 3671 *entry = e; 3672 3673 return rc; 3674 } 3675 3676 static int 3677 syncrepl_dirsync_cookie( 3678 syncinfo_t *si, 3679 Operation *op, 3680 LDAPControl **ctrls 3681 ) 3682 { 3683 LDAPControl *ctrl, **next; 3684 Backend *be = op->o_bd; 3685 Modifications mod; 3686 struct berval vals[2]; 3687 3688 int rc, continueFlag; 3689 3690 slap_callback cb = { NULL }; 3691 SlapReply rs_modify = {REP_RESULT}; 3692 3693 ctrl = ldap_control_find( LDAP_CONTROL_X_DIRSYNC, ctrls, &next ); 3694 if ( ctrl == NULL ) { 3695 ldap_controls_free( ctrls ); 3696 return -1; 3697 } 3698 rc = ldap_parse_dirsync_control( si->si_ld, ctrl, &continueFlag, &vals[0] ); 3699 if ( !bvmatch( &vals[0], &si->si_dirSyncCookie )) { 3700 3701 BER_BVZERO( &vals[1] ); 3702 mod.sml_op = LDAP_MOD_REPLACE; 3703 mod.sml_desc = sy_ad_dirSyncCookie; 3704 mod.sml_type = mod.sml_desc->ad_cname; 3705 mod.sml_flags = SLAP_MOD_INTERNAL; 3706 mod.sml_nvalues = NULL; 3707 mod.sml_next = NULL; 3708 3709 op->o_bd = si->si_wbe; 3710 op->o_tag = LDAP_REQ_MODIFY; 3711 3712 cb.sc_response = syncrepl_null_callback; 3713 cb.sc_private = si; 3714 3715 op->o_callback = &cb; 3716 op->o_req_dn = si->si_contextdn; 3717 op->o_req_ndn = si->si_contextdn; 3718 3719 op->o_dont_replicate = 0; 3720 3721 slap_op_time( &op->o_time, &op->o_tincr ); 3722 3723 mod.sml_numvals = 1; 3724 mod.sml_values = vals; 3725 3726 op->orm_modlist = &mod; 3727 op->orm_no_opattrs = 1; 3728 rc = op->o_bd->be_modify( op, &rs_modify ); 3729 op->orm_no_opattrs = 0; 3730 3731 op->o_bd = be; 3732 if ( mod.sml_next ) slap_mods_free( mod.sml_next, 1 ); 3733 3734 if ( rc == LDAP_SUCCESS ) { 3735 ber_bvreplace( &si->si_dirSyncCookie, &vals[0] ); 3736 /* there are more changes still remaining */ 3737 if ( continueFlag ) 3738 rc = LDAP_SYNC_REFRESH_REQUIRED; 3739 } 3740 } 3741 3742 ch_free( vals[0].bv_val ); 3743 ldap_controls_free( ctrls ); 3744 return rc; 3745 } 3746 3747 static int syncrepl_dirsync_schema() 3748 { 3749 const char *text; 3750 int rc; 3751 3752 rc = slap_str2ad( "objectGUID", &sy_ad_objectGUID, &text ); 3753 if ( rc ) 3754 return rc; 3755 rc = slap_str2ad( "instanceType", &sy_ad_instanceType, &text ); 3756 if ( rc ) 3757 return rc; 3758 rc = slap_str2ad( "isDeleted", &sy_ad_isDeleted, &text ); 3759 if ( rc ) 3760 return rc; 3761 rc = slap_str2ad( "whenCreated", &sy_ad_whenCreated, &text ); 3762 if ( rc ) 3763 return rc; 3764 return register_at( "( 1.3.6.1.4.1.4203.666.1.27 " /* OpenLDAP-specific */ 3765 "NAME 'dirSyncCookie' " 3766 "DESC 'DirSync Cookie for shadow copy' " 3767 "EQUALITY octetStringMatch " 3768 "ORDERING octetStringOrderingMatch " 3769 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 " 3770 "SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )", &sy_ad_dirSyncCookie, 0); 3771 } 3772 #endif /* LDAP_CONTROL_X_DIRSYNC */ 3773 3774 static int syncrepl_dsee_schema() 3775 { 3776 const char *text; 3777 int rc; 3778 3779 rc = slap_str2ad( "nsUniqueId", &sy_ad_nsUniqueId, &text ); 3780 if ( rc ) 3781 return rc; 3782 return register_at( "( 1.3.6.1.4.1.4203.666.1.28 " /* OpenLDAP-specific */ 3783 "NAME 'lastChangeNumber' " 3784 "DESC 'RetroChangelog latest change record' " 3785 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 3786 "SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )", &sy_ad_dseeLastChange, 0); 3787 } 3788 3789 /* During a refresh, we may get an LDAP_SYNC_ADD for an already existing 3790 * entry if a previous refresh was interrupted before sending us a new 3791 * context state. We try to compare the new entry to the existing entry 3792 * and ignore the new entry if they are the same. 3793 * 3794 * Also, we may get an update where the entryDN has changed, due to 3795 * a ModDn on the provider. We detect this as well, so we can issue 3796 * the corresponding operation locally. 3797 * 3798 * In the case of a modify, we get a list of all the attributes 3799 * in the original entry. Rather than deleting the entry and re-adding it, 3800 * we issue a Modify request that deletes all the attributes and adds all 3801 * the new ones. This avoids the issue of trying to delete/add a non-leaf 3802 * entry. 3803 * 3804 * We otherwise distinguish ModDN from Modify; in the case of 3805 * a ModDN we just use the CSN, modifyTimestamp and modifiersName 3806 * operational attributes from the entry, and do a regular ModDN. 3807 */ 3808 typedef struct dninfo { 3809 syncinfo_t *si; 3810 Entry *new_entry; 3811 struct berval dn; 3812 struct berval ndn; 3813 struct berval nnewSup; 3814 int syncstate; 3815 int renamed; /* Was an existing entry renamed? */ 3816 int delOldRDN; /* Was old RDN deleted? */ 3817 Modifications **modlist; /* the modlist we received */ 3818 Modifications *mods; /* the modlist we compared */ 3819 int oldNcount; /* #values of old naming attr */ 3820 AttributeDescription *oldDesc; /* for renames */ 3821 AttributeDescription *newDesc; /* for renames */ 3822 } dninfo; 3823 3824 #define HASHUUID 1 3825 3826 /* return 1 if inserted, 0 otherwise */ 3827 static int 3828 presentlist_insert( 3829 syncinfo_t* si, 3830 struct berval *syncUUID ) 3831 { 3832 char *val; 3833 3834 #ifdef HASHUUID 3835 Avlnode **av; 3836 unsigned short s; 3837 3838 if ( !si->si_presentlist ) 3839 si->si_presentlist = ch_calloc(65536, sizeof( Avlnode * )); 3840 3841 av = (Avlnode **)si->si_presentlist; 3842 3843 val = ch_malloc(UUIDLEN-2); 3844 memcpy(&s, syncUUID->bv_val, 2); 3845 memcpy(val, syncUUID->bv_val+2, UUIDLEN-2); 3846 3847 if ( ldap_avl_insert( &av[s], val, 3848 syncuuid_cmp, ldap_avl_dup_error ) ) 3849 { 3850 ch_free( val ); 3851 return 0; 3852 } 3853 #else 3854 val = ch_malloc(UUIDLEN); 3855 3856 AC_MEMCPY( val, syncUUID->bv_val, UUIDLEN ); 3857 3858 if ( ldap_avl_insert( &si->si_presentlist, val, 3859 syncuuid_cmp, ldap_avl_dup_error ) ) 3860 { 3861 ch_free( val ); 3862 return 0; 3863 } 3864 #endif 3865 3866 return 1; 3867 } 3868 3869 static char * 3870 presentlist_find( 3871 Avlnode *av, 3872 struct berval *val ) 3873 { 3874 #ifdef HASHUUID 3875 Avlnode **a2 = (Avlnode **)av; 3876 unsigned short s; 3877 3878 if (!av) 3879 return NULL; 3880 3881 memcpy(&s, val->bv_val, 2); 3882 return ldap_avl_find( a2[s], val->bv_val+2, syncuuid_cmp ); 3883 #else 3884 return ldap_avl_find( av, val->bv_val, syncuuid_cmp ); 3885 #endif 3886 } 3887 3888 static int 3889 presentlist_free( Avlnode *av ) 3890 { 3891 #ifdef HASHUUID 3892 Avlnode **a2 = (Avlnode **)av; 3893 int i, count = 0; 3894 3895 if ( av ) { 3896 for (i=0; i<65536; i++) { 3897 if (a2[i]) 3898 count += ldap_avl_free( a2[i], ch_free ); 3899 } 3900 ch_free( av ); 3901 } 3902 return count; 3903 #else 3904 return ldap_avl_free( av, ch_free ); 3905 #endif 3906 } 3907 3908 static void 3909 presentlist_delete( 3910 Avlnode **av, 3911 struct berval *val ) 3912 { 3913 #ifdef HASHUUID 3914 Avlnode **a2 = *(Avlnode ***)av; 3915 unsigned short s; 3916 3917 memcpy(&s, val->bv_val, 2); 3918 ldap_avl_delete( &a2[s], val->bv_val+2, syncuuid_cmp ); 3919 #else 3920 ldap_avl_delete( av, val->bv_val, syncuuid_cmp ); 3921 #endif 3922 } 3923 3924 static int 3925 syncrepl_entry( 3926 syncinfo_t* si, 3927 Operation *op, 3928 Entry* entry, 3929 Modifications** modlist, 3930 int syncstate, 3931 struct berval* syncUUID, 3932 struct berval* syncCSN ) 3933 { 3934 Backend *be = op->o_bd; 3935 slap_callback cb = { NULL, NULL, NULL, NULL }; 3936 int syncuuid_inserted = 0; 3937 3938 SlapReply rs_search = {REP_RESULT}; 3939 Filter f = {0}; 3940 AttributeAssertion ava = ATTRIBUTEASSERTION_INIT; 3941 int rc = LDAP_SUCCESS; 3942 3943 struct berval pdn = BER_BVNULL; 3944 dninfo dni = {0}; 3945 int retry = 1; 3946 int freecsn = 1; 3947 3948 Debug( LDAP_DEBUG_SYNC, 3949 "syncrepl_entry: %s LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_%s) csn=%s tid %p\n", 3950 si->si_ridtxt, syncrepl_state2str( syncstate ), syncCSN ? syncCSN->bv_val : "(none)", (void *)op->o_tid ); 3951 3952 if (( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD ) ) { 3953 if ( !si->si_refreshPresent && !si->si_refreshDone ) { 3954 syncuuid_inserted = presentlist_insert( si, syncUUID ); 3955 } 3956 } 3957 3958 if ( syncstate == LDAP_SYNC_PRESENT ) { 3959 return 0; 3960 } else if ( syncstate != LDAP_SYNC_DELETE ) { 3961 if ( entry == NULL ) { 3962 return 0; 3963 } 3964 } 3965 3966 if ( syncstate != LDAP_SYNC_DELETE ) { 3967 Attribute *a = attr_find( entry->e_attrs, slap_schema.si_ad_entryUUID ); 3968 3969 if ( a == NULL ) { 3970 /* add if missing */ 3971 attr_merge_one( entry, slap_schema.si_ad_entryUUID, 3972 &syncUUID[1], syncUUID ); 3973 3974 } else if ( !bvmatch( &a->a_nvals[0], syncUUID ) ) { 3975 /* replace only if necessary */ 3976 if ( a->a_nvals != a->a_vals ) { 3977 ber_memfree( a->a_nvals[0].bv_val ); 3978 ber_dupbv( &a->a_nvals[0], syncUUID ); 3979 } 3980 ber_memfree( a->a_vals[0].bv_val ); 3981 ber_dupbv( &a->a_vals[0], &syncUUID[1] ); 3982 } 3983 } 3984 3985 f.f_choice = LDAP_FILTER_EQUALITY; 3986 f.f_ava = &ava; 3987 ava.aa_desc = slap_schema.si_ad_entryUUID; 3988 ava.aa_value = *syncUUID; 3989 3990 if ( syncuuid_inserted ) { 3991 Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s inserted UUID %s\n", 3992 si->si_ridtxt, syncUUID[1].bv_val ); 3993 } 3994 op->ors_filter = &f; 3995 3996 op->ors_filterstr.bv_len = STRLENOF( "(entryUUID=)" ) + syncUUID[1].bv_len; 3997 op->ors_filterstr.bv_val = (char *) slap_sl_malloc( 3998 op->ors_filterstr.bv_len + 1, op->o_tmpmemctx ); 3999 AC_MEMCPY( op->ors_filterstr.bv_val, "(entryUUID=", STRLENOF( "(entryUUID=" ) ); 4000 AC_MEMCPY( &op->ors_filterstr.bv_val[STRLENOF( "(entryUUID=" )], 4001 syncUUID[1].bv_val, syncUUID[1].bv_len ); 4002 op->ors_filterstr.bv_val[op->ors_filterstr.bv_len - 1] = ')'; 4003 op->ors_filterstr.bv_val[op->ors_filterstr.bv_len] = '\0'; 4004 4005 op->o_tag = LDAP_REQ_SEARCH; 4006 op->ors_scope = LDAP_SCOPE_SUBTREE; 4007 op->ors_deref = LDAP_DEREF_NEVER; 4008 4009 /* get the entry for this UUID */ 4010 if ( si->si_rewrite ) { 4011 op->o_req_dn = si->si_suffixm; 4012 op->o_req_ndn = si->si_suffixm; 4013 } else 4014 { 4015 op->o_req_dn = si->si_base; 4016 op->o_req_ndn = si->si_base; 4017 } 4018 4019 op->o_time = slap_get_time(); 4020 op->ors_tlimit = SLAP_NO_LIMIT; 4021 op->ors_slimit = 1; 4022 op->ors_limit = NULL; 4023 4024 op->ors_attrs = slap_anlist_all_attributes; 4025 op->ors_attrsonly = 0; 4026 4027 /* set callback function */ 4028 op->o_callback = &cb; 4029 cb.sc_response = dn_callback; 4030 cb.sc_private = &dni; 4031 dni.si = si; 4032 dni.new_entry = entry; 4033 dni.modlist = modlist; 4034 dni.syncstate = syncstate; 4035 4036 rc = be->be_search( op, &rs_search ); 4037 Debug( LDAP_DEBUG_SYNC, 4038 "syncrepl_entry: %s be_search (%d)\n", 4039 si->si_ridtxt, rc ); 4040 4041 if ( !BER_BVISNULL( &op->ors_filterstr ) ) { 4042 slap_sl_free( op->ors_filterstr.bv_val, op->o_tmpmemctx ); 4043 } 4044 4045 cb.sc_response = syncrepl_null_callback; 4046 cb.sc_private = si; 4047 4048 if ( entry && !BER_BVISNULL( &entry->e_name ) ) { 4049 Debug( LDAP_DEBUG_SYNC, 4050 "syncrepl_entry: %s %s\n", 4051 si->si_ridtxt, entry->e_name.bv_val ); 4052 } else { 4053 Debug( LDAP_DEBUG_SYNC, 4054 "syncrepl_entry: %s %s\n", 4055 si->si_ridtxt, dni.dn.bv_val ? dni.dn.bv_val : "(null)" ); 4056 } 4057 4058 assert( BER_BVISNULL( &op->o_csn ) ); 4059 if ( syncCSN ) { 4060 slap_queue_csn( op, syncCSN ); 4061 } 4062 4063 #ifdef SLAP_CONTROL_X_LAZY_COMMIT 4064 if ( !si->si_refreshDone && si->si_lazyCommit ) 4065 op->o_lazyCommit = SLAP_CONTROL_NONCRITICAL; 4066 #endif 4067 4068 slap_op_time( &op->o_time, &op->o_tincr ); 4069 switch ( syncstate ) { 4070 case LDAP_SYNC_ADD: 4071 case LDAP_SYNC_MODIFY: 4072 case DSEE_SYNC_ADD: 4073 if ( BER_BVISNULL( &op->o_csn )) 4074 { 4075 4076 Attribute *a = attr_find( entry->e_attrs, slap_schema.si_ad_entryCSN ); 4077 if ( a ) { 4078 /* FIXME: op->o_csn is assumed to be 4079 * on the thread's slab; this needs 4080 * to be cleared ASAP. 4081 */ 4082 op->o_csn = a->a_vals[0]; 4083 freecsn = 0; 4084 } 4085 } 4086 retry_add:; 4087 if ( BER_BVISNULL( &dni.dn ) ) { 4088 SlapReply rs_add = {REP_RESULT}; 4089 4090 op->o_req_dn = entry->e_name; 4091 op->o_req_ndn = entry->e_nname; 4092 op->o_tag = LDAP_REQ_ADD; 4093 op->ora_e = entry; 4094 op->o_bd = si->si_wbe; 4095 4096 rc = op->o_bd->be_add( op, &rs_add ); 4097 Debug( LDAP_DEBUG_SYNC, 4098 "syncrepl_entry: %s be_add %s (%d)\n", 4099 si->si_ridtxt, op->o_req_dn.bv_val, rc ); 4100 switch ( rs_add.sr_err ) { 4101 case LDAP_SUCCESS: 4102 if ( op->ora_e == entry ) { 4103 be_entry_release_w( op, entry ); 4104 } 4105 entry = NULL; 4106 break; 4107 4108 case LDAP_REFERRAL: 4109 /* we assume that LDAP_NO_SUCH_OBJECT is returned 4110 * only if the suffix entry is not present. 4111 * This should not happen during Persist phase. 4112 */ 4113 case LDAP_NO_SUCH_OBJECT: 4114 if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST && 4115 si->si_refreshDone ) { 4116 /* Something's wrong, start over */ 4117 ber_bvarray_free( si->si_syncCookie.ctxcsn ); 4118 si->si_syncCookie.ctxcsn = NULL; 4119 entry_free( entry ); 4120 ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex ); 4121 ber_bvarray_free( si->si_cookieState->cs_vals ); 4122 ch_free( si->si_cookieState->cs_sids ); 4123 si->si_cookieState->cs_vals = NULL; 4124 si->si_cookieState->cs_sids = 0; 4125 si->si_cookieState->cs_num = 0; 4126 ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex ); 4127 return LDAP_NO_SUCH_OBJECT; 4128 } 4129 rc = syncrepl_add_glue( op, entry ); 4130 entry = NULL; 4131 break; 4132 4133 /* if an entry was added via syncrepl_add_glue(), 4134 * it likely has no entryUUID, so the previous 4135 * be_search() doesn't find it. In this case, 4136 * give syncrepl a chance to modify it. Also 4137 * allow for entries that were recreated with the 4138 * same DN but a different entryUUID. 4139 */ 4140 case LDAP_ALREADY_EXISTS: 4141 if ( retry ) { 4142 Operation op2 = *op; 4143 SlapReply rs2 = { REP_RESULT }; 4144 slap_callback cb2 = { 0 }; 4145 4146 op2.o_bd = be; 4147 op2.o_tag = LDAP_REQ_SEARCH; 4148 op2.o_req_dn = entry->e_name; 4149 op2.o_req_ndn = entry->e_nname; 4150 op2.ors_scope = LDAP_SCOPE_BASE; 4151 op2.ors_deref = LDAP_DEREF_NEVER; 4152 op2.ors_attrs = slap_anlist_all_attributes; 4153 op2.ors_attrsonly = 0; 4154 op2.ors_limit = NULL; 4155 op2.ors_slimit = 1; 4156 op2.ors_tlimit = SLAP_NO_LIMIT; 4157 4158 f.f_choice = LDAP_FILTER_PRESENT; 4159 f.f_desc = slap_schema.si_ad_objectClass; 4160 op2.ors_filter = &f; 4161 op2.ors_filterstr = generic_filterstr; 4162 4163 op2.o_callback = &cb2; 4164 cb2.sc_response = dn_callback; 4165 cb2.sc_private = &dni; 4166 4167 rc = be->be_search( &op2, &rs2 ); 4168 if ( rc ) goto done; 4169 4170 retry = 0; 4171 slap_op_time( &op->o_time, &op->o_tincr ); 4172 goto retry_add; 4173 } 4174 /* FALLTHRU */ 4175 4176 default: 4177 Debug( LDAP_DEBUG_ANY, 4178 "syncrepl_entry: %s be_add %s failed (%d)\n", 4179 si->si_ridtxt, op->o_req_dn.bv_val, rs_add.sr_err ); 4180 break; 4181 } 4182 syncCSN = NULL; 4183 op->o_bd = be; 4184 goto done; 4185 } 4186 /* FALLTHRU */ 4187 #ifdef LDAP_CONTROL_X_DIRSYNC 4188 case MSAD_DIRSYNC_MODIFY: 4189 #endif 4190 op->o_req_dn = dni.dn; 4191 op->o_req_ndn = dni.ndn; 4192 if ( dni.renamed ) { 4193 struct berval noldp, newp; 4194 Modifications *mod, **modtail, **ml, *m2 = NULL; 4195 int i, got_replace = 0, just_rename = 0; 4196 SlapReply rs_modify = {REP_RESULT}; 4197 4198 op->o_tag = LDAP_REQ_MODRDN; 4199 dnRdn( &entry->e_name, &op->orr_newrdn ); 4200 dnRdn( &entry->e_nname, &op->orr_nnewrdn ); 4201 4202 if ( !BER_BVISNULL( &dni.nnewSup )) { 4203 dnParent( &entry->e_name, &newp ); 4204 op->orr_newSup = &newp; 4205 op->orr_nnewSup = &dni.nnewSup; 4206 } else { 4207 op->orr_newSup = NULL; 4208 op->orr_nnewSup = NULL; 4209 } 4210 op->orr_deleteoldrdn = dni.delOldRDN; 4211 op->orr_modlist = NULL; 4212 #ifdef LDAP_CONTROL_X_DIRSYNC 4213 if ( syncstate != MSAD_DIRSYNC_MODIFY ) 4214 #endif 4215 { 4216 if ( ( rc = slap_modrdn2mods( op, &rs_modify ) ) ) { 4217 goto done; 4218 } 4219 } 4220 4221 /* Drop the RDN-related mods from this op, because their 4222 * equivalents were just setup by slap_modrdn2mods. 4223 * 4224 * If delOldRDN is TRUE then we should see a delete modop 4225 * for oldDesc. We might see a replace instead. 4226 * delete with no values: therefore newDesc != oldDesc. 4227 * if oldNcount == 1, then Drop this op. 4228 * delete with 1 value: can only be the oldRDN value. Drop op. 4229 * delete with N values: Drop oldRDN value, keep remainder. 4230 * replace with 1 value: if oldNcount == 1 and 4231 * newDesc == oldDesc, Drop this op. 4232 * Any other cases must be left intact. 4233 * 4234 * We should also see an add modop for newDesc. (But not if 4235 * we got a replace modop due to delOldRDN.) If it has 4236 * multiple values, we'll have to drop the new RDN value. 4237 */ 4238 modtail = &op->orr_modlist; 4239 if ( dni.delOldRDN ) { 4240 for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next ) { 4241 if ( (*ml)->sml_desc == dni.oldDesc ) { 4242 mod = *ml; 4243 if ( mod->sml_op == LDAP_MOD_REPLACE && 4244 dni.oldDesc != dni.newDesc ) { 4245 /* This Replace is due to other Mods. 4246 * Just let it ride. 4247 */ 4248 continue; 4249 } 4250 if ( mod->sml_numvals <= 1 && 4251 dni.oldNcount == 1 && 4252 ( mod->sml_op == LDAP_MOD_DELETE || 4253 mod->sml_op == LDAP_MOD_REPLACE )) { 4254 if ( mod->sml_op == LDAP_MOD_REPLACE ) 4255 got_replace = 1; 4256 /* Drop this op */ 4257 *ml = mod->sml_next; 4258 mod->sml_next = NULL; 4259 slap_mods_free( mod, 1 ); 4260 break; 4261 } 4262 if ( mod->sml_op != LDAP_MOD_DELETE || mod->sml_numvals == 0 ) 4263 continue; 4264 for ( m2 = op->orr_modlist; m2; m2=m2->sml_next ) { 4265 if ( m2->sml_desc == dni.oldDesc && 4266 m2->sml_op == LDAP_MOD_DELETE ) break; 4267 } 4268 for ( i=0; i<mod->sml_numvals; i++ ) { 4269 if ( bvmatch( &mod->sml_values[i], &m2->sml_values[0] )) { 4270 mod->sml_numvals--; 4271 ch_free( mod->sml_values[i].bv_val ); 4272 mod->sml_values[i] = mod->sml_values[mod->sml_numvals]; 4273 BER_BVZERO( &mod->sml_values[mod->sml_numvals] ); 4274 if ( mod->sml_nvalues ) { 4275 ch_free( mod->sml_nvalues[i].bv_val ); 4276 mod->sml_nvalues[i] = mod->sml_nvalues[mod->sml_numvals]; 4277 BER_BVZERO( &mod->sml_nvalues[mod->sml_numvals] ); 4278 } 4279 break; 4280 } 4281 } 4282 if ( !mod->sml_numvals ) { 4283 /* Drop this op */ 4284 *ml = mod->sml_next; 4285 mod->sml_next = NULL; 4286 slap_mods_free( mod, 1 ); 4287 } 4288 break; 4289 } 4290 } 4291 } 4292 if ( !got_replace ) { 4293 for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next ) { 4294 if ( (*ml)->sml_desc == dni.newDesc ) { 4295 mod = *ml; 4296 if ( mod->sml_op != LDAP_MOD_ADD ) 4297 continue; 4298 if ( mod->sml_numvals == 1 ) { 4299 /* Drop this op */ 4300 *ml = mod->sml_next; 4301 mod->sml_next = NULL; 4302 slap_mods_free( mod, 1 ); 4303 break; 4304 } 4305 for ( m2 = op->orr_modlist; m2; m2=m2->sml_next ) { 4306 if ( m2->sml_desc == dni.oldDesc && 4307 m2->sml_op == SLAP_MOD_SOFTADD ) break; 4308 } 4309 for ( i=0; i<mod->sml_numvals; i++ ) { 4310 if ( bvmatch( &mod->sml_values[i], &m2->sml_values[0] )) { 4311 mod->sml_numvals--; 4312 ch_free( mod->sml_values[i].bv_val ); 4313 mod->sml_values[i] = mod->sml_values[mod->sml_numvals]; 4314 BER_BVZERO( &mod->sml_values[mod->sml_numvals] ); 4315 if ( mod->sml_nvalues ) { 4316 ch_free( mod->sml_nvalues[i].bv_val ); 4317 mod->sml_nvalues[i] = mod->sml_nvalues[mod->sml_numvals]; 4318 BER_BVZERO( &mod->sml_nvalues[mod->sml_numvals] ); 4319 } 4320 break; 4321 } 4322 } 4323 break; 4324 } 4325 } 4326 } 4327 4328 /* RDNs must be NUL-terminated for back-ldap */ 4329 noldp = op->orr_newrdn; 4330 ber_dupbv_x( &op->orr_newrdn, &noldp, op->o_tmpmemctx ); 4331 noldp = op->orr_nnewrdn; 4332 ber_dupbv_x( &op->orr_nnewrdn, &noldp, op->o_tmpmemctx ); 4333 4334 /* Setup opattrs too */ 4335 { 4336 static AttributeDescription *nullattr = NULL; 4337 static AttributeDescription **const opattrs[] = { 4338 &slap_schema.si_ad_entryCSN, 4339 &slap_schema.si_ad_modifiersName, 4340 &slap_schema.si_ad_modifyTimestamp, 4341 &nullattr 4342 }; 4343 AttributeDescription *opattr; 4344 int i; 4345 4346 modtail = &m2; 4347 /* pull mod off incoming modlist */ 4348 for ( i = 0; (opattr = *opattrs[i]) != NULL; i++ ) { 4349 for ( ml = &dni.mods; *ml; ml = &(*ml)->sml_next ) 4350 { 4351 if ( (*ml)->sml_desc == opattr ) { 4352 mod = *ml; 4353 *ml = mod->sml_next; 4354 mod->sml_next = NULL; 4355 *modtail = mod; 4356 modtail = &mod->sml_next; 4357 break; 4358 } 4359 } 4360 } 4361 /* If there are still Modifications left, put the opattrs 4362 * back, and let be_modify run. Otherwise, append the opattrs 4363 * to the orr_modlist. 4364 */ 4365 if ( dni.mods ) { 4366 mod = dni.mods; 4367 /* don't set a CSN for the rename op */ 4368 if ( syncCSN ) 4369 slap_graduate_commit_csn( op ); 4370 } else { 4371 mod = op->orr_modlist; 4372 just_rename = 1; 4373 } 4374 for ( ; mod->sml_next; mod=mod->sml_next ); 4375 mod->sml_next = m2; 4376 } 4377 op->o_bd = si->si_wbe; 4378 retry_modrdn:; 4379 rs_reinit( &rs_modify, REP_RESULT ); 4380 rc = op->o_bd->be_modrdn( op, &rs_modify ); 4381 4382 /* NOTE: noSuchObject should result because the new superior 4383 * has not been added yet (ITS#6472) */ 4384 if ( rc == LDAP_NO_SUCH_OBJECT && op->orr_nnewSup != NULL ) { 4385 Operation op2 = *op; 4386 rc = syncrepl_add_glue_ancestors( &op2, entry ); 4387 if ( rc == LDAP_SUCCESS ) { 4388 goto retry_modrdn; 4389 } 4390 } 4391 4392 op->o_tmpfree( op->orr_nnewrdn.bv_val, op->o_tmpmemctx ); 4393 op->o_tmpfree( op->orr_newrdn.bv_val, op->o_tmpmemctx ); 4394 4395 slap_mods_free( op->orr_modlist, 1 ); 4396 Debug( LDAP_DEBUG_SYNC, 4397 "syncrepl_entry: %s be_modrdn %s (%d)\n", 4398 si->si_ridtxt, op->o_req_dn.bv_val, rc ); 4399 op->o_bd = be; 4400 /* Renamed entries may still have other mods so just fallthru */ 4401 op->o_req_dn = entry->e_name; 4402 op->o_req_ndn = entry->e_nname; 4403 /* Use CSN on the modify */ 4404 if ( just_rename ) 4405 syncCSN = NULL; 4406 else if ( syncCSN ) 4407 slap_queue_csn( op, syncCSN ); 4408 } 4409 if ( dni.mods ) { 4410 SlapReply rs_modify = {REP_RESULT}; 4411 4412 op->o_tag = LDAP_REQ_MODIFY; 4413 op->orm_modlist = dni.mods; 4414 op->orm_no_opattrs = 1; 4415 op->o_bd = si->si_wbe; 4416 4417 rc = op->o_bd->be_modify( op, &rs_modify ); 4418 slap_mods_free( op->orm_modlist, 1 ); 4419 op->orm_no_opattrs = 0; 4420 Debug( LDAP_DEBUG_SYNC, 4421 "syncrepl_entry: %s be_modify %s (%d)\n", 4422 si->si_ridtxt, op->o_req_dn.bv_val, rc ); 4423 if ( rs_modify.sr_err != LDAP_SUCCESS ) { 4424 Debug( LDAP_DEBUG_ANY, 4425 "syncrepl_entry: %s be_modify failed (%d)\n", 4426 si->si_ridtxt, rs_modify.sr_err ); 4427 } 4428 syncCSN = NULL; 4429 op->o_bd = be; 4430 } else if ( !dni.renamed ) { 4431 Debug( LDAP_DEBUG_SYNC, 4432 "syncrepl_entry: %s entry unchanged, ignored (%s)\n", 4433 si->si_ridtxt, op->o_req_dn.bv_val ); 4434 if ( syncCSN ) { 4435 slap_graduate_commit_csn( op ); 4436 syncCSN = NULL; 4437 } 4438 } 4439 goto done; 4440 case LDAP_SYNC_DELETE : 4441 if ( !BER_BVISNULL( &dni.dn ) ) { 4442 SlapReply rs_delete = {REP_RESULT}; 4443 op->o_req_dn = dni.dn; 4444 op->o_req_ndn = dni.ndn; 4445 op->o_tag = LDAP_REQ_DELETE; 4446 op->o_bd = si->si_wbe; 4447 if ( !syncCSN && si->si_syncCookie.ctxcsn ) { 4448 slap_queue_csn( op, si->si_syncCookie.ctxcsn ); 4449 } 4450 rc = op->o_bd->be_delete( op, &rs_delete ); 4451 Debug( LDAP_DEBUG_SYNC, 4452 "syncrepl_entry: %s be_delete %s (%d)\n", 4453 si->si_ridtxt, op->o_req_dn.bv_val, rc ); 4454 if ( rc == LDAP_NO_SUCH_OBJECT ) 4455 rc = LDAP_SUCCESS; 4456 4457 while ( rs_delete.sr_err == LDAP_SUCCESS 4458 && op->o_delete_glue_parent ) { 4459 op->o_delete_glue_parent = 0; 4460 if ( !be_issuffix( be, &op->o_req_ndn ) ) { 4461 slap_callback cb = { NULL }; 4462 cb.sc_response = syncrepl_null_callback; 4463 dnParent( &op->o_req_ndn, &pdn ); 4464 op->o_req_dn = pdn; 4465 op->o_req_ndn = pdn; 4466 op->o_callback = &cb; 4467 rs_reinit( &rs_delete, REP_RESULT ); 4468 op->o_bd->be_delete( op, &rs_delete ); 4469 } else { 4470 break; 4471 } 4472 } 4473 syncCSN = NULL; 4474 op->o_bd = be; 4475 } 4476 goto done; 4477 4478 default : 4479 Debug( LDAP_DEBUG_ANY, 4480 "syncrepl_entry: %s unknown syncstate\n", si->si_ridtxt ); 4481 goto done; 4482 } 4483 4484 done: 4485 slap_sl_free( syncUUID[1].bv_val, op->o_tmpmemctx ); 4486 BER_BVZERO( &syncUUID[1] ); 4487 if ( !BER_BVISNULL( &dni.ndn ) ) { 4488 op->o_tmpfree( dni.ndn.bv_val, op->o_tmpmemctx ); 4489 } 4490 if ( !BER_BVISNULL( &dni.dn ) ) { 4491 op->o_tmpfree( dni.dn.bv_val, op->o_tmpmemctx ); 4492 } 4493 if ( entry ) { 4494 entry_free( entry ); 4495 } 4496 if ( syncCSN ) { 4497 slap_graduate_commit_csn( op ); 4498 } 4499 if ( !BER_BVISNULL( &op->o_csn ) && freecsn ) { 4500 op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx ); 4501 } 4502 BER_BVZERO( &op->o_csn ); 4503 return rc; 4504 } 4505 4506 static struct berval gcbva[] = { 4507 BER_BVC("top"), 4508 BER_BVC("glue"), 4509 BER_BVNULL 4510 }; 4511 4512 #define NP_DELETE_ONE 2 4513 4514 static void 4515 syncrepl_del_nonpresent( 4516 Operation *op, 4517 syncinfo_t *si, 4518 BerVarray uuids, 4519 struct sync_cookie *sc, 4520 int m ) 4521 { 4522 Backend* be = op->o_bd; 4523 slap_callback cb = { NULL }; 4524 struct nonpresent_entry *np_list, *np_prev; 4525 int rc; 4526 AttributeName an[3]; /* entryUUID, entryCSN, NULL */ 4527 4528 struct berval pdn = BER_BVNULL; 4529 struct berval csn; 4530 4531 if ( si->si_rewrite ) { 4532 op->o_req_dn = si->si_suffixm; 4533 op->o_req_ndn = si->si_suffixm; 4534 } else 4535 { 4536 op->o_req_dn = si->si_base; 4537 op->o_req_ndn = si->si_base; 4538 } 4539 4540 cb.sc_response = nonpresent_callback; 4541 cb.sc_private = si; 4542 4543 op->o_callback = &cb; 4544 op->o_tag = LDAP_REQ_SEARCH; 4545 op->ors_scope = si->si_scope; 4546 op->ors_deref = LDAP_DEREF_NEVER; 4547 op->o_time = slap_get_time(); 4548 op->ors_tlimit = SLAP_NO_LIMIT; 4549 4550 4551 if ( uuids ) { 4552 Filter uf; 4553 AttributeAssertion eq = ATTRIBUTEASSERTION_INIT; 4554 int i; 4555 4556 op->ors_attrsonly = 1; 4557 op->ors_attrs = slap_anlist_no_attrs; 4558 op->ors_limit = NULL; 4559 op->ors_filter = &uf; 4560 4561 uf.f_ava = &eq; 4562 uf.f_av_desc = slap_schema.si_ad_entryUUID; 4563 uf.f_next = NULL; 4564 uf.f_choice = LDAP_FILTER_EQUALITY; 4565 si->si_refreshDelete |= NP_DELETE_ONE; 4566 4567 for (i=0; uuids[i].bv_val; i++) { 4568 SlapReply rs_search = {REP_RESULT}; 4569 4570 op->ors_slimit = 1; 4571 uf.f_av_value = uuids[i]; 4572 filter2bv_x( op, op->ors_filter, &op->ors_filterstr ); 4573 Debug( LDAP_DEBUG_SYNC, "syncrepl_del_nonpresent: %s " 4574 "checking non-present filter=%s\n", 4575 si->si_ridtxt, op->ors_filterstr.bv_val ); 4576 rc = be->be_search( op, &rs_search ); 4577 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); 4578 } 4579 si->si_refreshDelete ^= NP_DELETE_ONE; 4580 } else { 4581 Filter *cf, *of; 4582 Filter mmf[2]; 4583 AttributeAssertion mmaa; 4584 SlapReply rs_search = {REP_RESULT}; 4585 4586 memset( &an[0], 0, 3 * sizeof( AttributeName ) ); 4587 an[0].an_name = slap_schema.si_ad_entryUUID->ad_cname; 4588 an[0].an_desc = slap_schema.si_ad_entryUUID; 4589 an[1].an_name = slap_schema.si_ad_entryCSN->ad_cname; 4590 an[1].an_desc = slap_schema.si_ad_entryCSN; 4591 op->ors_attrs = an; 4592 op->ors_slimit = SLAP_NO_LIMIT; 4593 op->ors_tlimit = SLAP_NO_LIMIT; 4594 op->ors_limit = NULL; 4595 op->ors_attrsonly = 0; 4596 op->ors_filter = filter_dup( si->si_filter, op->o_tmpmemctx ); 4597 /* In multi-provider, updates can continue to arrive while 4598 * we're searching. Limit the search result to entries 4599 * older than our newest cookie CSN. 4600 */ 4601 if ( SLAP_MULTIPROVIDER( op->o_bd )) { 4602 Filter *f; 4603 int i; 4604 4605 f = mmf; 4606 f->f_choice = LDAP_FILTER_AND; 4607 f->f_next = op->ors_filter; 4608 f->f_and = f+1; 4609 of = f->f_and; 4610 f = of; 4611 f->f_choice = LDAP_FILTER_LE; 4612 f->f_ava = &mmaa; 4613 f->f_av_desc = slap_schema.si_ad_entryCSN; 4614 f->f_next = NULL; 4615 BER_BVZERO( &f->f_av_value ); 4616 for ( i=0; i<sc->numcsns; i++ ) { 4617 if ( ber_bvcmp( &sc->ctxcsn[i], &f->f_av_value ) > 0 ) 4618 f->f_av_value = sc->ctxcsn[i]; 4619 } 4620 of = op->ors_filter; 4621 op->ors_filter = mmf; 4622 filter2bv_x( op, op->ors_filter, &op->ors_filterstr ); 4623 } else { 4624 cf = NULL; 4625 op->ors_filterstr = si->si_filterstr; 4626 } 4627 op->o_nocaching = 1; 4628 4629 4630 rc = be->be_search( op, &rs_search ); 4631 if ( SLAP_MULTIPROVIDER( op->o_bd )) { 4632 op->ors_filter = of; 4633 } 4634 if ( op->ors_filter ) filter_free_x( op, op->ors_filter, 1 ); 4635 if ( op->ors_filterstr.bv_val != si->si_filterstr.bv_val ) { 4636 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx ); 4637 } 4638 4639 } 4640 4641 op->o_nocaching = 0; 4642 4643 if ( !LDAP_LIST_EMPTY( &si->si_nonpresentlist ) ) { 4644 4645 if ( !BER_BVISNULL( &sc->delcsn ) ) { 4646 Debug( LDAP_DEBUG_SYNC, "syncrepl_del_nonpresent: %s " 4647 "using delcsn=%s\n", 4648 si->si_ridtxt, sc->delcsn.bv_val ); 4649 csn = sc->delcsn; 4650 } else if ( sc->ctxcsn && !BER_BVISNULL( &sc->ctxcsn[m] ) ) { 4651 csn = sc->ctxcsn[m]; 4652 } else { 4653 csn = si->si_syncCookie.ctxcsn[0]; 4654 } 4655 4656 op->o_bd = si->si_wbe; 4657 slap_queue_csn( op, &csn ); 4658 4659 np_list = LDAP_LIST_FIRST( &si->si_nonpresentlist ); 4660 while ( np_list != NULL ) { 4661 SlapReply rs_delete = {REP_RESULT}; 4662 4663 LDAP_LIST_REMOVE( np_list, npe_link ); 4664 np_prev = np_list; 4665 np_list = LDAP_LIST_NEXT( np_list, npe_link ); 4666 op->o_tag = LDAP_REQ_DELETE; 4667 op->o_callback = &cb; 4668 cb.sc_response = syncrepl_null_callback; 4669 cb.sc_private = si; 4670 op->o_req_dn = *np_prev->npe_name; 4671 op->o_req_ndn = *np_prev->npe_nname; 4672 rc = op->o_bd->be_delete( op, &rs_delete ); 4673 Debug( LDAP_DEBUG_SYNC, 4674 "syncrepl_del_nonpresent: %s be_delete %s (%d)\n", 4675 si->si_ridtxt, op->o_req_dn.bv_val, rc ); 4676 4677 if ( rs_delete.sr_err == LDAP_NOT_ALLOWED_ON_NONLEAF ) { 4678 SlapReply rs_modify = {REP_RESULT}; 4679 Modifications mod1, mod2; 4680 mod1.sml_op = LDAP_MOD_REPLACE; 4681 mod1.sml_flags = 0; 4682 mod1.sml_desc = slap_schema.si_ad_objectClass; 4683 mod1.sml_type = mod1.sml_desc->ad_cname; 4684 mod1.sml_numvals = 2; 4685 mod1.sml_values = &gcbva[0]; 4686 mod1.sml_nvalues = NULL; 4687 mod1.sml_next = &mod2; 4688 4689 mod2.sml_op = LDAP_MOD_REPLACE; 4690 mod2.sml_flags = 0; 4691 mod2.sml_desc = slap_schema.si_ad_structuralObjectClass; 4692 mod2.sml_type = mod2.sml_desc->ad_cname; 4693 mod2.sml_numvals = 1; 4694 mod2.sml_values = &gcbva[1]; 4695 mod2.sml_nvalues = NULL; 4696 mod2.sml_next = NULL; 4697 4698 op->o_tag = LDAP_REQ_MODIFY; 4699 op->orm_modlist = &mod1; 4700 4701 rc = op->o_bd->be_modify( op, &rs_modify ); 4702 if ( mod2.sml_next ) slap_mods_free( mod2.sml_next, 1 ); 4703 } 4704 4705 while ( rs_delete.sr_err == LDAP_SUCCESS && 4706 op->o_delete_glue_parent ) { 4707 op->o_delete_glue_parent = 0; 4708 if ( !be_issuffix( be, &op->o_req_ndn ) ) { 4709 slap_callback cb = { NULL }; 4710 cb.sc_response = syncrepl_null_callback; 4711 dnParent( &op->o_req_ndn, &pdn ); 4712 op->o_req_dn = pdn; 4713 op->o_req_ndn = pdn; 4714 op->o_callback = &cb; 4715 rs_reinit( &rs_delete, REP_RESULT ); 4716 /* give it a root privil ? */ 4717 op->o_bd->be_delete( op, &rs_delete ); 4718 } else { 4719 break; 4720 } 4721 } 4722 4723 op->o_delete_glue_parent = 0; 4724 4725 ber_bvfree( np_prev->npe_name ); 4726 ber_bvfree( np_prev->npe_nname ); 4727 ch_free( np_prev ); 4728 4729 if ( slapd_shutdown ) { 4730 break; 4731 } 4732 } 4733 4734 slap_graduate_commit_csn( op ); 4735 op->o_bd = be; 4736 4737 op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx ); 4738 BER_BVZERO( &op->o_csn ); 4739 } 4740 4741 return; 4742 } 4743 4744 static int 4745 syncrepl_add_glue_ancestors( 4746 Operation* op, 4747 Entry *e ) 4748 { 4749 Backend *be = op->o_bd; 4750 slap_callback cb = { NULL }; 4751 Attribute *a; 4752 int rc = LDAP_SUCCESS; 4753 int suffrdns; 4754 int i; 4755 struct berval dn = BER_BVNULL; 4756 struct berval ndn = BER_BVNULL; 4757 Entry *glue; 4758 struct berval ptr, nptr; 4759 char *comma; 4760 4761 op->o_tag = LDAP_REQ_ADD; 4762 op->o_callback = &cb; 4763 cb.sc_response = syncrepl_null_callback; 4764 cb.sc_private = NULL; 4765 4766 dn = e->e_name; 4767 ndn = e->e_nname; 4768 4769 /* count RDNs in suffix */ 4770 if ( !BER_BVISEMPTY( &be->be_nsuffix[0] ) ) { 4771 for ( i = 0, ptr = be->be_nsuffix[0], comma = ptr.bv_val; comma != NULL; comma = ber_bvchr( &ptr, ',' ) ) { 4772 comma++; 4773 ptr.bv_len -= comma - ptr.bv_val; 4774 ptr.bv_val = comma; 4775 i++; 4776 } 4777 suffrdns = i; 4778 } else { 4779 /* suffix is "" */ 4780 suffrdns = 0; 4781 } 4782 4783 /* Start with BE suffix */ 4784 ptr = dn; 4785 for ( i = 0; i < suffrdns; i++ ) { 4786 comma = ber_bvrchr( &ptr, ',' ); 4787 if ( comma != NULL ) { 4788 ptr.bv_len = comma - ptr.bv_val; 4789 } else { 4790 ptr.bv_len = 0; 4791 break; 4792 } 4793 } 4794 4795 if ( !BER_BVISEMPTY( &ptr ) ) { 4796 dn.bv_len -= ptr.bv_len + ( suffrdns != 0 ); 4797 dn.bv_val += ptr.bv_len + ( suffrdns != 0 ); 4798 } 4799 4800 /* the normalizedDNs are always the same length, no counting 4801 * required. 4802 */ 4803 nptr = ndn; 4804 if ( ndn.bv_len > be->be_nsuffix[0].bv_len ) { 4805 ndn.bv_val += ndn.bv_len - be->be_nsuffix[0].bv_len; 4806 ndn.bv_len = be->be_nsuffix[0].bv_len; 4807 4808 nptr.bv_len = ndn.bv_val - nptr.bv_val - 1; 4809 4810 } else { 4811 nptr.bv_len = 0; 4812 } 4813 4814 while ( ndn.bv_val > e->e_nname.bv_val ) { 4815 SlapReply rs_add = {REP_RESULT}; 4816 4817 glue = entry_alloc(); 4818 ber_dupbv( &glue->e_name, &dn ); 4819 ber_dupbv( &glue->e_nname, &ndn ); 4820 4821 a = attr_alloc( slap_schema.si_ad_objectClass ); 4822 4823 a->a_numvals = 2; 4824 a->a_vals = ch_calloc( 3, sizeof( struct berval ) ); 4825 ber_dupbv( &a->a_vals[0], &gcbva[0] ); 4826 ber_dupbv( &a->a_vals[1], &gcbva[1] ); 4827 ber_dupbv( &a->a_vals[2], &gcbva[2] ); 4828 4829 a->a_nvals = a->a_vals; 4830 4831 a->a_next = glue->e_attrs; 4832 glue->e_attrs = a; 4833 4834 a = attr_alloc( slap_schema.si_ad_structuralObjectClass ); 4835 4836 a->a_numvals = 1; 4837 a->a_vals = ch_calloc( 2, sizeof( struct berval ) ); 4838 ber_dupbv( &a->a_vals[0], &gcbva[1] ); 4839 ber_dupbv( &a->a_vals[1], &gcbva[2] ); 4840 4841 a->a_nvals = a->a_vals; 4842 4843 a->a_next = glue->e_attrs; 4844 glue->e_attrs = a; 4845 4846 op->o_req_dn = glue->e_name; 4847 op->o_req_ndn = glue->e_nname; 4848 op->ora_e = glue; 4849 rc = be->be_add ( op, &rs_add ); 4850 if ( rs_add.sr_err == LDAP_SUCCESS ) { 4851 if ( op->ora_e == glue ) 4852 be_entry_release_w( op, glue ); 4853 } else { 4854 /* incl. ALREADY EXIST */ 4855 entry_free( glue ); 4856 if ( rs_add.sr_err != LDAP_ALREADY_EXISTS ) { 4857 entry_free( e ); 4858 return rc; 4859 } 4860 } 4861 4862 /* Move to next child */ 4863 comma = ber_bvrchr( &ptr, ',' ); 4864 if ( comma == NULL ) { 4865 break; 4866 } 4867 ptr.bv_len = comma - ptr.bv_val; 4868 4869 dn.bv_val = ++comma; 4870 dn.bv_len = e->e_name.bv_len - (dn.bv_val - e->e_name.bv_val); 4871 4872 comma = ber_bvrchr( &nptr, ',' ); 4873 assert( comma != NULL ); 4874 nptr.bv_len = comma - nptr.bv_val; 4875 4876 ndn.bv_val = ++comma; 4877 ndn.bv_len = e->e_nname.bv_len - (ndn.bv_val - e->e_nname.bv_val); 4878 } 4879 4880 return rc; 4881 } 4882 4883 int 4884 syncrepl_add_glue( 4885 Operation* op, 4886 Entry *e ) 4887 { 4888 slap_callback cb = { NULL }; 4889 int rc; 4890 Backend *be = op->o_bd; 4891 SlapReply rs_add = {REP_RESULT}; 4892 4893 rc = syncrepl_add_glue_ancestors( op, e ); 4894 switch ( rc ) { 4895 case LDAP_SUCCESS: 4896 case LDAP_ALREADY_EXISTS: 4897 break; 4898 4899 default: 4900 return rc; 4901 } 4902 4903 op->o_tag = LDAP_REQ_ADD; 4904 op->o_callback = &cb; 4905 cb.sc_response = syncrepl_null_callback; 4906 cb.sc_private = NULL; 4907 4908 op->o_req_dn = e->e_name; 4909 op->o_req_ndn = e->e_nname; 4910 op->ora_e = e; 4911 rc = be->be_add ( op, &rs_add ); 4912 if ( rs_add.sr_err == LDAP_SUCCESS ) { 4913 if ( op->ora_e == e ) 4914 be_entry_release_w( op, e ); 4915 } else { 4916 entry_free( e ); 4917 } 4918 4919 return rc; 4920 } 4921 4922 static int 4923 syncrepl_dsee_update( 4924 syncinfo_t *si, 4925 Operation *op 4926 ) 4927 { 4928 Backend *be = op->o_bd; 4929 Modifications mod; 4930 struct berval first = BER_BVNULL; 4931 slap_callback cb = { NULL }; 4932 SlapReply rs_modify = {REP_RESULT}; 4933 char valbuf[sizeof("18446744073709551615")]; 4934 struct berval bvals[2]; 4935 int rc; 4936 4937 if ( si->si_lastchange == si->si_prevchange ) 4938 return 0; 4939 4940 mod.sml_op = LDAP_MOD_REPLACE; 4941 mod.sml_desc = sy_ad_dseeLastChange; 4942 mod.sml_type = mod.sml_desc->ad_cname; 4943 mod.sml_flags = SLAP_MOD_INTERNAL; 4944 mod.sml_nvalues = NULL; 4945 mod.sml_values = bvals; 4946 mod.sml_numvals = 1; 4947 mod.sml_next = NULL; 4948 bvals[0].bv_val = valbuf; 4949 bvals[0].bv_len = sprintf( valbuf, "%lu", si->si_lastchange ); 4950 BER_BVZERO( &bvals[1] ); 4951 4952 op->o_bd = si->si_wbe; 4953 4954 op->o_tag = LDAP_REQ_MODIFY; 4955 4956 cb.sc_response = syncrepl_null_callback; 4957 cb.sc_private = si; 4958 4959 op->o_callback = &cb; 4960 op->o_req_dn = si->si_contextdn; 4961 op->o_req_ndn = si->si_contextdn; 4962 4963 /* update contextCSN */ 4964 op->o_dont_replicate = 1; 4965 4966 /* avoid timestamp collisions */ 4967 slap_op_time( &op->o_time, &op->o_tincr ); 4968 4969 op->orm_modlist = &mod; 4970 op->orm_no_opattrs = 1; 4971 rc = op->o_bd->be_modify( op, &rs_modify ); 4972 4973 op->o_bd = be; 4974 si->si_prevchange = si->si_lastchange; 4975 4976 return rc; 4977 } 4978 4979 static int 4980 syncrepl_updateCookie( 4981 syncinfo_t *si, 4982 Operation *op, 4983 struct sync_cookie *syncCookie, 4984 int save ) 4985 { 4986 Backend *be = op->o_bd; 4987 Modifications mod; 4988 struct berval first = BER_BVNULL; 4989 struct sync_cookie sc; 4990 #ifdef CHECK_CSN 4991 Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax; 4992 #endif 4993 4994 int rc, i, j, changed = 0; 4995 ber_len_t len; 4996 4997 slap_callback cb = { NULL }; 4998 SlapReply rs_modify = {REP_RESULT}; 4999 5000 mod.sml_op = LDAP_MOD_REPLACE; 5001 mod.sml_desc = slap_schema.si_ad_contextCSN; 5002 mod.sml_type = mod.sml_desc->ad_cname; 5003 mod.sml_flags = SLAP_MOD_INTERNAL; 5004 mod.sml_nvalues = NULL; 5005 mod.sml_next = NULL; 5006 5007 ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex ); 5008 while ( si->si_cookieState->cs_updating ) 5009 ldap_pvt_thread_cond_wait( &si->si_cookieState->cs_cond, &si->si_cookieState->cs_mutex ); 5010 5011 #ifdef CHECK_CSN 5012 for ( i=0; i<syncCookie->numcsns; i++ ) { 5013 assert( !syn->ssyn_validate( syn, syncCookie->ctxcsn+i )); 5014 } 5015 for ( i=0; i<si->si_cookieState->cs_num; i++ ) { 5016 assert( !syn->ssyn_validate( syn, si->si_cookieState->cs_vals+i )); 5017 } 5018 #endif 5019 5020 /* clone the cookieState CSNs so we can Replace the whole thing */ 5021 sc.numcsns = si->si_cookieState->cs_num; 5022 if ( sc.numcsns ) { 5023 ber_bvarray_dup_x( &sc.ctxcsn, si->si_cookieState->cs_vals, NULL ); 5024 sc.sids = ch_malloc( sc.numcsns * sizeof(int)); 5025 for ( i=0; i<sc.numcsns; i++ ) 5026 sc.sids[i] = si->si_cookieState->cs_sids[i]; 5027 } else { 5028 sc.ctxcsn = NULL; 5029 sc.sids = NULL; 5030 } 5031 5032 /* find any CSNs in the syncCookie that are newer than the cookieState */ 5033 for ( i=0; i<syncCookie->numcsns; i++ ) { 5034 for ( j=0; j<sc.numcsns; j++ ) { 5035 if ( syncCookie->sids[i] < sc.sids[j] ) 5036 break; 5037 if ( syncCookie->sids[i] != sc.sids[j] ) 5038 continue; 5039 len = syncCookie->ctxcsn[i].bv_len; 5040 if ( len > sc.ctxcsn[j].bv_len ) 5041 len = sc.ctxcsn[j].bv_len; 5042 if ( memcmp( syncCookie->ctxcsn[i].bv_val, 5043 sc.ctxcsn[j].bv_val, len ) > 0 ) { 5044 ber_bvreplace( &sc.ctxcsn[j], &syncCookie->ctxcsn[i] ); 5045 changed = 1; 5046 if ( BER_BVISNULL( &first ) || 5047 memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 ) { 5048 first = syncCookie->ctxcsn[i]; 5049 } 5050 } 5051 break; 5052 } 5053 /* there was no match for this SID, it's a new CSN */ 5054 if ( j == sc.numcsns || 5055 syncCookie->sids[i] != sc.sids[j] ) { 5056 slap_insert_csn_sids( &sc, j, syncCookie->sids[i], 5057 &syncCookie->ctxcsn[i] ); 5058 if ( BER_BVISNULL( &first ) || 5059 memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 ) { 5060 first = syncCookie->ctxcsn[i]; 5061 } 5062 changed = 1; 5063 } 5064 } 5065 /* Should never happen, ITS#5065 */ 5066 if ( BER_BVISNULL( &first ) || !changed ) { 5067 ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex ); 5068 ber_bvarray_free( sc.ctxcsn ); 5069 ch_free( sc.sids ); 5070 return 0; 5071 } 5072 5073 si->si_cookieState->cs_updating = 1; 5074 ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex ); 5075 5076 op->o_bd = si->si_wbe; 5077 slap_queue_csn( op, &first ); 5078 5079 op->o_tag = LDAP_REQ_MODIFY; 5080 5081 cb.sc_response = syncrepl_null_callback; 5082 cb.sc_private = si; 5083 5084 op->o_callback = &cb; 5085 op->o_req_dn = si->si_contextdn; 5086 op->o_req_ndn = si->si_contextdn; 5087 5088 /* update contextCSN */ 5089 op->o_dont_replicate = !save; 5090 5091 /* avoid timestamp collisions */ 5092 if ( save ) 5093 slap_op_time( &op->o_time, &op->o_tincr ); 5094 5095 mod.sml_numvals = sc.numcsns; 5096 mod.sml_values = sc.ctxcsn; 5097 5098 op->orm_modlist = &mod; 5099 op->orm_no_opattrs = 1; 5100 rc = op->o_bd->be_modify( op, &rs_modify ); 5101 5102 if ( rs_modify.sr_err == LDAP_NO_SUCH_OBJECT && 5103 SLAP_SYNC_SUBENTRY( op->o_bd )) { 5104 const char *text; 5105 char txtbuf[SLAP_TEXT_BUFLEN]; 5106 size_t textlen = sizeof txtbuf; 5107 Entry *e = slap_create_context_csn_entry( op->o_bd, NULL ); 5108 rs_reinit( &rs_modify, REP_RESULT ); 5109 rc = slap_mods2entry( &mod, &e, 0, 1, &text, txtbuf, textlen); 5110 slap_queue_csn( op, &first ); 5111 op->o_tag = LDAP_REQ_ADD; 5112 op->ora_e = e; 5113 rc = op->o_bd->be_add( op, &rs_modify ); 5114 if ( e == op->ora_e ) 5115 be_entry_release_w( op, op->ora_e ); 5116 } 5117 5118 op->orm_no_opattrs = 0; 5119 op->o_dont_replicate = 0; 5120 ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex ); 5121 5122 if ( rs_modify.sr_err == LDAP_SUCCESS ) { 5123 slap_sync_cookie_free( &si->si_syncCookie, 0 ); 5124 ber_bvarray_free( si->si_cookieState->cs_vals ); 5125 ch_free( si->si_cookieState->cs_sids ); 5126 si->si_cookieState->cs_vals = sc.ctxcsn; 5127 si->si_cookieState->cs_sids = sc.sids; 5128 si->si_cookieState->cs_num = sc.numcsns; 5129 5130 /* Don't just dup the provider's cookie, recreate it */ 5131 si->si_syncCookie.numcsns = si->si_cookieState->cs_num; 5132 ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn, si->si_cookieState->cs_vals, NULL ); 5133 si->si_syncCookie.sids = ch_malloc( si->si_cookieState->cs_num * sizeof(int) ); 5134 for ( i=0; i<si->si_cookieState->cs_num; i++ ) 5135 si->si_syncCookie.sids[i] = si->si_cookieState->cs_sids[i]; 5136 5137 si->si_cookieState->cs_age++; 5138 si->si_cookieAge = si->si_cookieState->cs_age; 5139 } else { 5140 Debug( LDAP_DEBUG_ANY, 5141 "syncrepl_updateCookie: %s be_modify failed (%d)\n", 5142 si->si_ridtxt, rs_modify.sr_err ); 5143 ch_free( sc.sids ); 5144 ber_bvarray_free( sc.ctxcsn ); 5145 } 5146 5147 #ifdef CHECK_CSN 5148 for ( i=0; i<si->si_cookieState->cs_num; i++ ) { 5149 assert( !syn->ssyn_validate( syn, si->si_cookieState->cs_vals+i )); 5150 } 5151 #endif 5152 5153 si->si_cookieState->cs_updating = 0; 5154 ldap_pvt_thread_cond_broadcast( &si->si_cookieState->cs_cond ); 5155 ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex ); 5156 5157 op->o_bd = be; 5158 op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx ); 5159 BER_BVZERO( &op->o_csn ); 5160 if ( mod.sml_next ) slap_mods_free( mod.sml_next, 1 ); 5161 5162 return rc; 5163 } 5164 5165 /* Compare the attribute from the old entry to the one in the new 5166 * entry. The Modifications from the new entry will either be left 5167 * in place, or changed to an Add or Delete as needed. 5168 */ 5169 static void 5170 attr_cmp( Operation *op, Attribute *old, Attribute *new, 5171 Modifications ***mret, Modifications ***mcur ) 5172 { 5173 int i, j; 5174 Modifications *mod, **modtail; 5175 5176 modtail = *mret; 5177 5178 if ( old ) { 5179 int n, o, nn, no; 5180 struct berval **adds, **dels; 5181 /* count old and new */ 5182 for ( o=0; old->a_vals[o].bv_val; o++ ) ; 5183 for ( n=0; new->a_vals[n].bv_val; n++ ) ; 5184 5185 /* there MUST be both old and new values */ 5186 assert( o != 0 ); 5187 assert( n != 0 ); 5188 j = 0; 5189 5190 adds = op->o_tmpalloc( sizeof(struct berval *) * n, op->o_tmpmemctx ); 5191 dels = op->o_tmpalloc( sizeof(struct berval *) * o, op->o_tmpmemctx ); 5192 5193 for ( i=0; i<o; i++ ) dels[i] = &old->a_vals[i]; 5194 for ( i=0; i<n; i++ ) adds[i] = &new->a_vals[i]; 5195 5196 nn = n; no = o; 5197 5198 for ( i=0; i<o; i++ ) { 5199 for ( j=0; j<n; j++ ) { 5200 if ( !adds[j] ) 5201 continue; 5202 if ( bvmatch( dels[i], adds[j] ) ) { 5203 no--; 5204 nn--; 5205 adds[j] = NULL; 5206 dels[i] = NULL; 5207 break; 5208 } 5209 } 5210 } 5211 5212 /* Don't delete/add an objectClass, always use the replace op. 5213 * Modify would fail if provider has replaced entry with a new, 5214 * and the new explicitly includes a superior of a class that was 5215 * only included implicitly in the old entry. Ref ITS#5517. 5216 * 5217 * Also use replace op if attr has no equality matching rule. 5218 * (ITS#5781) 5219 */ 5220 if ( ( nn || ( no > 0 && no < o ) ) && 5221 ( old->a_desc == slap_schema.si_ad_objectClass || 5222 !old->a_desc->ad_type->sat_equality ) ) 5223 { 5224 no = o; 5225 } 5226 5227 i = j; 5228 /* all old values were deleted, just use the replace op */ 5229 if ( no == o ) { 5230 i = j-1; 5231 } else if ( no ) { 5232 /* delete some values */ 5233 mod = ch_malloc( sizeof( Modifications ) ); 5234 mod->sml_op = LDAP_MOD_DELETE; 5235 mod->sml_flags = 0; 5236 mod->sml_desc = old->a_desc; 5237 mod->sml_type = mod->sml_desc->ad_cname; 5238 mod->sml_numvals = no; 5239 mod->sml_values = ch_malloc( ( no + 1 ) * sizeof(struct berval) ); 5240 if ( old->a_vals != old->a_nvals ) { 5241 mod->sml_nvalues = ch_malloc( ( no + 1 ) * sizeof(struct berval) ); 5242 } else { 5243 mod->sml_nvalues = NULL; 5244 } 5245 j = 0; 5246 for ( i = 0; i < o; i++ ) { 5247 if ( !dels[i] ) continue; 5248 ber_dupbv( &mod->sml_values[j], &old->a_vals[i] ); 5249 if ( mod->sml_nvalues ) { 5250 ber_dupbv( &mod->sml_nvalues[j], &old->a_nvals[i] ); 5251 } 5252 j++; 5253 } 5254 BER_BVZERO( &mod->sml_values[j] ); 5255 if ( mod->sml_nvalues ) { 5256 BER_BVZERO( &mod->sml_nvalues[j] ); 5257 } 5258 *modtail = mod; 5259 modtail = &mod->sml_next; 5260 i = j; 5261 } 5262 op->o_tmpfree( dels, op->o_tmpmemctx ); 5263 /* some values were added */ 5264 if ( nn && no < o ) { 5265 mod = ch_malloc( sizeof( Modifications ) ); 5266 if ( is_at_single_value( old->a_desc->ad_type )) 5267 mod->sml_op = LDAP_MOD_REPLACE; 5268 else 5269 mod->sml_op = LDAP_MOD_ADD; 5270 mod->sml_flags = 0; 5271 mod->sml_desc = old->a_desc; 5272 mod->sml_type = mod->sml_desc->ad_cname; 5273 mod->sml_numvals = nn; 5274 mod->sml_values = ch_malloc( ( nn + 1 ) * sizeof(struct berval) ); 5275 if ( old->a_vals != old->a_nvals ) { 5276 mod->sml_nvalues = ch_malloc( ( nn + 1 ) * sizeof(struct berval) ); 5277 } else { 5278 mod->sml_nvalues = NULL; 5279 } 5280 j = 0; 5281 for ( i = 0; i < n; i++ ) { 5282 if ( !adds[i] ) continue; 5283 ber_dupbv( &mod->sml_values[j], &new->a_vals[i] ); 5284 if ( mod->sml_nvalues ) { 5285 ber_dupbv( &mod->sml_nvalues[j], &new->a_nvals[i] ); 5286 } 5287 j++; 5288 } 5289 BER_BVZERO( &mod->sml_values[j] ); 5290 if ( mod->sml_nvalues ) { 5291 BER_BVZERO( &mod->sml_nvalues[j] ); 5292 } 5293 *modtail = mod; 5294 modtail = &mod->sml_next; 5295 i = j; 5296 } 5297 op->o_tmpfree( adds, op->o_tmpmemctx ); 5298 } else { 5299 /* new attr, just use the new mod */ 5300 i = 0; 5301 j = 1; 5302 } 5303 /* advance to next element */ 5304 mod = **mcur; 5305 if ( mod ) { 5306 if ( i != j ) { 5307 **mcur = mod->sml_next; 5308 *modtail = mod; 5309 modtail = &mod->sml_next; 5310 } else { 5311 *mcur = &mod->sml_next; 5312 } 5313 } 5314 *mret = modtail; 5315 } 5316 5317 /* Generate a set of modifications to change the old entry into the 5318 * new one. On input ml is a list of modifications equivalent to 5319 * the new entry. It will be massaged and the result will be stored 5320 * in mods. 5321 */ 5322 void syncrepl_diff_entry( Operation *op, Attribute *old, Attribute *new, 5323 Modifications **mods, Modifications **ml, int is_ctx) 5324 { 5325 Modifications **modtail = mods; 5326 5327 /* We assume that attributes are saved in the same order 5328 * in the remote and local databases. So if we walk through 5329 * the attributeDescriptions one by one they should match in 5330 * lock step. If not, look for an add or delete. 5331 */ 5332 while ( old && new ) 5333 { 5334 /* If we've seen this before, use its mod now */ 5335 if ( new->a_flags & SLAP_ATTR_IXADD ) { 5336 attr_cmp( op, NULL, new, &modtail, &ml ); 5337 new = new->a_next; 5338 continue; 5339 } 5340 /* Skip contextCSN */ 5341 if ( is_ctx && old->a_desc == 5342 slap_schema.si_ad_contextCSN ) { 5343 old = old->a_next; 5344 continue; 5345 } 5346 5347 if ( old->a_desc != new->a_desc ) { 5348 Modifications *mod; 5349 Attribute *tmp; 5350 5351 /* If it's just been re-added later, 5352 * remember that we've seen it. 5353 */ 5354 tmp = attr_find( new, old->a_desc ); 5355 if ( tmp ) { 5356 tmp->a_flags |= SLAP_ATTR_IXADD; 5357 } else { 5358 /* If it's a new attribute, pull it in. 5359 */ 5360 tmp = attr_find( old, new->a_desc ); 5361 if ( !tmp ) { 5362 attr_cmp( op, NULL, new, &modtail, &ml ); 5363 new = new->a_next; 5364 continue; 5365 } 5366 /* Delete old attr */ 5367 mod = ch_malloc( sizeof( Modifications ) ); 5368 mod->sml_op = LDAP_MOD_DELETE; 5369 mod->sml_flags = 0; 5370 mod->sml_desc = old->a_desc; 5371 mod->sml_type = mod->sml_desc->ad_cname; 5372 mod->sml_numvals = 0; 5373 mod->sml_values = NULL; 5374 mod->sml_nvalues = NULL; 5375 *modtail = mod; 5376 modtail = &mod->sml_next; 5377 } 5378 old = old->a_next; 5379 continue; 5380 } 5381 /* kludge - always update modifiersName so that it 5382 * stays co-located with the other mod opattrs. But only 5383 * if we know there are other valid mods. 5384 */ 5385 if ( *mods && ( old->a_desc == slap_schema.si_ad_modifiersName || 5386 old->a_desc == slap_schema.si_ad_modifyTimestamp )) 5387 attr_cmp( op, NULL, new, &modtail, &ml ); 5388 else 5389 attr_cmp( op, old, new, &modtail, &ml ); 5390 new = new->a_next; 5391 old = old->a_next; 5392 } 5393 5394 /* These are all missing from provider */ 5395 while ( old ) { 5396 Modifications *mod = ch_malloc( sizeof( Modifications ) ); 5397 5398 mod->sml_op = LDAP_MOD_DELETE; 5399 mod->sml_flags = 0; 5400 mod->sml_desc = old->a_desc; 5401 mod->sml_type = mod->sml_desc->ad_cname; 5402 mod->sml_numvals = 0; 5403 mod->sml_values = NULL; 5404 mod->sml_nvalues = NULL; 5405 5406 *modtail = mod; 5407 modtail = &mod->sml_next; 5408 5409 old = old->a_next; 5410 } 5411 5412 /* Newly added attributes */ 5413 while ( new ) { 5414 attr_cmp( op, NULL, new, &modtail, &ml ); 5415 5416 new = new->a_next; 5417 } 5418 5419 *modtail = *ml; 5420 *ml = NULL; 5421 } 5422 5423 /* shallow copy attrs, excluding non-replicated attrs */ 5424 static Attribute * 5425 attrs_exdup( Operation *op, dninfo *dni, Attribute *attrs ) 5426 { 5427 int i; 5428 Attribute *tmp, *anew; 5429 5430 if ( attrs == NULL ) return NULL; 5431 5432 /* count attrs */ 5433 for ( tmp = attrs,i=0; tmp; tmp=tmp->a_next ) i++; 5434 5435 anew = op->o_tmpalloc( i * sizeof(Attribute), op->o_tmpmemctx ); 5436 for ( tmp = anew; attrs; attrs=attrs->a_next ) { 5437 int flag = is_at_operational( attrs->a_desc->ad_type ) ? dni->si->si_allopattrs : 5438 dni->si->si_allattrs; 5439 if ( !flag && !ad_inlist( attrs->a_desc, dni->si->si_anlist )) 5440 continue; 5441 if ( dni->si->si_exattrs && ad_inlist( attrs->a_desc, dni->si->si_exanlist )) 5442 continue; 5443 *tmp = *attrs; 5444 tmp->a_next = tmp+1; 5445 tmp++; 5446 } 5447 if ( tmp == anew ) { 5448 /* excluded everything */ 5449 op->o_tmpfree( anew, op->o_tmpmemctx ); 5450 return NULL; 5451 } 5452 tmp[-1].a_next = NULL; 5453 return anew; 5454 } 5455 5456 static int 5457 dn_callback( 5458 Operation* op, 5459 SlapReply* rs ) 5460 { 5461 dninfo *dni = op->o_callback->sc_private; 5462 5463 if ( rs->sr_type == REP_SEARCH ) { 5464 if ( !BER_BVISNULL( &dni->dn ) ) { 5465 Debug( LDAP_DEBUG_ANY, 5466 "dn_callback : consistency error - " 5467 "entryUUID is not unique\n" ); 5468 } else { 5469 ber_dupbv_x( &dni->dn, &rs->sr_entry->e_name, op->o_tmpmemctx ); 5470 ber_dupbv_x( &dni->ndn, &rs->sr_entry->e_nname, op->o_tmpmemctx ); 5471 /* If there is a new entry, see if it differs from the old. 5472 * We compare the non-normalized values so that cosmetic changes 5473 * in the provider are always propagated. 5474 */ 5475 if ( dni->new_entry ) { 5476 Attribute *old, *new; 5477 struct berval old_rdn, new_rdn; 5478 struct berval old_p, new_p; 5479 int is_ctx, new_sup = 0; 5480 5481 #ifdef LDAP_CONTROL_X_DIRSYNC 5482 if ( dni->syncstate != MSAD_DIRSYNC_MODIFY ) 5483 #endif 5484 { 5485 /* If old entry is not a glue entry, make sure new entry 5486 * is actually newer than old entry 5487 */ 5488 if ( !is_entry_glue( rs->sr_entry )) { 5489 old = attr_find( rs->sr_entry->e_attrs, 5490 slap_schema.si_ad_entryCSN ); 5491 new = attr_find( dni->new_entry->e_attrs, 5492 slap_schema.si_ad_entryCSN ); 5493 if ( new && old ) { 5494 int rc; 5495 ber_len_t len = old->a_vals[0].bv_len; 5496 if ( len > new->a_vals[0].bv_len ) 5497 len = new->a_vals[0].bv_len; 5498 rc = memcmp( old->a_vals[0].bv_val, 5499 new->a_vals[0].bv_val, len ); 5500 if ( rc > 0 ) { 5501 Debug( LDAP_DEBUG_SYNC, 5502 "dn_callback : new entry is older than ours " 5503 "%s ours %s, new %s\n", 5504 rs->sr_entry->e_name.bv_val, 5505 old->a_vals[0].bv_val, 5506 new->a_vals[0].bv_val ); 5507 return LDAP_SUCCESS; 5508 } else if ( rc == 0 ) { 5509 Debug( LDAP_DEBUG_SYNC, 5510 "dn_callback : entries have identical CSN " 5511 "%s %s\n", 5512 rs->sr_entry->e_name.bv_val, 5513 old->a_vals[0].bv_val ); 5514 return LDAP_SUCCESS; 5515 } 5516 } 5517 } 5518 5519 is_ctx = dn_match( &rs->sr_entry->e_nname, 5520 &op->o_bd->be_nsuffix[0] ); 5521 } 5522 5523 /* Did the DN change? 5524 * case changes in the parent are ignored, 5525 * we only want to know if the RDN was 5526 * actually changed. 5527 */ 5528 dnRdn( &rs->sr_entry->e_name, &old_rdn ); 5529 dnRdn( &dni->new_entry->e_name, &new_rdn ); 5530 dnParent( &rs->sr_entry->e_nname, &old_p ); 5531 dnParent( &dni->new_entry->e_nname, &new_p ); 5532 5533 new_sup = !dn_match( &old_p, &new_p ); 5534 if ( !dn_match( &old_rdn, &new_rdn ) || new_sup ) 5535 { 5536 struct berval oldRDN, oldVal; 5537 AttributeDescription *ad = NULL; 5538 int oldpos, newpos; 5539 Attribute *a; 5540 5541 dni->renamed = 1; 5542 if ( new_sup ) 5543 dni->nnewSup = new_p; 5544 5545 /* See if the oldRDN was deleted */ 5546 dnRdn( &rs->sr_entry->e_nname, &oldRDN ); 5547 oldVal.bv_val = strchr(oldRDN.bv_val, '=') + 1; 5548 oldVal.bv_len = oldRDN.bv_len - ( oldVal.bv_val - 5549 oldRDN.bv_val ); 5550 oldRDN.bv_len -= oldVal.bv_len + 1; 5551 slap_bv2ad( &oldRDN, &ad, &rs->sr_text ); 5552 dni->oldDesc = ad; 5553 for ( oldpos=0, a=rs->sr_entry->e_attrs; 5554 a && a->a_desc != ad; oldpos++, a=a->a_next ); 5555 /* a should not be NULL but apparently it happens. 5556 * ITS#7144 5557 */ 5558 if ( a ) { 5559 dni->oldNcount = a->a_numvals; 5560 for ( newpos=0, a=dni->new_entry->e_attrs; 5561 a && a->a_desc != ad; newpos++, a=a->a_next ); 5562 if ( !a || oldpos != newpos || attr_valfind( a, 5563 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH | 5564 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | 5565 SLAP_MR_VALUE_OF_SYNTAX, 5566 &oldVal, NULL, op->o_tmpmemctx ) != LDAP_SUCCESS ) 5567 { 5568 dni->delOldRDN = 1; 5569 } 5570 } 5571 /* Get the newRDN's desc */ 5572 dnRdn( &dni->new_entry->e_nname, &oldRDN ); 5573 oldVal.bv_val = strchr(oldRDN.bv_val, '='); 5574 oldRDN.bv_len = oldVal.bv_val - oldRDN.bv_val; 5575 ad = NULL; 5576 slap_bv2ad( &oldRDN, &ad, &rs->sr_text ); 5577 dni->newDesc = ad; 5578 5579 /* A ModDN has happened, but in Refresh mode other 5580 * changes may have occurred before we picked it up. 5581 * So fallthru to regular Modify processing. 5582 */ 5583 } 5584 5585 #ifdef LDAP_CONTROL_X_DIRSYNC 5586 if ( dni->syncstate == MSAD_DIRSYNC_MODIFY ) { 5587 /* DirSync actually sends a diff already, mostly. 5588 * It has no way to indicate deletion of single-valued attrs. 5589 * FIXME: should do an auxiliary search to get the true 5590 * entry contents. 5591 */ 5592 dni->mods = *dni->modlist; 5593 *dni->modlist = NULL; 5594 } else 5595 #endif 5596 { 5597 Attribute *old = attrs_exdup( op, dni, rs->sr_entry->e_attrs ); 5598 syncrepl_diff_entry( op, old, 5599 dni->new_entry->e_attrs, &dni->mods, dni->modlist, 5600 is_ctx ); 5601 op->o_tmpfree( old, op->o_tmpmemctx ); 5602 } 5603 } 5604 } 5605 } else if ( rs->sr_type == REP_RESULT ) { 5606 if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ) { 5607 Debug( LDAP_DEBUG_ANY, 5608 "dn_callback : consistency error - " 5609 "entryUUID is not unique\n" ); 5610 } 5611 } 5612 5613 return LDAP_SUCCESS; 5614 } 5615 5616 static int 5617 nonpresent_callback( 5618 Operation* op, 5619 SlapReply* rs ) 5620 { 5621 syncinfo_t *si = op->o_callback->sc_private; 5622 Attribute *a; 5623 int count = 0; 5624 char *present_uuid = NULL; 5625 struct nonpresent_entry *np_entry; 5626 struct sync_cookie *syncCookie = op->o_controls[slap_cids.sc_LDAPsync]; 5627 5628 if ( rs->sr_type == REP_RESULT ) { 5629 count = presentlist_free( si->si_presentlist ); 5630 si->si_presentlist = NULL; 5631 Debug( LDAP_DEBUG_SYNC, "nonpresent_callback: %s " 5632 "had %d items left in the list\n", si->si_ridtxt, count ); 5633 5634 } else if ( rs->sr_type == REP_SEARCH ) { 5635 if ( !( si->si_refreshDelete & NP_DELETE_ONE ) ) { 5636 a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID ); 5637 5638 if ( a ) { 5639 present_uuid = presentlist_find( si->si_presentlist, &a->a_nvals[0] ); 5640 } 5641 5642 Debug(LDAP_DEBUG_SYNC, "nonpresent_callback: " 5643 "%s %spresent UUID %s, dn %s\n", 5644 si->si_ridtxt, 5645 present_uuid ? "" : "non", 5646 a ? a->a_vals[0].bv_val : "<missing>", 5647 rs->sr_entry->e_name.bv_val ); 5648 5649 if ( a == NULL ) return 0; 5650 } 5651 5652 if ( present_uuid == NULL ) { 5653 int covered = 1; /* covered by our new contextCSN? */ 5654 5655 if ( !syncCookie ) 5656 syncCookie = &si->si_syncCookie; 5657 5658 /* TODO: This can go once we can build a filter that takes care of 5659 * the check for us */ 5660 a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryCSN ); 5661 if ( a ) { 5662 int i, sid = slap_parse_csn_sid( &a->a_nvals[0] ); 5663 if ( sid != -1 ) { 5664 covered = 0; 5665 for ( i=0; i < syncCookie->numcsns && syncCookie->sids[i] <= sid; i++ ) { 5666 if ( syncCookie->sids[i] == sid && 5667 ber_bvcmp( &a->a_nvals[0], &syncCookie->ctxcsn[i] ) <= 0 ) { 5668 covered = 1; 5669 } 5670 } 5671 } 5672 } 5673 5674 if ( covered ) { 5675 np_entry = (struct nonpresent_entry *) 5676 ch_calloc( 1, sizeof( struct nonpresent_entry ) ); 5677 np_entry->npe_name = ber_dupbv( NULL, &rs->sr_entry->e_name ); 5678 np_entry->npe_nname = ber_dupbv( NULL, &rs->sr_entry->e_nname ); 5679 LDAP_LIST_INSERT_HEAD( &si->si_nonpresentlist, np_entry, npe_link ); 5680 Debug( LDAP_DEBUG_SYNC, "nonpresent_callback: %s " 5681 "adding entry %s to non-present list\n", 5682 si->si_ridtxt, np_entry->npe_name->bv_val ); 5683 } 5684 5685 } else { 5686 presentlist_delete( &si->si_presentlist, &a->a_nvals[0] ); 5687 ch_free( present_uuid ); 5688 } 5689 } 5690 return LDAP_SUCCESS; 5691 } 5692 5693 static struct berval * 5694 slap_uuidstr_from_normalized( 5695 struct berval* uuidstr, 5696 struct berval* normalized, 5697 void *ctx ) 5698 { 5699 #if 0 5700 struct berval *new; 5701 unsigned char nibble; 5702 int i, d = 0; 5703 5704 if ( normalized == NULL ) return NULL; 5705 if ( normalized->bv_len != 16 ) return NULL; 5706 5707 if ( uuidstr ) { 5708 new = uuidstr; 5709 } else { 5710 new = (struct berval *)slap_sl_malloc( sizeof(struct berval), ctx ); 5711 if ( new == NULL ) { 5712 return NULL; 5713 } 5714 } 5715 5716 new->bv_len = 36; 5717 5718 if ( ( new->bv_val = slap_sl_malloc( new->bv_len + 1, ctx ) ) == NULL ) { 5719 if ( new != uuidstr ) { 5720 slap_sl_free( new, ctx ); 5721 } 5722 return NULL; 5723 } 5724 5725 for ( i = 0; i < 16; i++ ) { 5726 if ( i == 4 || i == 6 || i == 8 || i == 10 ) { 5727 new->bv_val[(i<<1)+d] = '-'; 5728 d += 1; 5729 } 5730 5731 nibble = (normalized->bv_val[i] >> 4) & 0xF; 5732 if ( nibble < 10 ) { 5733 new->bv_val[(i<<1)+d] = nibble + '0'; 5734 } else { 5735 new->bv_val[(i<<1)+d] = nibble - 10 + 'a'; 5736 } 5737 5738 nibble = (normalized->bv_val[i]) & 0xF; 5739 if ( nibble < 10 ) { 5740 new->bv_val[(i<<1)+d+1] = nibble + '0'; 5741 } else { 5742 new->bv_val[(i<<1)+d+1] = nibble - 10 + 'a'; 5743 } 5744 } 5745 5746 new->bv_val[new->bv_len] = '\0'; 5747 return new; 5748 #endif 5749 5750 struct berval *new; 5751 int rc = 0; 5752 5753 if ( normalized == NULL ) return NULL; 5754 if ( normalized->bv_len != 16 ) return NULL; 5755 5756 if ( uuidstr ) { 5757 new = uuidstr; 5758 5759 } else { 5760 new = (struct berval *)slap_sl_malloc( sizeof(struct berval), ctx ); 5761 if ( new == NULL ) { 5762 return NULL; 5763 } 5764 } 5765 5766 new->bv_len = 36; 5767 5768 if ( ( new->bv_val = slap_sl_malloc( new->bv_len + 1, ctx ) ) == NULL ) { 5769 rc = 1; 5770 goto done; 5771 } 5772 5773 rc = lutil_uuidstr_from_normalized( normalized->bv_val, 5774 normalized->bv_len, new->bv_val, new->bv_len + 1 ); 5775 5776 done:; 5777 if ( rc == -1 ) { 5778 if ( new != NULL ) { 5779 if ( new->bv_val != NULL ) { 5780 slap_sl_free( new->bv_val, ctx ); 5781 } 5782 5783 if ( new != uuidstr ) { 5784 slap_sl_free( new, ctx ); 5785 } 5786 } 5787 new = NULL; 5788 5789 } else { 5790 new->bv_len = rc; 5791 } 5792 5793 return new; 5794 } 5795 5796 static int 5797 syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 ) 5798 { 5799 #ifdef HASHUUID 5800 return ( memcmp( v_uuid1, v_uuid2, UUIDLEN-2 )); 5801 #else 5802 return ( memcmp( v_uuid1, v_uuid2, UUIDLEN )); 5803 #endif 5804 } 5805 5806 void 5807 syncinfo_free( syncinfo_t *sie, int free_all ) 5808 { 5809 syncinfo_t *si_next; 5810 5811 Debug( LDAP_DEBUG_TRACE, "syncinfo_free: %s\n", 5812 sie->si_ridtxt ); 5813 5814 do { 5815 si_next = sie->si_next; 5816 5817 if ( !BER_BVISEMPTY( &sie->si_monitor_ndn )) { 5818 syncrepl_monitor_del( sie ); 5819 } 5820 5821 if ( sie->si_ld ) { 5822 if ( sie->si_conn ) { 5823 connection_client_stop( sie->si_conn ); 5824 sie->si_conn = NULL; 5825 } 5826 ldap_unbind_ext( sie->si_ld, NULL, NULL ); 5827 } 5828 5829 if ( sie->si_re ) { 5830 struct re_s *re = sie->si_re; 5831 sie->si_re = NULL; 5832 5833 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 5834 if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) ) 5835 ldap_pvt_runqueue_stoptask( &slapd_rq, re ); 5836 ldap_pvt_runqueue_remove( &slapd_rq, re ); 5837 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 5838 } 5839 5840 ldap_pvt_thread_mutex_destroy( &sie->si_mutex ); 5841 ldap_pvt_thread_mutex_destroy( &sie->si_monitor_mutex ); 5842 5843 bindconf_free( &sie->si_bindconf ); 5844 5845 if ( sie->si_filterstr.bv_val ) { 5846 ch_free( sie->si_filterstr.bv_val ); 5847 } 5848 if ( sie->si_filter ) { 5849 filter_free( sie->si_filter ); 5850 } 5851 if ( sie->si_logfilterstr.bv_val ) { 5852 ch_free( sie->si_logfilterstr.bv_val ); 5853 } 5854 if ( sie->si_logfilter ) { 5855 filter_free( sie->si_logfilter ); 5856 } 5857 if ( sie->si_base.bv_val ) { 5858 ch_free( sie->si_base.bv_val ); 5859 } 5860 if ( sie->si_logbase.bv_val ) { 5861 ch_free( sie->si_logbase.bv_val ); 5862 } 5863 if ( sie->si_be && SLAP_SYNC_SUBENTRY( sie->si_be )) { 5864 ch_free( sie->si_contextdn.bv_val ); 5865 } 5866 if ( sie->si_attrs ) { 5867 int i = 0; 5868 while ( sie->si_attrs[i] != NULL ) { 5869 ch_free( sie->si_attrs[i] ); 5870 i++; 5871 } 5872 ch_free( sie->si_attrs ); 5873 } 5874 if ( sie->si_exattrs ) { 5875 int i = 0; 5876 while ( sie->si_exattrs[i] != NULL ) { 5877 ch_free( sie->si_exattrs[i] ); 5878 i++; 5879 } 5880 ch_free( sie->si_exattrs ); 5881 } 5882 if ( sie->si_anlist ) { 5883 int i = 0; 5884 while ( sie->si_anlist[i].an_name.bv_val != NULL ) { 5885 ch_free( sie->si_anlist[i].an_name.bv_val ); 5886 i++; 5887 } 5888 ch_free( sie->si_anlist ); 5889 } 5890 if ( sie->si_exanlist ) { 5891 int i = 0; 5892 while ( sie->si_exanlist[i].an_name.bv_val != NULL ) { 5893 ch_free( sie->si_exanlist[i].an_name.bv_val ); 5894 i++; 5895 } 5896 ch_free( sie->si_exanlist ); 5897 } 5898 if ( sie->si_retryinterval ) { 5899 ch_free( sie->si_retryinterval ); 5900 } 5901 if ( sie->si_retrynum ) { 5902 ch_free( sie->si_retrynum ); 5903 } 5904 if ( sie->si_retrynum_init ) { 5905 ch_free( sie->si_retrynum_init ); 5906 } 5907 slap_sync_cookie_free( &sie->si_syncCookie, 0 ); 5908 #ifdef LDAP_CONTROL_X_DIRSYNC 5909 if ( sie->si_dirSyncCookie.bv_val ) { 5910 ch_free( sie->si_dirSyncCookie.bv_val ); 5911 } 5912 #endif 5913 if ( sie->si_presentlist ) { 5914 presentlist_free( sie->si_presentlist ); 5915 } 5916 while ( !LDAP_LIST_EMPTY( &sie->si_nonpresentlist ) ) { 5917 struct nonpresent_entry* npe; 5918 npe = LDAP_LIST_FIRST( &sie->si_nonpresentlist ); 5919 LDAP_LIST_REMOVE( npe, npe_link ); 5920 if ( npe->npe_name ) { 5921 if ( npe->npe_name->bv_val ) { 5922 ch_free( npe->npe_name->bv_val ); 5923 } 5924 ch_free( npe->npe_name ); 5925 } 5926 if ( npe->npe_nname ) { 5927 if ( npe->npe_nname->bv_val ) { 5928 ch_free( npe->npe_nname->bv_val ); 5929 } 5930 ch_free( npe->npe_nname ); 5931 } 5932 ch_free( npe ); 5933 } 5934 if ( sie->si_cookieState ) { 5935 sie->si_cookieState->cs_ref--; 5936 if ( !sie->si_cookieState->cs_ref ) { 5937 ch_free( sie->si_cookieState->cs_sids ); 5938 ber_bvarray_free( sie->si_cookieState->cs_vals ); 5939 ldap_pvt_thread_cond_destroy( &sie->si_cookieState->cs_cond ); 5940 ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_mutex ); 5941 ch_free( sie->si_cookieState->cs_psids ); 5942 ber_bvarray_free( sie->si_cookieState->cs_pvals ); 5943 ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_pmutex ); 5944 ch_free( sie->si_cookieState ); 5945 } 5946 } 5947 if ( sie->si_rewrite ) 5948 rewrite_info_delete( &sie->si_rewrite ); 5949 if ( sie->si_suffixm.bv_val ) 5950 ch_free( sie->si_suffixm.bv_val ); 5951 ch_free( sie ); 5952 sie = si_next; 5953 } while ( free_all && si_next ); 5954 } 5955 5956 static int 5957 config_suffixm( ConfigArgs *c, syncinfo_t *si ) 5958 { 5959 char *argvEngine[] = { "rewriteEngine", "on", NULL }; 5960 char *argvContext[] = { "rewriteContext", SUFFIXM_CTX, NULL }; 5961 char *argvRule[] = { "rewriteRule", NULL, NULL, ":", NULL }; 5962 char *vnc, *rnc; 5963 int rc; 5964 5965 if ( si->si_rewrite ) 5966 rewrite_info_delete( &si->si_rewrite ); 5967 si->si_rewrite = rewrite_info_init( REWRITE_MODE_USE_DEFAULT ); 5968 5969 rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 2, argvEngine ); 5970 if ( rc != LDAP_SUCCESS ) 5971 return rc; 5972 5973 rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 2, argvContext ); 5974 if ( rc != LDAP_SUCCESS ) 5975 return rc; 5976 5977 vnc = ch_malloc( si->si_base.bv_len + 6 ); 5978 strcpy( vnc, "(.*)" ); 5979 lutil_strcopy( lutil_strcopy( vnc+4, si->si_base.bv_val ), "$" ); 5980 argvRule[1] = vnc; 5981 5982 rnc = ch_malloc( si->si_suffixm.bv_len + 3 ); 5983 strcpy( rnc, "%1" ); 5984 strcpy( rnc+2, si->si_suffixm.bv_val ); 5985 argvRule[2] = rnc; 5986 5987 rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 4, argvRule ); 5988 ch_free( vnc ); 5989 ch_free( rnc ); 5990 return rc; 5991 } 5992 5993 /* NOTE: used & documented in slapd.conf(5) */ 5994 #define IDSTR "rid" 5995 #define PROVIDERSTR "provider" 5996 #define SCHEMASTR "schemachecking" 5997 #define FILTERSTR "filter" 5998 #define SEARCHBASESTR "searchbase" 5999 #define SCOPESTR "scope" 6000 #define ATTRSONLYSTR "attrsonly" 6001 #define ATTRSSTR "attrs" 6002 #define TYPESTR "type" 6003 #define INTERVALSTR "interval" 6004 #define RETRYSTR "retry" 6005 #define SLIMITSTR "sizelimit" 6006 #define TLIMITSTR "timelimit" 6007 #define SYNCDATASTR "syncdata" 6008 #define LOGBASESTR "logbase" 6009 #define LOGFILTERSTR "logfilter" 6010 #define SUFFIXMSTR "suffixmassage" 6011 #define STRICT_REFRESH "strictrefresh" 6012 #define LAZY_COMMIT "lazycommit" 6013 6014 /* FIXME: undocumented */ 6015 #define EXATTRSSTR "exattrs" 6016 #define MANAGEDSAITSTR "manageDSAit" 6017 6018 /* mandatory */ 6019 enum { 6020 GOT_RID = 0x00000001U, 6021 GOT_PROVIDER = 0x00000002U, 6022 GOT_SCHEMACHECKING = 0x00000004U, 6023 GOT_FILTER = 0x00000008U, 6024 GOT_SEARCHBASE = 0x00000010U, 6025 GOT_SCOPE = 0x00000020U, 6026 GOT_ATTRSONLY = 0x00000040U, 6027 GOT_ATTRS = 0x00000080U, 6028 GOT_TYPE = 0x00000100U, 6029 GOT_INTERVAL = 0x00000200U, 6030 GOT_RETRY = 0x00000400U, 6031 GOT_SLIMIT = 0x00000800U, 6032 GOT_TLIMIT = 0x00001000U, 6033 GOT_SYNCDATA = 0x00002000U, 6034 GOT_LOGBASE = 0x00004000U, 6035 GOT_LOGFILTER = 0x00008000U, 6036 GOT_EXATTRS = 0x00010000U, 6037 GOT_MANAGEDSAIT = 0x00020000U, 6038 GOT_BINDCONF = 0x00040000U, 6039 GOT_SUFFIXM = 0x00080000U, 6040 6041 /* check */ 6042 GOT_REQUIRED = (GOT_RID|GOT_PROVIDER|GOT_SEARCHBASE) 6043 }; 6044 6045 static slap_verbmasks datamodes[] = { 6046 { BER_BVC("default"), SYNCDATA_DEFAULT }, 6047 { BER_BVC("accesslog"), SYNCDATA_ACCESSLOG }, 6048 { BER_BVC("changelog"), SYNCDATA_CHANGELOG }, 6049 { BER_BVNULL, 0 } 6050 }; 6051 6052 static int 6053 parse_syncrepl_retry( 6054 ConfigArgs *c, 6055 char *arg, 6056 syncinfo_t *si ) 6057 { 6058 char **retry_list; 6059 int j, k, n; 6060 int use_default = 0; 6061 6062 char *val = arg + STRLENOF( RETRYSTR "=" ); 6063 if ( strcasecmp( val, "undefined" ) == 0 ) { 6064 val = "3600 +"; 6065 use_default = 1; 6066 } 6067 6068 retry_list = (char **) ch_calloc( 1, sizeof( char * ) ); 6069 retry_list[0] = NULL; 6070 6071 slap_str2clist( &retry_list, val, " ,\t" ); 6072 6073 for ( k = 0; retry_list && retry_list[k]; k++ ) ; 6074 n = k / 2; 6075 if ( k % 2 ) { 6076 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6077 "Error: incomplete syncrepl retry list" ); 6078 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6079 for ( k = 0; retry_list && retry_list[k]; k++ ) { 6080 ch_free( retry_list[k] ); 6081 } 6082 ch_free( retry_list ); 6083 return 1; 6084 } 6085 si->si_retryinterval = (time_t *) ch_calloc( n + 1, sizeof( time_t ) ); 6086 si->si_retrynum = (int *) ch_calloc( n + 1, sizeof( int ) ); 6087 si->si_retrynum_init = (int *) ch_calloc( n + 1, sizeof( int ) ); 6088 for ( j = 0; j < n; j++ ) { 6089 unsigned long t; 6090 if ( lutil_atoul( &t, retry_list[j*2] ) != 0 ) { 6091 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6092 "Error: invalid retry interval \"%s\" (#%d)", 6093 retry_list[j*2], j ); 6094 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6095 /* do some cleanup */ 6096 return 1; 6097 } 6098 si->si_retryinterval[j] = (time_t)t; 6099 if ( *retry_list[j*2+1] == '+' ) { 6100 si->si_retrynum_init[j] = RETRYNUM_FOREVER; 6101 si->si_retrynum[j] = RETRYNUM_FOREVER; 6102 j++; 6103 break; 6104 } else { 6105 if ( lutil_atoi( &si->si_retrynum_init[j], retry_list[j*2+1] ) != 0 6106 || si->si_retrynum_init[j] <= 0 ) 6107 { 6108 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6109 "Error: invalid initial retry number \"%s\" (#%d)", 6110 retry_list[j*2+1], j ); 6111 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6112 /* do some cleanup */ 6113 return 1; 6114 } 6115 if ( lutil_atoi( &si->si_retrynum[j], retry_list[j*2+1] ) != 0 6116 || si->si_retrynum[j] <= 0 ) 6117 { 6118 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6119 "Error: invalid retry number \"%s\" (#%d)", 6120 retry_list[j*2+1], j ); 6121 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6122 /* do some cleanup */ 6123 return 1; 6124 } 6125 } 6126 } 6127 if ( j < 1 || si->si_retrynum_init[j-1] != RETRYNUM_FOREVER ) { 6128 Debug( LDAP_DEBUG_CONFIG, 6129 "%s: syncrepl will eventually stop retrying; the \"retry\" parameter should end with a '+'.\n", 6130 c->log ); 6131 } 6132 6133 si->si_retrynum_init[j] = RETRYNUM_TAIL; 6134 si->si_retrynum[j] = RETRYNUM_TAIL; 6135 si->si_retryinterval[j] = 0; 6136 6137 for ( k = 0; retry_list && retry_list[k]; k++ ) { 6138 ch_free( retry_list[k] ); 6139 } 6140 ch_free( retry_list ); 6141 if ( !use_default ) { 6142 si->si_got |= GOT_RETRY; 6143 } 6144 6145 return 0; 6146 } 6147 6148 static int 6149 parse_syncrepl_line( 6150 ConfigArgs *c, 6151 syncinfo_t *si ) 6152 { 6153 int i; 6154 char *val; 6155 6156 for ( i = 1; i < c->argc; i++ ) { 6157 if ( !strncasecmp( c->argv[ i ], IDSTR "=", 6158 STRLENOF( IDSTR "=" ) ) ) 6159 { 6160 int tmp; 6161 /* '\0' string terminator accounts for '=' */ 6162 val = c->argv[ i ] + STRLENOF( IDSTR "=" ); 6163 if ( lutil_atoi( &tmp, val ) != 0 ) { 6164 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6165 "Error: parse_syncrepl_line: " 6166 "unable to parse syncrepl id \"%s\"", val ); 6167 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6168 return -1; 6169 } 6170 if ( tmp > SLAP_SYNC_RID_MAX || tmp < 0 ) { 6171 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6172 "Error: parse_syncrepl_line: " 6173 "syncrepl id %d is out of range [0..%d]", tmp, SLAP_SYNC_RID_MAX ); 6174 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6175 return -1; 6176 } 6177 si->si_rid = tmp; 6178 sprintf( si->si_ridtxt, IDSTR "=%03d", si->si_rid ); 6179 si->si_got |= GOT_RID; 6180 } else if ( !strncasecmp( c->argv[ i ], PROVIDERSTR "=", 6181 STRLENOF( PROVIDERSTR "=" ) ) ) 6182 { 6183 val = c->argv[ i ] + STRLENOF( PROVIDERSTR "=" ); 6184 ber_str2bv( val, 0, 1, &si->si_bindconf.sb_uri ); 6185 #ifdef HAVE_TLS 6186 if ( ldap_is_ldaps_url( val )) 6187 si->si_bindconf.sb_tls_do_init = 1; 6188 #endif 6189 si->si_got |= GOT_PROVIDER; 6190 } else if ( !strncasecmp( c->argv[ i ], SCHEMASTR "=", 6191 STRLENOF( SCHEMASTR "=" ) ) ) 6192 { 6193 val = c->argv[ i ] + STRLENOF( SCHEMASTR "=" ); 6194 if ( !strncasecmp( val, "on", STRLENOF( "on" ) ) ) { 6195 si->si_schemachecking = 1; 6196 } else if ( !strncasecmp( val, "off", STRLENOF( "off" ) ) ) { 6197 si->si_schemachecking = 0; 6198 } else { 6199 si->si_schemachecking = 1; 6200 } 6201 si->si_got |= GOT_SCHEMACHECKING; 6202 } else if ( !strncasecmp( c->argv[ i ], FILTERSTR "=", 6203 STRLENOF( FILTERSTR "=" ) ) ) 6204 { 6205 val = c->argv[ i ] + STRLENOF( FILTERSTR "=" ); 6206 if ( si->si_filterstr.bv_val ) 6207 ch_free( si->si_filterstr.bv_val ); 6208 ber_str2bv( val, 0, 1, &si->si_filterstr ); 6209 si->si_got |= GOT_FILTER; 6210 } else if ( !strncasecmp( c->argv[ i ], LOGFILTERSTR "=", 6211 STRLENOF( LOGFILTERSTR "=" ) ) ) 6212 { 6213 val = c->argv[ i ] + STRLENOF( LOGFILTERSTR "=" ); 6214 if ( si->si_logfilterstr.bv_val ) 6215 ch_free( si->si_logfilterstr.bv_val ); 6216 ber_str2bv( val, 0, 1, &si->si_logfilterstr ); 6217 si->si_got |= GOT_LOGFILTER; 6218 } else if ( !strncasecmp( c->argv[ i ], SEARCHBASESTR "=", 6219 STRLENOF( SEARCHBASESTR "=" ) ) ) 6220 { 6221 struct berval bv; 6222 int rc; 6223 6224 val = c->argv[ i ] + STRLENOF( SEARCHBASESTR "=" ); 6225 if ( si->si_base.bv_val ) { 6226 ch_free( si->si_base.bv_val ); 6227 } 6228 ber_str2bv( val, 0, 0, &bv ); 6229 rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_base, NULL ); 6230 if ( rc != LDAP_SUCCESS ) { 6231 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6232 "Invalid base DN \"%s\": %d (%s)", 6233 val, rc, ldap_err2string( rc ) ); 6234 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6235 return -1; 6236 } 6237 si->si_got |= GOT_SEARCHBASE; 6238 } else if ( !strncasecmp( c->argv[ i ], SUFFIXMSTR "=", 6239 STRLENOF( SUFFIXMSTR "=" ) ) ) 6240 { 6241 struct berval bv; 6242 int rc; 6243 6244 val = c->argv[ i ] + STRLENOF( SUFFIXMSTR "=" ); 6245 if ( si->si_suffixm.bv_val ) { 6246 ch_free( si->si_suffixm.bv_val ); 6247 } 6248 ber_str2bv( val, 0, 0, &bv ); 6249 rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_suffixm, NULL ); 6250 if ( rc != LDAP_SUCCESS ) { 6251 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6252 "Invalid massage DN \"%s\": %d (%s)", 6253 val, rc, ldap_err2string( rc ) ); 6254 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6255 return -1; 6256 } 6257 if ( !be_issubordinate( c->be, &si->si_suffixm )) { 6258 ch_free( si->si_suffixm.bv_val ); 6259 BER_BVZERO( &si->si_suffixm ); 6260 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6261 "Massage DN \"%s\" is not within the database naming context", 6262 val ); 6263 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6264 return -1; 6265 } 6266 si->si_got |= GOT_SUFFIXM; 6267 } else if ( !strncasecmp( c->argv[ i ], LOGBASESTR "=", 6268 STRLENOF( LOGBASESTR "=" ) ) ) 6269 { 6270 struct berval bv; 6271 int rc; 6272 6273 val = c->argv[ i ] + STRLENOF( LOGBASESTR "=" ); 6274 if ( si->si_logbase.bv_val ) { 6275 ch_free( si->si_logbase.bv_val ); 6276 } 6277 ber_str2bv( val, 0, 0, &bv ); 6278 rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_logbase, NULL ); 6279 if ( rc != LDAP_SUCCESS ) { 6280 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6281 "Invalid logbase DN \"%s\": %d (%s)", 6282 val, rc, ldap_err2string( rc ) ); 6283 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6284 return -1; 6285 } 6286 si->si_got |= GOT_LOGBASE; 6287 } else if ( !strncasecmp( c->argv[ i ], SCOPESTR "=", 6288 STRLENOF( SCOPESTR "=" ) ) ) 6289 { 6290 int j; 6291 val = c->argv[ i ] + STRLENOF( SCOPESTR "=" ); 6292 j = ldap_pvt_str2scope( val ); 6293 if ( j < 0 ) { 6294 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6295 "Error: parse_syncrepl_line: " 6296 "unknown scope \"%s\"", val); 6297 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6298 return -1; 6299 } 6300 si->si_scope = j; 6301 si->si_got |= GOT_SCOPE; 6302 } else if ( !strncasecmp( c->argv[ i ], ATTRSONLYSTR, 6303 STRLENOF( ATTRSONLYSTR ) ) ) 6304 { 6305 si->si_attrsonly = 1; 6306 si->si_got |= GOT_ATTRSONLY; 6307 } else if ( !strncasecmp( c->argv[ i ], ATTRSSTR "=", 6308 STRLENOF( ATTRSSTR "=" ) ) ) 6309 { 6310 val = c->argv[ i ] + STRLENOF( ATTRSSTR "=" ); 6311 if ( !strncasecmp( val, ":include:", STRLENOF(":include:") ) ) { 6312 char *attr_fname; 6313 attr_fname = ch_strdup( val + STRLENOF(":include:") ); 6314 si->si_anlist = file2anlist( si->si_anlist, attr_fname, " ,\t" ); 6315 if ( si->si_anlist == NULL ) { 6316 ch_free( attr_fname ); 6317 return -1; 6318 } 6319 si->si_anfile = attr_fname; 6320 } else { 6321 char *str, *s, *next; 6322 const char *delimstr = " ,\t"; 6323 str = ch_strdup( val ); 6324 for ( s = ldap_pvt_strtok( str, delimstr, &next ); 6325 s != NULL; 6326 s = ldap_pvt_strtok( NULL, delimstr, &next ) ) 6327 { 6328 if ( strlen(s) == 1 && *s == '*' ) { 6329 si->si_allattrs = 1; 6330 val[ s - str ] = delimstr[0]; 6331 } 6332 if ( strlen(s) == 1 && *s == '+' ) { 6333 si->si_allopattrs = 1; 6334 val [ s - str ] = delimstr[0]; 6335 } 6336 } 6337 ch_free( str ); 6338 si->si_anlist = str2anlist( si->si_anlist, val, " ,\t" ); 6339 if ( si->si_anlist == NULL ) { 6340 return -1; 6341 } 6342 } 6343 si->si_got |= GOT_ATTRS; 6344 } else if ( !strncasecmp( c->argv[ i ], EXATTRSSTR "=", 6345 STRLENOF( EXATTRSSTR "=" ) ) ) 6346 { 6347 val = c->argv[ i ] + STRLENOF( EXATTRSSTR "=" ); 6348 if ( !strncasecmp( val, ":include:", STRLENOF(":include:") ) ) { 6349 char *attr_fname; 6350 attr_fname = ch_strdup( val + STRLENOF(":include:") ); 6351 si->si_exanlist = file2anlist( 6352 si->si_exanlist, attr_fname, " ,\t" ); 6353 if ( si->si_exanlist == NULL ) { 6354 ch_free( attr_fname ); 6355 return -1; 6356 } 6357 ch_free( attr_fname ); 6358 } else { 6359 si->si_exanlist = str2anlist( si->si_exanlist, val, " ,\t" ); 6360 if ( si->si_exanlist == NULL ) { 6361 return -1; 6362 } 6363 } 6364 si->si_got |= GOT_EXATTRS; 6365 } else if ( !strncasecmp( c->argv[ i ], TYPESTR "=", 6366 STRLENOF( TYPESTR "=" ) ) ) 6367 { 6368 val = c->argv[ i ] + STRLENOF( TYPESTR "=" ); 6369 if ( !strncasecmp( val, "refreshOnly", 6370 STRLENOF("refreshOnly") ) ) 6371 { 6372 si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_ONLY; 6373 } else if ( !strncasecmp( val, "refreshAndPersist", 6374 STRLENOF("refreshAndPersist") ) ) 6375 { 6376 si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_AND_PERSIST; 6377 si->si_interval = 60; 6378 #ifdef LDAP_CONTROL_X_DIRSYNC 6379 } else if ( !strncasecmp( val, "dirSync", 6380 STRLENOF("dirSync") ) ) 6381 { 6382 if ( sy_ad_objectGUID == NULL && syncrepl_dirsync_schema()) { 6383 sprintf( c->cr_msg, "Error: dirSync schema is missing" ); 6384 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6385 return -1; 6386 } 6387 /* MS DirSync is refreshOnly, no persist */ 6388 si->si_type = si->si_ctype = MSAD_DIRSYNC; 6389 #endif 6390 } else { 6391 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6392 "Error: parse_syncrepl_line: " 6393 "unknown sync type \"%s\"", val); 6394 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6395 return -1; 6396 } 6397 si->si_got |= GOT_TYPE; 6398 } else if ( !strncasecmp( c->argv[ i ], INTERVALSTR "=", 6399 STRLENOF( INTERVALSTR "=" ) ) ) 6400 { 6401 val = c->argv[ i ] + STRLENOF( INTERVALSTR "=" ); 6402 if ( si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ) { 6403 si->si_interval = 0; 6404 } else if ( strchr( val, ':' ) != NULL ) { 6405 char *next, *ptr = val; 6406 int dd, hh, mm, ss; 6407 6408 dd = strtol( ptr, &next, 10 ); 6409 if ( next == ptr || next[0] != ':' || dd < 0 ) { 6410 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6411 "Error: parse_syncrepl_line: " 6412 "invalid interval \"%s\", unable to parse days", val ); 6413 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6414 return -1; 6415 } 6416 ptr = next + 1; 6417 hh = strtol( ptr, &next, 10 ); 6418 if ( next == ptr || next[0] != ':' || hh < 0 || hh > 24 ) { 6419 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6420 "Error: parse_syncrepl_line: " 6421 "invalid interval \"%s\", unable to parse hours", val ); 6422 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6423 return -1; 6424 } 6425 ptr = next + 1; 6426 mm = strtol( ptr, &next, 10 ); 6427 if ( next == ptr || next[0] != ':' || mm < 0 || mm > 60 ) { 6428 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6429 "Error: parse_syncrepl_line: " 6430 "invalid interval \"%s\", unable to parse minutes", val ); 6431 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6432 return -1; 6433 } 6434 ptr = next + 1; 6435 ss = strtol( ptr, &next, 10 ); 6436 if ( next == ptr || next[0] != '\0' || ss < 0 || ss > 60 ) { 6437 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6438 "Error: parse_syncrepl_line: " 6439 "invalid interval \"%s\", unable to parse seconds", val ); 6440 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6441 return -1; 6442 } 6443 si->si_interval = (( dd * 24 + hh ) * 60 + mm ) * 60 + ss; 6444 } else { 6445 unsigned long t; 6446 6447 if ( lutil_parse_time( val, &t ) != 0 ) { 6448 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6449 "Error: parse_syncrepl_line: " 6450 "invalid interval \"%s\"", val ); 6451 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6452 return -1; 6453 } 6454 si->si_interval = (time_t)t; 6455 } 6456 if ( si->si_interval < 0 ) { 6457 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6458 "Error: parse_syncrepl_line: " 6459 "invalid interval \"%ld\"", 6460 (long) si->si_interval); 6461 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6462 return -1; 6463 } 6464 si->si_got |= GOT_INTERVAL; 6465 } else if ( !strncasecmp( c->argv[ i ], RETRYSTR "=", 6466 STRLENOF( RETRYSTR "=" ) ) ) 6467 { 6468 if ( parse_syncrepl_retry( c, c->argv[ i ], si ) ) { 6469 return 1; 6470 } 6471 } else if ( !strncasecmp( c->argv[ i ], MANAGEDSAITSTR "=", 6472 STRLENOF( MANAGEDSAITSTR "=" ) ) ) 6473 { 6474 val = c->argv[ i ] + STRLENOF( MANAGEDSAITSTR "=" ); 6475 if ( lutil_atoi( &si->si_manageDSAit, val ) != 0 6476 || si->si_manageDSAit < 0 || si->si_manageDSAit > 1 ) 6477 { 6478 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6479 "invalid manageDSAit value \"%s\".\n", 6480 val ); 6481 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6482 return 1; 6483 } 6484 si->si_got |= GOT_MANAGEDSAIT; 6485 } else if ( !strncasecmp( c->argv[ i ], SLIMITSTR "=", 6486 STRLENOF( SLIMITSTR "=") ) ) 6487 { 6488 val = c->argv[ i ] + STRLENOF( SLIMITSTR "=" ); 6489 if ( strcasecmp( val, "unlimited" ) == 0 ) { 6490 si->si_slimit = 0; 6491 6492 } else if ( lutil_atoi( &si->si_slimit, val ) != 0 || si->si_slimit < 0 ) { 6493 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6494 "invalid size limit value \"%s\".\n", 6495 val ); 6496 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6497 return 1; 6498 } 6499 si->si_got |= GOT_SLIMIT; 6500 } else if ( !strncasecmp( c->argv[ i ], TLIMITSTR "=", 6501 STRLENOF( TLIMITSTR "=" ) ) ) 6502 { 6503 val = c->argv[ i ] + STRLENOF( TLIMITSTR "=" ); 6504 if ( strcasecmp( val, "unlimited" ) == 0 ) { 6505 si->si_tlimit = 0; 6506 6507 } else if ( lutil_atoi( &si->si_tlimit, val ) != 0 || si->si_tlimit < 0 ) { 6508 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6509 "invalid time limit value \"%s\".\n", 6510 val ); 6511 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6512 return 1; 6513 } 6514 si->si_got |= GOT_TLIMIT; 6515 } else if ( !strncasecmp( c->argv[ i ], SYNCDATASTR "=", 6516 STRLENOF( SYNCDATASTR "=" ) ) ) 6517 { 6518 val = c->argv[ i ] + STRLENOF( SYNCDATASTR "=" ); 6519 si->si_syncdata = verb_to_mask( val, datamodes ); 6520 si->si_got |= GOT_SYNCDATA; 6521 if ( si->si_syncdata == SYNCDATA_CHANGELOG ) { 6522 if ( sy_ad_nsUniqueId == NULL ) { 6523 int rc = syncrepl_dsee_schema(); 6524 if ( rc ) { 6525 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6526 "changelog schema problem (%d)\n", rc ); 6527 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6528 return 1; 6529 } 6530 } 6531 } 6532 } else if ( !strncasecmp( c->argv[ i ], STRICT_REFRESH, 6533 STRLENOF( STRICT_REFRESH ) ) ) 6534 { 6535 si->si_strict_refresh = 1; 6536 } else if ( !strncasecmp( c->argv[ i ], LAZY_COMMIT, 6537 STRLENOF( LAZY_COMMIT ) ) ) 6538 { 6539 si->si_lazyCommit = 1; 6540 } else if ( !bindconf_parse( c->argv[i], &si->si_bindconf ) ) { 6541 si->si_got |= GOT_BINDCONF; 6542 } else { 6543 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6544 "Error: parse_syncrepl_line: " 6545 "unable to parse \"%s\"\n", c->argv[ i ] ); 6546 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6547 return -1; 6548 } 6549 } 6550 6551 if ( ( si->si_got & GOT_REQUIRED ) != GOT_REQUIRED ) { 6552 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6553 "Error: Malformed \"syncrepl\" line in slapd config file, missing%s%s%s", 6554 si->si_got & GOT_RID ? "" : " "IDSTR, 6555 si->si_got & GOT_PROVIDER ? "" : " "PROVIDERSTR, 6556 si->si_got & GOT_SEARCHBASE ? "" : " "SEARCHBASESTR ); 6557 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6558 return -1; 6559 } 6560 6561 if ( !be_issubordinate( c->be, &si->si_base ) && !( si->si_got & GOT_SUFFIXM )) { 6562 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6563 "Base DN \"%s\" is not within the database naming context", 6564 si->si_base.bv_val ); 6565 ch_free( si->si_base.bv_val ); 6566 BER_BVZERO( &si->si_base ); 6567 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6568 return -1; 6569 } 6570 6571 if ( si->si_got & GOT_SUFFIXM ) { 6572 if (config_suffixm( c, si )) { 6573 ch_free( si->si_suffixm.bv_val ); 6574 BER_BVZERO( &si->si_suffixm ); 6575 snprintf( c->cr_msg, sizeof( c->cr_msg ), 6576 "Error configuring rewrite engine" ); 6577 Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg ); 6578 return -1; 6579 } 6580 } 6581 6582 if ( !( si->si_got & GOT_RETRY ) ) { 6583 Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": no retry defined, using default\n", 6584 si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)" ); 6585 if ( si->si_retryinterval == NULL ) { 6586 if ( parse_syncrepl_retry( c, "retry=undefined", si ) ) { 6587 return 1; 6588 } 6589 } 6590 } 6591 6592 si->si_filter = str2filter( si->si_filterstr.bv_val ); 6593 if ( si->si_filter == NULL ) { 6594 Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": unable to parse filter=\"%s\"\n", 6595 si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", si->si_filterstr.bv_val ); 6596 return 1; 6597 } 6598 6599 if ( si->si_got & GOT_LOGFILTER ) { 6600 si->si_logfilter = str2filter( si->si_logfilterstr.bv_val ); 6601 if ( si->si_logfilter == NULL ) { 6602 Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": unable to parse logfilter=\"%s\"\n", 6603 si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", si->si_logfilterstr.bv_val ); 6604 return 1; 6605 } 6606 } 6607 6608 return 0; 6609 } 6610 6611 /* monitor entry contains: 6612 provider URLs 6613 timestamp of last contact 6614 cookievals 6615 */ 6616 6617 static ObjectClass *oc_olmSyncRepl; 6618 static AttributeDescription *ad_olmProviderURIList, 6619 *ad_olmConnection, *ad_olmSyncPhase, 6620 *ad_olmNextConnect, *ad_olmLastConnect, *ad_olmLastContact, 6621 *ad_olmLastCookieRcvd, *ad_olmLastCookieSent; 6622 6623 static struct { 6624 char *name; 6625 char *oid; 6626 } s_oid[] = { 6627 { "olmSyncReplAttributes", "olmOverlayAttributes:1" }, 6628 { "olmSyncReplObjectClasses", "olmOverlayObjectClasses:1" }, 6629 { NULL } 6630 }; 6631 6632 static struct { 6633 char *desc; 6634 AttributeDescription **ad; 6635 } s_at[] = { 6636 { "( olmSyncReplAttributes:1 " 6637 "NAME ( 'olmSRProviderURIList' ) " 6638 "DESC 'List of provider URIs for this consumer instance' " 6639 "SUP monitoredInfo " 6640 "NO-USER-MODIFICATION " 6641 "USAGE dSAOperation )", 6642 &ad_olmProviderURIList }, 6643 { "( olmSyncReplAttributes:2 " 6644 "NAME ( 'olmSRConnection' ) " 6645 "DESC 'Local address:port of connection to provider' " 6646 "SUP monitoredInfo " 6647 "SINGLE-VALUE " 6648 "NO-USER-MODIFICATION " 6649 "USAGE dSAOperation )", 6650 &ad_olmConnection }, 6651 { "( olmSyncReplAttributes:3 " 6652 "NAME ( 'olmSRSyncPhase' ) " 6653 "DESC 'Current syncrepl mode' " 6654 "SUP monitoredInfo " 6655 "SINGLE-VALUE " 6656 "NO-USER-MODIFICATION " 6657 "USAGE dSAOperation )", 6658 &ad_olmSyncPhase }, 6659 { "( olmSyncReplAttributes:4 " 6660 "NAME ( 'olmSRNextConnect' ) " 6661 "DESC 'Scheduled time of next connection attempt' " 6662 "SUP monitorTimestamp " 6663 "SINGLE-VALUE " 6664 "NO-USER-MODIFICATION " 6665 "USAGE dSAOperation )", 6666 &ad_olmNextConnect }, 6667 { "( olmSyncReplAttributes:5 " 6668 "NAME ( 'olmSRLastConnect' ) " 6669 "DESC 'Time last connected to provider' " 6670 "SUP monitorTimestamp " 6671 "SINGLE-VALUE " 6672 "NO-USER-MODIFICATION " 6673 "USAGE dSAOperation )", 6674 &ad_olmLastConnect }, 6675 { "( olmSyncReplAttributes:6 " 6676 "NAME ( 'olmSRLastContact' ) " 6677 "DESC 'Time last message received from provider' " 6678 "SUP monitorTimestamp " 6679 "SINGLE-VALUE " 6680 "NO-USER-MODIFICATION " 6681 "USAGE dSAOperation )", 6682 &ad_olmLastContact }, 6683 { "( olmSyncReplAttributes:7 " 6684 "NAME ( 'olmSRLastCookieRcvd' ) " 6685 "DESC 'Last sync cookie received from provider' " 6686 "SUP monitoredInfo " 6687 "NO-USER-MODIFICATION " 6688 "USAGE dSAOperation )", 6689 &ad_olmLastCookieRcvd }, 6690 { "( olmSyncReplAttributes:8 " 6691 "NAME ( 'olmSRLastCookieSent' ) " 6692 "DESC 'Last sync cookie sent to provider' " 6693 "SUP monitoredInfo " 6694 "NO-USER-MODIFICATION " 6695 "USAGE dSAOperation )", 6696 &ad_olmLastCookieSent }, 6697 { NULL } 6698 }; 6699 6700 static struct { 6701 char *desc; 6702 ObjectClass **oc; 6703 } s_oc[] = { 6704 { "( olmSyncReplObjectClasses:1 " 6705 "NAME ( 'olmSyncReplInstance' ) " 6706 "SUP monitoredObject STRUCTURAL " 6707 "MAY ( " 6708 "olmSRProviderURIList " 6709 "$ olmSRConnection " 6710 "$ olmSRSyncPhase " 6711 "$ olmSRNextConnect " 6712 "$ olmSRLastConnect " 6713 "$ olmSRLastContact " 6714 "$ olmSRLastCookieRcvd " 6715 "$ olmSRLastCookieSent " 6716 ") )", 6717 &oc_olmSyncRepl }, 6718 { NULL } 6719 }; 6720 6721 static int 6722 syncrepl_monitor_initialized; 6723 6724 int 6725 syncrepl_monitor_init( void ) 6726 { 6727 int i, code; 6728 6729 if ( syncrepl_monitor_initialized ) 6730 return 0; 6731 6732 if ( backend_info( "monitor" ) == NULL ) 6733 return -1; 6734 6735 { 6736 ConfigArgs c; 6737 char *argv[3]; 6738 6739 argv[ 0 ] = "syncrepl monitor"; 6740 c.argv = argv; 6741 c.argc = 2; 6742 c.fname = argv[0]; 6743 for ( i=0; s_oid[i].name; i++ ) { 6744 argv[1] = s_oid[i].name; 6745 argv[2] = s_oid[i].oid; 6746 if ( parse_oidm( &c, 0, NULL )) { 6747 Debug( LDAP_DEBUG_ANY, 6748 "syncrepl_monitor_init: unable to add " 6749 "objectIdentifier \"%s=%s\"\n", 6750 s_oid[i].name, s_oid[i].oid ); 6751 return 2; 6752 } 6753 } 6754 } 6755 6756 for ( i=0; s_at[i].desc != NULL; i++ ) { 6757 code = register_at( s_at[i].desc, s_at[i].ad, 1 ); 6758 if ( code != LDAP_SUCCESS ) { 6759 Debug( LDAP_DEBUG_ANY, 6760 "syncrepl_monitor_init: register_at failed for attributeType (%s)\n", 6761 s_at[i].desc ); 6762 return 3; 6763 } else { 6764 (*s_at[i].ad)->ad_type->sat_flags |= SLAP_AT_HIDE; 6765 } 6766 } 6767 6768 for ( i=0; s_oc[i].desc != NULL; i++ ) { 6769 code = register_oc( s_oc[i].desc, s_oc[i].oc, 1 ); 6770 if ( code != LDAP_SUCCESS ) { 6771 Debug( LDAP_DEBUG_ANY, 6772 "syncrepl_monitor_init: register_oc failed for objectClass (%s)\n", 6773 s_oc[i].desc ); 6774 return 4; 6775 } else { 6776 (*s_oc[i].oc)->soc_flags |= SLAP_OC_HIDE; 6777 } 6778 } 6779 syncrepl_monitor_initialized = 1; 6780 6781 return 0; 6782 } 6783 6784 static const struct berval zerotime = BER_BVC("00000101000000Z"); 6785 6786 static int 6787 syncrepl_monitor_update( 6788 Operation *op, 6789 SlapReply *rs, 6790 Entry *e, 6791 void *priv ) 6792 { 6793 syncinfo_t *si = (syncinfo_t *)priv; 6794 Attribute *a; 6795 int isConnected = 0; 6796 6797 a = attr_find( e->e_attrs, ad_olmConnection ); 6798 if ( !a ) 6799 return SLAP_CB_CONTINUE; 6800 if ( si->si_ld ) { 6801 if (!bvmatch( &a->a_vals[0], &si->si_connaddr )) { 6802 AC_MEMCPY( a->a_vals[0].bv_val, si->si_connaddr.bv_val, si->si_connaddr.bv_len ); 6803 a->a_vals[0].bv_len = si->si_connaddr.bv_len; 6804 } 6805 isConnected = 1; 6806 } else { 6807 a->a_vals[0].bv_val[0] = '\0'; 6808 a->a_vals[0].bv_len = 0; 6809 } 6810 6811 a = a->a_next; 6812 if ( a->a_desc != ad_olmSyncPhase ) 6813 return SLAP_CB_CONTINUE; 6814 6815 if ( si->si_refreshDone ) { 6816 struct berval bv = BER_BVC("Persist"); 6817 ber_bvreplace( &a->a_vals[0], &bv ); 6818 } else { 6819 if ( si->si_syncdata && si->si_logstate == SYNCLOG_FALLBACK ) { 6820 struct berval bv = BER_BVC("Fallback Refresh"); 6821 ber_bvreplace( &a->a_vals[0], &bv ); 6822 } else { 6823 struct berval bv = BER_BVC("Refresh"); 6824 ber_bvreplace( &a->a_vals[0], &bv ); 6825 } 6826 } 6827 6828 { 6829 struct tm tm; 6830 char tmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; 6831 ber_len_t len; 6832 6833 a = a->a_next; 6834 if ( a->a_desc != ad_olmNextConnect ) 6835 return SLAP_CB_CONTINUE; 6836 6837 if ( !isConnected && si->si_re && si->si_re->next_sched.tv_sec ) { 6838 time_t next_sched = si->si_re->next_sched.tv_sec; 6839 ldap_pvt_gmtime( &next_sched, &tm ); 6840 lutil_gentime( tmbuf, sizeof( tmbuf ), &tm ); 6841 len = strlen( tmbuf ); 6842 assert( len == a->a_vals[0].bv_len ); 6843 AC_MEMCPY( a->a_vals[0].bv_val, tmbuf, len ); 6844 } else { 6845 AC_MEMCPY( a->a_vals[0].bv_val, zerotime.bv_val, zerotime.bv_len ); 6846 } 6847 6848 a = a->a_next; 6849 if ( a->a_desc != ad_olmLastConnect ) 6850 return SLAP_CB_CONTINUE; 6851 6852 if ( si->si_lastconnect ) { 6853 ldap_pvt_gmtime( &si->si_lastconnect, &tm ); 6854 lutil_gentime( tmbuf, sizeof( tmbuf ), &tm ); 6855 len = strlen( tmbuf ); 6856 assert( len == a->a_vals[0].bv_len ); 6857 AC_MEMCPY( a->a_vals[0].bv_val, tmbuf, len ); 6858 } 6859 6860 a = a->a_next; 6861 if ( a->a_desc != ad_olmLastContact ) 6862 return SLAP_CB_CONTINUE; 6863 6864 if ( si->si_lastcontact ) { 6865 ldap_pvt_gmtime( &si->si_lastcontact, &tm ); 6866 lutil_gentime( tmbuf, sizeof( tmbuf ), &tm ); 6867 len = strlen( tmbuf ); 6868 assert( len == a->a_vals[0].bv_len ); 6869 AC_MEMCPY( a->a_vals[0].bv_val, tmbuf, len ); 6870 } 6871 } 6872 6873 a = a->a_next; 6874 if ( a->a_desc != ad_olmLastCookieRcvd ) 6875 return SLAP_CB_CONTINUE; 6876 6877 ldap_pvt_thread_mutex_lock( &si->si_monitor_mutex ); 6878 if ( !BER_BVISEMPTY( &si->si_lastCookieRcvd ) && 6879 !bvmatch( &a->a_vals[0], &si->si_lastCookieRcvd )) 6880 ber_bvreplace( &a->a_vals[0], &si->si_lastCookieRcvd ); 6881 6882 a = a->a_next; 6883 if ( a->a_desc != ad_olmLastCookieSent ) { 6884 ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex ); 6885 return SLAP_CB_CONTINUE; 6886 } 6887 6888 if ( !BER_BVISEMPTY( &si->si_lastCookieSent ) && 6889 !bvmatch( &a->a_vals[0], &si->si_lastCookieSent )) 6890 ber_bvreplace( &a->a_vals[0], &si->si_lastCookieSent ); 6891 ldap_pvt_thread_mutex_unlock( &si->si_monitor_mutex ); 6892 6893 return SLAP_CB_CONTINUE; 6894 } 6895 6896 static int 6897 syncrepl_monitor_add( 6898 syncinfo_t *si 6899 ) 6900 { 6901 BackendInfo *mi; 6902 monitor_extra_t *mbe; 6903 struct berval pndn, pdn, rdn, bv; 6904 char rdnbuf[sizeof("cn=Consumer 999")]; 6905 Entry *e, *p; 6906 int rc; 6907 6908 if ( !syncrepl_monitor_initialized ) 6909 return -1; 6910 6911 mi = backend_info( "monitor" ); 6912 if ( !mi || !mi->bi_extra ) { 6913 SLAP_DBFLAGS( si->si_be ) ^= SLAP_DBFLAG_MONITORING; 6914 return 0; 6915 } 6916 mbe = mi->bi_extra; 6917 6918 if ( !mbe->is_configured() ) { 6919 return 0; 6920 } 6921 6922 rc = mbe->register_database( si->si_be, &pndn ); 6923 if ( rc ) { 6924 Debug( LDAP_DEBUG_ANY, "syncrepl_monitor_add: " 6925 "failed to register the database with back-monitor\n" ); 6926 return rc; 6927 } 6928 rdn.bv_len = sprintf(rdnbuf, "cn=Consumer %03d", si->si_rid ); 6929 rdn.bv_val = rdnbuf; 6930 p = mbe->entry_get_unlocked( &pndn ); 6931 if ( p ) { 6932 pdn = p->e_name; 6933 } else { 6934 pdn = pndn; 6935 } 6936 6937 e = mbe->entry_stub( &pdn, &pndn, &rdn, 6938 oc_olmSyncRepl, NULL, NULL ); 6939 if ( e == NULL ) { 6940 Debug( LDAP_DEBUG_ANY, 6941 "syncrepl_monitor_add: " 6942 "unable to create entry \"%s,%s\"\n", 6943 rdn.bv_val, pndn.bv_val ); 6944 return -1; 6945 } 6946 6947 attr_merge_normalize_one( e, ad_olmProviderURIList, 6948 &si->si_bindconf.sb_uri, NULL ); 6949 6950 { 6951 si->si_connaddr.bv_val = si->si_connaddrbuf; 6952 si->si_connaddr.bv_len = sizeof( si->si_connaddrbuf ); 6953 si->si_connaddrbuf[0] = '\0'; 6954 attr_merge_normalize_one( e, ad_olmConnection, &si->si_connaddr, NULL ); 6955 } 6956 { 6957 struct berval bv = BER_BVC("Refresh"); 6958 attr_merge_normalize_one( e, ad_olmSyncPhase, &bv, NULL ); 6959 } 6960 { 6961 attr_merge_normalize_one( e, ad_olmNextConnect, (struct berval *)&zerotime, NULL ); 6962 attr_merge_normalize_one( e, ad_olmLastConnect, (struct berval *)&zerotime, NULL ); 6963 attr_merge_normalize_one( e, ad_olmLastContact, (struct berval *)&zerotime, NULL ); 6964 } 6965 { 6966 struct berval bv = BER_BVC(""); 6967 attr_merge_normalize_one( e, ad_olmLastCookieRcvd, &bv, NULL ); 6968 attr_merge_normalize_one( e, ad_olmLastCookieSent, &bv, NULL ); 6969 } 6970 { 6971 monitor_callback_t *cb = ch_calloc( sizeof( monitor_callback_t ), 1 ); 6972 cb->mc_update = syncrepl_monitor_update; 6973 cb->mc_private = si; 6974 rc = mbe->register_entry( e, cb, NULL, 0 ); 6975 } 6976 6977 si->si_monitor_ndn = e->e_nname; 6978 BER_BVZERO( &e->e_nname ); 6979 entry_free( e ); 6980 6981 return rc; 6982 } 6983 6984 static int 6985 syncrepl_monitor_del( 6986 syncinfo_t *si 6987 ) 6988 { 6989 BackendInfo *mi; 6990 6991 mi = backend_info( "monitor" ); 6992 if ( mi && mi->bi_extra ) { 6993 monitor_extra_t *mbe = mi->bi_extra; 6994 mbe->unregister_entry( &si->si_monitor_ndn ); 6995 } 6996 ch_free( si->si_lastCookieSent.bv_val ); 6997 ch_free( si->si_lastCookieRcvd.bv_val ); 6998 ch_free( si->si_monitor_ndn.bv_val ); 6999 return 0; 7000 } 7001 7002 static int 7003 add_syncrepl( 7004 ConfigArgs *c ) 7005 { 7006 syncinfo_t *si; 7007 int rc = 0; 7008 7009 if ( !( c->be->be_search && c->be->be_add && c->be->be_modify && c->be->be_delete ) ) { 7010 snprintf( c->cr_msg, sizeof(c->cr_msg), "database %s does not support " 7011 "operations required for syncrepl", c->be->be_type ); 7012 Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg ); 7013 return 1; 7014 } 7015 if ( BER_BVISEMPTY( &c->be->be_rootdn ) ) { 7016 strcpy( c->cr_msg, "rootDN must be defined before syncrepl may be used" ); 7017 Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg ); 7018 return 1; 7019 } 7020 si = (syncinfo_t *) ch_calloc( 1, sizeof( syncinfo_t ) ); 7021 7022 if ( si == NULL ) { 7023 Debug( LDAP_DEBUG_ANY, "out of memory in add_syncrepl\n" ); 7024 return 1; 7025 } 7026 7027 si->si_bindconf.sb_tls = SB_TLS_OFF; 7028 si->si_bindconf.sb_method = LDAP_AUTH_SIMPLE; 7029 si->si_schemachecking = 0; 7030 ber_str2bv( "(objectclass=*)", STRLENOF("(objectclass=*)"), 1, 7031 &si->si_filterstr ); 7032 si->si_base.bv_val = NULL; 7033 si->si_scope = LDAP_SCOPE_SUBTREE; 7034 si->si_attrsonly = 0; 7035 si->si_anlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ) ); 7036 si->si_exanlist = (AttributeName *) ch_calloc( 1, sizeof( AttributeName ) ); 7037 si->si_attrs = NULL; 7038 si->si_allattrs = 0; 7039 si->si_allopattrs = 0; 7040 si->si_exattrs = NULL; 7041 si->si_type = si->si_ctype = LDAP_SYNC_REFRESH_ONLY; 7042 si->si_interval = 86400; 7043 si->si_retryinterval = NULL; 7044 si->si_retrynum_init = NULL; 7045 si->si_retrynum = NULL; 7046 si->si_manageDSAit = 0; 7047 si->si_tlimit = 0; 7048 si->si_slimit = 0; 7049 7050 si->si_presentlist = NULL; 7051 LDAP_LIST_INIT( &si->si_nonpresentlist ); 7052 ldap_pvt_thread_mutex_init( &si->si_monitor_mutex ); 7053 ldap_pvt_thread_mutex_init( &si->si_mutex ); 7054 7055 si->si_is_configdb = strcmp( c->be->be_suffix[0].bv_val, "cn=config" ) == 0; 7056 7057 rc = parse_syncrepl_line( c, si ); 7058 7059 if ( rc == 0 ) { 7060 LDAPURLDesc *lud; 7061 7062 /* Must be LDAPv3 because we need controls */ 7063 switch ( si->si_bindconf.sb_version ) { 7064 case 0: 7065 /* not explicitly set */ 7066 si->si_bindconf.sb_version = LDAP_VERSION3; 7067 break; 7068 case 3: 7069 /* explicitly set */ 7070 break; 7071 default: 7072 Debug( LDAP_DEBUG_ANY, 7073 "version %d incompatible with syncrepl\n", 7074 si->si_bindconf.sb_version ); 7075 syncinfo_free( si, 0 ); 7076 return 1; 7077 } 7078 7079 if ( ldap_url_parse( si->si_bindconf.sb_uri.bv_val, &lud )) { 7080 snprintf( c->cr_msg, sizeof( c->cr_msg ), 7081 "<%s> invalid URL", c->argv[0] ); 7082 Debug( LDAP_DEBUG_ANY, "%s: %s %s\n", 7083 c->log, c->cr_msg, si->si_bindconf.sb_uri.bv_val ); 7084 return 1; 7085 } 7086 7087 si->si_be = c->be; 7088 if ( slapMode & SLAP_SERVER_MODE ) { 7089 int isMe = 0; 7090 /* check if consumer points to current server and database. 7091 * If so, ignore this configuration. 7092 */ 7093 if ( !SLAP_DBHIDDEN( c->be ) ) { 7094 int i; 7095 /* if searchbase doesn't match current DB suffix, 7096 * assume it's different 7097 */ 7098 for ( i=0; !BER_BVISNULL( &c->be->be_nsuffix[i] ); i++ ) { 7099 if ( bvmatch( &si->si_base, &c->be->be_nsuffix[i] )) { 7100 isMe = 1; 7101 break; 7102 } 7103 } 7104 /* if searchbase matches, see if URLs match */ 7105 if ( isMe && config_check_my_url( si->si_bindconf.sb_uri.bv_val, 7106 lud ) == NULL ) 7107 isMe = 0; 7108 } 7109 7110 if ( !isMe ) { 7111 init_syncrepl( si ); 7112 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 7113 si->si_re = ldap_pvt_runqueue_insert( &slapd_rq, 7114 si->si_interval, do_syncrepl, si, "do_syncrepl", 7115 si->si_ridtxt ); 7116 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 7117 if ( si->si_re ) 7118 rc = config_sync_shadow( c ) ? -1 : 0; 7119 else 7120 rc = -1; 7121 } 7122 } else { 7123 /* multiprovider still needs to see this flag in tool mode */ 7124 rc = config_sync_shadow( c ) ? -1 : 0; 7125 } 7126 ldap_free_urldesc( lud ); 7127 } 7128 7129 #ifdef HAVE_TLS 7130 /* Use main slapd defaults */ 7131 bindconf_tls_defaults( &si->si_bindconf ); 7132 #endif 7133 if ( rc != 0 ) { 7134 Debug( LDAP_DEBUG_ANY, "failed to add syncinfo\n" ); 7135 syncinfo_free( si, 0 ); 7136 return 1; 7137 } else { 7138 Debug( LDAP_DEBUG_CONFIG, 7139 "Config: ** successfully added syncrepl %s \"%s\"\n", 7140 si->si_ridtxt, 7141 BER_BVISNULL( &si->si_bindconf.sb_uri ) ? 7142 "(null)" : si->si_bindconf.sb_uri.bv_val ); 7143 if ( c->be->be_syncinfo ) { 7144 syncinfo_t *sip; 7145 7146 si->si_cookieState = c->be->be_syncinfo->si_cookieState; 7147 7148 /* add new syncrepl to end of list (same order as when deleting) */ 7149 for ( sip = c->be->be_syncinfo; sip->si_next; sip = sip->si_next ); 7150 sip->si_next = si; 7151 } else { 7152 si->si_cookieState = ch_calloc( 1, sizeof( cookie_state )); 7153 ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_mutex ); 7154 ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_pmutex ); 7155 ldap_pvt_thread_cond_init( &si->si_cookieState->cs_cond ); 7156 7157 c->be->be_syncinfo = si; 7158 } 7159 si->si_cookieState->cs_ref++; 7160 7161 si->si_next = NULL; 7162 syncrepl_monitor_init(); 7163 7164 return 0; 7165 } 7166 } 7167 7168 static void 7169 syncrepl_unparse( syncinfo_t *si, struct berval *bv ) 7170 { 7171 struct berval bc, uri, bs; 7172 char buf[BUFSIZ*2], *ptr; 7173 ber_len_t len; 7174 int i; 7175 # define WHATSLEFT ((ber_len_t) (&buf[sizeof( buf )] - ptr)) 7176 7177 BER_BVZERO( bv ); 7178 7179 /* temporarily inhibit bindconf from printing URI */ 7180 uri = si->si_bindconf.sb_uri; 7181 BER_BVZERO( &si->si_bindconf.sb_uri ); 7182 si->si_bindconf.sb_version = 0; 7183 bindconf_unparse( &si->si_bindconf, &bc ); 7184 si->si_bindconf.sb_uri = uri; 7185 si->si_bindconf.sb_version = LDAP_VERSION3; 7186 7187 ptr = buf; 7188 assert( si->si_rid >= 0 && si->si_rid <= SLAP_SYNC_RID_MAX ); 7189 len = snprintf( ptr, WHATSLEFT, IDSTR "=%03d " PROVIDERSTR "=%s", 7190 si->si_rid, si->si_bindconf.sb_uri.bv_val ); 7191 if ( len >= sizeof( buf ) ) return; 7192 ptr += len; 7193 if ( !BER_BVISNULL( &bc ) ) { 7194 if ( WHATSLEFT <= bc.bv_len ) { 7195 free( bc.bv_val ); 7196 return; 7197 } 7198 ptr = lutil_strcopy( ptr, bc.bv_val ); 7199 free( bc.bv_val ); 7200 } 7201 if ( !BER_BVISEMPTY( &si->si_filterstr ) ) { 7202 if ( WHATSLEFT <= STRLENOF( " " FILTERSTR "=\"" "\"" ) + si->si_filterstr.bv_len ) return; 7203 ptr = lutil_strcopy( ptr, " " FILTERSTR "=\"" ); 7204 ptr = lutil_strcopy( ptr, si->si_filterstr.bv_val ); 7205 *ptr++ = '"'; 7206 } 7207 if ( !BER_BVISNULL( &si->si_base ) ) { 7208 if ( WHATSLEFT <= STRLENOF( " " SEARCHBASESTR "=\"" "\"" ) + si->si_base.bv_len ) return; 7209 ptr = lutil_strcopy( ptr, " " SEARCHBASESTR "=\"" ); 7210 ptr = lutil_strcopy( ptr, si->si_base.bv_val ); 7211 *ptr++ = '"'; 7212 } 7213 if ( !BER_BVISNULL( &si->si_suffixm ) ) { 7214 if ( WHATSLEFT <= STRLENOF( " " SUFFIXMSTR "=\"" "\"" ) + si->si_suffixm.bv_len ) return; 7215 ptr = lutil_strcopy( ptr, " " SUFFIXMSTR "=\"" ); 7216 ptr = lutil_strcopy( ptr, si->si_suffixm.bv_val ); 7217 *ptr++ = '"'; 7218 } 7219 if ( !BER_BVISEMPTY( &si->si_logfilterstr ) ) { 7220 if ( WHATSLEFT <= STRLENOF( " " LOGFILTERSTR "=\"" "\"" ) + si->si_logfilterstr.bv_len ) return; 7221 ptr = lutil_strcopy( ptr, " " LOGFILTERSTR "=\"" ); 7222 ptr = lutil_strcopy( ptr, si->si_logfilterstr.bv_val ); 7223 *ptr++ = '"'; 7224 } 7225 if ( !BER_BVISNULL( &si->si_logbase ) ) { 7226 if ( WHATSLEFT <= STRLENOF( " " LOGBASESTR "=\"" "\"" ) + si->si_logbase.bv_len ) return; 7227 ptr = lutil_strcopy( ptr, " " LOGBASESTR "=\"" ); 7228 ptr = lutil_strcopy( ptr, si->si_logbase.bv_val ); 7229 *ptr++ = '"'; 7230 } 7231 if ( ldap_pvt_scope2bv( si->si_scope, &bs ) == LDAP_SUCCESS ) { 7232 if ( WHATSLEFT <= STRLENOF( " " SCOPESTR "=" ) + bs.bv_len ) return; 7233 ptr = lutil_strcopy( ptr, " " SCOPESTR "=" ); 7234 ptr = lutil_strcopy( ptr, bs.bv_val ); 7235 } 7236 if ( si->si_attrsonly ) { 7237 if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return; 7238 ptr = lutil_strcopy( ptr, " " ATTRSONLYSTR ); 7239 } 7240 if ( si->si_anfile ) { 7241 if ( WHATSLEFT <= STRLENOF( " " ATTRSSTR "=\":include:" "\"" ) + strlen( si->si_anfile ) ) return; 7242 ptr = lutil_strcopy( ptr, " " ATTRSSTR "=:include:\"" ); 7243 ptr = lutil_strcopy( ptr, si->si_anfile ); 7244 *ptr++ = '"'; 7245 } else if ( si->si_allattrs || si->si_allopattrs || 7246 ( si->si_anlist && !BER_BVISNULL(&si->si_anlist[0].an_name) ) ) 7247 { 7248 char *old; 7249 7250 if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return; 7251 ptr = lutil_strcopy( ptr, " " ATTRSSTR "=\"" ); 7252 old = ptr; 7253 ptr = anlist_unparse( si->si_anlist, ptr, WHATSLEFT ); 7254 if ( ptr == NULL ) return; 7255 if ( si->si_allattrs ) { 7256 if ( WHATSLEFT <= STRLENOF( ",*\"" ) ) return; 7257 if ( old != ptr ) *ptr++ = ','; 7258 *ptr++ = '*'; 7259 } 7260 if ( si->si_allopattrs ) { 7261 if ( WHATSLEFT <= STRLENOF( ",+\"" ) ) return; 7262 if ( old != ptr ) *ptr++ = ','; 7263 *ptr++ = '+'; 7264 } 7265 *ptr++ = '"'; 7266 } 7267 if ( si->si_exanlist && !BER_BVISNULL(&si->si_exanlist[0].an_name) ) { 7268 if ( WHATSLEFT <= STRLENOF( " " EXATTRSSTR "=" ) ) return; 7269 ptr = lutil_strcopy( ptr, " " EXATTRSSTR "=" ); 7270 ptr = anlist_unparse( si->si_exanlist, ptr, WHATSLEFT ); 7271 if ( ptr == NULL ) return; 7272 } 7273 if ( WHATSLEFT <= STRLENOF( " " SCHEMASTR "=" ) + STRLENOF( "off" ) ) return; 7274 ptr = lutil_strcopy( ptr, " " SCHEMASTR "=" ); 7275 ptr = lutil_strcopy( ptr, si->si_schemachecking ? "on" : "off" ); 7276 7277 if ( WHATSLEFT <= STRLENOF( " " TYPESTR "=" ) + STRLENOF( "refreshAndPersist" ) ) return; 7278 ptr = lutil_strcopy( ptr, " " TYPESTR "=" ); 7279 #ifdef LDAP_CONTROL_X_DIRSYNC 7280 if ( si->si_type == MSAD_DIRSYNC ) 7281 ptr = lutil_strcopy( ptr, "dirSync" ); 7282 else 7283 #endif 7284 ptr = lutil_strcopy( ptr, si->si_type == LDAP_SYNC_REFRESH_AND_PERSIST ? 7285 "refreshAndPersist" : "refreshOnly" ); 7286 7287 if ( si->si_type == LDAP_SYNC_REFRESH_ONLY 7288 #ifdef LDAP_CONTROL_X_DIRSYNC 7289 || si->si_type == MSAD_DIRSYNC 7290 #endif 7291 ) { 7292 int dd, hh, mm, ss; 7293 7294 dd = si->si_interval; 7295 ss = dd % 60; 7296 dd /= 60; 7297 mm = dd % 60; 7298 dd /= 60; 7299 hh = dd % 24; 7300 dd /= 24; 7301 len = snprintf( ptr, WHATSLEFT, " %s=%02d:%02d:%02d:%02d", 7302 INTERVALSTR, dd, hh, mm, ss ); 7303 if ( len >= WHATSLEFT ) return; 7304 ptr += len; 7305 } 7306 7307 if ( si->si_got & GOT_RETRY ) { 7308 const char *space = ""; 7309 if ( WHATSLEFT <= STRLENOF( " " RETRYSTR "=\"" "\"" ) ) return; 7310 ptr = lutil_strcopy( ptr, " " RETRYSTR "=\"" ); 7311 for (i=0; si->si_retryinterval[i]; i++) { 7312 len = snprintf( ptr, WHATSLEFT, "%s%ld ", space, 7313 (long) si->si_retryinterval[i] ); 7314 space = " "; 7315 if ( WHATSLEFT - 1 <= len ) return; 7316 ptr += len; 7317 if ( si->si_retrynum_init[i] == RETRYNUM_FOREVER ) 7318 *ptr++ = '+'; 7319 else { 7320 len = snprintf( ptr, WHATSLEFT, "%d", si->si_retrynum_init[i] ); 7321 if ( WHATSLEFT <= len ) return; 7322 ptr += len; 7323 } 7324 } 7325 if ( WHATSLEFT <= STRLENOF( "\"" ) ) return; 7326 *ptr++ = '"'; 7327 } else { 7328 ptr = lutil_strcopy( ptr, " " RETRYSTR "=undefined" ); 7329 } 7330 7331 if ( si->si_slimit ) { 7332 len = snprintf( ptr, WHATSLEFT, " " SLIMITSTR "=%d", si->si_slimit ); 7333 if ( WHATSLEFT <= len ) return; 7334 ptr += len; 7335 } 7336 7337 if ( si->si_tlimit ) { 7338 len = snprintf( ptr, WHATSLEFT, " " TLIMITSTR "=%d", si->si_tlimit ); 7339 if ( WHATSLEFT <= len ) return; 7340 ptr += len; 7341 } 7342 7343 if ( si->si_syncdata ) { 7344 if ( enum_to_verb( datamodes, si->si_syncdata, &bc ) >= 0 ) { 7345 if ( WHATSLEFT <= STRLENOF( " " SYNCDATASTR "=" ) + bc.bv_len ) return; 7346 ptr = lutil_strcopy( ptr, " " SYNCDATASTR "=" ); 7347 ptr = lutil_strcopy( ptr, bc.bv_val ); 7348 } 7349 } 7350 7351 if ( si->si_lazyCommit ) { 7352 ptr = lutil_strcopy( ptr, " " LAZY_COMMIT ); 7353 } 7354 7355 bc.bv_len = ptr - buf; 7356 bc.bv_val = buf; 7357 ber_dupbv( bv, &bc ); 7358 } 7359 7360 int 7361 syncrepl_config( ConfigArgs *c ) 7362 { 7363 if (c->op == SLAP_CONFIG_EMIT) { 7364 if ( c->be->be_syncinfo ) { 7365 struct berval bv; 7366 syncinfo_t *si; 7367 7368 for ( si = c->be->be_syncinfo; si; si=si->si_next ) { 7369 syncrepl_unparse( si, &bv ); 7370 ber_bvarray_add( &c->rvalue_vals, &bv ); 7371 } 7372 return 0; 7373 } 7374 return 1; 7375 } else if ( c->op == LDAP_MOD_DELETE ) { 7376 int isrunning = 0; 7377 if ( c->be->be_syncinfo ) { 7378 syncinfo_t *si, **sip; 7379 int i; 7380 7381 for ( sip = &c->be->be_syncinfo, i=0; *sip; i++ ) { 7382 si = *sip; 7383 if ( c->valx == -1 || i == c->valx ) { 7384 *sip = si->si_next; 7385 si->si_ctype = -1; 7386 si->si_next = NULL; 7387 /* If the task is currently active, we have to leave 7388 * it running. It will exit on its own. This will only 7389 * happen when running on the cn=config DB. 7390 */ 7391 if ( si->si_re ) { 7392 if ( si->si_be == c->be || ldap_pvt_thread_mutex_trylock( &si->si_mutex )) { 7393 isrunning = 1; 7394 } else { 7395 /* There is no active thread, but we must still 7396 * ensure that no thread is (or will be) queued 7397 * while we removes the task. 7398 */ 7399 struct re_s *re = si->si_re; 7400 si->si_re = NULL; 7401 7402 if ( si->si_conn ) { 7403 connection_client_stop( si->si_conn ); 7404 si->si_conn = NULL; 7405 } 7406 7407 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 7408 if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) ) { 7409 ldap_pvt_runqueue_stoptask( &slapd_rq, re ); 7410 isrunning = 1; 7411 } 7412 if ( ldap_pvt_thread_pool_retract( re->pool_cookie ) > 0 ) 7413 isrunning = 0; 7414 7415 ldap_pvt_runqueue_remove( &slapd_rq, re ); 7416 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 7417 7418 ldap_pvt_thread_mutex_unlock( &si->si_mutex ); 7419 } 7420 } 7421 if ( !isrunning ) { 7422 syncinfo_free( si, 0 ); 7423 } 7424 if ( i == c->valx ) 7425 break; 7426 } else { 7427 sip = &si->si_next; 7428 } 7429 } 7430 } 7431 if ( !c->be->be_syncinfo ) { 7432 SLAP_DBFLAGS( c->be ) &= ~SLAP_DBFLAG_SHADOW_MASK; 7433 } 7434 return 0; 7435 } 7436 if ( SLAP_SLURP_SHADOW( c->be ) ) { 7437 Debug(LDAP_DEBUG_ANY, "%s: " 7438 "syncrepl: database already shadowed.\n", 7439 c->log ); 7440 return(1); 7441 } else { 7442 return add_syncrepl( c ); 7443 } 7444 } 7445