X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fsyncrepl.c;h=0c4bb5b9787cb3b075e79e6d5dace216cc25810a;hb=ef7f5f5e32e6e0f129aee7fa1626017a7dadcb48;hp=11ad325d7603cb381a4415355545a036a1d5614a;hpb=6fc4af8a18e436d231f430cef87aae941d1c6fb6;p=openldap
diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c
index 11ad325d76..0c4bb5b978 100644
--- a/servers/slapd/syncrepl.c
+++ b/servers/slapd/syncrepl.c
@@ -2,7 +2,7 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software .
*
- * Copyright 2003-2009 The OpenLDAP Foundation.
+ * Copyright 2003-2011 The OpenLDAP Foundation.
* Portions Copyright 2003 by IBM Corporation.
* Portions Copyright 2003-2008 by Howard Chu, Symas Corporation.
* All rights reserved.
@@ -31,6 +31,11 @@
#include "ldap_rq.h"
+#ifdef ENABLE_REWRITE
+#include "rewrite.h"
+#define SUFFIXM_CTX ""
+#endif
+
struct nonpresent_entry {
struct berval *npe_name;
struct berval *npe_nname;
@@ -39,13 +44,19 @@ struct nonpresent_entry {
typedef struct cookie_state {
ldap_pvt_thread_mutex_t cs_mutex;
+ struct berval *cs_vals;
+ int *cs_sids;
int cs_num;
int cs_age;
int cs_ref;
- struct berval *cs_vals;
- int *cs_sids;
+
+ /* pending changes, not yet committed */
+ ldap_pvt_thread_mutex_t cs_pmutex;
+ struct berval *cs_pvals;
+ int *cs_psids;
+ int cs_pnum;
} cookie_state;
-
+
#define SYNCDATA_DEFAULT 0 /* entries are plain LDAP entries */
#define SYNCDATA_ACCESSLOG 1 /* entries are accesslog format */
#define SYNCDATA_CHANGELOG 2 /* entries are changelog format */
@@ -69,7 +80,9 @@ typedef struct syncinfo_s {
struct berval si_base;
struct berval si_logbase;
struct berval si_filterstr;
+ Filter *si_filter;
struct berval si_logfilterstr;
+ struct berval si_contextdn;
int si_scope;
int si_attrsonly;
char *si_anfile;
@@ -98,11 +111,16 @@ typedef struct syncinfo_s {
int si_syncdata;
int si_logstate;
int si_got;
+ int si_strict_refresh; /* stop listening during fallback refresh */
ber_int_t si_msgid;
Avlnode *si_presentlist;
LDAP *si_ld;
Connection *si_conn;
LDAP_LIST_HEAD(np, nonpresent_entry) si_nonpresentlist;
+#ifdef ENABLE_REWRITE
+ struct rewrite_info *si_rewrite;
+ struct berval si_suffixm;
+#endif
ldap_pvt_thread_mutex_t si_mutex;
} syncinfo_t;
@@ -119,10 +137,15 @@ static int syncrepl_entry(
Modifications**,int, struct berval*,
struct berval *cookieCSN );
static int syncrepl_updateCookie(
- syncinfo_t *, Operation *, struct berval *,
+ syncinfo_t *, Operation *,
struct sync_cookie * );
static struct berval * slap_uuidstr_from_normalized(
struct berval *, struct berval *, void * );
+static int syncrepl_add_glue_ancestors(
+ Operation* op, Entry *e );
+
+/* delta-mmr overlay handler */
+static int syncrepl_op_modify( Operation *op, SlapReply *rs );
/* callback functions */
static int dn_callback( Operation *, SlapReply * );
@@ -131,6 +154,36 @@ static int null_callback( Operation *, SlapReply * );
static AttributeDescription *sync_descs[4];
+/* delta-mmr */
+static AttributeDescription *ad_reqMod, *ad_reqDN;
+
+typedef struct logschema {
+ struct berval ls_dn;
+ struct berval ls_req;
+ struct berval ls_mod;
+ struct berval ls_newRdn;
+ struct berval ls_delRdn;
+ struct berval ls_newSup;
+} logschema;
+
+static logschema changelog_sc = {
+ BER_BVC("targetDN"),
+ BER_BVC("changeType"),
+ BER_BVC("changes"),
+ BER_BVC("newRDN"),
+ BER_BVC("deleteOldRDN"),
+ BER_BVC("newSuperior")
+};
+
+static logschema accesslog_sc = {
+ BER_BVC("reqDN"),
+ BER_BVC("reqType"),
+ BER_BVC("reqMod"),
+ BER_BVC("reqNewRDN"),
+ BER_BVC("reqDeleteOldRDN"),
+ BER_BVC("reqNewSuperior")
+};
+
static const char *
syncrepl_state2str( int state )
{
@@ -151,12 +204,35 @@ syncrepl_state2str( int state )
return "UNKNOWN";
}
+static slap_overinst syncrepl_ov;
+
static void
init_syncrepl(syncinfo_t *si)
{
int i, j, k, l, n;
char **attrs, **exattrs;
+ if ( !syncrepl_ov.on_bi.bi_type ) {
+ syncrepl_ov.on_bi.bi_type = "syncrepl";
+ syncrepl_ov.on_bi.bi_op_modify = syncrepl_op_modify;
+ overlay_register( &syncrepl_ov );
+ }
+
+ /* delta-MMR needs the overlay, nothing else does.
+ * This must happen before accesslog overlay is configured.
+ */
+ if ( si->si_syncdata &&
+ !overlay_is_inst( si->si_be, syncrepl_ov.on_bi.bi_type )) {
+ overlay_config( si->si_be, syncrepl_ov.on_bi.bi_type, -1, NULL, NULL );
+ if ( !ad_reqMod ) {
+ const char *text;
+ logschema *ls = &accesslog_sc;
+
+ slap_bv2ad( &ls->ls_mod, &ad_reqMod, &text );
+ slap_bv2ad( &ls->ls_dn, &ad_reqDN, &text );
+ }
+ }
+
if ( !sync_descs[0] ) {
sync_descs[0] = slap_schema.si_ad_objectClass;
sync_descs[1] = slap_schema.si_ad_structuralObjectClass;
@@ -310,33 +386,6 @@ init_syncrepl(syncinfo_t *si)
si->si_exattrs = exattrs;
}
-typedef struct logschema {
- struct berval ls_dn;
- struct berval ls_req;
- struct berval ls_mod;
- struct berval ls_newRdn;
- struct berval ls_delRdn;
- struct berval ls_newSup;
-} logschema;
-
-static logschema changelog_sc = {
- BER_BVC("targetDN"),
- BER_BVC("changeType"),
- BER_BVC("changes"),
- BER_BVC("newRDN"),
- BER_BVC("deleteOldRDN"),
- BER_BVC("newSuperior")
-};
-
-static logschema accesslog_sc = {
- BER_BVC("reqDN"),
- BER_BVC("reqType"),
- BER_BVC("reqMod"),
- BER_BVC("reqNewRDN"),
- BER_BVC("reqDeleteOldRDN"),
- BER_BVC("reqNewSuperior")
-};
-
static int
ldap_sync_search(
syncinfo_t *si,
@@ -447,7 +496,7 @@ check_syncprov(
AttributeName at[2];
Attribute a = {0};
Entry e = {0};
- SlapReply rs = {0};
+ SlapReply rs = {REP_SEARCH};
int i, j, changed = 0;
/* Look for contextCSN from syncprov overlay. If
@@ -458,8 +507,8 @@ check_syncprov(
*/
a.a_desc = slap_schema.si_ad_contextCSN;
e.e_attrs = &a;
- e.e_name = op->o_bd->be_suffix[0];
- e.e_nname = op->o_bd->be_nsuffix[0];
+ e.e_name = si->si_contextdn;
+ e.e_nname = si->si_contextdn;
at[0].an_name = a.a_desc->ad_cname;
at[0].an_desc = a.a_desc;
BER_BVZERO( &at[1].an_name );
@@ -540,6 +589,7 @@ check_syncprov(
slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
si->si_syncCookie.sid );
+ slap_parse_sync_cookie( &si->si_syncCookie, NULL );
}
ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
return changed;
@@ -578,8 +628,9 @@ do_syncrep1(
{
ber_len_t ssf; /* ITS#5403, 3864 LDAP_OPT_X_SASL_SSF probably ought
to use sasl_ssf_t but currently uses ber_len_t */
- ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf );
- op->o_sasl_ssf = ssf;
+ if ( ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf )
+ == LDAP_SUCCESS )
+ op->o_sasl_ssf = ssf;
}
op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
? op->o_sasl_ssf : op->o_tls_ssf;
@@ -600,7 +651,7 @@ do_syncrep1(
/* We've just started up, or the remote server hasn't sent us
* any meaningful state.
*/
- if ( BER_BVISNULL( &si->si_syncCookie.octet_str ) ) {
+ if ( !si->si_syncCookie.ctxcsn ) {
int i;
LDAP_STAILQ_FOREACH( sc, &slap_sync_cookie, sc_next ) {
@@ -627,7 +678,7 @@ do_syncrep1(
BerVarray csn = NULL;
void *ctx = op->o_tmpmemctx;
- op->o_req_ndn = op->o_bd->be_nsuffix[0];
+ op->o_req_ndn = si->si_contextdn;
op->o_req_dn = op->o_req_ndn;
/* try to read stored contextCSN */
@@ -640,6 +691,7 @@ do_syncrep1(
for (i=0; !BER_BVISNULL( &csn[i] ); i++);
si->si_cookieState->cs_num = i;
si->si_cookieState->cs_sids = slap_parse_csn_sids( csn, i, NULL );
+ slap_sort_csn_sids( csn, si->si_cookieState->cs_sids, i, NULL );
}
}
if ( si->si_cookieState->cs_num ) {
@@ -663,8 +715,15 @@ do_syncrep1(
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 );
}
si->si_refreshDone = 0;
@@ -731,39 +790,26 @@ do_syncrep2(
Operation *op,
syncinfo_t *si )
{
- LDAPControl **rctrls = NULL;
-
BerElementBuffer berbuf;
BerElement *ber = (BerElement *)&berbuf;
LDAPMessage *msg = NULL;
- char *retoid = NULL;
- struct berval *retdata = NULL;
-
- Entry *entry = NULL;
-
- int syncstate;
- struct berval syncUUID = BER_BVNULL;
struct sync_cookie syncCookie = { NULL };
struct sync_cookie syncCookie_req = { NULL };
- struct berval cookie = BER_BVNULL;
int rc,
err = LDAP_SUCCESS;
- ber_len_t len;
- struct berval *psub;
Modifications *modlist = NULL;
- int match, m;
+ int m;
struct timeval *tout_p = NULL;
struct timeval tout = { 0, 0 };
int refreshDeletes = 0;
- BerVarray syncUUIDs = NULL;
- ber_tag_t si_tag;
+ char empty[6] = "empty";
if ( slapd_shutdown ) {
rc = -2;
@@ -775,11 +821,9 @@ do_syncrep2(
Debug( LDAP_DEBUG_TRACE, "=>do_syncrep2 %s\n", si->si_ridtxt, 0, 0 );
- psub = &si->si_be->be_nsuffix[0];
-
slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
- if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
+ if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST && si->si_refreshDone ) {
tout_p = &tout;
} else {
tout_p = NULL;
@@ -788,7 +832,15 @@ do_syncrep2(
while ( ( rc = ldap_result( si->si_ld, si->si_msgid, LDAP_MSG_ONE,
tout_p, &msg ) ) > 0 )
{
- LDAPControl *rctrlp = NULL;
+ int match, punlock, syncstate;
+ struct berval *retdata, syncUUID, cookie = BER_BVNULL;
+ char *retoid;
+ LDAPControl **rctrls = NULL, *rctrlp = NULL;
+ BerVarray syncUUIDs;
+ ber_len_t len;
+ ber_tag_t si_tag;
+ Entry *entry;
+ struct berval bdn;
if ( slapd_shutdown ) {
rc = -2;
@@ -797,9 +849,14 @@ do_syncrep2(
switch( ldap_msgtype( msg ) ) {
case LDAP_RES_SEARCH_ENTRY:
ldap_get_entry_controls( si->si_ld, msg, &rctrls );
+ ldap_get_dn_ber( si->si_ld, msg, NULL, &bdn );
+ if (!bdn.bv_len) {
+ bdn.bv_val = empty;
+ bdn.bv_len = sizeof(empty)-1;
+ }
/* we can't work without the control */
if ( rctrls ) {
- LDAPControl **next;
+ LDAPControl **next = NULL;
/* NOTE: make sure we use the right one;
* a better approach would be to run thru
* the whole list and take care of all */
@@ -810,39 +867,52 @@ do_syncrep2(
rctrlp = ldap_control_find( LDAP_CONTROL_SYNC_STATE, rctrls, &next );
if ( next && ldap_control_find( LDAP_CONTROL_SYNC_STATE, next, NULL ) )
{
+ bdn.bv_val[bdn.bv_len] = '\0';
Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
"got search entry with multiple "
- "Sync State control\n", si->si_ridtxt, 0, 0 );
+ "Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val, 0 );
ldap_controls_free( rctrls );
rc = -1;
goto done;
}
}
if ( rctrlp == NULL ) {
+ bdn.bv_val[bdn.bv_len] = '\0';
Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
"got search entry without "
- "Sync State control\n", si->si_ridtxt, 0, 0 );
+ "Sync State control (%s)\n", si->si_ridtxt, bdn.bv_val, 0 );
rc = -1;
goto done;
}
ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
- ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID );
+ if ( ber_scanf( ber, "{em" /*"}"*/, &syncstate, &syncUUID )
+ == LBER_ERROR ) {
+ bdn.bv_val[bdn.bv_len] = '\0';
+ Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s malformed message (%s)\n",
+ si->si_ridtxt, bdn.bv_val, 0 );
+ ldap_controls_free( rctrls );
+ rc = -1;
+ goto done;
+ }
/* FIXME: what if syncUUID is NULL or empty?
* (happens with back-sql...) */
if ( BER_BVISEMPTY( &syncUUID ) ) {
+ bdn.bv_val[bdn.bv_len] = '\0';
Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
- "got empty syncUUID with LDAP_SYNC_%s\n",
+ "got empty syncUUID with LDAP_SYNC_%s (%s)\n",
si->si_ridtxt,
- syncrepl_state2str( syncstate ), 0 );
+ syncrepl_state2str( syncstate ), bdn.bv_val );
ldap_controls_free( rctrls );
rc = -1;
goto done;
}
+ punlock = -1;
if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
ber_scanf( ber, /*"{"*/ "m}", &cookie );
- Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
- BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
+ Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
+ si->si_ridtxt,
+ BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
if ( !BER_BVISNULL( &cookie ) ) {
ch_free( syncCookie.octet_str.bv_val );
@@ -853,16 +923,59 @@ do_syncrep2(
slap_parse_sync_cookie( &syncCookie, NULL );
if ( syncCookie.ctxcsn ) {
int i, sid = slap_parse_csn_sid( syncCookie.ctxcsn );
+ check_syncprov( op, si );
for ( i =0; isi_cookieState->cs_num; i++ ) {
- if ( si->si_cookieState->cs_sids[i] == sid &&
- ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_vals[i] ) <= 0 ) {
- Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s\n",
- si->si_ridtxt, syncCookie.ctxcsn->bv_val, 0 );
- ldap_controls_free( rctrls );
- rc = 0;
+ /* 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 );
+ ldap_controls_free( rctrls );
+ rc = 0;
+ goto done;
+ }
+ break;
+ }
+ }
+ /* check pending CSNs too */
+ while ( ldap_pvt_thread_mutex_trylock( &si->si_cookieState->cs_pmutex )) {
+ if ( slapd_shutdown ) {
+ rc = -2;
goto done;
}
+ if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool ))
+ ldap_pvt_thread_yield();
+ }
+ for ( i =0; isi_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 ) {
+ 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;
+ ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
+ goto done;
+ }
+ ber_bvreplace( &si->si_cookieState->cs_pvals[i],
+ syncCookie.ctxcsn );
+ break;
+ }
}
+ /* 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 );
+ }
+ assert( punlock < 0 );
+ punlock = i;
}
op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
}
@@ -873,7 +986,7 @@ do_syncrep2(
if ( ( rc = syncrepl_message_to_op( si, op, msg ) ) == LDAP_SUCCESS &&
syncCookie.ctxcsn )
{
- rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
+ rc = syncrepl_updateCookie( si, op, &syncCookie );
} else switch ( rc ) {
case LDAP_ALREADY_EXISTS:
case LDAP_NO_SUCH_OBJECT:
@@ -882,6 +995,13 @@ do_syncrep2(
rc = LDAP_SYNC_REFRESH_REQUIRED;
si->si_logstate = SYNCLOG_FALLBACK;
ldap_abandon_ext( si->si_ld, si->si_msgid, NULL, NULL );
+ bdn.bv_val[bdn.bv_len] = '\0';
+ Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s delta-sync lost sync on (%s), switching to REFRESH\n",
+ si->si_ridtxt, bdn.bv_val, 0 );
+ if (si->si_strict_refresh) {
+ slap_suspend_listeners();
+ connections_drop();
+ }
break;
default:
break;
@@ -893,9 +1013,25 @@ do_syncrep2(
syncstate, &syncUUID, syncCookie.ctxcsn ) ) == LDAP_SUCCESS &&
syncCookie.ctxcsn )
{
- rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
+ rc = syncrepl_updateCookie( si, op, &syncCookie );
}
}
+ if ( punlock >= 0 ) {
+ /* on failure, revert pending CSN */
+ if ( rc != LDAP_SUCCESS ) {
+ int i;
+ for ( i = 0; isi_cookieState->cs_num; i++ ) {
+ if ( si->si_cookieState->cs_sids[i] == si->si_cookieState->cs_psids[punlock] ) {
+ ber_bvreplace( &si->si_cookieState->cs_pvals[punlock],
+ &si->si_cookieState->cs_vals[i] );
+ break;
+ }
+ }
+ if ( i == si->si_cookieState->cs_num )
+ si->si_cookieState->cs_pvals[punlock].bv_val[0] = '\0';
+ }
+ ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
+ }
ldap_controls_free( rctrls );
if ( modlist ) {
slap_mods_free( modlist, 1 );
@@ -914,6 +1050,7 @@ do_syncrep2(
Debug( LDAP_DEBUG_SYNC,
"do_syncrep2: %s LDAP_RES_SEARCH_RESULT\n",
si->si_ridtxt, 0, 0 );
+ err = LDAP_OTHER; /* FIXME check parse result properly */
ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL,
&rctrls, 0 );
#ifdef LDAP_X_SYNC_REFRESH_REQUIRED
@@ -925,6 +1062,12 @@ do_syncrep2(
if ( err == LDAP_SYNC_REFRESH_REQUIRED ) {
if ( si->si_logstate == SYNCLOG_LOGGING ) {
si->si_logstate = SYNCLOG_FALLBACK;
+ Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s delta-sync lost sync, switching to REFRESH\n",
+ si->si_ridtxt, 0, 0 );
+ if (si->si_strict_refresh) {
+ slap_suspend_listeners();
+ connections_drop();
+ }
}
rc = err;
goto done;
@@ -935,7 +1078,7 @@ do_syncrep2(
si->si_ridtxt, err, ldap_err2string( err ) );
}
if ( rctrls ) {
- LDAPControl **next;
+ LDAPControl **next = NULL;
/* NOTE: make sure we use the right one;
* a better approach would be to run thru
* the whole list and take care of all */
@@ -961,8 +1104,9 @@ do_syncrep2(
if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
ber_scanf( ber, "m", &cookie );
- Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
- BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
+ Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
+ si->si_ridtxt,
+ BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
if ( !BER_BVISNULL( &cookie ) ) {
ch_free( syncCookie.octet_str.bv_val );
@@ -1013,19 +1157,21 @@ do_syncrep2(
}
if ( syncCookie.ctxcsn && match < 0 && err == LDAP_SUCCESS )
{
- rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
+ rc = syncrepl_updateCookie( si, op, &syncCookie );
}
if ( err == LDAP_SUCCESS
&& si->si_logstate == SYNCLOG_FALLBACK ) {
si->si_logstate = SYNCLOG_LOGGING;
rc = LDAP_SYNC_REFRESH_REQUIRED;
+ slap_resume_listeners();
} else {
rc = -2;
}
goto done;
- break;
case LDAP_RES_INTERMEDIATE:
+ retoid = NULL;
+ retdata = NULL;
rc = ldap_parse_intermediate( si->si_ld, msg,
&retoid, &retdata, NULL, 0 );
if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) {
@@ -1071,8 +1217,9 @@ do_syncrep2(
{
ber_scanf( ber, "m", &cookie );
- Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
- BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
+ Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
+ si->si_ridtxt,
+ BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
if ( !BER_BVISNULL( &cookie ) ) {
ch_free( syncCookie.octet_str.bv_val );
@@ -1094,6 +1241,9 @@ do_syncrep2(
si->si_refreshDone = 1;
}
ber_scanf( ber, /*"{"*/ "}" );
+ if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST &&
+ si->si_refreshDone )
+ tout_p = &tout;
break;
case LDAP_TAG_SYNC_ID_SET:
Debug( LDAP_DEBUG_SYNC,
@@ -1107,8 +1257,9 @@ do_syncrep2(
{
ber_scanf( ber, "m", &cookie );
- Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
- BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
+ Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
+ si->si_ridtxt,
+ BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
if ( !BER_BVISNULL( &cookie ) ) {
ch_free( syncCookie.octet_str.bv_val );
@@ -1126,6 +1277,7 @@ do_syncrep2(
{
ber_scanf( ber, "b", &refreshDeletes );
}
+ syncUUIDs = NULL;
ber_scanf( ber, "[W]", &syncUUIDs );
ber_scanf( ber, /*"{"*/ "}" );
if ( refreshDeletes ) {
@@ -1174,13 +1326,12 @@ do_syncrep2(
if ( syncCookie.ctxcsn )
{
- rc = syncrepl_updateCookie( si, op, psub, &syncCookie);
+ rc = syncrepl_updateCookie( si, op, &syncCookie);
}
}
ldap_memfree( retoid );
ber_bvfree( retdata );
- break;
} else {
Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
@@ -1188,7 +1339,6 @@ do_syncrep2(
si->si_ridtxt, rc, 0 );
ldap_memfree( retoid );
ber_bvfree( retdata );
- break;
}
break;
@@ -1215,6 +1365,7 @@ do_syncrep2(
}
if ( rc == -1 ) {
+ rc = LDAP_OTHER;
ldap_get_option( si->si_ld, LDAP_OPT_ERROR_NUMBER, &rc );
err = rc;
}
@@ -1256,7 +1407,7 @@ do_syncrepl(
int rc = LDAP_SUCCESS;
int dostop = 0;
ber_socket_t s;
- int i, defer = 1, fail = 0;
+ int i, defer = 1, fail = 0, freeinfo = 0;
Backend *be;
if ( si == NULL )
@@ -1274,8 +1425,9 @@ do_syncrepl(
ldap_pvt_thread_yield();
}
- if ( !si->si_ctype )
+ if ( si->si_ctype < 1 ) {
goto deleted;
+ }
switch( abs( si->si_type ) ) {
case LDAP_SYNC_REFRESH_ONLY:
@@ -1301,6 +1453,8 @@ do_syncrepl(
connection_fake_init( &conn, &opbuf, ctx );
op = &opbuf.ob_op;
+ /* o_connids must be unique for slap_graduate_commit_csn */
+ op->o_connid = SLAPD_SYNC_RID2SYNCCONN(si->si_rid);
op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
be = si->si_be;
@@ -1323,12 +1477,18 @@ do_syncrepl(
if ( SLAP_GLUE_SUBORDINATE( be ) && !overlay_is_inst( be, "syncprov" )) {
BackendDB * top_be = select_backend( &be->be_nsuffix[0], 1 );
if ( overlay_is_inst( top_be, "syncprov" ))
- si->si_wbe = select_backend( &be->be_nsuffix[0], 1 );
+ si->si_wbe = top_be;
else
si->si_wbe = be;
} else {
si->si_wbe = be;
}
+ if ( SLAP_SYNC_SUBENTRY( si->si_wbe )) {
+ build_new_dn( &si->si_contextdn, &si->si_wbe->be_nsuffix[0],
+ (struct berval *)&slap_ldapsync_cn_bv, NULL );
+ } else {
+ si->si_contextdn = si->si_wbe->be_nsuffix[0];
+ }
}
if ( !si->si_schemachecking )
op->o_no_schema_check = 1;
@@ -1338,6 +1498,11 @@ do_syncrepl(
si->si_refreshDelete = 0;
si->si_refreshPresent = 0;
+ if ( si->si_presentlist ) {
+ avl_free( si->si_presentlist, ch_free );
+ si->si_presentlist = NULL;
+ }
+
/* use main DB when retrieving contextCSN */
op->o_bd = si->si_wbe;
op->o_dn = op->o_bd->be_rootdn;
@@ -1362,7 +1527,11 @@ reload:
deleted:
/* We got deleted while running on cn=config */
- if ( !si->si_ctype ) {
+ if ( si->si_ctype < 1 ) {
+ if ( si->si_ctype == -1 ) {
+ si->si_ctype = 0;
+ freeinfo = 1;
+ }
if ( si->si_conn )
dostop = 1;
rc = -1;
@@ -1429,7 +1598,7 @@ deleted:
break;
}
- if ( !si->si_ctype
+ if ( si->si_ctype < 1
|| !si->si_retrynum || si->si_retrynum[i] == RETRYNUM_TAIL ) {
if ( si->si_re ) {
ldap_pvt_runqueue_remove( &slapd_rq, rtask );
@@ -1466,12 +1635,52 @@ deleted:
}
/* Do final delete cleanup */
- if ( !si->si_ctype ) {
+ if ( freeinfo ) {
syncinfo_free( si, 0 );
}
return NULL;
}
+#ifdef ENABLE_REWRITE
+static int
+syncrepl_rewrite_dn(
+ syncinfo_t *si,
+ struct berval *dn,
+ struct berval *sdn )
+{
+ char nul;
+ int rc;
+
+ nul = dn->bv_val[dn->bv_len];
+ dn->bv_val[dn->bv_len] = 0;
+ rc = rewrite( si->si_rewrite, SUFFIXM_CTX, dn->bv_val, &sdn->bv_val );
+ dn->bv_val[dn->bv_len] = nul;
+
+ if ( sdn->bv_val == dn->bv_val )
+ sdn->bv_val = NULL;
+ else if ( rc == REWRITE_REGEXEC_OK && sdn->bv_val )
+ sdn->bv_len = strlen( sdn->bv_val );
+ return rc;
+}
+#define REWRITE_VAL(si, ad, bv, bv2) \
+ BER_BVZERO( &bv2 ); \
+ if ( si->si_rewrite && ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName) \
+ syncrepl_rewrite_dn( si, &bv, &bv2); \
+ if ( BER_BVISNULL( &bv2 )) \
+ ber_dupbv( &bv2, &bv )
+#define REWRITE_DN(si, bv, bv2, dn, ndn) \
+ BER_BVZERO( &bv2 ); \
+ if (si->si_rewrite) \
+ syncrepl_rewrite_dn(si, &bv, &bv2); \
+ rc = dnPrettyNormal( NULL, bv2.bv_val ? &bv2 : &bv, &dn, &ndn, op->o_tmpmemctx ); \
+ ch_free(bv2.bv_val)
+#else
+#define REWRITE_VAL(si, ad, bv, bv2) ber_dupbv(&bv2, &bv)
+#define REWRITE_DN(si, bv, bv2, dn, ndn) \
+ rc = dnPrettyNormal( NULL, &bv, &dn, &ndn, op->o_tmpmemctx )
+#endif
+
+
static slap_verbmasks modops[] = {
{ BER_BVC("add"), LDAP_REQ_ADD },
{ BER_BVC("delete"), LDAP_REQ_DELETE },
@@ -1480,10 +1689,11 @@ static slap_verbmasks modops[] = {
{ BER_BVNULL, 0 }
};
-static Modifications *
+static int
syncrepl_accesslog_mods(
syncinfo_t *si,
- struct berval *vals
+ struct berval *vals,
+ struct Modifications **modres
)
{
char *colon;
@@ -1492,7 +1702,7 @@ syncrepl_accesslog_mods(
struct berval bv, bv2;
short op;
Modifications *mod = NULL, *modlist = NULL, **modtail;
- int i;
+ int i, rc = 0;
modtail = &modlist;
@@ -1509,7 +1719,13 @@ syncrepl_accesslog_mods(
bv.bv_len = colon - bv.bv_val;
if ( slap_bv2ad( &bv, &ad, &text ) ) {
/* Invalid */
- continue;
+ Debug( LDAP_DEBUG_ANY, "syncrepl_accesslog_mods: %s "
+ "Invalid attribute %s, %s\n",
+ si->si_ridtxt, bv.bv_val, text );
+ slap_mods_free( modlist, 1 );
+ modlist = NULL;
+ rc = -1;
+ break;
}
/* Ignore dynamically generated attrs */
@@ -1549,21 +1765,384 @@ syncrepl_accesslog_mods(
if ( colon[2] == ' ' ) {
bv.bv_val = colon + 3;
bv.bv_len = vals[i].bv_len - ( bv.bv_val - vals[i].bv_val );
- ber_dupbv( &bv2, &bv );
+ REWRITE_VAL( si, ad, bv, bv2 );
ber_bvarray_add( &mod->sml_values, &bv2 );
mod->sml_numvals++;
}
}
- return modlist;
+ *modres = modlist;
+ return rc;
}
-static Modifications *
+static int
syncrepl_changelog_mods(
syncinfo_t *si,
- struct berval *vals
+ struct berval *vals,
+ struct Modifications **modres
)
{
- return NULL; /* FIXME */
+ return -1; /* FIXME */
+}
+
+typedef struct OpExtraSync {
+ OpExtra oe;
+ syncinfo_t *oe_si;
+} OpExtraSync;
+
+/* Copy the original modlist, split Replace ops into Delete/Add,
+ * and drop mod opattrs since this modification is in the past.
+ */
+static Modifications *mods_dup( Operation *op, Modifications *modlist, int match )
+{
+ Modifications *mod, *modnew = NULL, *modtail = NULL;
+ int size;
+ for ( ; modlist; modlist = modlist->sml_next ) {
+ /* older ops */
+ if ( match < 0 ) {
+ if ( modlist->sml_desc == slap_schema.si_ad_modifiersName ||
+ modlist->sml_desc == slap_schema.si_ad_modifyTimestamp ||
+ modlist->sml_desc == slap_schema.si_ad_entryCSN )
+ continue;
+ 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;
+ mod->sml_nvalues = NULL;
+ mod->sml_op = LDAP_MOD_DELETE;
+ mod->sml_numvals = 0;
+ mod->sml_flags = 0;
+ if ( !modnew )
+ modnew = mod;
+ if ( modtail )
+ modtail->sml_next = mod;
+ modtail = mod;
+ }
+ }
+ if ( modlist->sml_numvals ) {
+ size = (modlist->sml_numvals+1) * sizeof(struct berval);
+ if ( modlist->sml_nvalues ) size *= 2;
+ } else {
+ size = 0;
+ }
+ size += sizeof(Modifications);
+ mod = op->o_tmpalloc( size, op->o_tmpmemctx );
+ if ( !modnew )
+ modnew = mod;
+ if ( modtail )
+ modtail->sml_next = mod;
+ modtail = mod;
+ mod->sml_desc = modlist->sml_desc;
+ mod->sml_numvals = modlist->sml_numvals;
+ mod->sml_flags = 0;
+ if ( modlist->sml_numvals ) {
+ int i;
+ mod->sml_values = (BerVarray)(mod+1);
+ for (i=0; isml_numvals; i++)
+ mod->sml_values[i] = modlist->sml_values[i];
+ BER_BVZERO(&mod->sml_values[i]);
+ if ( modlist->sml_nvalues ) {
+ mod->sml_nvalues = mod->sml_values + mod->sml_numvals + 1;
+ for (i=0; isml_numvals; i++)
+ mod->sml_nvalues[i] = modlist->sml_nvalues[i];
+ BER_BVZERO(&mod->sml_nvalues[i]);
+ } else {
+ mod->sml_nvalues = NULL;
+ }
+ } else {
+ mod->sml_values = NULL;
+ mod->sml_nvalues = NULL;
+ }
+ if ( match < 0 && modlist->sml_op == LDAP_MOD_REPLACE )
+ mod->sml_op = LDAP_MOD_ADD;
+ else
+ mod->sml_op = modlist->sml_op;
+ mod->sml_next = NULL;
+ }
+ return modnew;
+}
+
+typedef struct resolve_ctxt {
+ syncinfo_t *rx_si;
+ Modifications *rx_mods;
+} resolve_ctxt;
+
+static void
+compare_vals( Modifications *m1, Modifications *m2 )
+{
+ int i, j;
+ struct berval *bv1, *bv2;
+
+ if ( m2->sml_nvalues ) {
+ bv2 = m2->sml_nvalues;
+ bv1 = m1->sml_nvalues;
+ } else {
+ bv2 = m2->sml_values;
+ bv1 = m1->sml_values;
+ }
+ for ( j=0; jsml_numvals; j++ ) {
+ for ( i=0; isml_numvals; i++ ) {
+ if ( !ber_bvcmp( &bv1[i], &bv2[j] )) {
+ int k;
+ for ( k=i; ksml_numvals-1; k++ ) {
+ m1->sml_values[k] = m1->sml_values[k+1];
+ if ( m1->sml_nvalues )
+ m1->sml_nvalues[k] = m1->sml_nvalues[k+1];
+ }
+ BER_BVZERO(&m1->sml_values[k]);
+ if ( m1->sml_nvalues ) {
+ BER_BVZERO(&m1->sml_nvalues[k]);
+ }
+ m1->sml_numvals--;
+ i--;
+ }
+ }
+ }
+}
+
+static int
+syncrepl_resolve_cb( Operation *op, SlapReply *rs )
+{
+ if ( rs->sr_type == REP_SEARCH ) {
+ resolve_ctxt *rx = op->o_callback->sc_private;
+ Attribute *a = attr_find( rs->sr_entry->e_attrs, ad_reqMod );
+ if ( a ) {
+ Modifications *oldmods, *newmods, *m1, *m2, **prev;
+ oldmods = rx->rx_mods;
+ syncrepl_accesslog_mods( rx->rx_si, a->a_vals, &newmods );
+ for ( m2 = newmods; m2; m2=m2->sml_next ) {
+ for ( prev = &oldmods, m1 = *prev; m1; m1 = *prev ) {
+ if ( m1->sml_desc != m2->sml_desc ) {
+ prev = &m1->sml_next;
+ continue;
+ }
+ if ( m2->sml_op == LDAP_MOD_DELETE ||
+ m2->sml_op == LDAP_MOD_REPLACE ) {
+ int numvals = m2->sml_numvals;
+ if ( m2->sml_op == LDAP_MOD_REPLACE )
+ numvals = 0;
+ /* New delete All cancels everything */
+ if ( numvals == 0 ) {
+drop:
+ *prev = m1->sml_next;
+ op->o_tmpfree( m1, op->o_tmpmemctx );
+ continue;
+ }
+ if ( m1->sml_op == LDAP_MOD_DELETE ) {
+ if ( m1->sml_numvals == 0 ) {
+ /* turn this to SOFTDEL later */
+ m1->sml_flags = SLAP_MOD_INTERNAL;
+ } else {
+ compare_vals( m1, m2 );
+ if ( !m1->sml_numvals )
+ goto drop;
+ }
+ } else if ( m1->sml_op == LDAP_MOD_ADD ) {
+ compare_vals( m1, m2 );
+ if ( !m1->sml_numvals )
+ goto drop;
+ }
+ }
+
+ if ( m2->sml_op == LDAP_MOD_ADD ||
+ m2->sml_op == LDAP_MOD_REPLACE ) {
+ if ( m1->sml_op == LDAP_MOD_DELETE ) {
+ if ( !m1->sml_numvals ) goto drop;
+ compare_vals( m1, m2 );
+ if ( !m1->sml_numvals )
+ goto drop;
+ }
+ if ( m2->sml_desc->ad_type->sat_atype.at_single_value )
+ goto drop;
+ compare_vals( m1, m2 );
+ if ( !m1->sml_numvals )
+ goto drop;
+ }
+ prev = &m1->sml_next;
+ }
+ }
+ slap_mods_free( newmods, 1 );
+ }
+ }
+ return LDAP_SUCCESS;
+}
+
+typedef struct modify_ctxt {
+ Modifications *mx_orig;
+ Modifications *mx_free;
+} modify_ctxt;
+
+static int
+syncrepl_modify_cb( Operation *op, SlapReply *rs )
+{
+ slap_callback *sc = op->o_callback;
+ modify_ctxt *mx = sc->sc_private;
+ Modifications *ml;
+
+ op->orm_no_opattrs = 0;
+ op->orm_modlist = mx->mx_orig;
+ for ( ml = mx->mx_free; ml; ml = mx->mx_free ) {
+ mx->mx_free = ml->sml_next;
+ op->o_tmpfree( ml, op->o_tmpmemctx );
+ }
+ op->o_callback = sc->sc_next;
+ op->o_tmpfree( sc, op->o_tmpmemctx );
+ return SLAP_CB_CONTINUE;
+}
+
+static int
+syncrepl_op_modify( Operation *op, SlapReply *rs )
+{
+ slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
+ OpExtra *oex;
+ syncinfo_t *si;
+ Entry *e;
+ int rc, match = 0;
+ Modifications *mod, *newlist;
+
+ LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
+ if ( oex->oe_key == (void *)syncrepl_message_to_op )
+ break;
+ }
+ if ( !oex )
+ return SLAP_CB_CONTINUE;
+
+ si = ((OpExtraSync *)oex)->oe_si;
+
+ /* Check if entryCSN in modlist is newer than entryCSN in entry.
+ * We do it here because the op has been serialized by accesslog
+ * by the time we get here. If the CSN is new enough, just do the
+ * mod. If not, we need to resolve conflicts.
+ */
+
+ for ( mod = op->orm_modlist; mod; mod=mod->sml_next ) {
+ if ( mod->sml_desc == slap_schema.si_ad_entryCSN ) break;
+ }
+ /* FIXME: what should we do if entryCSN is missing from the mod? */
+ if ( !mod )
+ return SLAP_CB_CONTINUE;
+
+ rc = overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on );
+ if ( rc == 0 ) {
+ 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 );
+ overlay_entry_release_ov( op, e, 0, on );
+ }
+ /* equal? Should never happen */
+ if ( match == 0 )
+ return LDAP_SUCCESS;
+
+ /* mod is older: resolve conflicts...
+ * 1. Save/copy original modlist. Split Replace to Del/Add.
+ * 2. Find all mods to this reqDN newer than the mod stamp.
+ * 3. Resolve any mods in this request that affect attributes
+ * touched by newer mods.
+ * old new
+ * delete all delete all drop
+ * delete all delete X SOFTDEL
+ * delete X delete all drop
+ * delete X delete X drop
+ * delete X delete Y OK
+ * delete all add X drop
+ * delete X add X drop
+ * delete X add Y OK
+ * add X delete all drop
+ * add X delete X drop
+ * add X add X drop
+ * add X add Y if SV, drop else OK
+ *
+ * 4. Swap original modlist back in response callback so
+ * that accesslog logs the original mod.
+ *
+ * Even if the mod is newer, other out-of-order changes may
+ * have been committed, forcing us to tweak the modlist:
+ * 1. Save/copy original modlist.
+ * 2. Change deletes to soft deletes.
+ * 3. Change Adds of single-valued attrs to Replace.
+ */
+
+ newlist = mods_dup( op, op->orm_modlist, match );
+
+ /* mod is older */
+ if ( match < 0 ) {
+ Operation op2 = *op;
+ AttributeName an[2];
+ const char *text;
+ struct berval bv;
+ char *ptr;
+ Modifications *ml;
+ int size, rc;
+ SlapReply rs1 = {0};
+ resolve_ctxt rx;
+ slap_callback cb = { NULL, syncrepl_resolve_cb, NULL, NULL };
+
+ rx.rx_si = si;
+ rx.rx_mods = newlist;
+ cb.sc_private = ℞
+
+ op2.o_tag = LDAP_REQ_SEARCH;
+ op2.ors_scope = LDAP_SCOPE_SUBTREE;
+ op2.ors_deref = LDAP_DEREF_NEVER;
+ op2.o_req_dn = si->si_logbase;
+ op2.o_req_ndn = si->si_logbase;
+ op2.ors_tlimit = SLAP_NO_LIMIT;
+ op2.ors_slimit = SLAP_NO_LIMIT;
+ op2.ors_limit = NULL;
+ memset( an, 0, sizeof(an));
+ an[0].an_desc = ad_reqMod;
+ an[0].an_name = ad_reqMod->ad_cname;
+ op2.ors_attrs = an;
+ op2.ors_attrsonly = 0;
+
+ bv = mod->sml_nvalues[0];
+
+ size = sizeof("(&(entryCSN>=)(reqDN=))");
+ size += bv.bv_len + op->o_req_ndn.bv_len + si->si_logfilterstr.bv_len;
+ op2.ors_filterstr.bv_val = op->o_tmpalloc( size, op->o_tmpmemctx );
+ op2.ors_filterstr.bv_len = sprintf(op2.ors_filterstr.bv_val,
+ "(&(entryCSN>=%s)(reqDN=%s)%s)",
+ bv.bv_val, op->o_req_ndn.bv_val, si->si_logfilterstr.bv_val );
+ op2.ors_filter = str2filter_x( op, op2.ors_filterstr.bv_val );
+
+ op2.o_callback = &cb;
+ op2.o_bd = select_backend( &op2.o_req_ndn, 1 );
+ op2.o_bd->be_search( &op2, &rs1 );
+ newlist = rx.rx_mods;
+ }
+
+ {
+ slap_callback *sc = op->o_tmpalloc( sizeof(slap_callback) +
+ sizeof(modify_ctxt), op->o_tmpmemctx );
+ modify_ctxt *mx = (modify_ctxt *)(sc+1);
+ Modifications *ml;
+
+ sc->sc_response = syncrepl_modify_cb;
+ sc->sc_private = mx;
+ sc->sc_next = op->o_callback;
+ sc->sc_cleanup = NULL;
+ op->o_callback = sc;
+ op->orm_no_opattrs = 1;
+ mx->mx_orig = op->orm_modlist;
+ mx->mx_free = newlist;
+ for ( ml = newlist; ml; ml=ml->sml_next ) {
+ if ( ml->sml_flags == SLAP_MOD_INTERNAL ) {
+ ml->sml_flags = 0;
+ ml->sml_op = SLAP_MOD_SOFTDEL;
+ }
+ else if ( ml->sml_op == LDAP_MOD_DELETE )
+ ml->sml_op = SLAP_MOD_SOFTDEL;
+ else if ( ml->sml_op == LDAP_MOD_ADD &&
+ ml->sml_desc->ad_type->sat_atype.at_single_value )
+ ml->sml_op = LDAP_MOD_REPLACE;
+ }
+ op->orm_modlist = newlist;
+ op->o_csn = mod->sml_nvalues[0];
+ }
+ return SLAP_CB_CONTINUE;
}
static int
@@ -1584,7 +2163,7 @@ syncrepl_message_to_op(
size_t textlen = sizeof txtbuf;
struct berval bdn, dn = BER_BVNULL, ndn;
- struct berval bv, *bvals = NULL;
+ struct berval bv, bv2, *bvals = NULL;
struct berval rdn = BER_BVNULL, sup = BER_BVNULL,
prdn = BER_BVNULL, nrdn = BER_BVNULL,
psup = BER_BVNULL, nsup = BER_BVNULL;
@@ -1615,6 +2194,13 @@ syncrepl_message_to_op(
op->o_tag = LBER_DEFAULT;
op->o_bd = si->si_wbe;
+ if ( BER_BVISEMPTY( &bdn )) {
+ Debug( LDAP_DEBUG_ANY,
+ "syncrepl_message_to_op: %s got empty dn",
+ si->si_ridtxt, 0, 0 );
+ return LDAP_OTHER;
+ }
+
while (( rc = ldap_get_attribute_ber( si->si_ld, msg, ber, &bv, &bvals ) )
== LDAP_SUCCESS ) {
if ( bv.bv_val == NULL )
@@ -1622,7 +2208,16 @@ syncrepl_message_to_op(
if ( !ber_bvstrcasecmp( &bv, &ls->ls_dn ) ) {
bdn = bvals[0];
- dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
+ REWRITE_DN( si, bdn, bv2, dn, ndn );
+ if ( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY,
+ "syncrepl_message_to_op: %s "
+ "dn \"%s\" normalization failed (%d)",
+ si->si_ridtxt, bdn.bv_val, rc );
+ rc = -1;
+ ch_free( bvals );
+ goto done;
+ }
ber_dupbv( &op->o_req_dn, &dn );
ber_dupbv( &op->o_req_ndn, &ndn );
slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
@@ -1642,10 +2237,11 @@ syncrepl_message_to_op(
} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_mod ) ) {
/* Parse attribute into modlist */
if ( si->si_syncdata == SYNCDATA_ACCESSLOG ) {
- modlist = syncrepl_accesslog_mods( si, bvals );
+ rc = syncrepl_accesslog_mods( si, bvals, &modlist );
} else {
- modlist = syncrepl_changelog_mods( si, bvals );
+ rc = syncrepl_changelog_mods( si, bvals, &modlist );
}
+ if ( rc ) goto done;
} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_newRdn ) ) {
rdn = bvals[0];
} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_delRdn ) ) {
@@ -1708,9 +2304,20 @@ syncrepl_message_to_op(
if ( e == op->ora_e )
be_entry_release_w( op, op->ora_e );
} else {
+ OpExtraSync oes;
op->orm_modlist = modlist;
op->o_bd = si->si_wbe;
+ /* delta-mmr needs additional checks in syncrepl_op_modify */
+ if ( SLAP_MULTIMASTER( op->o_bd )) {
+ oes.oe.oe_key = (void *)syncrepl_message_to_op;
+ oes.oe_si = si;
+ LDAP_SLIST_INSERT_HEAD( &op->o_extra, &oes.oe, oe_next );
+ }
rc = op->o_bd->be_modify( op, &rs );
+ if ( SLAP_MULTIMASTER( op->o_bd )) {
+ LDAP_SLIST_REMOVE( &op->o_extra, &oes.oe, OpExtra, oe_next );
+ BER_BVZERO( &op->o_csn );
+ }
modlist = op->orm_modlist;
Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
"syncrepl_message_to_op: %s be_modify %s (%d)\n",
@@ -1729,9 +2336,9 @@ syncrepl_message_to_op(
goto done;
}
if ( !BER_BVISNULL( &sup ) ) {
- if ( dnPrettyNormal( NULL, &sup, &psup, &nsup, NULL ) ) {
+ REWRITE_DN( si, sup, bv2, psup, nsup );
+ if ( rc )
goto done;
- }
op->orr_newSup = &psup;
op->orr_nnewSup = ⊅
} else {
@@ -1821,7 +2428,7 @@ syncrepl_message_to_entry(
char txtbuf[SLAP_TEXT_BUFLEN];
size_t textlen = sizeof txtbuf;
- struct berval bdn = BER_BVNULL, dn, ndn;
+ struct berval bdn = BER_BVNULL, dn, ndn, bv2;
int rc, is_ctx;
*modlist = NULL;
@@ -1843,6 +2450,13 @@ syncrepl_message_to_entry(
return rc;
}
+ if ( BER_BVISEMPTY( &bdn ) && !BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "syncrepl_message_to_entry: %s got empty dn",
+ si->si_ridtxt, 0, 0 );
+ return LDAP_OTHER;
+ }
+
if ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_DELETE ) {
/* NOTE: this could be done even before decoding the DN,
* although encoding errors wouldn't be detected */
@@ -1854,7 +2468,21 @@ syncrepl_message_to_entry(
return -1;
}
- dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
+ REWRITE_DN( si, bdn, bv2, dn, ndn );
+ if ( rc != LDAP_SUCCESS ) {
+ /* One of the things that could happen is that the schema
+ * is not lined-up; this could result in unknown attributes.
+ * A value non conformant to the syntax should be unlikely,
+ * except when replicating between different versions
+ * of the software, or when syntax validation bugs are fixed
+ */
+ Debug( LDAP_DEBUG_ANY,
+ "syncrepl_message_to_entry: "
+ "%s dn \"%s\" normalization failed (%d)",
+ si->si_ridtxt, bdn.bv_val, rc );
+ return rc;
+ }
+
ber_dupbv( &op->o_req_dn, &dn );
ber_dupbv( &op->o_req_ndn, &ndn );
slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
@@ -1893,6 +2521,26 @@ syncrepl_message_to_entry(
mod->sml_nvalues = NULL;
mod->sml_numvals = 0; /* slap_mods_check will set this */
+#ifdef ENABLE_REWRITE
+ if (si->si_rewrite) {
+ AttributeDescription *ad = NULL;
+ slap_bv2ad( &tmp.sml_type, &ad, &text );
+ if ( ad ) {
+ mod->sml_desc = ad;
+ mod->sml_type = ad->ad_cname;
+ if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) {
+ int i;
+ for ( i = 0; tmp.sml_values[i].bv_val; i++ ) {
+ syncrepl_rewrite_dn( si, &tmp.sml_values[i], &bv2);
+ if ( !BER_BVISNULL( &bv2 )) {
+ ber_memfree( tmp.sml_values[i].bv_val );
+ tmp.sml_values[i] = bv2;
+ }
+ }
+ }
+ }
+ }
+#endif
*modtail = mod;
modtail = &mod->sml_next;
}
@@ -2032,9 +2680,6 @@ syncrepl_entry(
struct berval syncUUID_strrep = BER_BVNULL;
SlapReply rs_search = {REP_RESULT};
- SlapReply rs_delete = {REP_RESULT};
- SlapReply rs_add = {REP_RESULT};
- SlapReply rs_modify = {REP_RESULT};
Filter f = {0};
AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
int rc = LDAP_SUCCESS;
@@ -2107,8 +2752,16 @@ syncrepl_entry(
op->ors_deref = LDAP_DEREF_NEVER;
/* get the entry for this UUID */
- op->o_req_dn = si->si_base;
- op->o_req_ndn = si->si_base;
+#ifdef ENABLE_REWRITE
+ if ( si->si_rewrite ) {
+ op->o_req_dn = si->si_suffixm;
+ op->o_req_ndn = si->si_suffixm;
+ } else
+#endif
+ {
+ op->o_req_dn = si->si_base;
+ op->o_req_ndn = si->si_base;
+ }
op->o_time = slap_get_time();
op->ors_tlimit = SLAP_NO_LIMIT;
@@ -2173,6 +2826,7 @@ syncrepl_entry(
}
retry_add:;
if ( BER_BVISNULL( &dni.dn ) ) {
+ SlapReply rs_add = {REP_RESULT};
op->o_req_dn = entry->e_name;
op->o_req_ndn = entry->e_nname;
@@ -2210,7 +2864,7 @@ retry_add:;
case LDAP_ALREADY_EXISTS:
if ( retry ) {
Operation op2 = *op;
- SlapReply rs2 = { 0 };
+ SlapReply rs2 = { REP_RESULT };
slap_callback cb2 = { 0 };
op2.o_bd = be;
@@ -2260,6 +2914,7 @@ retry_add:;
struct berval noldp, newp;
Modifications *mod, **modtail, **ml, *m2;
int i, got_replace = 0, just_rename = 0;
+ SlapReply rs_modify = {REP_RESULT};
op->o_tag = LDAP_REQ_MODRDN;
dnRdn( &entry->e_name, &op->orr_newrdn );
@@ -2436,7 +3091,20 @@ retry_add:;
mod->sml_next = m2;
}
op->o_bd = si->si_wbe;
+retry_modrdn:;
+ rs_reinit( &rs_modify, REP_RESULT );
rc = op->o_bd->be_modrdn( op, &rs_modify );
+
+ /* NOTE: noSuchObject should result because the new superior
+ * has not been added yet (ITS#6472) */
+ if ( rc == LDAP_NO_SUCH_OBJECT && op->orr_nnewSup != NULL ) {
+ Operation op2 = *op;
+ rc = syncrepl_add_glue_ancestors( &op2, entry );
+ if ( rc == LDAP_SUCCESS ) {
+ goto retry_modrdn;
+ }
+ }
+
op->o_tmpfree( op->orr_nnewrdn.bv_val, op->o_tmpmemctx );
op->o_tmpfree( op->orr_newrdn.bv_val, op->o_tmpmemctx );
@@ -2455,6 +3123,8 @@ retry_add:;
slap_queue_csn( op, syncCSN );
}
if ( dni.mods ) {
+ SlapReply rs_modify = {REP_RESULT};
+
op->o_tag = LDAP_REQ_MODIFY;
op->orm_modlist = dni.mods;
op->orm_no_opattrs = 1;
@@ -2485,6 +3155,7 @@ retry_add:;
goto done;
case LDAP_SYNC_DELETE :
if ( !BER_BVISNULL( &dni.dn ) ) {
+ SlapReply rs_delete = {REP_RESULT};
op->o_req_dn = dni.dn;
op->o_req_ndn = dni.ndn;
op->o_tag = LDAP_REQ_DELETE;
@@ -2504,6 +3175,7 @@ retry_add:;
op->o_req_dn = pdn;
op->o_req_ndn = pdn;
op->o_callback = &cb;
+ rs_reinit( &rs_delete, REP_RESULT );
op->o_bd->be_delete( op, &rs_delete );
} else {
break;
@@ -2562,9 +3234,6 @@ syncrepl_del_nonpresent(
{
Backend* be = op->o_bd;
slap_callback cb = { NULL };
- SlapReply rs_search = {REP_RESULT};
- SlapReply rs_delete = {REP_RESULT};
- SlapReply rs_modify = {REP_RESULT};
struct nonpresent_entry *np_list, *np_prev;
int rc;
AttributeName an[2];
@@ -2572,8 +3241,16 @@ syncrepl_del_nonpresent(
struct berval pdn = BER_BVNULL;
struct berval csn;
- op->o_req_dn = si->si_base;
- op->o_req_ndn = si->si_base;
+#ifdef ENABLE_REWRITE
+ if ( si->si_rewrite ) {
+ op->o_req_dn = si->si_suffixm;
+ op->o_req_ndn = si->si_suffixm;
+ } else
+#endif
+ {
+ op->o_req_dn = si->si_base;
+ op->o_req_ndn = si->si_base;
+ }
cb.sc_response = nonpresent_callback;
cb.sc_private = si;
@@ -2603,6 +3280,8 @@ syncrepl_del_nonpresent(
si->si_refreshDelete |= NP_DELETE_ONE;
for (i=0; uuids[i].bv_val; i++) {
+ SlapReply rs_search = {REP_RESULT};
+
op->ors_slimit = 1;
uf.f_av_value = uuids[i];
filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
@@ -2614,6 +3293,7 @@ syncrepl_del_nonpresent(
Filter *cf, *of;
Filter mmf[2];
AttributeAssertion mmaa;
+ SlapReply rs_search = {REP_RESULT};
memset( &an[0], 0, 2 * sizeof( AttributeName ) );
an[0].an_name = slap_schema.si_ad_entryUUID->ad_cname;
@@ -2623,7 +3303,7 @@ syncrepl_del_nonpresent(
op->ors_tlimit = SLAP_NO_LIMIT;
op->ors_limit = NULL;
op->ors_attrsonly = 0;
- op->ors_filter = str2filter_x( op, si->si_filterstr.bv_val );
+ op->ors_filter = filter_dup( si->si_filter, op->o_tmpmemctx );
/* In multimaster, updates can continue to arrive while
* we're searching. Limit the search result to entries
* older than our newest cookie CSN.
@@ -2683,6 +3363,8 @@ syncrepl_del_nonpresent(
np_list = LDAP_LIST_FIRST( &si->si_nonpresentlist );
while ( np_list != NULL ) {
+ SlapReply rs_delete = {REP_RESULT};
+
LDAP_LIST_REMOVE( np_list, npe_link );
np_prev = np_list;
np_list = LDAP_LIST_NEXT( np_list, npe_link );
@@ -2698,6 +3380,7 @@ syncrepl_del_nonpresent(
si->si_ridtxt, op->o_req_dn.bv_val, rc );
if ( rs_delete.sr_err == LDAP_NOT_ALLOWED_ON_NONLEAF ) {
+ SlapReply rs_modify = {REP_RESULT};
Modifications mod1, mod2;
mod1.sml_op = LDAP_MOD_REPLACE;
mod1.sml_flags = 0;
@@ -2734,6 +3417,7 @@ syncrepl_del_nonpresent(
op->o_req_dn = pdn;
op->o_req_ndn = pdn;
op->o_callback = &cb;
+ rs_reinit( &rs_delete, REP_RESULT );
/* give it a root privil ? */
op->o_bd->be_delete( op, &rs_delete );
} else {
@@ -2762,21 +3446,20 @@ syncrepl_del_nonpresent(
return;
}
-int
-syncrepl_add_glue(
+static int
+syncrepl_add_glue_ancestors(
Operation* op,
Entry *e )
{
Backend *be = op->o_bd;
slap_callback cb = { NULL };
Attribute *a;
- int rc;
+ int rc = LDAP_SUCCESS;
int suffrdns;
int i;
struct berval dn = BER_BVNULL;
struct berval ndn = BER_BVNULL;
Entry *glue;
- SlapReply rs_add = {REP_RESULT};
struct berval ptr, nptr;
char *comma;
@@ -2834,6 +3517,8 @@ syncrepl_add_glue(
}
while ( ndn.bv_val > e->e_nname.bv_val ) {
+ SlapReply rs_add = {REP_RESULT};
+
glue = entry_alloc();
ber_dupbv( &glue->e_name, &dn );
ber_dupbv( &glue->e_nname, &ndn );
@@ -2897,6 +3582,34 @@ syncrepl_add_glue(
ndn.bv_len = e->e_nname.bv_len - (ndn.bv_val - e->e_nname.bv_val);
}
+ return rc;
+}
+
+int
+syncrepl_add_glue(
+ Operation* op,
+ Entry *e )
+{
+ slap_callback cb = { NULL };
+ int rc;
+ Backend *be = op->o_bd;
+ SlapReply rs_add = {REP_RESULT};
+
+ rc = syncrepl_add_glue_ancestors( op, e );
+ switch ( rc ) {
+ case LDAP_SUCCESS:
+ case LDAP_ALREADY_EXISTS:
+ break;
+
+ default:
+ return rc;
+ }
+
+ op->o_tag = LDAP_REQ_ADD;
+ op->o_callback = &cb;
+ cb.sc_response = null_callback;
+ cb.sc_private = NULL;
+
op->o_req_dn = e->e_name;
op->o_req_ndn = e->e_nname;
op->ora_e = e;
@@ -2915,17 +3628,17 @@ static int
syncrepl_updateCookie(
syncinfo_t *si,
Operation *op,
- struct berval *pdn,
struct sync_cookie *syncCookie )
{
Backend *be = op->o_bd;
Modifications mod;
struct berval first = BER_BVNULL;
+ struct sync_cookie sc;
#ifdef CHECK_CSN
Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax;
#endif
- int rc, i, j;
+ int rc, i, j, changed = 0;
ber_len_t len;
slap_callback cb = { NULL };
@@ -2950,51 +3663,55 @@ syncrepl_updateCookie(
#endif
/* clone the cookieState CSNs so we can Replace the whole thing */
- mod.sml_numvals = si->si_cookieState->cs_num;
- mod.sml_values = op->o_tmpalloc(( mod.sml_numvals+1 )*sizeof(struct berval), op->o_tmpmemctx );
- for ( i=0; isi_cookieState->cs_vals[i];
- BER_BVZERO( &mod.sml_values[i] );
+ sc.numcsns = si->si_cookieState->cs_num;
+ if ( sc.numcsns ) {
+ ber_bvarray_dup_x( &sc.ctxcsn, si->si_cookieState->cs_vals, NULL );
+ sc.sids = ch_malloc( sc.numcsns * sizeof(int));
+ for ( i=0; isi_cookieState->cs_sids[i];
+ } else {
+ sc.ctxcsn = NULL;
+ sc.sids = NULL;
+ }
/* find any CSNs in the syncCookie that are newer than the cookieState */
for ( i=0; inumcsns; i++ ) {
- for ( j=0; jsi_cookieState->cs_num; j++ ) {
- if ( syncCookie->sids[i] != si->si_cookieState->cs_sids[j] )
+ for ( j=0; jsids[i] < sc.sids[j] )
+ break;
+ if ( syncCookie->sids[i] != sc.sids[j] )
continue;
len = syncCookie->ctxcsn[i].bv_len;
- if ( len > si->si_cookieState->cs_vals[j].bv_len )
- len = si->si_cookieState->cs_vals[j].bv_len;
+ if ( len > sc.ctxcsn[j].bv_len )
+ len = sc.ctxcsn[j].bv_len;
if ( memcmp( syncCookie->ctxcsn[i].bv_val,
- si->si_cookieState->cs_vals[j].bv_val, len ) > 0 ) {
- mod.sml_values[j] = syncCookie->ctxcsn[i];
- if ( BER_BVISNULL( &first ) ) {
- first = syncCookie->ctxcsn[i];
-
- } else if ( memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 )
- {
+ sc.ctxcsn[j].bv_val, len ) > 0 ) {
+ ber_bvreplace( &sc.ctxcsn[j], &syncCookie->ctxcsn[i] );
+ changed = 1;
+ if ( BER_BVISNULL( &first ) ||
+ memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 ) {
first = syncCookie->ctxcsn[i];
}
}
break;
}
/* there was no match for this SID, it's a new CSN */
- if ( j == si->si_cookieState->cs_num ) {
- mod.sml_values = op->o_tmprealloc( mod.sml_values,
- ( mod.sml_numvals+2 )*sizeof(struct berval), op->o_tmpmemctx );
- mod.sml_values[mod.sml_numvals++] = syncCookie->ctxcsn[i];
- BER_BVZERO( &mod.sml_values[mod.sml_numvals] );
- if ( BER_BVISNULL( &first ) ) {
- first = syncCookie->ctxcsn[i];
- } else if ( memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 )
- {
+ if ( j == sc.numcsns ||
+ syncCookie->sids[i] != sc.sids[j] ) {
+ slap_insert_csn_sids( &sc, j, syncCookie->sids[i],
+ &syncCookie->ctxcsn[i] );
+ if ( BER_BVISNULL( &first ) ||
+ memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 ) {
first = syncCookie->ctxcsn[i];
}
+ changed = 1;
}
}
/* Should never happen, ITS#5065 */
- if ( BER_BVISNULL( &first )) {
+ if ( BER_BVISNULL( &first ) || !changed ) {
ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
- op->o_tmpfree( mod.sml_values, op->o_tmpmemctx );
+ ber_bvarray_free( sc.ctxcsn );
+ ch_free( sc.sids );
return 0;
}
op->o_bd = si->si_wbe;
@@ -3006,35 +3723,50 @@ syncrepl_updateCookie(
cb.sc_private = si;
op->o_callback = &cb;
- op->o_req_dn = op->o_bd->be_suffix[0];
- op->o_req_ndn = op->o_bd->be_nsuffix[0];
+ op->o_req_dn = si->si_contextdn;
+ op->o_req_ndn = si->si_contextdn;
/* update contextCSN */
op->o_dont_replicate = 1;
+ mod.sml_numvals = sc.numcsns;
+ mod.sml_values = sc.ctxcsn;
+
op->orm_modlist = &mod;
op->orm_no_opattrs = 1;
rc = op->o_bd->be_modify( op, &rs_modify );
+
+ if ( rs_modify.sr_err == LDAP_NO_SUCH_OBJECT &&
+ SLAP_SYNC_SUBENTRY( op->o_bd )) {
+ const char *text;
+ char txtbuf[SLAP_TEXT_BUFLEN];
+ size_t textlen = sizeof txtbuf;
+ Entry *e = slap_create_context_csn_entry( op->o_bd, NULL );
+ rs_reinit( &rs_modify, REP_RESULT );
+ rc = slap_mods2entry( &mod, &e, 0, 1, &text, txtbuf, textlen);
+ op->ora_e = e;
+ rc = op->o_bd->be_add( op, &rs_modify );
+ if ( e == op->ora_e )
+ be_entry_release_w( op, op->ora_e );
+ }
+
op->orm_no_opattrs = 0;
op->o_dont_replicate = 0;
if ( rs_modify.sr_err == LDAP_SUCCESS ) {
slap_sync_cookie_free( &si->si_syncCookie, 0 );
- slap_dup_sync_cookie( &si->si_syncCookie, syncCookie );
- /* If we replaced any old values */
- for ( i=0; isi_cookieState->cs_num; i++ ) {
- if ( mod.sml_values[i].bv_val != si->si_cookieState->cs_vals[i].bv_val )
- ber_bvreplace( &si->si_cookieState->cs_vals[i],
- &mod.sml_values[i] );
- }
- /* Handle any added values */
- if ( i < mod.sml_numvals ) {
- si->si_cookieState->cs_num = mod.sml_numvals;
- value_add( &si->si_cookieState->cs_vals, &mod.sml_values[i] );
- free( si->si_cookieState->cs_sids );
- si->si_cookieState->cs_sids = slap_parse_csn_sids(
- si->si_cookieState->cs_vals, si->si_cookieState->cs_num, NULL );
- }
+ ber_bvarray_free( si->si_cookieState->cs_vals );
+ ch_free( si->si_cookieState->cs_sids );
+ si->si_cookieState->cs_vals = sc.ctxcsn;
+ si->si_cookieState->cs_sids = sc.sids;
+ si->si_cookieState->cs_num = sc.numcsns;
+
+ /* Don't just dup the provider's cookie, recreate it */
+ si->si_syncCookie.numcsns = si->si_cookieState->cs_num;
+ ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn, si->si_cookieState->cs_vals, NULL );
+ si->si_syncCookie.sids = ch_malloc( si->si_cookieState->cs_num * sizeof(int) );
+ for ( i=0; isi_cookieState->cs_num; i++ )
+ si->si_syncCookie.sids[i] = si->si_cookieState->cs_sids[i];
si->si_cookieState->cs_age++;
si->si_cookieAge = si->si_cookieState->cs_age;
@@ -3042,6 +3774,8 @@ syncrepl_updateCookie(
Debug( LDAP_DEBUG_ANY,
"syncrepl_updateCookie: %s be_modify failed (%d)\n",
si->si_ridtxt, rs_modify.sr_err, 0 );
+ ch_free( sc.sids );
+ ber_bvarray_free( sc.ctxcsn );
}
ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
@@ -3049,7 +3783,6 @@ syncrepl_updateCookie(
op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
BER_BVZERO( &op->o_csn );
if ( mod.sml_next ) slap_mods_free( mod.sml_next, 1 );
- op->o_tmpfree( mod.sml_values, op->o_tmpmemctx );
#ifdef CHECK_CSN
for ( i=0; isi_cookieState->cs_num; i++ ) {
@@ -3060,6 +3793,10 @@ syncrepl_updateCookie(
return rc;
}
+/* Compare the attribute from the old entry to the one in the new
+ * entry. The Modifications from the new entry will either be left
+ * in place, or changed to an Add or Delete as needed.
+ */
static void
attr_cmp( Operation *op, Attribute *old, Attribute *new,
Modifications ***mret, Modifications ***mcur )
@@ -3111,10 +3848,12 @@ attr_cmp( Operation *op, Attribute *old, Attribute *new,
* Also use replace op if attr has no equality matching rule.
* (ITS#5781)
*/
- if ( nn && no < o &&
+ if ( ( nn || ( no > 0 && no < o ) ) &&
( old->a_desc == slap_schema.si_ad_objectClass ||
- !old->a_desc->ad_type->sat_equality ))
+ !old->a_desc->ad_type->sat_equality ) )
+ {
no = o;
+ }
i = j;
/* all old values were deleted, just use the replace op */
@@ -3203,6 +3942,86 @@ attr_cmp( Operation *op, Attribute *old, Attribute *new,
*mret = modtail;
}
+/* Generate a set of modifications to change the old entry into the
+ * new one. On input ml is a list of modifications equivalent to
+ * the new entry. It will be massaged and the result will be stored
+ * in mods.
+ */
+void syncrepl_diff_entry( Operation *op, Attribute *old, Attribute *new,
+ Modifications **mods, Modifications **ml, int is_ctx)
+{
+ Modifications **modtail = mods;
+
+ /* We assume that attributes are saved in the same order
+ * in the remote and local databases. So if we walk through
+ * the attributeDescriptions one by one they should match in
+ * lock step. If not, look for an add or delete.
+ */
+ while ( old && new )
+ {
+ /* If we've seen this before, use its mod now */
+ if ( new->a_flags & SLAP_ATTR_IXADD ) {
+ attr_cmp( op, NULL, new, &modtail, &ml );
+ new = new->a_next;
+ continue;
+ }
+ /* Skip contextCSN */
+ if ( is_ctx && old->a_desc ==
+ slap_schema.si_ad_contextCSN ) {
+ old = old->a_next;
+ continue;
+ }
+
+ if ( old->a_desc != new->a_desc ) {
+ Modifications *mod;
+ Attribute *tmp;
+
+ /* If it's just been re-added later,
+ * remember that we've seen it.
+ */
+ tmp = attr_find( new, old->a_desc );
+ if ( tmp ) {
+ tmp->a_flags |= SLAP_ATTR_IXADD;
+ } else {
+ /* If it's a new attribute, pull it in.
+ */
+ tmp = attr_find( old, new->a_desc );
+ if ( !tmp ) {
+ attr_cmp( op, NULL, new, &modtail, &ml );
+ new = new->a_next;
+ continue;
+ }
+ /* Delete old attr */
+ mod = ch_malloc( sizeof( Modifications ) );
+ mod->sml_op = LDAP_MOD_DELETE;
+ mod->sml_flags = 0;
+ mod->sml_desc = old->a_desc;
+ mod->sml_type = mod->sml_desc->ad_cname;
+ mod->sml_numvals = 0;
+ mod->sml_values = NULL;
+ mod->sml_nvalues = NULL;
+ *modtail = mod;
+ modtail = &mod->sml_next;
+ }
+ old = old->a_next;
+ continue;
+ }
+ /* kludge - always update modifiersName so that it
+ * stays co-located with the other mod opattrs. But only
+ * if we know there are other valid mods.
+ */
+ if ( *mods && ( old->a_desc == slap_schema.si_ad_modifiersName ||
+ old->a_desc == slap_schema.si_ad_modifyTimestamp ))
+ attr_cmp( op, NULL, new, &modtail, &ml );
+ else
+ attr_cmp( op, old, new, &modtail, &ml );
+ new = new->a_next;
+ old = old->a_next;
+ }
+ *modtail = *ml;
+ *ml = NULL;
+}
+
static int
dn_callback(
Operation* op,
@@ -3223,7 +4042,6 @@ dn_callback(
* in the provider are always propagated.
*/
if ( dni->new_entry ) {
- Modifications **modtail, **ml;
Attribute *old, *new;
struct berval old_rdn, new_rdn;
struct berval old_p, new_p;
@@ -3323,78 +4141,9 @@ dn_callback(
*/
}
- modtail = &dni->mods;
- ml = dni->modlist;
-
- /* We assume that attributes are saved in the same order
- * in the remote and local databases. So if we walk through
- * the attributeDescriptions one by one they should match in
- * lock step. If not, look for an add or delete.
- */
- for ( old = rs->sr_entry->e_attrs, new = dni->new_entry->e_attrs;
- old && new; )
- {
- /* If we've seen this before, use its mod now */
- if ( new->a_flags & SLAP_ATTR_IXADD ) {
- attr_cmp( op, NULL, new, &modtail, &ml );
- new = new->a_next;
- continue;
- }
- /* Skip contextCSN */
- if ( is_ctx && old->a_desc ==
- slap_schema.si_ad_contextCSN ) {
- old = old->a_next;
- continue;
- }
-
- if ( old->a_desc != new->a_desc ) {
- Modifications *mod;
- Attribute *tmp;
-
- /* If it's just been re-added later,
- * remember that we've seen it.
- */
- tmp = attr_find( new, old->a_desc );
- if ( tmp ) {
- tmp->a_flags |= SLAP_ATTR_IXADD;
- } else {
- /* If it's a new attribute, pull it in.
- */
- tmp = attr_find( old, new->a_desc );
- if ( !tmp ) {
- attr_cmp( op, NULL, new, &modtail, &ml );
- new = new->a_next;
- continue;
- }
- /* Delete old attr */
- mod = ch_malloc( sizeof( Modifications ) );
- mod->sml_op = LDAP_MOD_DELETE;
- mod->sml_flags = 0;
- mod->sml_desc = old->a_desc;
- mod->sml_type = mod->sml_desc->ad_cname;
- mod->sml_numvals = 0;
- mod->sml_values = NULL;
- mod->sml_nvalues = NULL;
- *modtail = mod;
- modtail = &mod->sml_next;
- }
- old = old->a_next;
- continue;
- }
- /* kludge - always update modifiersName so that it
- * stays co-located with the other mod opattrs. But only
- * if we know there are other valid mods.
- */
- if ( dni->mods && ( old->a_desc == slap_schema.si_ad_modifiersName ||
- old->a_desc == slap_schema.si_ad_modifyTimestamp ))
- attr_cmp( op, NULL, new, &modtail, &ml );
- else
- attr_cmp( op, old, new, &modtail, &ml );
- new = new->a_next;
- old = old->a_next;
- }
- *modtail = *ml;
- *ml = NULL;
+ syncrepl_diff_entry( op, rs->sr_entry->e_attrs,
+ dni->new_entry->e_attrs, &dni->mods, dni->modlist,
+ is_ctx );
}
}
} else if ( rs->sr_type == REP_RESULT ) {
@@ -3629,6 +4378,9 @@ syncinfo_free( syncinfo_t *sie, int free_all )
if ( sie->si_filterstr.bv_val ) {
ch_free( sie->si_filterstr.bv_val );
}
+ if ( sie->si_filter ) {
+ filter_free( sie->si_filter );
+ }
if ( sie->si_logfilterstr.bv_val ) {
ch_free( sie->si_logfilterstr.bv_val );
}
@@ -3638,6 +4390,9 @@ syncinfo_free( syncinfo_t *sie, int free_all )
if ( sie->si_logbase.bv_val ) {
ch_free( sie->si_logbase.bv_val );
}
+ if ( sie->si_be && SLAP_SYNC_SUBENTRY( sie->si_be )) {
+ ch_free( sie->si_contextdn.bv_val );
+ }
if ( sie->si_attrs ) {
int i = 0;
while ( sie->si_attrs[i] != NULL ) {
@@ -3701,19 +4456,67 @@ syncinfo_free( syncinfo_t *sie, int free_all )
}
ch_free( npe );
}
- sie->si_cookieState->cs_ref--;
- if ( !sie->si_cookieState->cs_ref ) {
- ch_free( sie->si_cookieState->cs_sids );
- ber_bvarray_free( sie->si_cookieState->cs_vals );
- ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_mutex );
- ch_free( sie->si_cookieState );
+ if ( sie->si_cookieState ) {
+ sie->si_cookieState->cs_ref--;
+ if ( !sie->si_cookieState->cs_ref ) {
+ ch_free( sie->si_cookieState->cs_sids );
+ ber_bvarray_free( sie->si_cookieState->cs_vals );
+ ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_mutex );
+ ch_free( sie->si_cookieState->cs_psids );
+ ber_bvarray_free( sie->si_cookieState->cs_pvals );
+ ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_pmutex );
+ ch_free( sie->si_cookieState );
+ }
}
+#ifdef ENABLE_REWRITE
+ if ( sie->si_rewrite )
+ rewrite_info_delete( &sie->si_rewrite );
+ if ( sie->si_suffixm.bv_val )
+ ch_free( sie->si_suffixm.bv_val );
+#endif
ch_free( sie );
sie = si_next;
} while ( free_all && si_next );
}
+#ifdef ENABLE_REWRITE
+static int
+config_suffixm( ConfigArgs *c, syncinfo_t *si )
+{
+ char *argvEngine[] = { "rewriteEngine", "on", NULL };
+ char *argvContext[] = { "rewriteContext", SUFFIXM_CTX, NULL };
+ char *argvRule[] = { "rewriteRule", NULL, NULL, ":", NULL };
+ char *vnc, *rnc;
+ int rc;
+
+ if ( si->si_rewrite )
+ rewrite_info_delete( &si->si_rewrite );
+ si->si_rewrite = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
+
+ rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 2, argvEngine );
+ if ( rc != LDAP_SUCCESS )
+ return rc;
+
+ rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 2, argvContext );
+ if ( rc != LDAP_SUCCESS )
+ return rc;
+
+ vnc = ch_malloc( si->si_base.bv_len + 6 );
+ strcpy( vnc, "(.*)" );
+ lutil_strcopy( lutil_strcopy( vnc+4, si->si_base.bv_val ), "$" );
+ argvRule[1] = vnc;
+ rnc = ch_malloc( si->si_suffixm.bv_len + 3 );
+ strcpy( rnc, "%1" );
+ strcpy( rnc+2, si->si_suffixm.bv_val );
+ argvRule[2] = rnc;
+
+ rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 4, argvRule );
+ ch_free( vnc );
+ ch_free( rnc );
+ return rc;
+}
+#endif
/* NOTE: used & documented in slapd.conf(5) */
#define IDSTR "rid"
@@ -3732,6 +4535,8 @@ syncinfo_free( syncinfo_t *sie, int free_all )
#define SYNCDATASTR "syncdata"
#define LOGBASESTR "logbase"
#define LOGFILTERSTR "logfilter"
+#define SUFFIXMSTR "suffixmassage"
+#define STRICT_REFRESH "strictrefresh"
/* FIXME: undocumented */
#define EXATTRSSTR "exattrs"
@@ -3758,26 +4563,12 @@ enum {
GOT_EXATTRS = 0x00010000U,
GOT_MANAGEDSAIT = 0x00020000U,
GOT_BINDCONF = 0x00040000U,
+ GOT_SUFFIXM = 0x00080000U,
/* check */
GOT_REQUIRED = (GOT_RID|GOT_PROVIDER|GOT_SEARCHBASE)
};
-static struct {
- struct berval key;
- int val;
-} scopes[] = {
- { BER_BVC("base"), LDAP_SCOPE_BASE },
- { BER_BVC("one"), LDAP_SCOPE_ONELEVEL },
- { BER_BVC("onelevel"), LDAP_SCOPE_ONELEVEL }, /* OpenLDAP extension */
- { BER_BVC("children"), LDAP_SCOPE_SUBORDINATE },
- { BER_BVC("subord"), LDAP_SCOPE_SUBORDINATE },
- { BER_BVC("subordinate"), LDAP_SCOPE_SUBORDINATE },
- { BER_BVC("sub"), LDAP_SCOPE_SUBTREE },
- { BER_BVC("subtree"), LDAP_SCOPE_SUBTREE }, /* OpenLDAP extension */
- { BER_BVNULL, 0 }
-};
-
static slap_verbmasks datamodes[] = {
{ BER_BVC("default"), SYNCDATA_DEFAULT },
{ BER_BVC("accesslog"), SYNCDATA_ACCESSLOG },
@@ -3860,6 +4651,12 @@ parse_syncrepl_retry(
}
}
}
+ if ( j < 1 || si->si_retrynum_init[j-1] != RETRYNUM_FOREVER ) {
+ Debug( LDAP_DEBUG_CONFIG,
+ "%s: syncrepl will eventually stop retrying; the \"retry\" parameter should end with a '+'.\n",
+ c->log, 0, 0 );
+ }
+
si->si_retrynum_init[j] = RETRYNUM_TAIL;
si->si_retrynum[j] = RETRYNUM_TAIL;
si->si_retryinterval[j] = 0;
@@ -3897,10 +4694,10 @@ parse_syncrepl_line(
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
- if ( tmp > SLAP_SYNC_SID_MAX || tmp < 0 ) {
+ if ( tmp > SLAP_SYNC_RID_MAX || tmp < 0 ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"Error: parse_syncrepl_line: "
- "syncrepl id %d is out of range [0..4095]", tmp );
+ "syncrepl id %d is out of range [0..%d]", tmp, SLAP_SYNC_RID_MAX );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
@@ -3912,6 +4709,10 @@ parse_syncrepl_line(
{
val = c->argv[ i ] + STRLENOF( PROVIDERSTR "=" );
ber_str2bv( val, 0, 1, &si->si_bindconf.sb_uri );
+#ifdef HAVE_TLS
+ if ( ldap_is_ldaps_url( val ))
+ si->si_bindconf.sb_tls_do_init = 1;
+#endif
si->si_got |= GOT_PROVIDER;
} else if ( !strncasecmp( c->argv[ i ], SCHEMASTR "=",
STRLENOF( SCHEMASTR "=" ) ) )
@@ -3960,16 +4761,38 @@ parse_syncrepl_line(
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
- if ( !be_issubordinate( c->be, &si->si_base ) ) {
- ch_free( si->si_base.bv_val );
- BER_BVZERO( &si->si_base );
+ si->si_got |= GOT_SEARCHBASE;
+#ifdef ENABLE_REWRITE
+ } else if ( !strncasecmp( c->argv[ i ], SUFFIXMSTR "=",
+ STRLENOF( SUFFIXMSTR "=" ) ) )
+ {
+ struct berval bv;
+ int rc;
+
+ val = c->argv[ i ] + STRLENOF( SUFFIXMSTR "=" );
+ if ( si->si_suffixm.bv_val ) {
+ ch_free( si->si_suffixm.bv_val );
+ }
+ ber_str2bv( val, 0, 0, &bv );
+ rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_suffixm, NULL );
+ if ( rc != LDAP_SUCCESS ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "Invalid massage DN \"%s\": %d (%s)",
+ val, rc, ldap_err2string( rc ) );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
+ return -1;
+ }
+ if ( !be_issubordinate( c->be, &si->si_suffixm )) {
+ ch_free( si->si_suffixm.bv_val );
+ BER_BVZERO( &si->si_suffixm );
snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "Base DN \"%s\" is not within the database naming context",
+ "Massage DN \"%s\" is not within the database naming context",
val );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
- si->si_got |= GOT_SEARCHBASE;
+ si->si_got |= GOT_SUFFIXM;
+#endif
} else if ( !strncasecmp( c->argv[ i ], LOGBASESTR "=",
STRLENOF( LOGBASESTR "=" ) ) )
{
@@ -3995,19 +4818,15 @@ parse_syncrepl_line(
{
int j;
val = c->argv[ i ] + STRLENOF( SCOPESTR "=" );
- for ( j = 0; !BER_BVISNULL(&scopes[j].key); j++ ) {
- if (!strcasecmp( val, scopes[j].key.bv_val ) ) {
- si->si_scope = scopes[j].val;
- break;
- }
- }
- if ( BER_BVISNULL(&scopes[j].key) ) {
+ j = ldap_pvt_str2scope( val );
+ if ( j < 0 ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"Error: parse_syncrepl_line: "
"unknown scope \"%s\"", val);
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
+ si->si_scope = j;
si->si_got |= GOT_SCOPE;
} else if ( !strncasecmp( c->argv[ i ], ATTRSONLYSTR,
STRLENOF( ATTRSONLYSTR ) ) )
@@ -4216,6 +5035,10 @@ parse_syncrepl_line(
val = c->argv[ i ] + STRLENOF( SYNCDATASTR "=" );
si->si_syncdata = verb_to_mask( val, datamodes );
si->si_got |= GOT_SYNCDATA;
+ } else if ( !strncasecmp( c->argv[ i ], STRICT_REFRESH,
+ STRLENOF( STRICT_REFRESH ) ) )
+ {
+ si->si_strict_refresh = 1;
} else if ( bindconf_parse( c->argv[i], &si->si_bindconf ) ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"Error: parse_syncrepl_line: "
@@ -4236,6 +5059,29 @@ parse_syncrepl_line(
return -1;
}
+ if ( !be_issubordinate( c->be, &si->si_base ) && !( si->si_got & GOT_SUFFIXM )) {
+ ch_free( si->si_base.bv_val );
+ BER_BVZERO( &si->si_base );
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "Base DN \"%s\" is not within the database naming context",
+ val );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
+ return -1;
+ }
+
+#ifdef ENABLE_REWRITE
+ if ( si->si_got & GOT_SUFFIXM ) {
+ if (config_suffixm( c, si )) {
+ ch_free( si->si_suffixm.bv_val );
+ BER_BVZERO( &si->si_suffixm );
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "Error configuring rewrite engine" );
+ Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
+ return -1;
+ }
+ }
+#endif
+
if ( !( si->si_got & GOT_RETRY ) ) {
Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": no retry defined, using default\n",
si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", 0 );
@@ -4246,6 +5092,13 @@ parse_syncrepl_line(
}
}
+ si->si_filter = str2filter( si->si_filterstr.bv_val );
+ if ( si->si_filter == NULL ) {
+ Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": unable to parse filter=\"%s\"\n",
+ si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", si->si_filterstr.bv_val );
+ return 1;
+ }
+
return 0;
}
@@ -4304,6 +5157,8 @@ add_syncrepl(
rc = parse_syncrepl_line( c, si );
if ( rc == 0 ) {
+ LDAPURLDesc *lud;
+
/* Must be LDAPv3 because we need controls */
switch ( si->si_bindconf.sb_version ) {
case 0:
@@ -4321,24 +5176,35 @@ add_syncrepl(
return 1;
}
+ if ( ldap_url_parse( si->si_bindconf.sb_uri.bv_val, &lud )) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "<%s> invalid URL", c->argv[0] );
+ Debug( LDAP_DEBUG_ANY, "%s: %s %s\n",
+ c->log, c->cr_msg, si->si_bindconf.sb_uri.bv_val );
+ return 1;
+ }
+
si->si_be = c->be;
if ( slapMode & SLAP_SERVER_MODE ) {
- Listener **l = slapd_get_listeners();
int isMe = 0;
-
- /* check if URL points to current server. If so, ignore
- * this configuration. We require an exact match. Just
- * in case they really want to do this, they can vary
- * the case of the URL to allow it.
+ /* check if consumer points to current server and database.
+ * If so, ignore this configuration.
*/
- if ( l && !SLAP_DBHIDDEN( c->be ) ) {
+ if ( !SLAP_DBHIDDEN( c->be ) ) {
int i;
- for ( i=0; l[i]; i++ ) {
- if ( bvmatch( &l[i]->sl_url, &si->si_bindconf.sb_uri ) ) {
+ /* if searchbase doesn't match current DB suffix,
+ * assume it's different
+ */
+ for ( i=0; !BER_BVISNULL( &c->be->be_nsuffix[i] ); i++ ) {
+ if ( bvmatch( &si->si_base, &c->be->be_nsuffix[i] )) {
isMe = 1;
break;
}
}
+ /* if searchbase matches, see if URLs match */
+ if ( isMe && config_check_my_url( si->si_bindconf.sb_uri.bv_val,
+ lud ) == NULL )
+ isMe = 0;
}
if ( !isMe ) {
@@ -4357,6 +5223,7 @@ add_syncrepl(
/* mirrormode still needs to see this flag in tool mode */
rc = config_sync_shadow( c ) ? -1 : 0;
}
+ ldap_free_urldesc( lud );
}
#ifdef HAVE_TLS
@@ -4369,20 +5236,22 @@ add_syncrepl(
return 1;
} else {
Debug( LDAP_DEBUG_CONFIG,
- "Config: ** successfully added syncrepl \"%s\"\n",
+ "Config: ** successfully added syncrepl %s \"%s\"\n",
+ si->si_ridtxt,
BER_BVISNULL( &si->si_bindconf.sb_uri ) ?
- "(null)" : si->si_bindconf.sb_uri.bv_val, 0, 0 );
+ "(null)" : si->si_bindconf.sb_uri.bv_val, 0 );
if ( c->be->be_syncinfo ) {
syncinfo_t *sip;
si->si_cookieState = c->be->be_syncinfo->si_cookieState;
- // add new syncrepl to end of list (same order as when deleting)
+ /* add new syncrepl to end of list (same order as when deleting) */
for ( sip = c->be->be_syncinfo; sip->si_next; sip = sip->si_next );
sip->si_next = si;
} else {
si->si_cookieState = ch_calloc( 1, sizeof( cookie_state ));
ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_mutex );
+ ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_pmutex );
c->be->be_syncinfo = si;
}
@@ -4397,7 +5266,7 @@ add_syncrepl(
static void
syncrepl_unparse( syncinfo_t *si, struct berval *bv )
{
- struct berval bc, uri;
+ struct berval bc, uri, bs;
char buf[BUFSIZ*2], *ptr;
ber_len_t len;
int i;
@@ -4414,7 +5283,7 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv )
si->si_bindconf.sb_version = LDAP_VERSION3;
ptr = buf;
- assert( si->si_rid >= 0 && si->si_rid <= SLAP_SYNC_SID_MAX );
+ assert( si->si_rid >= 0 && si->si_rid <= SLAP_SYNC_RID_MAX );
len = snprintf( ptr, WHATSLEFT, IDSTR "=%03d " PROVIDERSTR "=%s",
si->si_rid, si->si_bindconf.sb_uri.bv_val );
if ( len >= sizeof( buf ) ) return;
@@ -4439,6 +5308,14 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv )
ptr = lutil_strcopy( ptr, si->si_base.bv_val );
*ptr++ = '"';
}
+#ifdef ENABLE_REWRITE
+ if ( !BER_BVISNULL( &si->si_suffixm ) ) {
+ if ( WHATSLEFT <= STRLENOF( " " SUFFIXMSTR "=\"" "\"" ) + si->si_suffixm.bv_len ) return;
+ ptr = lutil_strcopy( ptr, " " SUFFIXMSTR "=\"" );
+ ptr = lutil_strcopy( ptr, si->si_suffixm.bv_val );
+ *ptr++ = '"';
+ }
+#endif
if ( !BER_BVISEMPTY( &si->si_logfilterstr ) ) {
if ( WHATSLEFT <= STRLENOF( " " LOGFILTERSTR "=\"" "\"" ) + si->si_logfilterstr.bv_len ) return;
ptr = lutil_strcopy( ptr, " " LOGFILTERSTR "=\"" );
@@ -4451,13 +5328,10 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv )
ptr = lutil_strcopy( ptr, si->si_logbase.bv_val );
*ptr++ = '"';
}
- for (i=0; !BER_BVISNULL(&scopes[i].key);i++) {
- if ( si->si_scope == scopes[i].val ) {
- if ( WHATSLEFT <= STRLENOF( " " SCOPESTR "=" ) + scopes[i].key.bv_len ) return;
- ptr = lutil_strcopy( ptr, " " SCOPESTR "=" );
- ptr = lutil_strcopy( ptr, scopes[i].key.bv_val );
- break;
- }
+ if ( ldap_pvt_scope2bv( si->si_scope, &bs ) == LDAP_SUCCESS ) {
+ if ( WHATSLEFT <= STRLENOF( " " SCOPESTR "=" ) + bs.bv_len ) return;
+ ptr = lutil_strcopy( ptr, " " SCOPESTR "=" );
+ ptr = lutil_strcopy( ptr, bs.bv_val );
}
if ( si->si_attrsonly ) {
if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;
@@ -4594,6 +5468,8 @@ syncrepl_config( ConfigArgs *c )
si = *sip;
if ( c->valx == -1 || i == c->valx ) {
*sip = si->si_next;
+ si->si_ctype = -1;
+ si->si_next = NULL;
/* If the task is currently active, we have to leave
* it running. It will exit on its own. This will only
* happen when running on the cn=config DB.
@@ -4602,30 +5478,34 @@ syncrepl_config( ConfigArgs *c )
if ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
isrunning = 1;
} else {
+ /* There is no active thread, but we must still
+ * ensure that no thread is (or will be) queued
+ * while we removes the task.
+ */
+ struct re_s *re = si->si_re;
+ si->si_re = NULL;
+
if ( si->si_conn ) {
+ connection_client_stop( si->si_conn );
+ si->si_conn = NULL;
+ }
+
+ ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+ if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) ) {
+ ldap_pvt_runqueue_stoptask( &slapd_rq, re );
isrunning = 1;
- /* If there's a persistent connection, we don't
- * know if it's already got a thread queued.
- * so defer the free, but reschedule the task.
- * If there's a connection thread queued, it
- * will cleanup as necessary. If not, then the
- * runqueue task will cleanup.
- */
- ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
- if ( !ldap_pvt_runqueue_isrunning( &slapd_rq, si->si_re )) {
- si->si_re->interval.tv_sec = 0;
- ldap_pvt_runqueue_resched( &slapd_rq, si->si_re, 0 );
- si->si_re->interval.tv_sec = si->si_interval;
- }
- ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
}
+ ldap_pvt_runqueue_remove( &slapd_rq, re );
+ ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+
+ if ( ldap_pvt_thread_pool_retract( &connection_pool,
+ re->routine, re ) > 0 )
+ isrunning = 0;
+
ldap_pvt_thread_mutex_unlock( &si->si_mutex );
}
}
- if ( isrunning ) {
- si->si_ctype = 0;
- si->si_next = NULL;
- } else {
+ if ( !isrunning ) {
syncinfo_free( si, 0 );
}
if ( i == c->valx )