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 &lt;<A 
HREF="http://www.openldap.org/";>http://www.openldap.org/</A>&gt;</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
 


Reply via email to