Hello community, here is the log from the commit of package openldap2 for openSUSE:Factory checked in at 2020-10-15 13:44:29 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/openldap2 (Old) and /work/SRC/openSUSE:Factory/.openldap2.new.3486 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "openldap2" Thu Oct 15 13:44:29 2020 rev:158 rq:841355 version:unknown Changes: -------- --- /work/SRC/openSUSE:Factory/openldap2/openldap2.changes 2020-09-10 22:45:29.655682780 +0200 +++ /work/SRC/openSUSE:Factory/.openldap2.new.3486/openldap2.changes 2020-10-15 13:44:38.657158703 +0200 @@ -1,0 +2,20 @@ +Mon Oct 12 20:21:23 UTC 2020 - Michael Ströder <mich...@stroeder.com> + +- updated to 2.4.54 + +OpenLDAP 2.4.54 Release (2020/10/12) + Fixed slapd delta-syncrepl to ignore delete ops on deleted entry (ITS#9342) + Fixed slapd delta-syncrepl to be fully serialized (ITS#9330) + Fixed slapd delta-syncrepl MOD on zero-length context entry (ITS#9352) + Fixed slapd sessionlog to use a TAVL tree (ITS#8486) + Fixed slapd syncrepl to be fully serialized (ITS#8102) + Fixed slapd syncrepl to call check_syncprov on fresh consumer (ITS#9345) + Fixed slapd syncrepl to propagate errors from overlay_entry_get_ov (ITS#9355) + Fixed slapd syncrepl to not create empty ADD ops (ITS#9359) + Fixed slapd syncrepl replace usage on single valued attrs (ITS#9295) + Fixed slapd-monitor fix monitor_back_register_database for empty suffix DB (ITS#9353) + Fixed slapo-accesslog normalizer for reqStart (ITS#9358) + Fixed slapo-accesslog to not generate new contextCSN on purge (ITS#9361) + Fixed slapo-syncprov contextCSN generation with empty suffix (ITS#9015) + +------------------------------------------------------------------- Old: ---- openldap-2.4.53.tgz New: ---- openldap-2.4.54.tgz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ openldap2.spec ++++++ --- /var/tmp/diff_new_pack.pjZV7Q/_old 2020-10-15 13:44:39.721159118 +0200 +++ /var/tmp/diff_new_pack.pjZV7Q/_new 2020-10-15 13:44:39.725159120 +0200 @@ -22,7 +22,7 @@ %endif %define run_test_suite 0 -%define version_main 2.4.53 +%define version_main 2.4.54 %define name_ppolicy_check_module ppolicy-check-password %define version_ppolicy_check_module 1.2 %define ppolicy_docdir %{_docdir}/openldap-%{name_ppolicy_check_module}-%{version_ppolicy_check_module} ++++++ openldap-2.4.53.tgz -> openldap-2.4.54.tgz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openldap-2.4.53/CHANGES new/openldap-2.4.54/CHANGES --- old/openldap-2.4.53/CHANGES 2020-09-07 17:13:36.000000000 +0200 +++ new/openldap-2.4.54/CHANGES 2020-10-12 20:27:28.000000000 +0200 @@ -1,6 +1,21 @@ OpenLDAP 2.4 Change Log -OpenLDAP 2.4.53 (2020/09/07) +OpenLDAP 2.4.54 Release (2020/10/12) + Fixed slapd delta-syncrepl to ignore delete ops on deleted entry (ITS#9342) + Fixed slapd delta-syncrepl to be fully serialized (ITS#9330) + Fixed slapd delta-syncrepl MOD on zero-length context entry (ITS#9352) + Fixed slapd sessionlog to use a TAVL tree (ITS#8486) + Fixed slapd syncrepl to be fully serialized (ITS#8102) + Fixed slapd syncrepl to call check_syncprov on fresh consumer (ITS#9345) + Fixed slapd syncrepl to propagate errors from overlay_entry_get_ov (ITS#9355) + Fixed slapd syncrepl to not create empty ADD ops (ITS#9359) + Fixed slapd syncrepl replace usage on single valued attrs (ITS#9295) + Fixed slapd-monitor fix monitor_back_register_database for empty suffix DB (ITS#9353) + Fixed slapo-accesslog normalizer for reqStart (ITS#9358) + Fixed slapo-accesslog to not generate new contextCSN on purge (ITS#9361) + Fixed slapo-syncprov contextCSN generation with empty suffix (ITS#9015) + +OpenLDAP 2.4.53 Release (2020/09/07) Added slapd syncrepl additional SYNC logging (ITS#9043) Fixed slapd syncrepl segfault on NULL cookie on REFRESH (ITS#9282) Fixed slapd syncrepl to use fresh connection on REFRESH fallback (ITS#9338) @@ -9,7 +24,7 @@ Require OpenSSL 1.0.2 or later (ITS#9323) Fixed libldap compilation issue with broken C compilers (ITS#9332) -OpenLDAP 2.4.52 (2020/08/28) +OpenLDAP 2.4.52 Release (2020/08/28) Added libldap LDAP_OPT_X_TLS_REQUIRE_SAN option (ITS#9318) Added libldap OpenSSL support for multiple EECDH curves (ITS#9054) Added slapd OpenSSL support for multiple EECDH curves (ITS#9054) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openldap-2.4.53/build/version.var new/openldap-2.4.54/build/version.var --- old/openldap-2.4.53/build/version.var 2020-09-07 17:13:36.000000000 +0200 +++ new/openldap-2.4.54/build/version.var 2020-10-12 20:27:28.000000000 +0200 @@ -15,9 +15,9 @@ ol_package=OpenLDAP ol_major=2 ol_minor=4 -ol_patch=53 -ol_api_inc=20453 +ol_patch=54 +ol_api_inc=20454 ol_api_current=13 -ol_api_revision=1 +ol_api_revision=2 ol_api_age=11 -ol_release_date="2020/09/07" +ol_release_date="2020/10/12" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openldap-2.4.53/doc/guide/admin/guide.html new/openldap-2.4.54/doc/guide/admin/guide.html --- old/openldap-2.4.53/doc/guide/admin/guide.html 2020-09-07 17:20:08.000000000 +0200 +++ new/openldap-2.4.54/doc/guide/admin/guide.html 2020-10-12 21:34:48.000000000 +0200 @@ -23,7 +23,7 @@ <DIV CLASS="title"> <H1 CLASS="doc-title">OpenLDAP Software 2.4 Administrator's Guide</H1> <ADDRESS CLASS="doc-author">The OpenLDAP Project <<A HREF="http://www.openldap.org/">http://www.openldap.org/</A>></ADDRESS> -<ADDRESS CLASS="doc-modified">7 September 2020</ADDRESS> +<ADDRESS CLASS="doc-modified">12 October 2020</ADDRESS> <BR CLEAR="All"> </DIV> <DIV CLASS="contents"> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openldap-2.4.53/servers/slapd/back-mdb/search.c new/openldap-2.4.54/servers/slapd/back-mdb/search.c --- old/openldap-2.4.53/servers/slapd/back-mdb/search.c 2020-09-07 17:13:36.000000000 +0200 +++ new/openldap-2.4.54/servers/slapd/back-mdb/search.c 2020-10-12 20:27:28.000000000 +0200 @@ -719,6 +719,7 @@ } wwctx.flag = 0; + wwctx.nentries = 0; /* If we're running in our own read txn */ if ( moi == &opinfo ) { cb.sc_writewait = mdb_writewait; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openldap-2.4.53/servers/slapd/back-monitor/back-monitor.h new/openldap-2.4.54/servers/slapd/back-monitor/back-monitor.h --- old/openldap-2.4.53/servers/slapd/back-monitor/back-monitor.h 2020-09-07 17:13:36.000000000 +0200 +++ new/openldap-2.4.54/servers/slapd/back-monitor/back-monitor.h 2020-10-12 20:27:28.000000000 +0200 @@ -72,6 +72,7 @@ /* NOTE: flags with 0xF0000000U mask are reserved for subsystem internals */ struct monitor_callback_t *mp_cb; /* callback sequence */ + void *mp_private; } monitor_entry_t; struct entry_limbo_t; /* in init.c */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openldap-2.4.53/servers/slapd/back-monitor/database.c new/openldap-2.4.54/servers/slapd/back-monitor/database.c --- old/openldap-2.4.53/servers/slapd/back-monitor/database.c 2020-09-07 17:13:36.000000000 +0200 +++ new/openldap-2.4.54/servers/slapd/back-monitor/database.c 2020-10-12 20:27:28.000000000 +0200 @@ -345,6 +345,7 @@ mp->mp_info = ms; mp->mp_flags = ms->mss_flags | MONITOR_F_SUB; + mp->mp_private = be; if ( monitor_cache_add( mi, e ) ) { Debug( LDAP_DEBUG_ANY, @@ -446,31 +447,13 @@ mp = ( monitor_entry_t * )e_database->e_private; for ( i = -1, ep = &mp->mp_children; *ep; i++ ) { - Attribute *a; - - a = attr_find( (*ep)->e_attrs, slap_schema.si_ad_namingContexts ); - if ( a ) { - int j, k; - - /* FIXME: RFC 4512 defines namingContexts without an - * equality matching rule, making comparisons - * like this one tricky. We use a_vals and - * be_suffix instead for now. - */ - for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ ) { - for ( k = 0; !BER_BVISNULL( &be->be_suffix[ k ] ); k++ ) { - if ( dn_match( &a->a_vals[ j ], - &be->be_suffix[ k ] ) ) { - rc = 0; - goto done; - } - } - } - } - mp = ( monitor_entry_t * )(*ep)->e_private; assert( mp != NULL ); + if ( mp->mp_private == be->bd_self ) { + rc = 0; + goto done; + } ep = &mp->mp_next; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openldap-2.4.53/servers/slapd/overlays/accesslog.c new/openldap-2.4.54/servers/slapd/overlays/accesslog.c --- old/openldap-2.4.53/servers/slapd/overlays/accesslog.c 2020-09-07 17:13:36.000000000 +0200 +++ new/openldap-2.4.54/servers/slapd/overlays/accesslog.c 2020-10-12 20:27:28.000000000 +0200 @@ -691,6 +691,7 @@ op->o_callback = &nullsc; op->o_csn = pd.csn; op->o_dont_replicate = 1; + op->o_csn = slap_empty_bv; for (i=0; i<pd.used; i++) { op->o_req_dn = pd.dn[i]; @@ -2296,9 +2297,167 @@ return 0; } +enum { start = 0 }; + +static int +check_rdntime_syntax (struct berval *val, + int *parts, + struct berval *fraction) +{ + /* + * GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) + * GeneralizedTime supports leap seconds, UTCTime does not. + */ + static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 }; + static const int mdays[2][12] = { + /* non-leap years */ + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + /* leap years */ + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } + }; + char *p, *e; + int part, c, c1, c2, tzoffset, leapyear = 0; + + p = val->bv_val; + e = p + val->bv_len; + + for (part = start; part < 7 && p < e; part++) { + c1 = *p; + if (!ASCII_DIGIT(c1)) { + break; + } + p++; + if (p == e) { + return LDAP_INVALID_SYNTAX; + } + c = *p++; + if (!ASCII_DIGIT(c)) { + return LDAP_INVALID_SYNTAX; + } + c += c1 * 10 - '0' * 11; + if ((part | 1) == 3) { + --c; + if (c < 0) { + return LDAP_INVALID_SYNTAX; + } + } + if (c >= ceiling[part]) { + if (! (c == 60 && part == 6 && start == 0)) + return LDAP_INVALID_SYNTAX; + } + parts[part] = c; + } + if (part < 5 + start) { + return LDAP_INVALID_SYNTAX; + } + for (; part < 9; part++) { + parts[part] = 0; + } + + /* leapyear check for the Gregorian calendar (year>1581) */ + if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) { + leapyear = 1; + } + + if (parts[3] >= mdays[leapyear][parts[2]]) { + return LDAP_INVALID_SYNTAX; + } + + if (start == 0) { + fraction->bv_val = p; + fraction->bv_len = 0; + if (p < e && (*p == '.' || *p == ',')) { + char *end_num; + while (++p < e && ASCII_DIGIT(*p)) { + /* EMPTY */; + } + if (p - fraction->bv_val == 1) { + return LDAP_INVALID_SYNTAX; + } + +#if 0 /* don't truncate trailing zeros */ + for (end_num = p; end_num[-1] == '0'; --end_num) { + /* EMPTY */; + } + c = end_num - fraction->bv_val; +#else + c = p - fraction->bv_val; +#endif + if (c != 1) fraction->bv_len = c; + } + } + + if (p == e) { + /* no time zone */ + return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS; + } + + tzoffset = *p++; + switch (tzoffset) { + case 'Z': + /* UTC */ + break; + default: + return LDAP_INVALID_SYNTAX; + } + + return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS; +} + +static int +rdnTimestampValidate( + Syntax *syntax, + struct berval *in ) +{ + int parts[9]; + struct berval fraction; + return check_rdntime_syntax(in, parts, &fraction); +} + +static int +rdnTimestampNormalize( + slap_mask_t usage, + Syntax *syntax, + MatchingRule *mr, + struct berval *val, + struct berval *normalized, + void *ctx ) +{ + int parts[9], rc; + unsigned int len; + struct berval fraction; + + rc = check_rdntime_syntax(val, parts, &fraction); + if (rc != LDAP_SUCCESS) { + return rc; + } + + len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len; + normalized->bv_val = slap_sl_malloc( len + 1, ctx ); + if ( BER_BVISNULL( normalized ) ) { + return LBER_ERROR_MEMORY; + } + + sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d", + parts[0], parts[1], parts[2] + 1, parts[3] + 1, + parts[4], parts[5], parts[6] ); + if ( !BER_BVISEMPTY( &fraction ) ) { + memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1, + fraction.bv_val, fraction.bv_len ); + normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.'; + } + strcpy( normalized->bv_val + len-1, "Z" ); + normalized->bv_len = len; + + return LDAP_SUCCESS; +} + + int accesslog_initialize() { int i, rc; + Syntax *rdnTimestampSyntax; + MatchingRule *rdnTimestampMatch; accesslog.on_bi.bi_type = "accesslog"; accesslog.on_bi.bi_db_init = accesslog_db_init; @@ -2365,6 +2524,25 @@ #endif } + /* Inject custom normalizer for reqStart/reqEnd */ + rdnTimestampMatch = ch_malloc( sizeof( MatchingRule )); + rdnTimestampSyntax = ch_malloc( sizeof( Syntax )); + *rdnTimestampMatch = *ad_reqStart->ad_type->sat_equality; + rdnTimestampMatch->smr_normalize = rdnTimestampNormalize; + *rdnTimestampSyntax = *ad_reqStart->ad_type->sat_syntax; + rdnTimestampSyntax->ssyn_validate = rdnTimestampValidate; + ad_reqStart->ad_type->sat_equality = rdnTimestampMatch; + ad_reqStart->ad_type->sat_syntax = rdnTimestampSyntax; + + rdnTimestampMatch = ch_malloc( sizeof( MatchingRule )); + rdnTimestampSyntax = ch_malloc( sizeof( Syntax )); + *rdnTimestampMatch = *ad_reqStart->ad_type->sat_equality; + rdnTimestampMatch->smr_normalize = rdnTimestampNormalize; + *rdnTimestampSyntax = *ad_reqStart->ad_type->sat_syntax; + rdnTimestampSyntax->ssyn_validate = rdnTimestampValidate; + ad_reqEnd->ad_type->sat_equality = rdnTimestampMatch; + ad_reqEnd->ad_type->sat_syntax = rdnTimestampSyntax; + for ( i=0; locs[i].ot; i++ ) { int code; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openldap-2.4.53/servers/slapd/overlays/syncprov.c new/openldap-2.4.54/servers/slapd/overlays/syncprov.c --- old/openldap-2.4.53/servers/slapd/overlays/syncprov.c 2020-09-07 17:13:36.000000000 +0200 +++ new/openldap-2.4.54/servers/slapd/overlays/syncprov.c 2020-10-12 20:27:28.000000000 +0200 @@ -117,7 +117,6 @@ /* Session log data */ typedef struct slog_entry { - struct slog_entry *se_next; struct berval se_uuid; struct berval se_csn; int se_sid; @@ -131,9 +130,8 @@ int sl_num; int sl_size; int sl_playing; - slog_entry *sl_head; - slog_entry *sl_tail; - ldap_pvt_thread_mutex_t sl_mutex; + Avlnode *sl_entries; + ldap_pvt_thread_rdwr_t sl_mutex; } sessionlog; /* The main state for this overlay */ @@ -402,6 +400,25 @@ return ber_bvcmp( &m1->mt_dn, &m2->mt_dn ); } +static int +syncprov_sessionlog_cmp( const void *l, const void *r ) +{ + const slog_entry *left = l, *right = r; + int ret = ber_bvcmp( &left->se_csn, &right->se_csn ); + if ( !ret ) + ret = ber_bvcmp( &left->se_uuid, &right->se_uuid ); + /* Only time we have two modifications with same CSN is when we detect a + * rename during replication. + * We invert the test here because LDAP_REQ_MODDN is + * numerically greater than LDAP_REQ_MODIFY but we + * want it to occur first. + */ + if ( !ret ) + ret = right->se_tag - left->se_tag; + + return ret; +} + /* syncprov_findbase: * finds the true DN of the base of a search (with alias dereferencing) and * checks to make sure the base entry doesn't get replaced with a different @@ -1577,6 +1594,7 @@ syncprov_info_t *si = on->on_bi.bi_private; sessionlog *sl; slog_entry *se; + int rc; sl = si->si_logs; { @@ -1586,24 +1604,20 @@ * state with respect to such operations, so we ignore them and * wipe out anything in the log if we see them. */ - ldap_pvt_thread_mutex_lock( &sl->sl_mutex ); + ldap_pvt_thread_rdwr_wlock( &sl->sl_mutex ); /* can only do this if no one else is reading the log at the moment */ - if (!sl->sl_playing) { - while ( se = sl->sl_head ) { - sl->sl_head = se->se_next; - ch_free( se ); + if ( !sl->sl_playing ) { + tavl_free( sl->sl_entries, (AVL_FREE)ch_free ); + sl->sl_num = 0; + sl->sl_entries = NULL; } - sl->sl_tail = NULL; - sl->sl_num = 0; - } - ldap_pvt_thread_mutex_unlock( &sl->sl_mutex ); + ldap_pvt_thread_rdwr_wunlock( &sl->sl_mutex ); return; } /* Allocate a record. UUIDs are not NUL-terminated. */ - se = ch_malloc( sizeof( slog_entry ) + opc->suuid.bv_len + + se = ch_malloc( sizeof( slog_entry ) + opc->suuid.bv_len + op->o_csn.bv_len + 1 ); - se->se_next = NULL; se->se_tag = op->o_tag; se->se_uuid.bv_val = (char *)(&se[1]); @@ -1616,7 +1630,7 @@ se->se_csn.bv_len = op->o_csn.bv_len; se->se_sid = slap_parse_csn_sid( &se->se_csn ); - ldap_pvt_thread_mutex_lock( &sl->sl_mutex ); + ldap_pvt_thread_rdwr_wlock( &sl->sl_mutex ); if ( LogTest( LDAP_DEBUG_SYNC ) ) { char uuidstr[40] = {}; if ( !BER_BVISEMPTY( &opc->suuid ) ) { @@ -1628,25 +1642,7 @@ "adding csn=%s to sessionlog, uuid=%s\n", op->o_log_prefix, se->se_csn.bv_val, uuidstr ); } - if ( sl->sl_head ) { - /* Keep the list in csn order. */ - if ( ber_bvcmp( &sl->sl_tail->se_csn, &se->se_csn ) <= 0 ) { - sl->sl_tail->se_next = se; - sl->sl_tail = se; - } else { - slog_entry **sep; - - for ( sep = &sl->sl_head; *sep; sep = &(*sep)->se_next ) { - if ( ber_bvcmp( &se->se_csn, &(*sep)->se_csn ) < 0 ) { - se->se_next = *sep; - *sep = se; - break; - } - } - } - } else { - sl->sl_head = se; - sl->sl_tail = se; + if ( !sl->sl_entries ) { if ( !sl->sl_mincsn ) { sl->sl_numcsns = 1; sl->sl_mincsn = ch_malloc( 2*sizeof( struct berval )); @@ -1656,35 +1652,40 @@ BER_BVZERO( &sl->sl_mincsn[1] ); } } + rc = tavl_insert( &sl->sl_entries, se, syncprov_sessionlog_cmp, avl_dup_error ); + assert( rc == LDAP_SUCCESS ); sl->sl_num++; - if (!sl->sl_playing) { - while ( sl->sl_num > sl->sl_size ) { - int i; - se = sl->sl_head; - sl->sl_head = se->se_next; - Debug( LDAP_DEBUG_SYNC, "%s syncprov_add_slog: " - "expiring csn=%s from sessionlog (sessionlog size=%d)\n", - op->o_log_prefix, se->se_csn.bv_val, sl->sl_num ); - for ( i=0; i<sl->sl_numcsns; i++ ) - if ( sl->sl_sids[i] >= se->se_sid ) - break; - if ( i == sl->sl_numcsns || sl->sl_sids[i] != se->se_sid ) { + if ( !sl->sl_playing && sl->sl_num > sl->sl_size ) { + Avlnode *edge = tavl_end( sl->sl_entries, TAVL_DIR_LEFT ); + while ( sl->sl_num > sl->sl_size ) { + int i; + Avlnode *next = tavl_next( edge, TAVL_DIR_RIGHT ); + se = edge->avl_data; Debug( LDAP_DEBUG_SYNC, "%s syncprov_add_slog: " - "adding csn=%s to mincsn\n", - op->o_log_prefix, se->se_csn.bv_val, 0 ); - slap_insert_csn_sids( (struct sync_cookie *)sl, - i, se->se_sid, &se->se_csn ); - } else { - Log4( LDAP_DEBUG_SYNC, ldap_syslog_level, "%s syncprov_add_slog: " - "updating mincsn for sid=%d csn=%s to %s\n", - op->o_log_prefix, se->se_sid, sl->sl_mincsn[i].bv_val, se->se_csn.bv_val ); - ber_bvreplace( &sl->sl_mincsn[i], &se->se_csn ); + "expiring csn=%s from sessionlog (sessionlog size=%d)\n", + op->o_log_prefix, se->se_csn.bv_val, sl->sl_num ); + for ( i=0; i<sl->sl_numcsns; i++ ) + if ( sl->sl_sids[i] >= se->se_sid ) + break; + if ( i == sl->sl_numcsns || sl->sl_sids[i] != se->se_sid ) { + Debug( LDAP_DEBUG_SYNC, "%s syncprov_add_slog: " + "adding csn=%s to mincsn\n", + op->o_log_prefix, se->se_csn.bv_val, 0 ); + slap_insert_csn_sids( (struct sync_cookie *)sl, + i, se->se_sid, &se->se_csn ); + } else { + Log4( LDAP_DEBUG_SYNC, ldap_syslog_level, "%s syncprov_add_slog: " + "updating mincsn for sid=%d csn=%s to %s\n", + op->o_log_prefix, se->se_sid, sl->sl_mincsn[i].bv_val, se->se_csn.bv_val ); + ber_bvreplace( &sl->sl_mincsn[i], &se->se_csn ); + } + tavl_delete( &sl->sl_entries, se, syncprov_sessionlog_cmp ); + ch_free( se ); + edge = next; + sl->sl_num--; } - ch_free( se ); - sl->sl_num--; } - } - ldap_pvt_thread_mutex_unlock( &sl->sl_mutex ); + ldap_pvt_thread_rdwr_wunlock( &sl->sl_mutex ); } } @@ -1701,17 +1702,18 @@ /* enter with sl->sl_mutex locked, release before returning */ static void syncprov_playlog( Operation *op, SlapReply *rs, sessionlog *sl, - sync_control *srs, BerVarray ctxcsn, int numcsns, int *sids ) + sync_control *srs, BerVarray ctxcsn, int numcsns, int *sids, + struct berval *mincsn ) { slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; - slog_entry *se; int i, j, ndel, num, nmods, mmods; + Avlnode *entry; char cbuf[LDAP_PVT_CSNSTR_BUFSIZE]; BerVarray uuids; struct berval delcsn[2]; if ( !sl->sl_num ) { - ldap_pvt_thread_mutex_unlock( &sl->sl_mutex ); + ldap_pvt_thread_rdwr_wunlock( &sl->sl_mutex ); return; } @@ -1719,7 +1721,7 @@ i = 0; nmods = 0; sl->sl_playing++; - ldap_pvt_thread_mutex_unlock( &sl->sl_mutex ); + ldap_pvt_thread_rdwr_wunlock( &sl->sl_mutex ); uuids = op->o_tmpalloc( (num+1) * sizeof( struct berval ) + num * UUID_LEN, op->o_tmpmemctx ); @@ -1729,23 +1731,31 @@ delcsn[0].bv_val = cbuf; BER_BVZERO(&delcsn[1]); + ldap_pvt_thread_rdwr_rlock( &sl->sl_mutex ); /* Make a copy of the relevant UUIDs. Put the Deletes up front * and everything else at the end. Do this first so we can - * unlock the list mutex. + * let the write side manage the sessionlog again. */ - Debug( LDAP_DEBUG_SYNC, "srs csn %s\n", - srs->sr_state.ctxcsn[0].bv_val, 0, 0 ); - for ( se=sl->sl_head; se; se=se->se_next ) { + assert( sl->sl_entries ); + + /* Find first relevant log entry. If greater than mincsn, backtrack one entry */ + { + slog_entry te = {0}; + te.se_csn = *mincsn; + entry = tavl_find3( sl->sl_entries, &te, syncprov_sessionlog_cmp, &ndel ); + } + if ( ndel > 0 && entry ) + entry = tavl_next( entry, TAVL_DIR_LEFT ); + /* if none, just start at beginning */ + if ( !entry ) + entry = tavl_end( sl->sl_entries, TAVL_DIR_LEFT ); + + do { + slog_entry *se = entry->avl_data; int k; - if ( LogTest( LDAP_DEBUG_SYNC ) ) { - char uuidstr[40]; - lutil_uuidstr_from_normalized( se->se_uuid.bv_val, se->se_uuid.bv_len, - uuidstr, 40 ); - Log4( LDAP_DEBUG_SYNC, ldap_syslog_level, "%s syncprov_playlog: " - "log entry tag=%lu uuid=%s cookie=%s\n", - op->o_log_prefix, se->se_tag, uuidstr, se->se_csn.bv_val ); - } + /* Make sure writes can still make progress */ + ldap_pvt_thread_rdwr_runlock( &sl->sl_mutex ); ndel = 1; for ( k=0; k<srs->sr_state.numcsns; k++ ) { if ( se->se_sid == srs->sr_state.sids[k] ) { @@ -1754,8 +1764,7 @@ } } if ( ndel <= 0 ) { - Debug( LDAP_DEBUG_SYNC, "%s syncprov_playlog: " - "cmp %d, too old\n", op->o_log_prefix, ndel, 0 ); + ldap_pvt_thread_rdwr_rlock( &sl->sl_mutex ); continue; } ndel = 0; @@ -1768,6 +1777,7 @@ if ( ndel > 0 ) { Debug( LDAP_DEBUG_SYNC, "%s syncprov_playlog: " "cmp %d, too new\n", op->o_log_prefix, ndel, 0 ); + ldap_pvt_thread_rdwr_rlock( &sl->sl_mutex ); break; } if ( se->se_tag == LDAP_REQ_DELETE ) { @@ -1777,8 +1787,10 @@ delcsn[0].bv_len = se->se_csn.bv_len; delcsn[0].bv_val[delcsn[0].bv_len] = '\0'; } else { - if ( se->se_tag == LDAP_REQ_ADD ) + if ( se->se_tag == LDAP_REQ_ADD ) { + ldap_pvt_thread_rdwr_rlock( &sl->sl_mutex ); continue; + } nmods++; j = num - nmods; } @@ -1787,7 +1799,7 @@ uuids[j].bv_len = UUID_LEN; if ( LogTest( LDAP_DEBUG_SYNC ) ) { - char uuidstr[40]; + char uuidstr[40] = {}; lutil_uuidstr_from_normalized( uuids[j].bv_val, uuids[j].bv_len, uuidstr, 40 ); Log4( LDAP_DEBUG_SYNC, ldap_syslog_level, "%s syncprov_playlog: " @@ -1795,10 +1807,12 @@ op->o_log_prefix, se->se_tag == LDAP_REQ_DELETE ? "deleted" : "modified", uuidstr, delcsn[0].bv_len ? delcsn[0].bv_val : "(null)" ); } - } - ldap_pvt_thread_mutex_lock( &sl->sl_mutex ); + ldap_pvt_thread_rdwr_rlock( &sl->sl_mutex ); + } while ( (entry = tavl_next( entry, TAVL_DIR_RIGHT )) != NULL ); + ldap_pvt_thread_rdwr_runlock( &sl->sl_mutex ); + ldap_pvt_thread_rdwr_wlock( &sl->sl_mutex ); sl->sl_playing--; - ldap_pvt_thread_mutex_unlock( &sl->sl_mutex ); + ldap_pvt_thread_rdwr_wunlock( &sl->sl_mutex ); ndel = i; @@ -2838,7 +2852,7 @@ sl=si->si_logs; if ( sl ) { int do_play = 0; - ldap_pvt_thread_mutex_lock( &sl->sl_mutex ); + ldap_pvt_thread_rdwr_wlock( &sl->sl_mutex ); /* Are there any log entries, and is the consumer state * present in the session log? */ @@ -2865,9 +2879,9 @@ if ( do_play ) { do_present = 0; /* mutex is unlocked in playlog */ - syncprov_playlog( op, rs, sl, srs, ctxcsn, numcsns, sids ); + syncprov_playlog( op, rs, sl, srs, ctxcsn, numcsns, sids, &mincsn ); } else { - ldap_pvt_thread_mutex_unlock( &sl->sl_mutex ); + ldap_pvt_thread_rdwr_wunlock( &sl->sl_mutex ); } } /* Is the CSN still present in the database? */ @@ -3197,7 +3211,7 @@ sl = si->si_logs; if ( !sl ) { sl = ch_calloc( 1, sizeof( sessionlog )); - ldap_pvt_thread_mutex_init( &sl->sl_mutex ); + ldap_pvt_thread_rdwr_init( &sl->sl_mutex ); si->si_logs = sl; } sl->sl_size = size; @@ -3225,6 +3239,49 @@ return NULL; } +static int +syncprov_db_ocallback( + Operation *op, + SlapReply *rs +) +{ + if ( rs->sr_type == REP_SEARCH && rs->sr_err == LDAP_SUCCESS ) { + if ( rs->sr_entry->e_name.bv_len ) + op->o_callback->sc_private = (void *)1; + } + return LDAP_SUCCESS; +} + +/* ITS#9015 see if the DB is really empty */ +static void * +syncprov_db_otask2( + void *ptr +) +{ + Operation *op = ptr; + SlapReply rs = {REP_RESULT}; + slap_callback cb = {0}; + int rc; + + cb.sc_response = syncprov_db_ocallback; + + op->o_managedsait = SLAP_CONTROL_CRITICAL; + op->o_callback = &cb; + op->o_tag = LDAP_REQ_SEARCH; + op->ors_scope = LDAP_SCOPE_SUBTREE; + op->ors_limit = NULL; + op->ors_slimit = 1; + op->ors_tlimit = SLAP_NO_LIMIT; + op->ors_attrs = slap_anlist_no_attrs; + op->ors_attrsonly = 1; + op->ors_deref = LDAP_DEREF_NEVER; + op->ors_filter = &generic_filter; + op->ors_filterstr = generic_filterstr; + rc = op->o_bd->be_search( op, &rs ); + if ( rc == LDAP_SIZELIMIT_EXCEEDED || cb.sc_private ) + op->ors_slimit = 2; + return NULL; +} /* Read any existing contextCSN from the underlying db. * Then search for any entries newer than that. If no value exists, @@ -3317,6 +3374,20 @@ /* If the DB is genuinely empty, don't generate one either. */ goto out; } + if ( !si->si_contextdn.bv_len ) { + ldap_pvt_thread_t tid; + /* a glue entry here with no contextCSN might mean an empty DB. + * we need to search for children, to be sure. + */ + op->o_req_dn = be->be_suffix[0]; + op->o_req_ndn = be->be_nsuffix[0]; + op->o_bd->bd_info = (BackendInfo *)on->on_info; + ldap_pvt_thread_create( &tid, 0, syncprov_db_otask2, op ); + ldap_pvt_thread_join( tid, NULL ); + if ( op->ors_slimit == 1 ) + goto out; + } + csn.bv_val = csnbuf; csn.bv_len = sizeof( csnbuf ); slap_get_csn( op, &csn, 0 ); @@ -3445,19 +3516,14 @@ if ( si ) { if ( si->si_logs ) { sessionlog *sl = si->si_logs; - slog_entry *se = sl->sl_head; - while ( se ) { - slog_entry *se_next = se->se_next; - ch_free( se ); - se = se_next; - } + tavl_free( sl->sl_entries, (AVL_FREE)ch_free ); if ( sl->sl_mincsn ) ber_bvarray_free( sl->sl_mincsn ); if ( sl->sl_sids ) ch_free( sl->sl_sids ); - ldap_pvt_thread_mutex_destroy(&si->si_logs->sl_mutex); + ldap_pvt_thread_rdwr_destroy(&si->si_logs->sl_mutex); ch_free( si->si_logs ); } if ( si->si_ctxcsn ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openldap-2.4.53/servers/slapd/syncrepl.c new/openldap-2.4.54/servers/slapd/syncrepl.c --- old/openldap-2.4.53/servers/slapd/syncrepl.c 2020-09-07 17:13:36.000000000 +0200 +++ new/openldap-2.4.54/servers/slapd/syncrepl.c 2020-10-12 20:27:28.000000000 +0200 @@ -44,6 +44,12 @@ LDAP_LIST_ENTRY(nonpresent_entry) npe_link; }; +typedef struct cookie_vals { + struct berval *cv_vals; + int *cv_sids; + int cv_num; +} cookie_vals; + typedef struct cookie_state { ldap_pvt_thread_mutex_t cs_mutex; ldap_pvt_thread_cond_t cs_cond; @@ -118,6 +124,7 @@ int si_got; int si_strict_refresh; /* stop listening during fallback refresh */ int si_too_old; + int si_is_configdb; ber_int_t si_msgid; Avlnode *si_presentlist; LDAP *si_ld; @@ -137,7 +144,7 @@ static int presentlist_free( Avlnode *av ); static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct sync_cookie *, int ); static int syncrepl_message_to_op( - syncinfo_t *, Operation *, LDAPMessage * ); + syncinfo_t *, Operation *, LDAPMessage *, int ); static int syncrepl_message_to_entry( syncinfo_t *, Operation *, LDAPMessage *, Modifications **, Entry **, int, struct berval* ); @@ -845,22 +852,19 @@ } ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex ); } + } - ch_free( si->si_syncCookie.octet_str.bv_val ); - slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str, - si->si_syncCookie.ctxcsn, si->si_syncCookie.rid, - si->si_syncCookie.sid ); - } else { - /* ITS#6367: recreate the cookie so it has our SID, not our peer's */ - ch_free( si->si_syncCookie.octet_str.bv_val ); - BER_BVZERO( &si->si_syncCookie.octet_str ); - /* Look for contextCSN from syncprov overlay. */ - check_syncprov( op, si ); - if ( BER_BVISNULL( &si->si_syncCookie.octet_str )) - slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str, - si->si_syncCookie.ctxcsn, si->si_syncCookie.rid, - si->si_syncCookie.sid ); - } + if ( !cmdline_cookie_found ) { + /* ITS#6367: recreate the cookie so it has our SID, not our peer's */ + ch_free( si->si_syncCookie.octet_str.bv_val ); + BER_BVZERO( &si->si_syncCookie.octet_str ); + /* Look for contextCSN from syncprov overlay. */ + check_syncprov( op, si ); + if ( BER_BVISNULL( &si->si_syncCookie.octet_str )) + slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str, + si->si_syncCookie.ctxcsn, si->si_syncCookie.rid, + si->si_syncCookie.sid ); + } si->si_refreshDone = 0; Debug( LDAP_DEBUG_SYNC, "do_syncrep1: %s starting refresh (sending cookie=%s)\n", @@ -921,6 +925,45 @@ return match; } +#define CV_CSN_OK 0 +#define CV_CSN_OLD 1 +#define CV_SID_NEW 2 + +static int +check_csn_age( + syncinfo_t *si, + struct berval *dn, + struct berval *csn, + int sid, + cookie_vals *cv, + int *slot ) +{ + int i, rc = CV_SID_NEW; + + for ( i =0; i<cv->cv_num; i++ ) { +#ifdef CHATTY_SYNCLOG + Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN for sid %d: %s\n", + si->si_ridtxt, i, cv->cv_vals[i].bv_val ); +#endif + /* new SID */ + if ( sid < cv->cv_sids[i] ) + break; + if ( cv->cv_sids[i] == sid ) { + if ( ber_bvcmp( csn, &cv->cv_vals[i] ) <= 0 ) { + dn->bv_val[dn->bv_len] = '\0'; + Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s (%s)\n", + si->si_ridtxt, csn->bv_val, dn->bv_val ); + return CV_CSN_OLD; + } + rc = CV_CSN_OK; + break; + } + } + if ( slot ) + *slot = i; + return rc; +} + #define SYNC_TIMEOUT 0 #define SYNC_SHUTDOWN -100 #define SYNC_ERROR -101 @@ -928,6 +971,26 @@ #define SYNC_PAUSED -103 static int +get_pmutex( + syncinfo_t *si +) +{ + if ( !si->si_is_configdb ) { + ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_pmutex ); + } else { + /* avoid deadlock when replicating cn=config */ + while ( ldap_pvt_thread_mutex_trylock( &si->si_cookieState->cs_pmutex )) { + if ( slapd_shutdown ) + return SYNC_SHUTDOWN; + if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool )) + ldap_pvt_thread_yield(); + } + } + + return 0; +} + +static int do_syncrep2( Operation *op, syncinfo_t *si ) @@ -1057,71 +1120,40 @@ { slap_parse_sync_cookie( &syncCookie, NULL ); if ( syncCookie.ctxcsn ) { - int i, sid = slap_parse_csn_sid( syncCookie.ctxcsn ); + int i, slot, sid = slap_parse_csn_sid( syncCookie.ctxcsn ); check_syncprov( op, si ); ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex ); - for ( i =0; i<si->si_cookieState->cs_num; i++ ) { -#ifdef CHATTY_SYNCLOG - Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN for sid %d: %s\n", - si->si_ridtxt, i, si->si_cookieState->cs_vals[i].bv_val ); -#endif - /* new SID */ - if ( sid < si->si_cookieState->cs_sids[i] ) - break; - if ( si->si_cookieState->cs_sids[i] == sid ) { - if ( ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_vals[i] ) <= 0 ) { - bdn.bv_val[bdn.bv_len] = '\0'; - Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s (%s)\n", - si->si_ridtxt, syncCookie.ctxcsn->bv_val, bdn.bv_val ); - si->si_too_old = 1; - ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex ); - ldap_controls_free( rctrls ); - rc = 0; - goto done; - } - si->si_too_old = 0; - break; - } - } + i = check_csn_age( si, &bdn, syncCookie.ctxcsn, sid, (cookie_vals *)&si->si_cookieState->cs_vals, NULL ); ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex ); + if ( i == CV_CSN_OLD ) { + si->si_too_old = 1; + ldap_controls_free( rctrls ); + rc = 0; + goto done; + } + si->si_too_old = 0; /* check pending CSNs too */ - while ( ldap_pvt_thread_mutex_trylock( &si->si_cookieState->cs_pmutex )) { - if ( slapd_shutdown ) { - rc = SYNC_SHUTDOWN; - goto done; - } - if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool )) - ldap_pvt_thread_yield(); - } + if (( rc = get_pmutex( si ))) + goto done; - for ( i =0; i<si->si_cookieState->cs_pnum; i++ ) { - if ( sid < si->si_cookieState->cs_psids[i] ) - break; - if ( si->si_cookieState->cs_psids[i] == sid ) { - if ( ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_pvals[i] ) <= 0 ) { - ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex ); - bdn.bv_val[bdn.bv_len] = '\0'; - Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN pending, ignoring %s (%s)\n", - si->si_ridtxt, syncCookie.ctxcsn->bv_val, bdn.bv_val ); - ldap_controls_free( rctrls ); - rc = 0; - goto done; - } - ber_bvreplace( &si->si_cookieState->cs_pvals[i], - syncCookie.ctxcsn ); - break; - } - } + i = check_csn_age( si, &bdn, syncCookie.ctxcsn, sid, (cookie_vals *)&si->si_cookieState->cs_pvals, &slot ); + if ( i == CV_CSN_OK ) { + ber_bvreplace( &si->si_cookieState->cs_pvals[slot], + syncCookie.ctxcsn ); + } else if ( i == CV_CSN_OLD ) { + ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex ); + ldap_controls_free( rctrls ); + rc = 0; + goto done; + } else { /* new SID, add it */ - if ( i == si->si_cookieState->cs_pnum || - sid != si->si_cookieState->cs_psids[i] ) { slap_insert_csn_sids( (struct sync_cookie *)&si->si_cookieState->cs_pvals, - i, sid, syncCookie.ctxcsn ); + slot, sid, syncCookie.ctxcsn ); } assert( punlock < 0 ); - punlock = i; + punlock = slot; } else if (si->si_too_old) { bdn.bv_val[bdn.bv_len] = '\0'; Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring (%s)\n", @@ -1137,7 +1169,7 @@ rc = 0; if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) { modlist = NULL; - if ( ( rc = syncrepl_message_to_op( si, op, msg ) ) == LDAP_SUCCESS && + if ( ( rc = syncrepl_message_to_op( si, op, msg, punlock < 0 ) ) == LDAP_SUCCESS && syncCookie.ctxcsn ) { rc = syncrepl_updateCookie( si, op, &syncCookie, 0 ); @@ -1164,12 +1196,18 @@ } else if ( ( rc = syncrepl_message_to_entry( si, op, msg, &modlist, &entry, syncstate, syncUUID ) ) == LDAP_SUCCESS ) { + if ( punlock < 0 ) { + if (( rc = get_pmutex( si ))) + goto done; + } if ( ( rc = syncrepl_entry( si, op, entry, &modlist, syncstate, syncUUID, syncCookie.ctxcsn ) ) == LDAP_SUCCESS && syncCookie.ctxcsn ) { rc = syncrepl_updateCookie( si, op, &syncCookie, 0 ); } + if ( punlock < 0 ) + ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex ); } if ( punlock >= 0 ) { /* on failure, revert pending CSN */ @@ -1918,8 +1956,6 @@ if ( !mod || ad != mod->sml_desc || op != mod->sml_op ) { mod = (Modifications *) ch_malloc( sizeof( Modifications ) ); - if ( op == LDAP_MOD_ADD && is_at_single_value( ad->ad_type )) - op = LDAP_MOD_REPLACE; mod->sml_flags = 0; mod->sml_op = op; mod->sml_next = NULL; @@ -1929,6 +1965,10 @@ mod->sml_nvalues = NULL; mod->sml_numvals = 0; + /* Keep 'op' to reflect what we read out from accesslog */ + if ( op == LDAP_MOD_ADD && is_at_single_value( ad->ad_type )) + mod->sml_op = LDAP_MOD_REPLACE; + *modtail = mod; modtail = &mod->sml_next; } @@ -1973,7 +2013,10 @@ modlist->sml_desc == slap_schema.si_ad_modifyTimestamp || modlist->sml_desc == slap_schema.si_ad_entryCSN ) continue; - if ( modlist->sml_op == LDAP_MOD_REPLACE ) { + if ( modlist->sml_values == NULL && modlist->sml_op == LDAP_MOD_REPLACE ) { + /* ITS#9359 This adds no values, just change to a delete op */ + modlist->sml_op = LDAP_MOD_DELETE; + } else if ( modlist->sml_op == LDAP_MOD_REPLACE ) { mod = op->o_tmpalloc( sizeof(Modifications), op->o_tmpmemctx ); mod->sml_desc = modlist->sml_desc; mod->sml_values = NULL; @@ -2193,30 +2236,17 @@ return SLAP_CB_CONTINUE; { - int i, sid; - sid = slap_parse_csn_sid( &mod->sml_nvalues[0] ); + int sid = slap_parse_csn_sid( &mod->sml_nvalues[0] ); ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex ); - for ( i =0; i<si->si_cookieState->cs_num; i++ ) { -#ifdef CHATTY_SYNCLOG - Debug( LDAP_DEBUG_SYNC, "syncrepl_op_modify: %s CSN for sid %d: %s\n", - si->si_ridtxt, i, si->si_cookieState->cs_vals[i].bv_val ); -#endif - /* new SID */ - if ( sid < si->si_cookieState->cs_sids[i] ) - break; - if ( si->si_cookieState->cs_sids[i] == sid ) { - if ( ber_bvcmp( &mod->sml_nvalues[0], &si->si_cookieState->cs_vals[i] ) <= 0 ) { - Debug( LDAP_DEBUG_SYNC, "syncrepl_op_modify: %s entryCSN too old, ignoring %s (%s)\n", - si->si_ridtxt, mod->sml_nvalues[0].bv_val, op->o_req_dn.bv_val ); - ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex ); - slap_graduate_commit_csn( op ); - /* tell accesslog this was a failure */ - rs->sr_err = LDAP_TYPE_OR_VALUE_EXISTS; - return LDAP_SUCCESS; - } - } - } + rc = check_csn_age( si, &op->o_req_dn, &mod->sml_nvalues[0], + sid, (cookie_vals *)&si->si_cookieState->cs_vals, NULL ); ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex ); + if ( rc == CV_CSN_OLD ) { + slap_graduate_commit_csn( op ); + /* tell accesslog this was a failure */ + rs->sr_err = LDAP_TYPE_OR_VALUE_EXISTS; + return LDAP_SUCCESS; + } } rc = overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on ); @@ -2224,12 +2254,20 @@ Attribute *a; const char *text; a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN ); - value_match( &match, slap_schema.si_ad_entryCSN, - slap_schema.si_ad_entryCSN->ad_type->sat_ordering, - SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, - &mod->sml_nvalues[0], &a->a_nvals[0], &text ); + if ( a ) { + value_match( &match, slap_schema.si_ad_entryCSN, + slap_schema.si_ad_entryCSN->ad_type->sat_ordering, + SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + &mod->sml_nvalues[0], &a->a_nvals[0], &text ); + } else { + /* no entryCSN? shouldn't happen. assume mod is newer. */ + match = 1; + } overlay_entry_release_ov( op, e, 0, on ); + } else { + return SLAP_CB_CONTINUE; } + /* equal? Should never happen */ if ( match == 0 ) { slap_graduate_commit_csn( op ); @@ -2393,7 +2431,8 @@ syncrepl_message_to_op( syncinfo_t *si, Operation *op, - LDAPMessage *msg + LDAPMessage *msg, + int do_lock ) { BerElement *ber = NULL; @@ -2412,7 +2451,7 @@ prdn = BER_BVNULL, nrdn = BER_BVNULL, psup = BER_BVNULL, nsup = BER_BVNULL; int rc, deleteOldRdn = 0, freeReqDn = 0; - int do_graduate = 0; + int do_graduate = 0, do_unlock = 0; if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) { Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s " @@ -2525,6 +2564,12 @@ goto done; } + if ( do_lock ) { + if (( rc = get_pmutex( si ))) + goto done; + do_unlock = 1; + } + op->o_callback = &cb; slap_op_time( &op->o_time, &op->o_tincr ); @@ -2560,9 +2605,19 @@ } else { rc = op->o_bd->be_add( op, &rs ); Debug( LDAP_DEBUG_SYNC, - "syncrepl_message_to_op: %s be_add %s (%d)\n", + "syncrepl_message_to_op: %s be_add %s (%d)\n", si->si_ridtxt, op->o_req_dn.bv_val, rc ); do_graduate = 0; + if ( rc == LDAP_ALREADY_EXISTS ) { + Attribute *a = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN ); + struct berval *vals; + if ( a && backend_attribute( op, NULL, &op->o_req_ndn, + slap_schema.si_ad_entryCSN, &vals, ACL_READ ) == LDAP_SUCCESS ) { + if ( ber_bvcmp( &vals[0], &a->a_vals[0] ) >= 0 ) + rc = LDAP_SUCCESS; + ber_bvarray_free_x( vals, op->o_tmpmemctx ); + } + } } if ( e == op->ora_e ) be_entry_release_w( op, op->ora_e ); @@ -2637,12 +2692,17 @@ Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC, "syncrepl_message_to_op: %s be_delete %s (%d)\n", si->si_ridtxt, op->o_req_dn.bv_val, rc ); + /* silently ignore this */ + if ( rc == LDAP_NO_SUCH_OBJECT ) + rc = LDAP_SUCCESS; do_graduate = 0; break; } done: if ( do_graduate ) slap_graduate_commit_csn( op ); + if ( do_unlock ) + ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex ); op->o_bd = si->si_be; op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx ); BER_BVZERO( &op->o_csn ); @@ -5606,6 +5666,8 @@ LDAP_LIST_INIT( &si->si_nonpresentlist ); ldap_pvt_thread_mutex_init( &si->si_mutex ); + si->si_is_configdb = strcmp( c->be->be_suffix[0].bv_val, "cn=config" ) == 0; + rc = parse_syncrepl_line( c, si ); if ( rc == 0 ) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/openldap-2.4.53/tests/scripts/test063-delta-multiprovider new/openldap-2.4.54/tests/scripts/test063-delta-multiprovider --- old/openldap-2.4.53/tests/scripts/test063-delta-multiprovider 2020-09-07 17:13:36.000000000 +0200 +++ new/openldap-2.4.54/tests/scripts/test063-delta-multiprovider 2020-10-12 20:27:28.000000000 +0200 @@ -390,6 +390,8 @@ >> $TESTOUT 2>&1 << EOF dn: $THEDN changetype: modify +replace: employeetype +- add: description description: Stupendous