From: Kurt Zeilenga Date: Wed, 5 Oct 2005 19:42:19 +0000 (+0000) Subject: Sync with HEAD X-Git-Tag: OPENLDAP_REL_ENG_2_3_8~5 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=164d5c2d0f4670ba46ca71c7b9cc409ad8e0faf6;p=openldap Sync with HEAD --- diff --git a/CHANGES b/CHANGES index 45b863c4a5..859b1708d1 100644 --- a/CHANGES +++ b/CHANGES @@ -38,6 +38,7 @@ OpenLDAP 2.3.8 Release Fixed slapcat out-of-memory problem (ITS#4010) Fixed slurpd unrecognized slave names bug (ITS#4012) Fixed liblber dgram len bug (ITS#4046) + Updated contrib/ldapc++ to avoid deprecated functions Documentation Added slapo-valsort(5) man page (ITS#3994) Added slap tool -F option documentation (ITS#4026) @@ -46,6 +47,7 @@ OpenLDAP 2.3.8 Release Fixed --without-threads build issue (ITS#4006) Fixed test script exit checks (ITS#4045) Added test suite parameterized directory support + Updated contrib/ldapc++ build environment OpenLDAP 2.3.7 Release Updated slapd ManageDIT support diff --git a/doc/man/man5/slapd-meta.5 b/doc/man/man5/slapd-meta.5 index 9c61bb15d1..548e9a2bbc 100644 --- a/doc/man/man5/slapd-meta.5 +++ b/doc/man/man5/slapd-meta.5 @@ -244,6 +244,13 @@ the target using the "pseudorootdn" DN. Note: cleartext credentials must be supplied here; as a consequence, using the pseudorootdn/pseudorootpw directives is inherently unsafe. +.TP +.B pseudoroot-bind-defer {NO|yes} +This directive, when set to +.BR yes , +causes the authentication to the remote servers with the pseudo-root +identity to be deferred until actually needed by subsequent operations. + .TP .B rewrite* ... The rewrite options are described in the "REWRITING" section. diff --git a/libraries/libldap/cyrus.c b/libraries/libldap/cyrus.c index 564cee7072..99893b285d 100644 --- a/libraries/libldap/cyrus.c +++ b/libraries/libldap/cyrus.c @@ -689,6 +689,9 @@ ldap_int_sasl_bind( if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) { rc = ld->ld_errno = sasl_err2ldap( saslrc ); #if SASL_VERSION_MAJOR >= 2 + if ( ld->ld_error ) { + LDAP_FREE( ld->ld_error ); + } ld->ld_error = LDAP_STRDUP( sasl_errdetail( ctx ) ); #endif goto done; @@ -710,11 +713,13 @@ ldap_int_sasl_bind( } if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) { - if( scred && scred->bv_len ) { - /* and server provided us with data? */ - Debug( LDAP_DEBUG_TRACE, - "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n", - rc, saslrc, scred->bv_len ); + if( scred ) { + if ( scred->bv_len ) { + /* and server provided us with data? */ + Debug( LDAP_DEBUG_TRACE, + "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n", + rc, saslrc, scred->bv_len ); + } ber_bvfree( scred ); } rc = ld->ld_errno; @@ -723,11 +728,13 @@ ldap_int_sasl_bind( if( rc == LDAP_SUCCESS && saslrc == SASL_OK ) { /* we're done, no need to step */ - if( scred && scred->bv_len ) { - /* but server provided us with data! */ - Debug( LDAP_DEBUG_TRACE, - "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n", - rc, saslrc, scred->bv_len ); + if( scred ) { + if ( scred->bv_len ) { + /* but server provided us with data! */ + Debug( LDAP_DEBUG_TRACE, + "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n", + rc, saslrc, scred->bv_len ); + } ber_bvfree( scred ); rc = ld->ld_errno = LDAP_LOCAL_ERROR; goto done; @@ -760,6 +767,9 @@ ldap_int_sasl_bind( if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) { ld->ld_errno = sasl_err2ldap( saslrc ); #if SASL_VERSION_MAJOR >= 2 + if ( ld->ld_error ) { + LDAP_FREE( ld->ld_error ); + } ld->ld_error = LDAP_STRDUP( sasl_errdetail( ctx ) ); #endif rc = ld->ld_errno; @@ -771,6 +781,9 @@ ldap_int_sasl_bind( if ( saslrc != SASL_OK ) { #if SASL_VERSION_MAJOR >= 2 + if ( ld->ld_error ) { + LDAP_FREE( ld->ld_error ); + } ld->ld_error = LDAP_STRDUP( sasl_errdetail( ctx ) ); #endif rc = ld->ld_errno = sasl_err2ldap( saslrc ); diff --git a/libraries/libldap/tls.c b/libraries/libldap/tls.c index 5e43f8aeb6..71a5e33d20 100644 --- a/libraries/libldap/tls.c +++ b/libraries/libldap/tls.c @@ -753,6 +753,10 @@ ldap_int_tls_connect( LDAP *ld, LDAPConn *conn ) if ((err = ERR_peek_error())) { char buf[256]; + + if ( ld->ld_error ) { + LDAP_FREE( ld->ld_error ); + } ld->ld_error = LDAP_STRDUP(ERR_error_string(err, buf)); #ifdef HAVE_EBCDIC if ( ld->ld_error ) __etoa(ld->ld_error); @@ -1036,7 +1040,10 @@ ldap_pvt_tls_check_hostname( LDAP *ld, void *s, const char *name_in ) Debug( LDAP_DEBUG_ANY, "TLS: unable to get common name from peer certificate.\n", 0, 0, 0 ); - ret = LDAP_CONNECT_ERROR; + ret = LDAP_CONNECT_ERROR; + if ( ld->ld_error ) { + LDAP_FREE( ld->ld_error ); + } ld->ld_error = LDAP_STRDUP( _("TLS: unable to get CN from peer certificate")); @@ -1061,12 +1068,15 @@ ldap_pvt_tls_check_hostname( LDAP *ld, void *s, const char *name_in ) } if( ret == LDAP_LOCAL_ERROR ) { - Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match " - "common name in certificate (%s).\n", - name, buf, 0 ); - ret = LDAP_CONNECT_ERROR; - ld->ld_error = LDAP_STRDUP( - _("TLS: hostname does not match CN in peer certificate")); + Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match " + "common name in certificate (%s).\n", + name, buf, 0 ); + ret = LDAP_CONNECT_ERROR; + if ( ld->ld_error ) { + LDAP_FREE( ld->ld_error ); + } + ld->ld_error = LDAP_STRDUP( + _("TLS: hostname does not match CN in peer certificate")); } } X509_free(x); diff --git a/libraries/libldap/unbind.c b/libraries/libldap/unbind.c index 3d92fc5076..86b9ab2baa 100644 --- a/libraries/libldap/unbind.c +++ b/libraries/libldap/unbind.c @@ -140,6 +140,13 @@ ldap_ld_free( ld->ld_options.ldo_defludp = NULL; } +#ifdef LDAP_CONNECTIONLESS + if ( ld->ld_options.ldo_peer != NULL ) { + LDAP_FREE( ld->ld_options.ldo_peer ); + ld->ld_options.ldo_peer = NULL; + } +#endif + if ( ld->ld_options.ldo_tm_api != NULL ) { LDAP_FREE( ld->ld_options.ldo_tm_api ); ld->ld_options.ldo_tm_api = NULL; diff --git a/libraries/liblutil/csn.c b/libraries/liblutil/csn.c index b6a43ddb33..4dcfc68079 100644 --- a/libraries/liblutil/csn.c +++ b/libraries/liblutil/csn.c @@ -67,7 +67,7 @@ lutil_csnstr(char *buf, size_t len, unsigned int replica, unsigned int mod) csntime = t; csnop = 0; } - op = ++csnop; + op = csnop++; #ifdef HAVE_GMTIME_R ltm = gmtime_r( &t, <m_buf ); diff --git a/servers/slapd/back-meta/back-meta.h b/servers/slapd/back-meta/back-meta.h index 5a7f92e1c2..5d1911d3ed 100644 --- a/servers/slapd/back-meta/back-meta.h +++ b/servers/slapd/back-meta/back-meta.h @@ -312,14 +312,17 @@ meta_back_retry( extern void meta_back_conn_free( - metaconn_t *mc ); + void *v_mc ); extern int meta_back_init_one_conn( Operation *op, SlapReply *rs, metatarget_t *mt, + metaconn_t *mc, metasingleconn_t *msc, + int ispriv, + int isauthz, ldap_back_send_t sendok ); extern int diff --git a/servers/slapd/back-meta/bind.c b/servers/slapd/back-meta/bind.c index 17dab2f397..2106a2d7e5 100644 --- a/servers/slapd/back-meta/bind.c +++ b/servers/slapd/back-meta/bind.c @@ -391,7 +391,9 @@ retry:; /* mc here must be the regular mc, * reset and ready for init */ rc = meta_back_init_one_conn( op, rs, - mt, msc, LDAP_BACK_DONTSEND ); + mt, mc, msc, LDAP_BACK_CONN_ISPRIV( mc ), + candidate == mc->mc_authz_target, + LDAP_BACK_DONTSEND ); } else { /* can't do anything about it */ @@ -567,7 +569,10 @@ retry:; /* mc here must be the regular mc, * reset and ready for init */ rc = meta_back_init_one_conn( op, rs, - mt, msc, LDAP_BACK_DONTSEND ); + mt, mc, msc, + LDAP_BACK_CONN_ISPRIV( mc ), + candidate == mc->mc_authz_target, + LDAP_BACK_DONTSEND ); } else { diff --git a/servers/slapd/back-meta/conn.c b/servers/slapd/back-meta/conn.c index 0c8d140166..1d0a548958 100644 --- a/servers/slapd/back-meta/conn.c +++ b/servers/slapd/back-meta/conn.c @@ -176,27 +176,6 @@ metaconn_alloc( return mc; } -/* - * meta_back_conn_free - * - * clears a metaconn - */ - -void -meta_back_conn_free( - metaconn_t *mc ) -{ - assert( mc != NULL ); - assert( mc->mc_refcnt == 0 ); - - if ( !BER_BVISNULL( &mc->mc_local_ndn ) ) { - free( mc->mc_local_ndn.bv_val ); - } - - ldap_pvt_thread_mutex_destroy( &mc->mc_mutex ); - free( mc ); -} - static void meta_back_freeconn( Operation *op, @@ -225,7 +204,10 @@ meta_back_init_one_conn( Operation *op, SlapReply *rs, metatarget_t *mt, + metaconn_t *mc, metasingleconn_t *msc, + int ispriv, + int isauthz, ldap_back_send_t sendok ) { metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; @@ -367,32 +349,54 @@ retry:; /* * If the connection DN is not null, an attempt to rewrite it is made */ - if ( !BER_BVISEMPTY( &op->o_conn->c_dn ) ) { - dc.target = mt; - dc.conn = op->o_conn; - dc.rs = rs; - dc.ctx = "bindDN"; - - /* - * Rewrite the bind dn if needed - */ - if ( ldap_back_dn_massage( &dc, &op->o_conn->c_dn, - &msc->msc_bound_ndn ) ) - { - goto error_return; - } - /* copy the DN idf needed */ - if ( msc->msc_bound_ndn.bv_val == op->o_conn->c_dn.bv_val ) { - ber_dupbv( &msc->msc_bound_ndn, &op->o_conn->c_dn ); + if ( ispriv ) { + if ( !BER_BVISNULL( &mt->mt_pseudorootdn ) ) { + ber_dupbv( &msc->msc_bound_ndn, &mt->mt_pseudorootdn ); + if ( !BER_BVISNULL( &mt->mt_pseudorootpw ) ) { + ber_dupbv( &msc->msc_cred, &mt->mt_pseudorootpw ); + } + + } else { + ber_str2bv( "", 0, 1, &msc->msc_bound_ndn ); } - assert( !BER_BVISNULL( &msc->msc_bound_ndn ) ); + LDAP_BACK_CONN_ISPRIV_SET( msc ); } else { - ber_str2bv( "", 0, 1, &msc->msc_bound_ndn ); + BER_BVZERO( &msc->msc_cred ); + BER_BVZERO( &msc->msc_bound_ndn ); + if ( !BER_BVISEMPTY( &op->o_ndn ) + && SLAP_IS_AUTHZ_BACKEND( op ) + && isauthz ) + { + dc.target = mt; + dc.conn = op->o_conn; + dc.rs = rs; + dc.ctx = "bindDN"; + + /* + * Rewrite the bind dn if needed + */ + if ( ldap_back_dn_massage( &dc, &op->o_conn->c_dn, + &msc->msc_bound_ndn ) ) + { + ldap_unbind_ext_s( msc->msc_ld, NULL, NULL ); + goto error_return; + } + + /* copy the DN idf needed */ + if ( msc->msc_bound_ndn.bv_val == op->o_conn->c_dn.bv_val ) { + ber_dupbv( &msc->msc_bound_ndn, &op->o_conn->c_dn ); + } + + } else { + ber_str2bv( "", 0, 1, &msc->msc_bound_ndn ); + } } + assert( !BER_BVISNULL( &msc->msc_bound_ndn ) ); + LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); error_return:; @@ -450,7 +454,9 @@ retry_lock:; ( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn ); /* mc here must be the regular mc, reset and ready for init */ - rc = meta_back_init_one_conn( op, rs, mt, msc, sendok ); + rc = meta_back_init_one_conn( op, rs, mt, mc, msc, + LDAP_BACK_CONN_ISPRIV( mc ), + candidate == mc->mc_authz_target, sendok ); if ( rc == LDAP_SUCCESS ) { rc = meta_back_single_dobind( op, rs, mc, candidate, @@ -781,27 +787,13 @@ meta_back_getconn( * also init'd */ candidates[ i ].sr_err = meta_back_init_one_conn( op, - rs, mt, msc, sendok ); + rs, mt, mc, msc, + LDAP_BACK_CONN_ISPRIV( &mc_curr ), + i == mc->mc_authz_target, sendok ); if ( candidates[ i ].sr_err == LDAP_SUCCESS ) { candidates[ i ].sr_tag = META_CANDIDATE; ncandidates++; - if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) { - ber_dupbv( &msc->msc_cred, &mt->mt_pseudorootpw ); - ber_dupbv( &msc->msc_bound_ndn, &mt->mt_pseudorootdn ); - LDAP_BACK_CONN_ISPRIV_SET( msc ); - - } else { - BER_BVZERO( &msc->msc_cred ); - BER_BVZERO( &msc->msc_bound_ndn ); - if ( !BER_BVISEMPTY( &op->o_ndn ) - && SLAP_IS_AUTHZ_BACKEND( op ) - && i == mc->mc_authz_target ) - { - ber_dupbv( &msc->msc_bound_ndn, &op->o_ndn ); - } - } - } else { /* @@ -941,7 +933,9 @@ meta_back_getconn( * also init'd. In case of error, meta_back_init_one_conn * sends the appropriate result. */ - err = meta_back_init_one_conn( op, rs, mt, msc, sendok ); + err = meta_back_init_one_conn( op, rs, mt, mc, msc, + LDAP_BACK_CONN_ISPRIV( &mc_curr ), + i == mc->mc_authz_target, sendok ); if ( err != LDAP_SUCCESS ) { /* * FIXME: in case one target cannot @@ -967,22 +961,6 @@ meta_back_getconn( *candidate = i; } - if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) { - ber_dupbv( &msc->msc_cred, &mt->mt_pseudorootpw ); - ber_dupbv( &msc->msc_bound_ndn, &mt->mt_pseudorootdn ); - LDAP_BACK_CONN_ISPRIV_SET( msc ); - - } else { - BER_BVZERO( &msc->msc_cred ); - BER_BVZERO( &msc->msc_bound_ndn ); - if ( !BER_BVISEMPTY( &op->o_ndn ) - && SLAP_IS_AUTHZ_BACKEND( op ) - && i == mc->mc_authz_target ) - { - ber_dupbv( &msc->msc_bound_ndn, &op->o_ndn ); - } - } - /* * if no unique candidate ... */ @@ -1012,28 +990,15 @@ meta_back_getconn( * also init'd */ int lerr = meta_back_init_one_conn( op, rs, - mt, msc, sendok ); + mt, mc, msc, + LDAP_BACK_CONN_ISPRIV( &mc_curr ), + i == mc->mc_authz_target, + sendok ); if ( lerr == LDAP_SUCCESS ) { candidates[ i ].sr_tag = META_CANDIDATE; candidates[ i ].sr_err = LDAP_SUCCESS; ncandidates++; - if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) { - ber_dupbv( &msc->msc_cred, &mt->mt_pseudorootpw ); - ber_dupbv( &msc->msc_bound_ndn, &mt->mt_pseudorootdn ); - LDAP_BACK_CONN_ISPRIV_SET( msc ); - - } else { - BER_BVZERO( &msc->msc_cred ); - BER_BVZERO( &msc->msc_bound_ndn ); - if ( !BER_BVISEMPTY( &op->o_ndn ) - && SLAP_IS_AUTHZ_BACKEND( op ) - && i == mc->mc_authz_target ) - { - ber_dupbv( &msc->msc_bound_ndn, &op->o_ndn ); - } - } - Debug( LDAP_DEBUG_TRACE, "%s: meta_back_init_one_conn(%d)\n", op->o_log_prefix, i, 0 ); diff --git a/servers/slapd/back-meta/init.c b/servers/slapd/back-meta/init.c index fb2b0d50ce..3f71a429f2 100644 --- a/servers/slapd/back-meta/init.c +++ b/servers/slapd/back-meta/init.c @@ -126,13 +126,20 @@ meta_back_db_open( return 0; } -static void -conn_free( +void +meta_back_conn_free( void *v_mc ) { metaconn_t *mc = v_mc; int i, ntargets; + assert( mc != NULL ); + assert( mc->mc_refcnt == 0 ); + + if ( !BER_BVISNULL( &mc->mc_local_ndn ) ) { + free( mc->mc_local_ndn.bv_val ); + } + assert( mc->mc_conns != NULL ); /* at least one must be present... */ @@ -156,6 +163,7 @@ conn_free( } } + ldap_pvt_thread_mutex_destroy( &mc->mc_mutex ); free( mc ); } @@ -220,7 +228,7 @@ meta_back_db_destroy( ldap_pvt_thread_mutex_lock( &mi->mi_conn_mutex ); if ( mi->mi_conntree ) { - avl_free( mi->mi_conntree, conn_free ); + avl_free( mi->mi_conntree, meta_back_conn_free ); } /* diff --git a/servers/slapd/back-sql/schema-map.c b/servers/slapd/back-sql/schema-map.c index 02a73924ce..ae97d27cf0 100644 --- a/servers/slapd/back-sql/schema-map.c +++ b/servers/slapd/back-sql/schema-map.c @@ -231,7 +231,7 @@ backsql_add_sysmaps( backsql_info *bi, backsql_oc_map_rec *oc_map ) snprintf( tmp, sizeof(tmp), "DELETE FROM ldap_entry_objclasses " "WHERE entry_id=(SELECT id FROM ldap_entries " - "WHERE oc_map_id=%lu" + "WHERE oc_map_id=%lu " "AND keyval=?) AND oc_name=?", oc_map->bom_id ); at_map->bam_delete_proc = ch_strdup( tmp ); diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c index f6f868a30d..77dcf4a422 100644 --- a/servers/slapd/backend.c +++ b/servers/slapd/backend.c @@ -614,7 +614,13 @@ select_backend( continue; } } else { - b2 = be; + /* If any parts of the tree are glued, use the first + * match regardless of manageDSAit. Otherwise use the + * last match. + */ + if( !( SLAP_DBFLAGS( be ) & ( SLAP_DBFLAG_GLUE_INSTANCE | + SLAP_DBFLAG_GLUE_SUBORDINATE ))) + b2 = be; } return b2; } diff --git a/servers/slapd/backover.c b/servers/slapd/backover.c index 4f5d1042f9..054edbe11a 100644 --- a/servers/slapd/backover.c +++ b/servers/slapd/backover.c @@ -868,6 +868,7 @@ overlay_config( BackendDB *be, const char *ov ) oi = ch_malloc( sizeof( slap_overinfo ) ); oi->oi_orig = be->bd_info; oi->oi_bi = *be->bd_info; + oi->oi_origdb = be; /* NOTE: the first time a global overlay is configured, * frontendDB gets this flag; it is used later by overlays diff --git a/servers/slapd/overlays/accesslog.c b/servers/slapd/overlays/accesslog.c index 2cbda0046e..88500027f8 100644 --- a/servers/slapd/overlays/accesslog.c +++ b/servers/slapd/overlays/accesslog.c @@ -654,30 +654,41 @@ static Entry *accesslog_entry( Operation *op, int logop ) { log_info *li = on->on_bi.bi_private; char rdnbuf[STRLENOF(RDNEQ)+LDAP_LUTIL_GENTIME_BUFSIZE+8]; - struct berval rdn, timestamp, bv; + char nrdnbuf[STRLENOF(RDNEQ)+LDAP_LUTIL_GENTIME_BUFSIZE+8]; + + struct berval rdn, nrdn, timestamp, ntimestamp, bv; slap_verbmasks *lo = logops+logop+EN_OFFSET; Entry *e = ch_calloc( 1, sizeof(Entry) ); strcpy( rdnbuf, RDNEQ ); rdn.bv_val = rdnbuf; + strcpy( nrdnbuf, RDNEQ ); + nrdn.bv_val = nrdnbuf; timestamp.bv_val = rdnbuf+STRLENOF(RDNEQ); timestamp.bv_len = sizeof(rdnbuf) - STRLENOF(RDNEQ); slap_timestamp( &op->o_time, ×tamp ); - if ( op->o_tincr ) { - sprintf( timestamp.bv_val + timestamp.bv_len-1, ".%06dZ", op->o_tincr ); - timestamp.bv_len += 7; - } + sprintf( timestamp.bv_val + timestamp.bv_len-1, ".%06dZ", op->o_tincr ); + timestamp.bv_len += 7; + rdn.bv_len = STRLENOF(RDNEQ)+timestamp.bv_len; + ad_reqStart->ad_type->sat_equality->smr_normalize( + SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, ad_reqStart->ad_type->sat_syntax, + ad_reqStart->ad_type->sat_equality, ×tamp, &ntimestamp, + op->o_tmpmemctx ); + + strcpy( nrdn.bv_val + STRLENOF(RDNEQ), ntimestamp.bv_val ); + nrdn.bv_len += ntimestamp.bv_len; build_new_dn( &e->e_name, li->li_db->be_suffix, &rdn, NULL ); - build_new_dn( &e->e_nname, li->li_db->be_nsuffix, &rdn, NULL ); + build_new_dn( &e->e_nname, li->li_db->be_nsuffix, &nrdn, NULL ); attr_merge_one( e, slap_schema.si_ad_objectClass, &log_ocs[logop]->soc_cname, NULL ); attr_merge_one( e, slap_schema.si_ad_structuralObjectClass, &log_ocs[logop]->soc_cname, NULL ); - attr_merge_one( e, ad_reqStart, ×tamp, NULL ); + attr_merge_one( e, ad_reqStart, ×tamp, &ntimestamp ); + op->o_tmpfree( ntimestamp.bv_val, op->o_tmpmemctx ); /* Exops have OID appended */ if ( logop == LOG_EN_EXTENDED ) { diff --git a/servers/slapd/overlays/syncprov.c b/servers/slapd/overlays/syncprov.c index 05f56c447d..4316dd042d 100644 --- a/servers/slapd/overlays/syncprov.c +++ b/servers/slapd/overlays/syncprov.c @@ -26,6 +26,7 @@ #include "lutil.h" #include "slap.h" #include "config.h" +#include "ldap_rq.h" /* A modify request on a particular entry */ typedef struct modinst { @@ -60,9 +61,16 @@ typedef struct syncops { int s_rid; struct berval s_filterstr; int s_flags; /* search status */ +#define PS_IS_REFRESHING 0x01 +#define PS_IS_DETACHED 0x02 +#define PS_WROTE_BASE 0x04 +#define PS_FIND_BASE 0x08 + int s_inuse; /* reference count */ struct syncres *s_res; struct syncres *s_restail; + struct re_s *s_qtask; /* task for playing psearch responses */ +#define RUNQ_INTERVAL 36000 /* a long time */ ldap_pvt_thread_mutex_t s_mutex; } syncops; @@ -83,9 +91,6 @@ typedef struct sync_control { #define SLAP_SYNC_PERSIST (LDAP_SYNC_RESERVED<fss->s_eid == NOID ) { - fc->fbase = 1; + fc->fbase = 2; fc->fss->s_eid = rs->sr_entry->e_id; ber_dupbv( &fc->fss->s_base, &rs->sr_entry->e_nname ); } else if ( rs->sr_entry->e_id == fc->fss->s_eid && dn_match( &rs->sr_entry->e_nname, &fc->fss->s_base )) { - /* OK, the DN is the same and the entryID is the same. Now - * see if the fdn resides in the scope. - */ + /* OK, the DN is the same and the entryID is the same. */ fc->fbase = 1; - switch ( fc->fss->s_op->ors_scope ) { - case LDAP_SCOPE_BASE: - fc->fscope = dn_match( fc->fdn, &rs->sr_entry->e_nname ); - break; - case LDAP_SCOPE_ONELEVEL: { - struct berval pdn; - dnParent( fc->fdn, &pdn ); - fc->fscope = dn_match( &pdn, &rs->sr_entry->e_nname ); - break; } - case LDAP_SCOPE_SUBTREE: - fc->fscope = dnIsSuffix( fc->fdn, &rs->sr_entry->e_nname ); - break; -#ifdef LDAP_SCOPE_SUBORDINATE - case LDAP_SCOPE_SUBORDINATE: - fc->fscope = dnIsSuffix( fc->fdn, &rs->sr_entry->e_nname ) && - !dn_match( fc->fdn, &rs->sr_entry->e_nname ); - break; -#endif - } } } if ( rs->sr_err != LDAP_SUCCESS ) { @@ -404,40 +388,73 @@ syncprov_findbase( Operation *op, fbase_cookie *fc ) opcookie *opc = op->o_callback->sc_private; slap_overinst *on = opc->son; - slap_callback cb = {0}; - Operation fop; - SlapReply frs = { REP_RESULT }; - int rc; - /* Use basic parameters from syncrepl search, but use * current op's threadctx / tmpmemctx */ - fop = *fc->fss->s_op; + ldap_pvt_thread_mutex_lock( &fc->fss->s_mutex ); + if ( fc->fss->s_flags & PS_FIND_BASE ) { + slap_callback cb = {0}; + Operation fop; + SlapReply frs = { REP_RESULT }; + int rc; - fop.o_hdr = op->o_hdr; - fop.o_bd = op->o_bd; - fop.o_time = op->o_time; - fop.o_tincr = op->o_tincr; + fc->fss->s_flags ^= PS_FIND_BASE; + ldap_pvt_thread_mutex_unlock( &fc->fss->s_mutex ); - cb.sc_response = findbase_cb; - cb.sc_private = fc; + fop = *fc->fss->s_op; - fop.o_sync_mode = 0; /* turn off sync mode */ - fop.o_managedsait = SLAP_CONTROL_CRITICAL; - fop.o_callback = &cb; - fop.o_tag = LDAP_REQ_SEARCH; - fop.ors_scope = LDAP_SCOPE_BASE; - fop.ors_limit = NULL; - fop.ors_slimit = 1; - fop.ors_tlimit = SLAP_NO_LIMIT; - fop.ors_attrs = slap_anlist_no_attrs; - fop.ors_attrsonly = 1; + fop.o_hdr = op->o_hdr; + fop.o_bd = op->o_bd; + fop.o_time = op->o_time; + fop.o_tincr = op->o_tincr; - fop.o_bd->bd_info = on->on_info->oi_orig; - rc = fop.o_bd->be_search( &fop, &frs ); - fop.o_bd->bd_info = (BackendInfo *)on; + cb.sc_response = findbase_cb; + cb.sc_private = fc; - if ( fc->fbase ) return LDAP_SUCCESS; + fop.o_sync_mode = 0; /* turn off sync mode */ + fop.o_managedsait = SLAP_CONTROL_CRITICAL; + fop.o_callback = &cb; + fop.o_tag = LDAP_REQ_SEARCH; + fop.ors_scope = LDAP_SCOPE_BASE; + fop.ors_limit = NULL; + fop.ors_slimit = 1; + fop.ors_tlimit = SLAP_NO_LIMIT; + fop.ors_attrs = slap_anlist_no_attrs; + fop.ors_attrsonly = 1; + + fop.o_bd->bd_info = on->on_info->oi_orig; + rc = fop.o_bd->be_search( &fop, &frs ); + fop.o_bd->bd_info = (BackendInfo *)on; + } else { + ldap_pvt_thread_mutex_unlock( &fc->fss->s_mutex ); + fc->fbase = 1; + } + + /* After the first call, see if the fdn resides in the scope */ + if ( fc->fbase == 1 ) { + switch ( fc->fss->s_op->ors_scope ) { + case LDAP_SCOPE_BASE: + fc->fscope = dn_match( fc->fdn, &fc->fss->s_base ); + break; + case LDAP_SCOPE_ONELEVEL: { + struct berval pdn; + dnParent( fc->fdn, &pdn ); + fc->fscope = dn_match( &pdn, &fc->fss->s_base ); + break; } + case LDAP_SCOPE_SUBTREE: + fc->fscope = dnIsSuffix( fc->fdn, &fc->fss->s_base ); + break; +#ifdef LDAP_SCOPE_SUBORDINATE + case LDAP_SCOPE_SUBORDINATE: + fc->fscope = dnIsSuffix( fc->fdn, &fc->fss->s_base ) && + !dn_match( fc->fdn, &fc->fss->s_base ); + break; +#endif + } + } + + if ( fc->fbase ) + return LDAP_SUCCESS; /* If entryID has changed, then the base of this search has * changed. Invalidate the psearch. @@ -680,90 +697,38 @@ again: return rc; } -/* Queue a persistent search response */ -static int -syncprov_qresp( opcookie *opc, syncops *so, int mode ) +static void +syncprov_free_syncop( syncops *so ) { - syncres *sr; - - sr = ch_malloc(sizeof(syncres) + opc->suuid.bv_len + 1 + - opc->sdn.bv_len + 1 + opc->sndn.bv_len + 1 + opc->sctxcsn.bv_len + 1 ); - sr->s_next = NULL; - sr->s_dn.bv_val = (char *)(sr + 1); - sr->s_dn.bv_len = opc->sdn.bv_len; - sr->s_mode = mode; - sr->s_isreference = opc->sreference; - sr->s_ndn.bv_val = lutil_strcopy( sr->s_dn.bv_val, opc->sdn.bv_val ); - sr->s_ndn.bv_len = opc->sndn.bv_len; - *(sr->s_ndn.bv_val++) = '\0'; - sr->s_uuid.bv_val = lutil_strcopy( sr->s_ndn.bv_val, opc->sndn.bv_val ); - sr->s_uuid.bv_len = opc->suuid.bv_len; - *(sr->s_uuid.bv_val++) = '\0'; - sr->s_csn.bv_val = lutil_strcopy( sr->s_uuid.bv_val, opc->suuid.bv_val ); - sr->s_csn.bv_len = opc->sctxcsn.bv_len; - strcpy( sr->s_csn.bv_val, opc->sctxcsn.bv_val ); + syncres *sr, *srnext; + GroupAssertion *ga, *gnext; - if ( !so->s_res ) { - so->s_res = sr; - } else { - so->s_restail->s_next = sr; + ldap_pvt_thread_mutex_lock( &so->s_mutex ); + if ( --so->s_inuse > 0 ) { + ldap_pvt_thread_mutex_unlock( &so->s_mutex ); + return; } - so->s_restail = sr; ldap_pvt_thread_mutex_unlock( &so->s_mutex ); - return LDAP_SUCCESS; -} - -/* Play back queued responses */ -static int -syncprov_sendresp( Operation *op, opcookie *opc, syncops *so, Entry **e, int mode, int queue ); - -static int -syncprov_qplay( Operation *op, slap_overinst *on, syncops *so ) -{ - syncres *sr, *srnext; - Entry *e; - opcookie opc; - int rc; - - opc.son = on; - op->o_bd->bd_info = (BackendInfo *)on->on_info; - for (sr = so->s_res; sr; sr=srnext) { - srnext = sr->s_next; - opc.sdn = sr->s_dn; - opc.sndn = sr->s_ndn; - opc.suuid = sr->s_uuid; - opc.sctxcsn = sr->s_csn; - opc.sreference = sr->s_isreference; - e = NULL; - - if ( sr->s_mode != LDAP_SYNC_DELETE ) { - rc = be_entry_get_rw( op, &opc.sndn, NULL, NULL, 0, &e ); - if ( rc ) { - ch_free( sr ); - so->s_res = srnext; - continue; - } - } - rc = syncprov_sendresp( op, &opc, so, &e, sr->s_mode, 0 ); - - if ( e ) { - be_entry_release_rw( op, e, 0 ); + if ( so->s_flags & PS_IS_DETACHED ) { + filter_free( so->s_op->ors_filter ); + for ( ga = so->s_op->o_groups; ga; ga=gnext ) { + gnext = ga->ga_next; + ch_free( ga ); } - if ( rc ) - break; - + ch_free( so->s_op ); + } + ch_free( so->s_base.bv_val ); + for ( sr=so->s_res; sr; sr=srnext ) { + srnext = sr->s_next; ch_free( sr ); - so->s_res = srnext; } - op->o_bd->bd_info = (BackendInfo *)on; - if ( !so->s_res ) - so->s_restail = NULL; - return rc; + ldap_pvt_thread_mutex_destroy( &so->s_mutex ); + ch_free( so ); } /* Send a persistent search response */ static int -syncprov_sendresp( Operation *op, opcookie *opc, syncops *so, Entry **e, int mode, int queue ) +syncprov_sendresp( Operation *op, opcookie *opc, syncops *so, Entry **e, int mode) { slap_overinst *on = opc->son; @@ -772,56 +737,17 @@ syncprov_sendresp( Operation *op, opcookie *opc, syncops *so, Entry **e, int mod struct berval cookie; Entry e_uuid = {0}; Attribute a_uuid = {0}; - Operation sop = *so->s_op; - Opheader ohdr; if ( so->s_op->o_abandon ) return SLAPD_ABANDON; - ohdr = *sop.o_hdr; - sop.o_hdr = &ohdr; - sop.o_tmpmemctx = op->o_tmpmemctx; - sop.o_bd = op->o_bd; - sop.o_controls = op->o_controls; - sop.o_private = op->o_private; - sop.o_callback = NULL; - - /* If queueing is allowed */ - if ( queue ) { - ldap_pvt_thread_mutex_lock( &so->s_mutex ); - /* If we're still in refresh mode, must queue */ - if (so->s_flags & PS_IS_REFRESHING) { - return syncprov_qresp( opc, so, mode ); - } - /* If connection is free but queue is non-empty, - * try to flush the queue. - */ - if ( so->s_res ) { - rs.sr_err = syncprov_qplay( &sop, on, so ); - } - /* If the connection is busy, must queue */ - if ( sop.o_conn->c_writewaiter || rs.sr_err == LDAP_BUSY ) { - return syncprov_qresp( opc, so, mode ); - } - ldap_pvt_thread_mutex_unlock( &so->s_mutex ); - - /* If syncprov_qplay returned any other error, bail out. */ - if ( rs.sr_err ) { - return rs.sr_err; - } - } else { - /* Queueing not allowed and conn is busy, give up */ - if ( sop.o_conn->c_writewaiter ) - return LDAP_BUSY; - } - ctrls[1] = NULL; slap_compose_sync_cookie( op, &cookie, &opc->sctxcsn, so->s_rid ); e_uuid.e_attrs = &a_uuid; a_uuid.a_desc = slap_schema.si_ad_entryUUID; a_uuid.a_nvals = &opc->suuid; - rs.sr_err = syncprov_state_ctrl( &sop, &rs, &e_uuid, + rs.sr_err = syncprov_state_ctrl( op, &rs, &e_uuid, mode, ctrls, 0, 1, &cookie ); rs.sr_ctrls = ctrls; @@ -832,8 +758,8 @@ syncprov_sendresp( Operation *op, opcookie *opc, syncops *so, Entry **e, int mod if ( rs.sr_entry->e_private ) rs.sr_flags = REP_ENTRY_MUSTRELEASE; if ( opc->sreference ) { - rs.sr_ref = get_entry_referrals( &sop, rs.sr_entry ); - send_search_reference( &sop, &rs ); + rs.sr_ref = get_entry_referrals( op, rs.sr_entry ); + send_search_reference( op, &rs ); ber_bvarray_free( rs.sr_ref ); if ( !rs.sr_entry ) *e = NULL; @@ -844,8 +770,8 @@ syncprov_sendresp( Operation *op, opcookie *opc, syncops *so, Entry **e, int mod rs.sr_entry = *e; if ( rs.sr_entry->e_private ) rs.sr_flags = REP_ENTRY_MUSTRELEASE; - rs.sr_attrs = sop.ors_attrs; - send_search_entry( &sop, &rs ); + rs.sr_attrs = op->ors_attrs; + send_search_entry( op, &rs ); if ( !rs.sr_entry ) *e = NULL; break; @@ -857,60 +783,176 @@ syncprov_sendresp( Operation *op, opcookie *opc, syncops *so, Entry **e, int mod if ( opc->sreference ) { struct berval bv = BER_BVNULL; rs.sr_ref = &bv; - send_search_reference( &sop, &rs ); + send_search_reference( op, &rs ); } else { - send_search_entry( &sop, &rs ); + send_search_entry( op, &rs ); } break; default: assert(0); } - op->o_tmpfree( rs.sr_ctrls[0], op->o_tmpmemctx ); - op->o_private = sop.o_private; - rs.sr_ctrls = NULL; - /* Check queue again here; if we were hanging in a send and eventually - * recovered, there may be more to send now. But don't check if the - * original psearch has been abandoned. - */ - if ( so->s_op->o_abandon ) - return SLAPD_ABANDON; + /* In case someone else freed it already? */ + if ( rs.sr_ctrls ) { + op->o_tmpfree( rs.sr_ctrls[0], op->o_tmpmemctx ); + rs.sr_ctrls = NULL; + } - if ( rs.sr_err == LDAP_SUCCESS && queue && so->s_res ) { + return rs.sr_err; +} + +/* Play back queued responses */ +static int +syncprov_qplay( Operation *op, slap_overinst *on, syncops *so ) +{ + syncres *sr; + Entry *e; + opcookie opc; + int rc; + + opc.son = on; + op->o_bd->bd_info = (BackendInfo *)on->on_info; + + for (;;) { ldap_pvt_thread_mutex_lock( &so->s_mutex ); - rs.sr_err = syncprov_qplay( &sop, on, so ); + sr = so->s_res; + if ( sr ) + so->s_res = sr->s_next; + if ( !so->s_res ) + so->s_restail = NULL; ldap_pvt_thread_mutex_unlock( &so->s_mutex ); + + if ( !sr || so->s_op->o_abandon ) + break; + + opc.sdn = sr->s_dn; + opc.sndn = sr->s_ndn; + opc.suuid = sr->s_uuid; + opc.sctxcsn = sr->s_csn; + opc.sreference = sr->s_isreference; + e = NULL; + + if ( sr->s_mode != LDAP_SYNC_DELETE ) { + rc = be_entry_get_rw( op, &opc.sndn, NULL, NULL, 0, &e ); + if ( rc ) { + ch_free( sr ); + continue; + } + } + rc = syncprov_sendresp( op, &opc, so, &e, sr->s_mode ); + + if ( e ) { + be_entry_release_rw( op, e, 0 ); + } + + ch_free( sr ); + + if ( rc ) + break; } - return rs.sr_err; + op->o_bd->bd_info = (BackendInfo *)on; + return rc; } -static void -syncprov_free_syncop( syncops *so ) +/* runqueue task for playing back queued responses */ +static void * +syncprov_qtask( void *ctx, void *arg ) { - syncres *sr, *srnext; - GroupAssertion *ga, *gnext; + struct re_s *rtask = arg; + syncops *so = rtask->arg; + slap_overinst *on = so->s_op->o_private; + char opbuf[OPERATION_BUFFER_SIZE]; + Operation *op; + BackendDB be; + + op = (Operation *)opbuf; + *op = *so->s_op; + op->o_hdr = (Opheader *)(op+1); + op->o_controls = (void **)(op->o_hdr+1); + memset( op->o_controls, 0, SLAP_MAX_CIDS * sizeof(void *)); + + *op->o_hdr = *so->s_op->o_hdr; + + op->o_tmpmemctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx); + op->o_tmpmfuncs = &slap_sl_mfuncs; + op->o_threadctx = ctx; + + /* syncprov_qplay expects a fake db */ + be = *so->s_op->o_bd; + be.be_flags |= SLAP_DBFLAG_OVERLAY; + op->o_bd = &be; + op->o_private = NULL; + op->o_callback = NULL; + + syncprov_qplay( op, on, so ); + + /* decrement use count... */ + syncprov_free_syncop( so ); + + /* wait until we get explicitly scheduled again */ + ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); + ldap_pvt_runqueue_stoptask( &slapd_rq, so->s_qtask ); + ldap_pvt_runqueue_resched( &slapd_rq, so->s_qtask, 1 ); + ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); + + return NULL; +} + +/* Queue a persistent search response */ +static int +syncprov_qresp( opcookie *opc, syncops *so, int mode ) +{ + syncres *sr; + + sr = ch_malloc(sizeof(syncres) + opc->suuid.bv_len + 1 + + opc->sdn.bv_len + 1 + opc->sndn.bv_len + 1 + opc->sctxcsn.bv_len + 1 ); + sr->s_next = NULL; + sr->s_dn.bv_val = (char *)(sr + 1); + sr->s_dn.bv_len = opc->sdn.bv_len; + sr->s_mode = mode; + sr->s_isreference = opc->sreference; + sr->s_ndn.bv_val = lutil_strcopy( sr->s_dn.bv_val, opc->sdn.bv_val ); + sr->s_ndn.bv_len = opc->sndn.bv_len; + *(sr->s_ndn.bv_val++) = '\0'; + sr->s_uuid.bv_val = lutil_strcopy( sr->s_ndn.bv_val, opc->sndn.bv_val ); + sr->s_uuid.bv_len = opc->suuid.bv_len; + *(sr->s_uuid.bv_val++) = '\0'; + sr->s_csn.bv_val = lutil_strcopy( sr->s_uuid.bv_val, opc->suuid.bv_val ); + sr->s_csn.bv_len = opc->sctxcsn.bv_len; + strcpy( sr->s_csn.bv_val, opc->sctxcsn.bv_val ); ldap_pvt_thread_mutex_lock( &so->s_mutex ); - so->s_inuse--; - if ( so->s_inuse > 0 ) { - ldap_pvt_thread_mutex_unlock( &so->s_mutex ); - return; + if ( !so->s_res ) { + so->s_res = sr; + } else { + so->s_restail->s_next = sr; + } + so->s_restail = sr; + + /* If the base of the psearch was modified, check it next time round */ + if ( so->s_flags & PS_WROTE_BASE ) { + so->s_flags ^= PS_WROTE_BASE; + so->s_flags |= PS_FIND_BASE; } - ldap_pvt_thread_mutex_unlock( &so->s_mutex ); if ( so->s_flags & PS_IS_DETACHED ) { - filter_free( so->s_op->ors_filter ); - for ( ga = so->s_op->o_groups; ga; ga=gnext ) { - gnext = ga->ga_next; - ch_free( ga ); + ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); + if ( !so->s_qtask ) { + so->s_qtask = ldap_pvt_runqueue_insert( &slapd_rq, RUNQ_INTERVAL, + syncprov_qtask, so, "syncprov_qtask", + so->s_op->o_conn->c_peer_name.bv_val ); + ++so->s_inuse; + } else { + if (!ldap_pvt_runqueue_isrunning( &slapd_rq, so->s_qtask ) && + !so->s_qtask->next_sched.tv_sec ) { + so->s_qtask->interval.tv_sec = 0; + ldap_pvt_runqueue_resched( &slapd_rq, so->s_qtask, 0 ); + so->s_qtask->interval.tv_sec = RUNQ_INTERVAL; + ++so->s_inuse; + } } - ch_free( so->s_op ); - } - ch_free( so->s_base.bv_val ); - for ( sr=so->s_res; sr; sr=srnext ) { - srnext = sr->s_next; - ch_free( sr ); + ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); } - ldap_pvt_thread_mutex_destroy( &so->s_mutex ); - ch_free( so ); + ldap_pvt_thread_mutex_unlock( &so->s_mutex ); + return LDAP_SUCCESS; } static int @@ -1019,15 +1061,18 @@ syncprov_matchops( Operation *op, opcookie *opc, int saveit ) e = op->ora_e; } - if ( saveit ) { + if ( saveit || op->o_tag == LDAP_REQ_ADD ) { ber_dupbv_x( &opc->sdn, &e->e_name, op->o_tmpmemctx ); ber_dupbv_x( &opc->sndn, &e->e_nname, op->o_tmpmemctx ); opc->sreference = is_entry_referral( e ); - } - if ( saveit || op->o_tag == LDAP_REQ_ADD ) { a = attr_find( e->e_attrs, slap_schema.si_ad_entryUUID ); if ( a ) ber_dupbv_x( &opc->suuid, &a->a_nvals[0], op->o_tmpmemctx ); + } else if ( op->o_tag == LDAP_REQ_MODRDN && !saveit ) { + op->o_tmpfree( opc->sndn.bv_val, op->o_tmpmemctx ); + op->o_tmpfree( opc->sdn.bv_val, op->o_tmpmemctx ); + ber_dupbv_x( &opc->sdn, &e->e_name, op->o_tmpmemctx ); + ber_dupbv_x( &opc->sndn, &e->e_nname, op->o_tmpmemctx ); } ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); @@ -1055,9 +1100,18 @@ syncprov_matchops( Operation *op, opcookie *opc, int saveit ) continue; } + /* If we're sending results now, look for this op in old matches */ if ( !saveit ) { syncmatches *old; + + /* Did we modify the search base? */ + if ( dn_match( &op->o_req_ndn, &ss->s_base )) { + ldap_pvt_thread_mutex_lock( &ss->s_mutex ); + ss->s_flags |= PS_WROTE_BASE; + ldap_pvt_thread_mutex_unlock( &ss->s_mutex ); + } + for ( sm=opc->smatches, old=(syncmatches *)&opc->smatches; sm; old=sm, sm=sm->sm_next ) { if ( sm->sm_op == ss ) { @@ -1076,22 +1130,18 @@ syncprov_matchops( Operation *op, opcookie *opc, int saveit ) sm = op->o_tmpalloc( sizeof(syncmatches), op->o_tmpmemctx ); sm->sm_next = opc->smatches; sm->sm_op = ss; - ss->s_inuse++; + ldap_pvt_thread_mutex_lock( &ss->s_mutex ); + ++ss->s_inuse; + ldap_pvt_thread_mutex_unlock( &ss->s_mutex ); opc->smatches = sm; } else { /* if found send UPDATE else send ADD */ - ss->s_inuse++; - ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); - syncprov_sendresp( op, opc, ss, &e, - found ? LDAP_SYNC_MODIFY : LDAP_SYNC_ADD, 1 ); - ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); - ss->s_inuse--; + syncprov_qresp( opc, ss, + found ? LDAP_SYNC_MODIFY : LDAP_SYNC_ADD ); } } else if ( !saveit && found ) { /* send DELETE */ - ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); - syncprov_sendresp( op, opc, ss, NULL, LDAP_SYNC_DELETE, 1 ); - ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); + syncprov_qresp( opc, ss, LDAP_SYNC_DELETE ); } } ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); @@ -1444,8 +1494,7 @@ syncprov_op_response( Operation *op, SlapReply *rs ) for ( sm = opc->smatches; sm; sm=sm->sm_next ) { if ( sm->sm_op->s_op->o_abandon ) continue; - syncprov_sendresp( op, opc, sm->sm_op, NULL, - LDAP_SYNC_DELETE, 1 ); + syncprov_qresp( opc, sm->sm_op, LDAP_SYNC_DELETE ); } break; } @@ -1633,7 +1682,7 @@ syncprov_search_cleanup( Operation *op, SlapReply *rs ) } static void -syncprov_detach_op( Operation *op, syncops *so ) +syncprov_detach_op( Operation *op, syncops *so, slap_overinst *on ) { Operation *op2; int i, alen = 0; @@ -1659,8 +1708,9 @@ syncprov_detach_op( Operation *op, syncops *so ) *op2->o_hdr = *op->o_hdr; op2->o_tag = op->o_tag; op2->o_time = op->o_time; - op2->o_bd = op->o_bd; + op2->o_bd = on->on_info->oi_origdb; op2->o_request = op->o_request; + op2->o_private = on; if ( i ) { op2->ors_attrs = (AttributeName *)(op2->o_hdr + 1); @@ -1761,25 +1811,19 @@ syncprov_search_response( Operation *op, SlapReply *rs ) 0, 1, &cookie, ss->ss_present ? LDAP_SYNC_REFRESH_PRESENTS : LDAP_SYNC_REFRESH_DELETES ); } else { - int locked = 0; /* It's RefreshAndPersist, transition to Persist phase */ syncprov_sendinfo( op, rs, ( ss->ss_present && rs->sr_nentries ) ? LDAP_TAG_SYNC_REFRESH_PRESENT : LDAP_TAG_SYNC_REFRESH_DELETE, &cookie, 1, NULL, 0 ); - /* Flush any queued persist messages */ - if ( ss->ss_so->s_res ) { - ldap_pvt_thread_mutex_lock( &ss->ss_so->s_mutex ); - locked = 1; - syncprov_qplay( op, on, ss->ss_so ); - } + + /* Detach this Op from frontend control */ + ldap_pvt_thread_mutex_lock( &ss->ss_so->s_mutex ); /* Turn off the refreshing flag */ ss->ss_so->s_flags ^= PS_IS_REFRESHING; - if ( locked ) - ldap_pvt_thread_mutex_unlock( &ss->ss_so->s_mutex ); - /* Detach this Op from frontend control */ - syncprov_detach_op( op, ss->ss_so ); + syncprov_detach_op( op, ss->ss_so, on ); + ldap_pvt_thread_mutex_unlock( &ss->ss_so->s_mutex ); return LDAP_SUCCESS; } @@ -1824,7 +1868,7 @@ syncprov_op_search( Operation *op, SlapReply *rs ) fc.fbase = 0; so.s_eid = NOID; so.s_op = op; - so.s_flags = PS_IS_REFRESHING; + so.s_flags = PS_IS_REFRESHING | PS_FIND_BASE; /* syncprov_findbase expects to be called as a callback... */ sc.sc_private = &opc; opc.son = on; diff --git a/servers/slapd/overlays/unique.c b/servers/slapd/overlays/unique.c index 9668b4b945..f80a1c35fe 100644 --- a/servers/slapd/overlays/unique.c +++ b/servers/slapd/overlays/unique.c @@ -347,6 +347,7 @@ static int unique_search( nop->o_req_ndn = ud->dn; nop->o_ndn = op->o_bd->be_rootndn; + nop->o_bd = on->on_info->oi_origdb; rc = nop->o_bd->be_search(nop, &nrs); filter_free_x(nop, nop->ors_filter); ch_free( key ); @@ -384,21 +385,8 @@ static int unique_add( Debug(LDAP_DEBUG_TRACE, "==> unique_add <%s>\n", op->o_req_dn.bv_val, 0, 0); - /* validate backend. Should have already been done, but whatever */ - nop.o_bd = select_backend(&ud->dn, 0, 1); - if(nop.o_bd) { - if (!nop.o_bd->be_search) { - op->o_bd->bd_info = (BackendInfo *) on->on_info; - send_ldap_error(op, rs, LDAP_UNWILLING_TO_PERFORM, - "backend missing search function"); - return(rs->sr_err); - } - } else { - op->o_bd->bd_info = (BackendInfo *) on->on_info; - send_ldap_error(op, rs, LDAP_OTHER, - "no known backend? this shouldn't be happening!"); - return(rs->sr_err); - } + if ( !dnIsSuffix( &op->o_req_ndn, &ud->dn )) + return SLAP_CB_CONTINUE; /* ** count everything first; @@ -447,20 +435,8 @@ static int unique_modify( Debug(LDAP_DEBUG_TRACE, "==> unique_modify <%s>\n", op->o_req_dn.bv_val, 0, 0); - nop.o_bd = select_backend(&ud->dn, 0, 1); - if(nop.o_bd) { - if (!nop.o_bd->be_search) { - op->o_bd->bd_info = (BackendInfo *) on->on_info; - send_ldap_error(op, rs, LDAP_UNWILLING_TO_PERFORM, - "backend missing search function"); - return(rs->sr_err); - } - } else { - op->o_bd->bd_info = (BackendInfo *) on->on_info; - send_ldap_error(op, rs, LDAP_OTHER, - "no known backend? this shouldn't be happening!"); - return(rs->sr_err); - } + if ( !dnIsSuffix( &op->o_req_ndn, &ud->dn )) + return SLAP_CB_CONTINUE; /* ** count everything first; @@ -513,20 +489,9 @@ static int unique_modrdn( Debug(LDAP_DEBUG_TRACE, "==> unique_modrdn <%s> <%s>\n", op->o_req_dn.bv_val, op->orr_newrdn.bv_val, 0); - nop.o_bd = select_backend(&ud->dn, 0, 1); - if(nop.o_bd) { - if (!nop.o_bd->be_search) { - op->o_bd->bd_info = (BackendInfo *) on->on_info; - send_ldap_error(op, rs, LDAP_UNWILLING_TO_PERFORM, - "backend missing search function"); - return(rs->sr_err); - } - } else { - op->o_bd->bd_info = (BackendInfo *) on->on_info; - send_ldap_error(op, rs, LDAP_OTHER, - "no known backend? this shouldn't be happening!"); - return(rs->sr_err); - } + if ( !dnIsSuffix( &op->o_req_ndn, &ud->dn ) && + (!op->orr_nnewSup || !dnIsSuffix( &op->orr_nnewSup, &ud->dn ))) + return SLAP_CB_CONTINUE; if(ldap_bv2rdn_x(&op->oq_modrdn.rs_newrdn, &newrdn, (char **)&rs->sr_text, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx )) { diff --git a/servers/slapd/passwd.c b/servers/slapd/passwd.c index 385e2be3c1..c8f8ce75b5 100644 --- a/servers/slapd/passwd.c +++ b/servers/slapd/passwd.c @@ -68,9 +68,7 @@ int passwd_extop( return LDAP_STRONG_AUTH_REQUIRED; } - qpw->rs_old.bv_len = 0; qpw->rs_old.bv_val = NULL; - qpw->rs_new.bv_len = 0; qpw->rs_new.bv_val = NULL; qpw->rs_mods = NULL; qpw->rs_modtail = NULL; @@ -84,8 +82,10 @@ int passwd_extop( qpw->rs_old.bv_val ? " old" : "", qpw->rs_new.bv_val ? " new" : "", 0 ); } else { - Statslog( LDAP_DEBUG_STATS, "%s PASSMOD\n", - op->o_log_prefix, 0, 0, 0, 0 ); + Statslog( LDAP_DEBUG_STATS, "%s PASSMOD %s%s\n", + op->o_log_prefix, + qpw->rs_old.bv_val ? " old" : "", + qpw->rs_new.bv_val ? " new" : "", 0, 0 ); } if ( rs->sr_err != LDAP_SUCCESS ) { @@ -209,11 +209,27 @@ int passwd_extop( } if ( qpw->rs_old.bv_val != NULL ) { + Entry *e = NULL; + + rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, + slap_schema.si_ad_userPassword, 0, &e ); + if ( rc == LDAP_SUCCESS && e ) { + Attribute *a = attr_find( e->e_attrs, + slap_schema.si_ad_userPassword ); + if ( a ) + rc = slap_passwd_check( op, e, a, &qpw->rs_old, &rs->sr_text ); + else + rc = 1; + be_entry_release_r( op, e ); + if ( rc == LDAP_SUCCESS ) + goto old_good; + } rs->sr_text = "unwilling to verify old password"; rc = LDAP_UNWILLING_TO_PERFORM; goto error_return; } +old_good: ml = ch_malloc( sizeof(Modifications) ); if ( !qpw->rs_modtail ) qpw->rs_modtail = &ml->sml_next; diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index bf02fa3666..0d4a7fb983 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -2274,6 +2274,7 @@ typedef struct slap_overinst { typedef struct slap_overinfo { BackendInfo oi_bi; BackendInfo *oi_orig; + BackendDB *oi_origdb; struct slap_overinst *oi_list; } slap_overinfo; diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c index 429638165d..2a4220be9a 100644 --- a/servers/slapd/syncrepl.c +++ b/servers/slapd/syncrepl.c @@ -2227,10 +2227,11 @@ dn_callback( * discover if the deleteOldRdn argument applies here. It * would save an unnecessary Modify if we detected it, but * that's a fair amount of trouble to compare the two attr - * lists in detail. + * lists in detail. (Just test normalized DN; we ignore + * insignificant changes here.) */ - if ( !dn_match( &rs->sr_entry->e_name, - &dni->new_entry->e_name ) ) + if ( !dn_match( &rs->sr_entry->e_nname, + &dni->new_entry->e_nname ) ) { dni->renamed = 1; }