From: Quanah Gibson-Mount Date: Wed, 18 Nov 2009 02:16:15 +0000 (+0000) Subject: ITS#6373 X-Git-Tag: OPENLDAP_REL_ENG_2_4_20~47 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=d9e9a8d4e54e27ab17959dbe27e810648f29a1c8;p=openldap ITS#6373 --- diff --git a/CHANGES b/CHANGES index 99921383cc..e1619a9fa1 100644 --- a/CHANGES +++ b/CHANGES @@ -9,6 +9,7 @@ OpenLDAP 2.4.20 Engineering Fixed libldap uninitialized return value (ITS#6355) Fixed liblutil constant (ITS#5909) Added slapd handling of hex server IDs (ITS#6297) + Added slapd syncrepl contextCSN storing in subentry (ITS#6373) Fixed slapd asserts in minimal environment (ITS#6361) Fixed slapd configArgs initialization (ITS#6363) Fixed slapd debug handling of LDAP_DEBUG_ANY (ITS#6324) diff --git a/doc/man/man5/slapd-config.5 b/doc/man/man5/slapd-config.5 index a646deecef..8ec7a52744 100644 --- a/doc/man/man5/slapd-config.5 +++ b/doc/man/man5/slapd-config.5 @@ -1614,6 +1614,11 @@ with the inner suffix must come first in the configuration file. You may also want to glue such databases together with the .B olcSubordinate attribute. +.TP +.B olcSyncUseSubentry: TRUE | FALSE +Store the syncrepl contextCSN in a subentry instead of the context entry +of the database. The subentry's RDN will be "cn=ldapsync". The default is +FALSE, meaning the contextCSN is stored in the context entry. .HP .hy 0 .B olcSyncrepl: rid= diff --git a/doc/man/man5/slapd.conf.5 b/doc/man/man5/slapd.conf.5 index 0ff35429e9..8d0e3c88cc 100644 --- a/doc/man/man5/slapd.conf.5 +++ b/doc/man/man5/slapd.conf.5 @@ -1602,6 +1602,11 @@ in order to work over all of the glued databases. E.g. overlay syncprov .fi .RE +.TP +.B sync_use_subentry +Store the syncrepl contextCSN in a subentry instead of the context entry +of the database. The subentry's RDN will be "cn=ldapsync". By default +the contextCSN is stored in the context entry. .HP .hy 0 .B syncrepl rid= diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c index 90cd622926..dbed5f1b83 100644 --- a/servers/slapd/bconfig.c +++ b/servers/slapd/bconfig.c @@ -190,6 +190,7 @@ enum { CFG_IX_INTLEN, CFG_SYNTAX, CFG_ACL_ADD, + CFG_SYNC_SUBENTRY, CFG_LAST }; @@ -604,6 +605,10 @@ static ConfigTable config_back_cf_table[] = { &config_suffix, "( OLcfgDbAt:0.10 NAME 'olcSuffix' " "EQUALITY distinguishedNameMatch " "SYNTAX OMsDN )", NULL, NULL }, + { "sync_use_subentry", NULL, 0, 0, 0, ARG_ON_OFF|ARG_DB|ARG_MAGIC|CFG_SYNC_SUBENTRY, + &config_generic, "( OLcfgDbAt:0.19 NAME 'olcSyncUseSubentry' " + "DESC 'Store sync context in a subentry' " + "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, { "syncrepl", NULL, 0, 0, 0, ARG_DB|ARG_MAGIC, &syncrepl_config, "( OLcfgDbAt:0.11 NAME 'olcSyncrepl' " "EQUALITY caseIgnoreMatch " @@ -815,7 +820,7 @@ static ConfigOCs cf_ocs[] = { "olcMaxDerefDepth $ olcPlugin $ olcReadOnly $ olcReplica $ " "olcReplicaArgsFile $ olcReplicaPidFile $ olcReplicationInterval $ " "olcReplogFile $ olcRequires $ olcRestrict $ olcRootDN $ olcRootPW $ " - "olcSchemaDN $ olcSecurity $ olcSizeLimit $ olcSyncrepl $ " + "olcSchemaDN $ olcSecurity $ olcSizeLimit $ olcSyncUseSubentry $ olcSyncrepl $ " "olcTimeLimit $ olcUpdateDN $ olcUpdateRef $ olcMirrorMode $ " "olcMonitoring ) )", Cft_Database, NULL, cfAddDatabase }, @@ -1085,6 +1090,9 @@ config_generic(ConfigArgs *c) { case CFG_LASTMOD: c->value_int = (SLAP_NOLASTMOD(c->be) == 0); break; + case CFG_SYNC_SUBENTRY: + c->value_int = (SLAP_SYNC_SUBENTRY(c->be) != 0); + break; case CFG_MIRRORMODE: if ( SLAP_SHADOW(c->be)) c->value_int = (SLAP_SINGLE_SHADOW(c->be) == 0); @@ -1197,6 +1205,7 @@ config_generic(ConfigArgs *c) { case CFG_SSTR_IF_MAX: case CFG_SSTR_IF_MIN: case CFG_ACL_ADD: + case CFG_SYNC_SUBENTRY: break; /* no-ops, requires slapd restart */ @@ -1901,6 +1910,13 @@ sortval_reject: SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_HIDDEN; break; + case CFG_SYNC_SUBENTRY: + if (c->value_int) + SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_SYNC_SUBENTRY; + else + SLAP_DBFLAGS(c->be) &= ~SLAP_DBFLAG_SYNC_SUBENTRY; + break; + case CFG_SSTR_IF_MAX: if (c->value_uint < index_substr_if_minlen) { snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> invalid value", c->argv[0] ); diff --git a/servers/slapd/ctxcsn.c b/servers/slapd/ctxcsn.c index cb828999cc..95d7ba6ed1 100644 --- a/servers/slapd/ctxcsn.c +++ b/servers/slapd/ctxcsn.c @@ -26,6 +26,8 @@ #include "slap.h" #include "lutil_ldap.h" +const struct berval slap_ldapsync_bv = BER_BVC("ldapsync"); +const struct berval slap_ldapsync_cn_bv = BER_BVC("cn=ldapsync"); int slap_serverID; /* maxcsn->bv_val must point to a char buf[LDAP_LUTIL_CSNSTR_BUFSIZE] */ @@ -133,6 +135,46 @@ slap_graduate_commit_csn( Operation *op ) return; } +static struct berval ocbva[] = { + BER_BVC("top"), + BER_BVC("subentry"), + BER_BVC("syncProviderSubentry"), + BER_BVNULL +}; + +Entry * +slap_create_context_csn_entry( + Backend *be, + struct berval *context_csn ) +{ + Entry* e; + + struct berval bv; + + e = entry_alloc(); + + attr_merge( e, slap_schema.si_ad_objectClass, + ocbva, NULL ); + attr_merge_one( e, slap_schema.si_ad_structuralObjectClass, + &ocbva[1], NULL ); + attr_merge_one( e, slap_schema.si_ad_cn, + (struct berval *)&slap_ldapsync_bv, NULL ); + + if ( context_csn ) { + attr_merge_one( e, slap_schema.si_ad_contextCSN, + context_csn, NULL ); + } + + BER_BVSTR( &bv, "{}" ); + attr_merge_one( e, slap_schema.si_ad_subtreeSpecification, &bv, NULL ); + + build_new_dn( &e->e_name, &be->be_nsuffix[0], + (struct berval *)&slap_ldapsync_cn_bv, NULL ); + ber_dupbv( &e->e_nname, &e->e_name ); + + return e; +} + void slap_queue_csn( Operation *op, diff --git a/servers/slapd/overlays/syncprov.c b/servers/slapd/overlays/syncprov.c index 2a1c565e02..49a2cbe8da 100644 --- a/servers/slapd/overlays/syncprov.c +++ b/servers/slapd/overlays/syncprov.c @@ -124,6 +124,7 @@ typedef struct sessionlog { typedef struct syncprov_info_t { syncops *si_ops; BerVarray si_ctxcsn; /* ldapsync context */ + struct berval si_contextdn; int *si_sids; int si_numcsns; int si_chkops; /* checkpointing info */ @@ -1361,6 +1362,7 @@ syncprov_checkpoint( Operation *op, SlapReply *rs, slap_overinst *on ) SlapReply rsm = { 0 }; slap_callback cb = {0}; BackendDB be; + #ifdef CHECK_CSN Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax; @@ -1387,12 +1389,26 @@ syncprov_checkpoint( Operation *op, SlapReply *rs, slap_overinst *on ) be = *on->on_info->oi_origdb; opm.o_bd = &be; } - opm.o_req_dn = opm.o_bd->be_suffix[0]; - opm.o_req_ndn = opm.o_bd->be_nsuffix[0]; + opm.o_req_dn = si->si_contextdn; + opm.o_req_ndn = si->si_contextdn; opm.o_bd->bd_info = on->on_info->oi_orig; opm.o_managedsait = SLAP_CONTROL_NONCRITICAL; opm.o_no_schema_check = 1; opm.o_bd->be_modify( &opm, &rsm ); + + if ( rsm.sr_err == LDAP_NO_SUCH_OBJECT && + SLAP_SYNC_SUBENTRY( opm.o_bd )) { + const char *text; + char txtbuf[SLAP_TEXT_BUFLEN]; + size_t textlen = sizeof txtbuf; + Entry *e = slap_create_context_csn_entry( opm.o_bd, NULL ); + slap_mods2entry( &mod, &e, 0, 1, &text, txtbuf, textlen); + opm.ora_e = e; + opm.o_bd->be_add( &opm, &rsm ); + if ( e == opm.ora_e ) + be_entry_release_w( &opm, opm.ora_e ); + } + if ( mod.sml_next != NULL ) { slap_mods_free( mod.sml_next, 1 ); } @@ -1763,7 +1779,7 @@ syncprov_op_response( Operation *op, SlapReply *rs ) * it will deadlock */ if ( op->o_tag != LDAP_REQ_ADD || - !dn_match( &op->o_req_ndn, &op->o_bd->be_nsuffix[0] )) { + !dn_match( &op->o_req_ndn, &si->si_contextdn )) { if ( si->si_chkops && si->si_numops >= si->si_chkops ) { do_check = 1; si->si_numops = 0; @@ -1837,14 +1853,14 @@ syncprov_op_compare( Operation *op, SlapReply *rs ) syncprov_info_t *si = on->on_bi.bi_private; int rc = SLAP_CB_CONTINUE; - if ( dn_match( &op->o_req_ndn, op->o_bd->be_nsuffix ) && + if ( dn_match( &op->o_req_ndn, &si->si_contextdn ) && op->oq_compare.rs_ava->aa_desc == slap_schema.si_ad_contextCSN ) { Entry e = {0}; Attribute a = {0}; - 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; e.e_attrs = &a; a.a_desc = slap_schema.si_ad_contextCSN; @@ -2583,7 +2599,7 @@ syncprov_operational( return SLAP_CB_CONTINUE; if ( rs->sr_entry && - dn_match( &rs->sr_entry->e_nname, op->o_bd->be_nsuffix )) { + dn_match( &rs->sr_entry->e_nname, &si->si_contextdn )) { if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ad_inlist( slap_schema.si_ad_contextCSN, rs->sr_attrs )) { @@ -2876,7 +2892,13 @@ syncprov_db_open( op->o_dn = be->be_rootdn; op->o_ndn = be->be_rootndn; - rc = overlay_entry_get_ov( op, be->be_nsuffix, NULL, + if ( SLAP_SYNC_SUBENTRY( be )) { + build_new_dn( &si->si_contextdn, be->be_nsuffix, + (struct berval *)&slap_ldapsync_cn_bv, NULL ); + } else { + si->si_contextdn = be->be_nsuffix[0]; + } + rc = overlay_entry_get_ov( op, &si->si_contextdn, NULL, slap_schema.si_ad_contextCSN, 0, &e, on ); if ( e ) { diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index d8a38ba801..0866c9f2b2 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -814,10 +814,13 @@ LDAP_SLAPD_F (ContentRule *) cr_bvfind LDAP_P(( */ LDAP_SLAPD_V( int ) slap_serverID; +LDAP_SLAPD_V( const struct berval ) slap_ldapsync_bv; +LDAP_SLAPD_V( const struct berval ) slap_ldapsync_cn_bv; LDAP_SLAPD_F (void) slap_get_commit_csn LDAP_P(( Operation *, struct berval *maxcsn, int *foundit )); LDAP_SLAPD_F (void) slap_rewind_commit_csn LDAP_P(( Operation * )); LDAP_SLAPD_F (void) slap_graduate_commit_csn LDAP_P(( Operation * )); +LDAP_SLAPD_F (Entry *) slap_create_context_csn_entry LDAP_P(( Backend *, struct berval *)); LDAP_SLAPD_F (int) slap_get_csn LDAP_P(( Operation *, struct berval *, int )); LDAP_SLAPD_F (void) slap_queue_csn LDAP_P(( Operation *, struct berval * )); diff --git a/servers/slapd/sasl.c b/servers/slapd/sasl.c index e12a82946f..7e17377876 100644 --- a/servers/slapd/sasl.c +++ b/servers/slapd/sasl.c @@ -266,7 +266,8 @@ slap_auxprop_lookup( const char *user, unsigned ulen) { - Operation op = {0}; + OperationBuffer opbuf = {0}; + Operation *op = (Operation *)&opbuf; int i, doit = 0; Connection *conn = NULL; lookup_info sl; @@ -286,22 +287,22 @@ slap_auxprop_lookup( if ( flags & SASL_AUXPROP_AUTHZID ) { if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHZLEN] )) { if ( sl.list[i].values && sl.list[i].values[0] ) - AC_MEMCPY( &op.o_req_ndn.bv_len, sl.list[i].values[0], - sizeof( op.o_req_ndn.bv_len ) ); + AC_MEMCPY( &op->o_req_ndn.bv_len, sl.list[i].values[0], + sizeof( op->o_req_ndn.bv_len ) ); } else if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHZ] )) { if ( sl.list[i].values ) - op.o_req_ndn.bv_val = (char *)sl.list[i].values[0]; + op->o_req_ndn.bv_val = (char *)sl.list[i].values[0]; break; } } if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHCLEN] )) { if ( sl.list[i].values && sl.list[i].values[0] ) - AC_MEMCPY( &op.o_req_ndn.bv_len, sl.list[i].values[0], - sizeof( op.o_req_ndn.bv_len ) ); + AC_MEMCPY( &op->o_req_ndn.bv_len, sl.list[i].values[0], + sizeof( op->o_req_ndn.bv_len ) ); } else if ( !strcmp( sl.list[i].name, slap_propnames[SLAP_SASL_PROP_AUTHC] ) ) { if ( sl.list[i].values ) { - op.o_req_ndn.bv_val = (char *)sl.list[i].values[0]; + op->o_req_ndn.bv_val = (char *)sl.list[i].values[0]; if ( !(flags & SASL_AUXPROP_AUTHZID) ) break; } @@ -336,30 +337,30 @@ slap_auxprop_lookup( cb.sc_private = &sl; - op.o_bd = select_backend( &op.o_req_ndn, 1 ); + op->o_bd = select_backend( &op->o_req_ndn, 1 ); - if ( op.o_bd ) { + if ( op->o_bd ) { /* For rootdn, see if we can use the rootpw */ - if ( be_isroot_dn( op.o_bd, &op.o_req_ndn ) && - !BER_BVISEMPTY( &op.o_bd->be_rootpw )) { + if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) && + !BER_BVISEMPTY( &op->o_bd->be_rootpw )) { struct berval cbv = BER_BVNULL; /* If there's a recognized scheme, see if it's CLEARTEXT */ - if ( lutil_passwd_scheme( op.o_bd->be_rootpw.bv_val )) { - if ( !strncasecmp( op.o_bd->be_rootpw.bv_val, + if ( lutil_passwd_scheme( op->o_bd->be_rootpw.bv_val )) { + if ( !strncasecmp( op->o_bd->be_rootpw.bv_val, sc_cleartext.bv_val, sc_cleartext.bv_len )) { /* If it's CLEARTEXT, skip past scheme spec */ - cbv.bv_len = op.o_bd->be_rootpw.bv_len - + cbv.bv_len = op->o_bd->be_rootpw.bv_len - sc_cleartext.bv_len; if ( cbv.bv_len ) { - cbv.bv_val = op.o_bd->be_rootpw.bv_val + + cbv.bv_val = op->o_bd->be_rootpw.bv_val + sc_cleartext.bv_len; } } /* No scheme, use the whole value */ } else { - cbv = op.o_bd->be_rootpw; + cbv = op->o_bd->be_rootpw; } if ( !BER_BVISEMPTY( &cbv )) { for( i = 0; sl.list[i].name; i++ ) { @@ -380,27 +381,28 @@ slap_auxprop_lookup( } } - if ( op.o_bd->be_search ) { + if ( op->o_bd->be_search ) { SlapReply rs = {REP_RESULT}; - op.o_hdr = conn->c_sasl_bindop->o_hdr; - op.o_tag = LDAP_REQ_SEARCH; - op.o_dn = conn->c_ndn; - op.o_ndn = conn->c_ndn; - op.o_callback = &cb; - slap_op_time( &op.o_time, &op.o_tincr ); - op.o_do_not_cache = 1; - op.o_is_auth_check = 1; - op.o_req_dn = op.o_req_ndn; - op.ors_scope = LDAP_SCOPE_BASE; - op.ors_deref = LDAP_DEREF_NEVER; - op.ors_tlimit = SLAP_NO_LIMIT; - op.ors_slimit = 1; - op.ors_filter = &generic_filter; - op.ors_filterstr = generic_filterstr; + op->o_hdr = conn->c_sasl_bindop->o_hdr; + op->o_controls = opbuf.ob_controls; + op->o_tag = LDAP_REQ_SEARCH; + op->o_dn = conn->c_ndn; + op->o_ndn = conn->c_ndn; + op->o_callback = &cb; + slap_op_time( &op->o_time, &op->o_tincr ); + op->o_do_not_cache = 1; + op->o_is_auth_check = 1; + op->o_req_dn = op->o_req_ndn; + op->ors_scope = LDAP_SCOPE_BASE; + op->ors_deref = LDAP_DEREF_NEVER; + op->ors_tlimit = SLAP_NO_LIMIT; + op->ors_slimit = 1; + op->ors_filter = &generic_filter; + op->ors_filterstr = generic_filterstr; /* FIXME: we want all attributes, right? */ - op.ors_attrs = NULL; + op->ors_attrs = NULL; - op.o_bd->be_search( &op, &rs ); + op->o_bd->be_search( op, &rs ); } } } diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 18e11a6e58..ef9c40f7b9 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -1804,6 +1804,7 @@ struct BackendDB { #define SLAP_DBFLAG_SHADOW_MASK (SLAP_DBFLAG_SHADOW|SLAP_DBFLAG_SINGLE_SHADOW|SLAP_DBFLAG_SYNC_SHADOW|SLAP_DBFLAG_SLURP_SHADOW) #define SLAP_DBFLAG_CLEAN 0x10000U /* was cleanly shutdown */ #define SLAP_DBFLAG_ACL_ADD 0x20000U /* check attr ACLs on adds */ +#define SLAP_DBFLAG_SYNC_SUBENTRY 0x40000U /* use subentry for context */ slap_mask_t be_flags; #define SLAP_DBFLAGS(be) ((be)->be_flags) #define SLAP_NOLASTMOD(be) (SLAP_DBFLAGS(be) & SLAP_DBFLAG_NOLASTMOD) @@ -1830,6 +1831,7 @@ struct BackendDB { #define SLAP_MULTIMASTER(be) (!SLAP_SINGLE_SHADOW(be)) #define SLAP_DBCLEAN(be) (SLAP_DBFLAGS(be) & SLAP_DBFLAG_CLEAN) #define SLAP_DBACL_ADD(be) (SLAP_DBFLAGS(be) & SLAP_DBFLAG_ACL_ADD) +#define SLAP_SYNC_SUBENTRY(be) (SLAP_DBFLAGS(be) & SLAP_DBFLAG_SYNC_SUBENTRY) slap_mask_t be_restrictops; /* restriction operations */ #define SLAP_RESTRICT_OP_ADD 0x0001U diff --git a/servers/slapd/slapadd.c b/servers/slapd/slapadd.c index 4159d8ff42..a57511eb73 100644 --- a/servers/slapd/slapadd.c +++ b/servers/slapd/slapadd.c @@ -438,10 +438,32 @@ slapadd( int argc, char **argv ) } if ( rc == EXIT_SUCCESS && update_ctxcsn && !dryrun && sid != SLAP_SYNC_SID_MAX + 1 ) { - ctxcsn_id = be->be_dn2id_get( be, be->be_nsuffix ); + struct berval ctxdn; + if ( SLAP_SYNC_SUBENTRY( be )) { + build_new_dn( &ctxdn, &be->be_nsuffix[0], + (struct berval *)&slap_ldapsync_cn_bv, NULL ); + } else { + ctxdn = be->be_nsuffix[0]; + } + ctxcsn_id = be->be_dn2id_get( be, &ctxdn ); if ( ctxcsn_id == NOID ) { - fprintf( stderr, "%s: context entry is missing\n", progname ); - rc = EXIT_FAILURE; + if ( SLAP_SYNC_SUBENTRY( be )) { + ctxcsn_e = slap_create_context_csn_entry( be, NULL ); + for ( sid = 0; sid <= SLAP_SYNC_SID_MAX; sid++ ) { + if ( maxcsn[ sid ].bv_len ) { + attr_merge_one( ctxcsn_e, slap_schema.si_ad_contextCSN, + &maxcsn[ sid ], NULL ); + } + } + ctxcsn_id = be->be_entry_put( be, ctxcsn_e, &bvtext ); + if ( ctxcsn_id == NOID ) { + fprintf( stderr, "%s: couldn't create context entry\n", progname ); + rc = EXIT_FAILURE; + } + } else { + fprintf( stderr, "%s: context entry is missing\n", progname ); + rc = EXIT_FAILURE; + } } else { ctxcsn_e = be->be_entry_get( be, ctxcsn_id ); if ( ctxcsn_e != NULL ) { diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c index 22496b66b3..e098251824 100644 --- a/servers/slapd/syncrepl.c +++ b/servers/slapd/syncrepl.c @@ -70,6 +70,7 @@ typedef struct syncinfo_s { struct berval si_logbase; struct berval si_filterstr; struct berval si_logfilterstr; + struct berval si_contextdn; int si_scope; int si_attrsonly; char *si_anfile; @@ -119,7 +120,7 @@ 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 * ); @@ -458,8 +459,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 ); @@ -627,7 +628,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 */ @@ -753,7 +754,6 @@ do_syncrep2( err = LDAP_SUCCESS; ber_len_t len; - struct berval *psub; Modifications *modlist = NULL; int match, m; @@ -775,8 +775,6 @@ 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 ) { @@ -873,7 +871,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: @@ -893,7 +891,7 @@ do_syncrep2( syncstate, &syncUUID, syncCookie.ctxcsn ) ) == LDAP_SUCCESS && syncCookie.ctxcsn ) { - rc = syncrepl_updateCookie( si, op, psub, &syncCookie ); + rc = syncrepl_updateCookie( si, op, &syncCookie ); } } ldap_controls_free( rctrls ); @@ -1013,7 +1011,7 @@ 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 ) { @@ -1174,7 +1172,7 @@ do_syncrep2( if ( syncCookie.ctxcsn ) { - rc = syncrepl_updateCookie( si, op, psub, &syncCookie); + rc = syncrepl_updateCookie( si, op, &syncCookie); } } @@ -1330,6 +1328,12 @@ do_syncrepl( } 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; @@ -2957,7 +2961,6 @@ static int syncrepl_updateCookie( syncinfo_t *si, Operation *op, - struct berval *pdn, struct sync_cookie *syncCookie ) { Backend *be = op->o_bd; @@ -3048,8 +3051,8 @@ 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; @@ -3057,6 +3060,20 @@ syncrepl_updateCookie( 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 ); + 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; @@ -3695,6 +3712,9 @@ syncinfo_free( syncinfo_t *sie, int free_all ) if ( sie->si_logbase.bv_val ) { ch_free( sie->si_logbase.bv_val ); } + if ( 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 ) {