From: Pierangelo Masarati Date: Sat, 16 Apr 2005 02:25:41 +0000 (+0000) Subject: a) implement a new candidate selection procedure, based on target naming X-Git-Tag: OPENLDAP_AC_BP~883 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=c1b5e84e2db2d754a9f0ebd26d607744cabe5fb6;p=openldap a) implement a new candidate selection procedure, based on target naming context checking and multiple match resolution via an internal search b) move the candidate listing in a persistent per-thread buffer c) fix bind procedure d) minor cleanup (a) and (b) should address ITS#2935; (b) and (c) should address ITS#3171 A test is also added --- diff --git a/servers/slapd/back-meta/add.c b/servers/slapd/back-meta/add.c index 857ce7ec5f..870c92ef55 100644 --- a/servers/slapd/back-meta/add.c +++ b/servers/slapd/back-meta/add.c @@ -50,8 +50,7 @@ meta_back_add( Operation *op, SlapReply *rs ) /* * get the current connection */ - lc = meta_back_getconn( op, rs, META_OP_REQUIRE_SINGLE, - &op->o_req_ndn, &candidate, LDAP_BACK_SENDERR ); + lc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR ); if ( !lc || !meta_back_dobind( lc, op, LDAP_BACK_SENDERR ) ) { return rs->sr_err; } @@ -65,7 +64,7 @@ meta_back_add( Operation *op, SlapReply *rs ) /* * Rewrite the add dn, if needed */ - dc.rwmap = &li->targets[ candidate ]->mt_rwmap; + dc.rwmap = &li->mi_targets[ candidate ]->mt_rwmap; dc.conn = op->o_conn; dc.rs = rs; dc.ctx = "addDN"; @@ -75,7 +74,7 @@ meta_back_add( Operation *op, SlapReply *rs ) return rs->sr_err; } - /* Count number of attributes in entry */ + /* Count number of attributes in entry ( +1 ) */ for ( i = 1, a = op->ora_e->e_attrs; a; i++, a = a->a_next ); /* Create array of LDAPMods for ldap_add() */ @@ -97,7 +96,7 @@ meta_back_add( Operation *op, SlapReply *rs ) mapped = a->a_desc->ad_cname; } else { - ldap_back_map( &li->targets[ candidate ]->mt_rwmap.rwm_at, + ldap_back_map( &li->mi_targets[ candidate ]->mt_rwmap.rwm_at, &a->a_desc->ad_cname, &mapped, BACKLDAP_MAP ); if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) { continue; @@ -122,11 +121,11 @@ meta_back_add( Operation *op, SlapReply *rs ) for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); ) { struct ldapmapping *mapping; - ldap_back_mapping( &li->targets[ candidate ]->mt_rwmap.rwm_oc, + ldap_back_mapping( &li->mi_targets[ candidate ]->mt_rwmap.rwm_oc, &a->a_vals[ j ], &mapping, BACKLDAP_MAP ); if ( mapping == NULL ) { - if ( li->targets[ candidate ]->mt_rwmap.rwm_oc.drop_missing ) { + if ( li->mi_targets[ candidate ]->mt_rwmap.rwm_oc.drop_missing ) { continue; } attrs[ i ]->mod_bvalues[ j ] = &a->a_vals[ j ]; @@ -178,6 +177,6 @@ meta_back_add( Operation *op, SlapReply *rs ) BER_BVZERO( &mdn ); } - return meta_back_op_result( lc, op, rs ); + return meta_back_op_result( lc, op, rs, candidate ); } diff --git a/servers/slapd/back-meta/back-meta.h b/servers/slapd/back-meta/back-meta.h index 6df5a58e5c..8b2f8a15e1 100644 --- a/servers/slapd/back-meta/back-meta.h +++ b/servers/slapd/back-meta/back-meta.h @@ -148,9 +148,9 @@ extern int ldap_dnattr_result_rewrite( dncookie *dc, BerVarray a_vals ); struct metasingleconn { int msc_candidate; -#define META_NOT_CANDIDATE 0 -#define META_CANDIDATE 1 -#define META_LAST_CONN -1 +#define META_NOT_CANDIDATE ((char)0) +#define META_CANDIDATE ((char)1) +#define META_LAST_CONN ((char)(-1)) LDAP *msc_ld; struct berval msc_bound_ndn; @@ -165,14 +165,13 @@ struct metasingleconn { struct metaconn { struct slap_conn *mc_conn; - struct rewrite_info *mc_rwinfo; /* * means that the connection is bound; * of course only one target actually is ... */ int mc_bound_target; -#define META_BOUND_NONE -1 +#define META_BOUND_NONE (-1) #define META_BOUND_ALL -2 /* supersedes the connection stuff */ struct metasingleconn *mc_conns; @@ -195,45 +194,48 @@ struct metadncache { ldap_pvt_thread_mutex_t mutex; Avlnode *tree; -#define META_DNCACHE_DISABLED 0 -#define META_DNCACHE_FOREVER -1 +#define META_DNCACHE_DISABLED (0) +#define META_DNCACHE_FOREVER (-1) long int ttl; /* seconds; 0: no cache, -1: no expiry */ }; struct metainfo { - int ntargets; - int defaulttarget; - int network_timeout; -#define META_DEFAULT_TARGET_NONE -1 - struct metatarget **targets; - - struct rewrite_info *rwinfo; - Backend *glue_be; - - struct metadncache cache; + int mi_ntargets; + int mi_defaulttarget; + int mi_network_timeout; +#define META_DEFAULT_TARGET_NONE (-1) + struct metatarget **mi_targets; + char *mi_candidates; + + struct metadncache mi_cache; - ldap_pvt_thread_mutex_t conn_mutex; - Avlnode *conntree; + ldap_pvt_thread_mutex_t mi_conn_mutex; + Avlnode *mi_conntree; unsigned flags; -/* defined in +#if 0 +/* defined in */ #define LDAP_BACK_F_NONE 0x00U #define LDAP_BACK_F_SAVECRED 0x01U #define LDAP_BACK_F_USE_TLS 0x02U #define LDAP_BACK_F_TLS_CRITICAL ( 0x04U | LDAP_BACK_F_USE_TLS ) #define LDAP_BACK_F_CHASE_REFERRALS 0x8U -*/ +#endif }; -#define META_OP_ALLOW_MULTIPLE 0x00 -#define META_OP_REQUIRE_SINGLE 0x01 -#define META_OP_REQUIRE_ALL 0x02 +typedef enum meta_op_type { + META_OP_ALLOW_MULTIPLE = 0, + META_OP_REQUIRE_SINGLE, + META_OP_REQUIRE_ALL +} meta_op_type; + +char * +meta_back_candidates_get( Operation *op ); + extern struct metaconn * meta_back_getconn( Operation *op, SlapReply *rs, - int op_type, - struct berval *dn, int *candidate, ldap_back_send_t sendok ); @@ -255,7 +257,8 @@ extern int meta_back_op_result( struct metaconn *lc, Operation *op, - SlapReply *rs + SlapReply *rs, + int candidate ); extern int @@ -285,18 +288,6 @@ meta_back_is_candidate( struct berval *ndn ); -extern int -meta_back_count_candidates( - struct metainfo *li, - struct berval *ndn -); - -extern int -meta_back_is_candidate_unique( - struct metainfo *li, - struct berval *ndn -); - extern int meta_back_select_unique_candidate( struct metainfo *li, @@ -305,16 +296,14 @@ meta_back_select_unique_candidate( extern int meta_clear_unused_candidates( - struct metainfo *li, + Operation *op, struct metaconn *lc, - int candidate, - int reallyclean + int candidate ); extern int meta_clear_one_candidate( - struct metasingleconn *lc, - int reallyclean + struct metasingleconn *lc ); /* @@ -333,6 +322,7 @@ meta_dncache_dup( ); #define META_TARGET_NONE (-1) +#define META_TARGET_MULTIPLE (-2) extern int meta_dncache_get_target( struct metadncache *cache, diff --git a/servers/slapd/back-meta/bind.c b/servers/slapd/back-meta/bind.c index 69fe2ea995..11093f2e6b 100644 --- a/servers/slapd/back-meta/bind.c +++ b/servers/slapd/back-meta/bind.c @@ -49,8 +49,10 @@ meta_back_bind( Operation *op, SlapReply *rs ) struct metainfo *li = ( struct metainfo * )op->o_bd->be_private; struct metaconn *lc; - int rc = -1, i, gotit = 0, ndnlen, isroot = 0; - int op_type = META_OP_ALLOW_MULTIPLE; + int rc = LDAP_OTHER, + i, gotit = 0, ndnlen, isroot = 0; + + char *candidates = meta_back_candidates_get( op ); rs->sr_err = LDAP_SUCCESS; @@ -60,17 +62,29 @@ meta_back_bind( Operation *op, SlapReply *rs ) if ( op->orb_method == LDAP_AUTH_SIMPLE && be_isroot_pw( op ) ) { isroot = 1; ber_dupbv( &op->orb_edn, be_root_dn( op->o_bd ) ); - op_type = META_OP_REQUIRE_ALL; } - lc = meta_back_getconn( op, rs, op_type, - &op->o_req_ndn, NULL, LDAP_BACK_SENDERR ); + + /* we need meta_back_getconn() not send result even on error, + * because we want to intercept the error and make it + * invalidCredentials */ + lc = meta_back_getconn( op, rs, NULL, LDAP_BACK_DONTSEND ); if ( !lc ) { Debug( LDAP_DEBUG_ANY, - "meta_back_bind: no target for dn %s.\n%s%s", - op->o_req_dn.bv_val, "", ""); - + "meta_back_bind: no target " + "for dn \"%s\" (%d: %s).\n", + op->o_req_dn.bv_val, rs->sr_err, + rs->sr_text ? rs->sr_text : "" ); + /* FIXME: there might be cases where we don't want + * to map the error onto invalidCredentials */ + switch ( rs->sr_err ) { + case LDAP_NO_SUCH_OBJECT: + case LDAP_UNWILLING_TO_PERFORM: + rs->sr_err = LDAP_INVALID_CREDENTIALS; + rs->sr_text = NULL; + break; + } send_ldap_result( op, rs ); - return -1; + return rs->sr_err; } /* @@ -78,7 +92,7 @@ meta_back_bind( Operation *op, SlapReply *rs ) */ lc->mc_bound_target = META_BOUND_NONE; ndnlen = op->o_req_ndn.bv_len; - for ( i = 0; i < li->ntargets; i++ ) { + for ( i = 0; i < li->mi_ntargets; i++ ) { int lerr; struct berval orig_dn = op->o_req_dn; struct berval orig_ndn = op->o_req_ndn; @@ -89,35 +103,39 @@ meta_back_bind( Operation *op, SlapReply *rs ) /* * Skip non-candidates */ - if ( lc->mc_conns[ i ].msc_candidate != META_CANDIDATE ) { + if ( candidates[ i ] != META_CANDIDATE ) { continue; } if ( gotit == 0 ) { gotit = 1; - } else { + + } else if ( isroot == 0 ) { /* * A bind operation is expected to have * ONE CANDIDATE ONLY! */ Debug( LDAP_DEBUG_ANY, "==>meta_back_bind: more than one" - " candidate is attempting to bind" - " ...\n%s%s%s", - "", "", "" ); + " candidate is trying to bind...\n", + 0, 0, 0 ); } - if ( isroot && li->targets[ i ]->mt_pseudorootdn.bv_val != NULL ) { - op->o_req_dn = li->targets[ i ]->mt_pseudorootdn; - op->o_req_ndn = li->targets[ i ]->mt_pseudorootdn; - op->orb_cred = li->targets[ i ]->mt_pseudorootpw; + if ( isroot && !BER_BVISNULL( &li->mi_targets[ i ]->mt_pseudorootdn ) ) + { + op->o_req_dn = li->mi_targets[ i ]->mt_pseudorootdn; + op->o_req_ndn = li->mi_targets[ i ]->mt_pseudorootdn; + op->orb_cred = li->mi_targets[ i ]->mt_pseudorootpw; op->orb_method = LDAP_AUTH_SIMPLE; } lerr = meta_back_do_single_bind( lc, op, rs, i ); if ( lerr != LDAP_SUCCESS ) { rs->sr_err = lerr; - ( void )meta_clear_one_candidate( &lc->mc_conns[ i ], 1 ); + candidates[ i ] = META_NOT_CANDIDATE; +#if 0 + ( void )meta_clear_one_candidate( &lc->mc_conns[ i ] ); +#endif } else { rc = LDAP_SUCCESS; @@ -138,7 +156,7 @@ meta_back_bind( Operation *op, SlapReply *rs ) * err is the last error that occurred during a bind; * if at least (and at most?) one bind succeedes, fine. */ - if ( rc != LDAP_SUCCESS /* && rs->sr_err != LDAP_SUCCESS */ ) { + if ( rc != LDAP_SUCCESS ) { /* * deal with bind failure ... @@ -154,10 +172,10 @@ meta_back_bind( Operation *op, SlapReply *rs ) rs->sr_err = slap_map_api2result( rs ); send_ldap_result( op, rs ); - return -1; + return rs->sr_err; } - return 0; + return LDAP_SUCCESS; } /* @@ -182,7 +200,7 @@ meta_back_do_single_bind( /* * Rewrite the bind dn if needed */ - dc.rwmap = &li->targets[ candidate ]->mt_rwmap; + dc.rwmap = &li->mi_targets[ candidate ]->mt_rwmap; dc.conn = op->o_conn; dc.rs = rs; dc.ctx = "bindDN"; @@ -258,9 +276,9 @@ retry:; ldap_set_rebind_proc( lsc->msc_ld, meta_back_rebind, lsc ); } - if ( li->cache.ttl != META_DNCACHE_DISABLED + if ( li->mi_cache.ttl != META_DNCACHE_DISABLED && op->o_req_ndn.bv_len != 0 ) { - ( void )meta_dncache_update_entry( &li->cache, + ( void )meta_dncache_update_entry( &li->mi_cache, &op->o_req_ndn, candidate ); } @@ -282,6 +300,8 @@ meta_back_dobind( struct metaconn *lc, Operation *op, ldap_back_send_t sendok ) struct metasingleconn *lsc; int bound = 0, i; + char *candidates = meta_back_candidates_get( op ); + /* * all the targets are bound as pseudoroot */ @@ -383,7 +403,10 @@ retry:; * due to technical reasons (remote host down?) * so better clear the handle */ - ( void )meta_clear_one_candidate( lsc, 1 ); + candidates[ i ] = META_NOT_CANDIDATE; +#if 0 + ( void )meta_clear_one_candidate( lsc ); +#endif continue; } /* else */ @@ -440,7 +463,11 @@ meta_back_rebind( LDAP *ld, LDAP_CONST char *url, ber_tag_t request, * FIXME: error return must be handled in a cleaner way ... */ int -meta_back_op_result( struct metaconn *lc, Operation *op, SlapReply *rs ) +meta_back_op_result( + struct metaconn *lc, + Operation *op, + SlapReply *rs, + int candidate ) { int i, rerr = LDAP_SUCCESS; @@ -450,9 +477,8 @@ meta_back_op_result( struct metaconn *lc, Operation *op, SlapReply *rs ) int free_rmsg = 0, free_rmatch = 0; - for ( i = 0, lsc = lc->mc_conns; !META_LAST( lsc ); ++i, ++lsc ) { - char *msg = NULL; - char *match = NULL; + if ( candidate != META_TARGET_NONE ) { + lsc = &lc->mc_conns[ candidate ]; rs->sr_err = LDAP_SUCCESS; @@ -465,49 +491,86 @@ meta_back_op_result( struct metaconn *lc, Operation *op, SlapReply *rs ) * positive result ... */ ldap_get_option( lsc->msc_ld, - LDAP_OPT_ERROR_STRING, &msg ); + LDAP_OPT_ERROR_STRING, &rmsg ); ldap_get_option( lsc->msc_ld, - LDAP_OPT_MATCHED_DN, &match ); - rs->sr_err = slap_map_api2result( rs ); + LDAP_OPT_MATCHED_DN, &rmatch ); + rerr = rs->sr_err = slap_map_api2result( rs ); + + if ( rmsg ) { + free_rmsg = 1; + } + if ( rmatch ) { + free_rmatch = 1; + } Debug(LDAP_DEBUG_ANY, "==> meta_back_op_result: target" " <%d> sending msg \"%s\"" " (matched \"%s\")\n", - i, ( msg ? msg : "" ), - ( match ? match : "" ) ); + candidate, ( rmsg ? rmsg : "" ), + ( rmatch ? rmatch : "" ) ); + } - /* - * FIXME: need to rewrite "match" (need rwinfo) - */ - switch ( rs->sr_err ) { - default: - rerr = rs->sr_err; - if ( rmsg ) { - ber_memfree( rmsg ); + } else { + for ( i = 0, lsc = lc->mc_conns; !META_LAST( lsc ); ++i, ++lsc ) { + char *msg = NULL; + char *match = NULL; + + rs->sr_err = LDAP_SUCCESS; + + ldap_get_option( lsc->msc_ld, LDAP_OPT_ERROR_NUMBER, &rs->sr_err ); + if ( rs->sr_err != LDAP_SUCCESS ) { + /* + * better check the type of error. In some cases + * (search ?) it might be better to return a + * success if at least one of the targets gave + * positive result ... + */ + ldap_get_option( lsc->msc_ld, + LDAP_OPT_ERROR_STRING, &msg ); + ldap_get_option( lsc->msc_ld, + LDAP_OPT_MATCHED_DN, &match ); + rs->sr_err = slap_map_api2result( rs ); + + Debug(LDAP_DEBUG_ANY, + "==> meta_back_op_result: target" + " <%d> sending msg \"%s\"" + " (matched \"%s\")\n", + i, ( msg ? msg : "" ), + ( match ? match : "" ) ); + + /* + * FIXME: need to rewrite "match" (need rwinfo) + */ + switch ( rs->sr_err ) { + default: + rerr = rs->sr_err; + if ( rmsg ) { + ber_memfree( rmsg ); + } + rmsg = msg; + free_rmsg = 1; + msg = NULL; + if ( rmatch ) { + ber_memfree( rmatch ); + } + rmatch = match; + free_rmatch = 1; + match = NULL; + break; } - rmsg = msg; - free_rmsg = 1; - msg = NULL; - if ( rmatch ) { - ber_memfree( rmatch ); + + /* better test the pointers before freeing? */ + if ( match ) { + free( match ); + } + if ( msg ) { + free( msg ); } - rmatch = match; - free_rmatch = 1; - match = NULL; - break; - } - - /* better test the pointers before freeing? */ - if ( match ) { - free( match ); - } - if ( msg ) { - free( msg ); } } } - + rs->sr_err = rerr; rs->sr_text = rmsg; rs->sr_matched = rmatch; diff --git a/servers/slapd/back-meta/candidates.c b/servers/slapd/back-meta/candidates.c index a018588d9c..96f0f22364 100644 --- a/servers/slapd/back-meta/candidates.c +++ b/servers/slapd/back-meta/candidates.c @@ -50,6 +50,18 @@ * A possible extension will include the handling of multiple suffixes */ +static int +meta_back_count_candidates( + struct metainfo *li, + struct berval *ndn +); + +static int +meta_back_is_candidate_unique( + struct metainfo *li, + struct berval *ndn +); + /* * returns 1 if suffix is candidate for dn, otherwise 0 * @@ -78,7 +90,7 @@ meta_back_is_candidate( * Note: dn MUST be normalized */ -int +static int meta_back_count_candidates( struct metainfo *li, struct berval *ndn @@ -91,11 +103,11 @@ meta_back_count_candidates( * at present I didn't find a place for such checks * after config.c */ - assert( li->targets != NULL ); - assert( li->ntargets != 0 ); + assert( li->mi_targets != NULL ); + assert( li->mi_ntargets != 0 ); - for ( i = 0; i < li->ntargets; ++i ) { - if ( meta_back_is_candidate( &li->targets[ i ]->mt_nsuffix, ndn ) ) + for ( i = 0; i < li->mi_ntargets; ++i ) { + if ( meta_back_is_candidate( &li->mi_targets[ i ]->mt_nsuffix, ndn ) ) { ++cnt; } @@ -110,7 +122,7 @@ meta_back_count_candidates( * checks whether a candidate is unique * Note: dn MUST be normalized */ -int +static int meta_back_is_candidate_unique( struct metainfo *li, struct berval *ndn @@ -132,25 +144,21 @@ meta_back_select_unique_candidate( struct berval *ndn ) { - int i; - - switch ( meta_back_count_candidates( li, ndn ) ) { - case 1: - break; - case 0: - default: - return ( li->defaulttarget == META_DEFAULT_TARGET_NONE - ? META_TARGET_NONE : li->defaulttarget ); - } + int i, candidate = META_TARGET_NONE; - for ( i = 0; i < li->ntargets; ++i ) { - if ( meta_back_is_candidate( &li->targets[ i ]->mt_nsuffix, ndn ) ) + for ( i = 0; i < li->mi_ntargets; ++i ) { + if ( meta_back_is_candidate( &li->mi_targets[ i ]->mt_nsuffix, ndn ) ) { - return i; + if ( candidate == META_TARGET_NONE ) { + candidate = i; + + } else { + return META_TARGET_MULTIPLE; + } } } - return META_TARGET_NONE; + return candidate; } /* @@ -160,19 +168,20 @@ meta_back_select_unique_candidate( */ int meta_clear_unused_candidates( - struct metainfo *li, + Operation *op, struct metaconn *lc, - int candidate, - int reallyclean + int candidate ) { - int i; + struct metainfo *li = ( struct metainfo * )op->o_bd->be_private; + int i; + char *candidates = meta_back_candidates_get( op ); - for ( i = 0; i < li->ntargets; ++i ) { + for ( i = 0; i < li->mi_ntargets; ++i ) { if ( i == candidate ) { continue; } - meta_clear_one_candidate( &lc->mc_conns[ i ], reallyclean ); + candidates[ i ] = META_NOT_CANDIDATE; } return 0; @@ -185,16 +194,9 @@ meta_clear_unused_candidates( */ int meta_clear_one_candidate( - struct metasingleconn *lsc, - int reallyclean + struct metasingleconn *lsc ) { - lsc->msc_candidate = META_NOT_CANDIDATE; - - if ( !reallyclean ) { - return 0; - } - if ( lsc->msc_ld ) { ldap_unbind_ext_s( lsc->msc_ld, NULL, NULL ); lsc->msc_ld = NULL; diff --git a/servers/slapd/back-meta/compare.c b/servers/slapd/back-meta/compare.c index ee15d1495d..c9fc9fb137 100644 --- a/servers/slapd/back-meta/compare.c +++ b/servers/slapd/back-meta/compare.c @@ -40,7 +40,7 @@ meta_back_compare( Operation *op, SlapReply *rs ) char *match = NULL, *err = NULL; struct berval mmatch = BER_BVNULL; - int candidates = 0, + int ncandidates = 0, last = 0, i, count = 0, @@ -50,13 +50,14 @@ meta_back_compare( Operation *op, SlapReply *rs ) *msgid; dncookie dc; - lc = meta_back_getconn( op, rs, META_OP_ALLOW_MULTIPLE, - &op->o_req_ndn, NULL, LDAP_BACK_SENDERR ); + char *candidates = meta_back_candidates_get( op ); + + lc = meta_back_getconn( op, rs, NULL, LDAP_BACK_SENDERR ); if ( !lc || !meta_back_dobind( lc, op, LDAP_BACK_SENDERR ) ) { return rs->sr_err; } - msgid = ch_calloc( sizeof( int ), li->ntargets ); + msgid = ch_calloc( sizeof( int ), li->mi_ntargets ); if ( msgid == NULL ) { return -1; } @@ -73,7 +74,7 @@ meta_back_compare( Operation *op, SlapReply *rs ) struct berval mapped_attr = op->orc_ava->aa_desc->ad_cname; struct berval mapped_value = op->orc_ava->aa_value; - if ( lsc->msc_candidate != META_CANDIDATE ) { + if ( candidates[ i ] != META_CANDIDATE ) { msgid[ i ] = -1; continue; } @@ -81,7 +82,7 @@ meta_back_compare( Operation *op, SlapReply *rs ) /* * Rewrite the compare dn, if needed */ - dc.rwmap = &li->targets[ i ]->mt_rwmap; + dc.rwmap = &li->mi_targets[ i ]->mt_rwmap; switch ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) { case LDAP_UNWILLING_TO_PERFORM: @@ -96,21 +97,21 @@ meta_back_compare( Operation *op, SlapReply *rs ) * if attr is objectClass, try to remap the value */ if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass ) { - ldap_back_map( &li->targets[ i ]->mt_rwmap.rwm_oc, + ldap_back_map( &li->mi_targets[ i ]->mt_rwmap.rwm_oc, &op->orc_ava->aa_value, &mapped_value, BACKLDAP_MAP ); - if ( mapped_value.bv_val == NULL || mapped_value.bv_val[0] == '\0' ) { + if ( BER_BVISNULL( &mapped_value ) || mapped_value.bv_val[0] == '\0' ) { continue; } /* * else try to remap the attribute */ } else { - ldap_back_map( &li->targets[ i ]->mt_rwmap.rwm_at, + ldap_back_map( &li->mi_targets[ i ]->mt_rwmap.rwm_at, &op->orc_ava->aa_desc->ad_cname, &mapped_attr, BACKLDAP_MAP ); - if ( mapped_attr.bv_val == NULL || mapped_attr.bv_val[0] == '\0' ) { + if ( BER_BVISNULL( &mapped_attr ) || mapped_attr.bv_val[0] == '\0' ) { continue; } @@ -159,13 +160,13 @@ meta_back_compare( Operation *op, SlapReply *rs ) continue; } - ++candidates; + ++ncandidates; } /* * wait for replies */ - for ( rc = 0, count = 0; candidates > 0; ) { + for ( rc = 0, count = 0; ncandidates > 0; ) { /* * FIXME: should we check for abandon? @@ -214,8 +215,8 @@ meta_back_compare( Operation *op, SlapReply *rs ) * true or flase, got it; * sending to cache ... */ - if ( li->cache.ttl != META_DNCACHE_DISABLED ) { - ( void )meta_dncache_update_entry( &li->cache, &op->o_req_ndn, i ); + if ( li->mi_cache.ttl != META_DNCACHE_DISABLED ) { + ( void )meta_dncache_update_entry( &li->mi_cache, &op->o_req_ndn, i ); } count++; @@ -241,11 +242,11 @@ meta_back_compare( Operation *op, SlapReply *rs ) break; } msgid[ i ] = -1; - --candidates; + --ncandidates; } else { msgid[ i ] = -1; - --candidates; + --ncandidates; if ( res ) { ldap_msgfree( res ); } @@ -280,8 +281,7 @@ finish:; } else if ( match != NULL && match[0] != '\0' ) { struct berval matched; - matched.bv_val = match; - matched.bv_len = strlen( match ); + ber_str2bv( match, 0, 0, &matched ); dc.ctx = "matchedDN"; ldap_back_dn_massage( &dc, &matched, &mmatch ); diff --git a/servers/slapd/back-meta/config.c b/servers/slapd/back-meta/config.c index a7a6fa1805..e9bd33fff0 100644 --- a/servers/slapd/back-meta/config.c +++ b/servers/slapd/back-meta/config.c @@ -97,7 +97,7 @@ meta_back_db_config( /* URI of server to query */ if ( strcasecmp( argv[ 0 ], "uri" ) == 0 ) { - int i = li->ntargets; + int i = li->mi_ntargets; #if 0 int j; #endif /* uncomment if uri MUST be a branch of suffix */ @@ -113,11 +113,11 @@ meta_back_db_config( return 1; } - ++li->ntargets; + ++li->mi_ntargets; - li->targets = ch_realloc( li->targets, - sizeof( struct metatarget *)*li->ntargets ); - if ( li->targets == NULL ) { + li->mi_targets = ch_realloc( li->mi_targets, + sizeof( struct metatarget *)*li->mi_ntargets ); + if ( li->mi_targets == NULL ) { fprintf( stderr, "%s: line %d: out of memory while storing server name" " in \"uri ://[:port]/\" line\n", @@ -125,7 +125,7 @@ meta_back_db_config( return 1; } - if ( ( li->targets[ i ] = new_target() ) == NULL ) { + if ( ( li->mi_targets[ i ] = new_target() ) == NULL ) { fprintf( stderr, "%s: line %d: unable to init server" " in \"uri ://[:port]/\" line\n", @@ -161,8 +161,8 @@ meta_back_db_config( dn.bv_val = ludp->lud_dn; dn.bv_len = strlen( ludp->lud_dn ); - rc = dnPrettyNormal( NULL, &dn, &li->targets[ i ]->mt_psuffix, - &li->targets[ i ]->mt_nsuffix, NULL ); + rc = dnPrettyNormal( NULL, &dn, &li->mi_targets[ i ]->mt_psuffix, + &li->mi_targets[ i ]->mt_nsuffix, NULL ); if( rc != LDAP_SUCCESS ) { fprintf( stderr, "%s: line %d: " "target '%s' DN is invalid\n", @@ -188,9 +188,9 @@ meta_back_db_config( } } - li->targets[ i ]->mt_uri = ldap_url_list2urls( ludp ); + li->mi_targets[ i ]->mt_uri = ldap_url_list2urls( ludp ); ldap_free_urllist( ludp ); - if ( li->targets[ i ]->mt_uri == NULL) { + if ( li->mi_targets[ i ]->mt_uri == NULL) { fprintf( stderr, "%s: line %d: no memory?\n", fname, lineno ); return( 1 ); @@ -200,7 +200,7 @@ meta_back_db_config( * uri MUST be a branch of suffix! */ #if 0 /* too strict a constraint */ - if ( select_backend( &li->targets[ i ]->suffix, 0, 0 ) != be ) { + if ( select_backend( &li->mi_targets[ i ]->suffix, 0, 0 ) != be ) { fprintf( stderr, "%s: line %d: of URI does not refer to current backend" " in \"uri ://[:port]/\" line\n", @@ -211,7 +211,7 @@ meta_back_db_config( /* * uri MUST be a branch of a suffix! */ - if ( select_backend( &li->targets[ i ]->mt_nsuffix, 0, 0 ) == NULL ) { + if ( select_backend( &li->mi_targets[ i ]->mt_nsuffix, 0, 0 ) == NULL ) { fprintf( stderr, "%s: line %d: of URI does not resolve to a backend" " in \"uri ://[:port]/\" line\n", @@ -228,8 +228,8 @@ meta_back_db_config( * or worked out, at least, in some manner */ for ( j = 0; j < i-1; j++ ) { - if ( dn_match( &li->targets[ i ]->suffix, - &li->targets[ j ]->suffix ) ) { + if ( dn_match( &li->mi_targets[ i ]->suffix, + &li->mi_targets[ j ]->suffix ) ) { fprintf( stderr, "%s: line %d: naming context \"%s\" already used" " in \"uri ://[:port]/\" line\n", @@ -241,13 +241,13 @@ meta_back_db_config( #if 0 fprintf(stderr, "%s: line %d: URI \"%s\", suffix \"%s\"\n", - fname, lineno, li->targets[ i ]->uri, - li->targets[ i ]->psuffix.bv_val ); + fname, lineno, li->mi_targets[ i ]->uri, + li->mi_targets[ i ]->psuffix.bv_val ); #endif /* default target directive */ } else if ( strcasecmp( argv[ 0 ], "default-target" ) == 0 ) { - int i = li->ntargets-1; + int i = li->mi_ntargets - 1; if ( argc == 1 ) { if ( i < 0 ) { @@ -257,7 +257,7 @@ meta_back_db_config( fname, lineno ); return 1; } - li->defaulttarget = i; + li->mi_defaulttarget = i; } else { if ( strcasecmp( argv[ 1 ], "none" ) == 0 ) { if ( i >= 0 ) { @@ -266,16 +266,18 @@ meta_back_db_config( " should go before uri definitions\n", fname, lineno ); } - li->defaulttarget = META_DEFAULT_TARGET_NONE; + li->mi_defaulttarget = META_DEFAULT_TARGET_NONE; + } else { - int n = atoi( argv[ 1 ] ); - if ( n < 1 || n >= i ) { + char *next; + int n = strtol( argv[ 1 ], &next, 10 ); + if ( n < 0 || n >= i - 1 ) { fprintf( stderr, "%s: line %d: illegal target number %d\n", fname, lineno, n ); return 1; } - li->defaulttarget = n-1; + li->mi_defaulttarget = n; } } @@ -289,11 +291,11 @@ meta_back_db_config( } if ( strcasecmp( argv[ 1 ], "forever" ) == 0 ) { - li->cache.ttl = META_DNCACHE_FOREVER; + li->mi_cache.ttl = META_DNCACHE_FOREVER; } else if ( strcasecmp( argv[ 1 ], "disabled" ) == 0 ) { - li->cache.ttl = META_DNCACHE_DISABLED; + li->mi_cache.ttl = META_DNCACHE_DISABLED; } else { - li->cache.ttl = atol( argv[ 1 ] ); + li->mi_cache.ttl = atol( argv[ 1 ] ); } /* network timeout when connecting to ldap servers */ @@ -304,13 +306,13 @@ meta_back_db_config( fname, lineno ); return 1; } - li->network_timeout = atol(argv[ 1 ]); + li->mi_network_timeout = atol(argv[ 1 ]); /* name to use for meta_back_group */ } else if ( strcasecmp( argv[ 0 ], "acl-authcDN" ) == 0 || strcasecmp( argv[ 0 ], "binddn" ) == 0 ) { - int i = li->ntargets-1; + int i = li->mi_ntargets - 1; struct berval dn; if ( i < 0 ) { @@ -337,7 +339,7 @@ meta_back_db_config( dn.bv_val = argv[ 1 ]; dn.bv_len = strlen( argv[ 1 ] ); - if ( dnNormalize( 0, NULL, NULL, &dn, &li->targets[ i ]->mt_binddn, + if ( dnNormalize( 0, NULL, NULL, &dn, &li->mi_targets[ i ]->mt_binddn, NULL ) != LDAP_SUCCESS ) { fprintf( stderr, "%s: line %d: " @@ -350,7 +352,7 @@ meta_back_db_config( } else if ( strcasecmp( argv[ 0 ], "acl-passwd" ) == 0 || strcasecmp( argv[ 0 ], "bindpw" ) == 0 ) { - int i = li->ntargets-1; + int i = li->mi_ntargets - 1; if ( i < 0 ) { fprintf( stderr, @@ -374,7 +376,7 @@ meta_back_db_config( /* FIXME: some day we'll need to throw an error */ } - ber_str2bv( argv[ 1 ], 0L, 1, &li->targets[ i ]->mt_bindpw ); + ber_str2bv( argv[ 1 ], 0L, 1, &li->mi_targets[ i ]->mt_bindpw ); /* save bind creds for referral rebinds? */ } else if ( strcasecmp( argv[0], "rebind-as-user" ) == 0 ) { @@ -454,7 +456,7 @@ meta_back_db_config( /* name to use as pseudo-root dn */ } else if ( strcasecmp( argv[ 0 ], "pseudorootdn" ) == 0 ) { - int i = li->ntargets-1; + int i = li->mi_ntargets - 1; struct berval dn; if ( i < 0 ) { @@ -474,7 +476,7 @@ meta_back_db_config( dn.bv_val = argv[ 1 ]; dn.bv_len = strlen( argv[ 1 ] ); if ( dnNormalize( 0, NULL, NULL, &dn, - &li->targets[ i ]->mt_pseudorootdn, NULL ) != LDAP_SUCCESS ) + &li->mi_targets[ i ]->mt_pseudorootdn, NULL ) != LDAP_SUCCESS ) { fprintf( stderr, "%s: line %d: " "pseudoroot DN '%s' is invalid\n", @@ -484,7 +486,7 @@ meta_back_db_config( /* password to use as pseudo-root */ } else if ( strcasecmp( argv[ 0 ], "pseudorootpw" ) == 0 ) { - int i = li->ntargets-1; + int i = li->mi_ntargets - 1; if ( i < 0 ) { fprintf( stderr, @@ -499,12 +501,12 @@ meta_back_db_config( fname, lineno ); return 1; } - ber_str2bv( argv[ 1 ], 0L, 1, &li->targets[ i ]->mt_pseudorootpw ); + ber_str2bv( argv[ 1 ], 0L, 1, &li->mi_targets[ i ]->mt_pseudorootpw ); /* dn massaging */ } else if ( strcasecmp( argv[ 0 ], "suffixmassage" ) == 0 ) { BackendDB *tmp_be; - int i = li->ntargets-1; + int i = li->mi_ntargets - 1; struct berval dn, nvnc, pvnc, nrnc, prnc; if ( i < 0 ) { @@ -584,27 +586,26 @@ meta_back_db_config( * FIXME: no extra rewrite capabilities should be added * to the database */ - return suffix_massage_config( li->targets[ i ]->mt_rwmap.rwm_rw, + return suffix_massage_config( li->mi_targets[ i ]->mt_rwmap.rwm_rw, &pvnc, &nvnc, &prnc, &nrnc ); /* rewrite stuff ... */ } else if ( strncasecmp( argv[ 0 ], "rewrite", 7 ) == 0 ) { - int i = li->ntargets-1; + int i = li->mi_ntargets - 1; if ( i < 0 ) { - if ( strcasecmp( argv[0], "rewriteEngine" ) == 0 ) { - li->rwinfo = rewrite_info_init( REWRITE_MODE_USE_DEFAULT ); - } - return rewrite_parse( li->rwinfo, fname, lineno, - argc, argv ); + fprintf( stderr, "%s: line %d: \"rewrite\" " + "statement outside target definition.\n", + fname, lineno ); + return 1; } - return rewrite_parse( li->targets[ i ]->mt_rwmap.rwm_rw, + return rewrite_parse( li->mi_targets[ i ]->mt_rwmap.rwm_rw, fname, lineno, argc, argv ); /* objectclass/attribute mapping */ } else if ( strcasecmp( argv[ 0 ], "map" ) == 0 ) { - int i = li->ntargets-1; + int i = li->mi_ntargets - 1; if ( i < 0 ) { fprintf( stderr, @@ -613,8 +614,8 @@ meta_back_db_config( return 1; } - return ldap_back_map_config( &li->targets[ i ]->mt_rwmap.rwm_oc, - &li->targets[ i ]->mt_rwmap.rwm_at, + return ldap_back_map_config( &li->mi_targets[ i ]->mt_rwmap.rwm_oc, + &li->mi_targets[ i ]->mt_rwmap.rwm_at, fname, lineno, argc, argv ); /* anything else */ } else { diff --git a/servers/slapd/back-meta/conn.c b/servers/slapd/back-meta/conn.c index 3b31118c3f..cfabeb1753 100644 --- a/servers/slapd/back-meta/conn.c +++ b/servers/slapd/back-meta/conn.c @@ -136,11 +136,13 @@ metaconn_alloc( int ntargets ) /* * make it a null-terminated array ... */ - lc->mc_conns = ch_calloc( sizeof( struct metasingleconn ), ntargets+1 ); + lc->mc_conns = ch_calloc( sizeof( struct metasingleconn ), ntargets + 1 ); if ( lc->mc_conns == NULL ) { free( lc ); return NULL; } + + /* FIXME: needed by META_LAST() */ lc->mc_conns[ ntargets ].msc_candidate = META_LAST_CONN; for ( ; ntargets-- > 0; ) { @@ -187,6 +189,7 @@ init_one_conn( SlapReply *rs, struct metatarget *lt, struct metasingleconn *lsc, + char *candidate, ldap_back_send_t sendok ) { struct metainfo *li = ( struct metainfo * )op->o_bd->be_private; @@ -197,7 +200,8 @@ init_one_conn( * Already init'ed */ if ( lsc->msc_ld != NULL ) { - return LDAP_SUCCESS; + rs->sr_err = LDAP_SUCCESS; + goto error_return; } /* @@ -225,7 +229,7 @@ init_one_conn( if ( ( LDAP_BACK_USE_TLS( li ) || ( op->o_conn->c_is_tls && LDAP_BACK_PROPAGATE_TLS( li ) ) ) && !ldap_is_ldaps_url( lt->mt_uri ) ) { -#if 1 +#ifdef SLAP_STARTTLS_ASYNCHRONOUS /* * use asynchronous StartTLS * in case, chase referral (not implemented yet) @@ -289,12 +293,12 @@ retry:; ldap_msgfree( res ); } } -#else +#else /* ! SLAP_STARTTLS_ASYNCHRONOUS */ /* * use synchronous StartTLS */ rs->sr_err = ldap_start_tls_s( lsc->msc_ld, NULL, NULL ); -#endif +#endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */ /* if StartTLS is requested, only attempt it if the URL * is not "ldaps://"; this may occur not only in case @@ -312,11 +316,11 @@ retry:; /* * Set the network timeout if set */ - if (li->network_timeout != 0){ + if ( li->mi_network_timeout != 0 ) { struct timeval network_timeout; network_timeout.tv_usec = 0; - network_timeout.tv_sec = li->network_timeout; + network_timeout.tv_sec = li->mi_network_timeout; ldap_set_option( lsc->msc_ld, LDAP_OPT_NETWORK_TIMEOUT, (void *)&network_timeout ); @@ -371,30 +375,189 @@ error_return:; /* * The candidate is activated */ - lsc->msc_candidate = META_CANDIDATE; + *candidate = META_CANDIDATE; } return rs->sr_err; } +/* + * callback for unique candidate selection + */ +static int +meta_back_conn_cb( Operation *op, SlapReply *rs ) +{ + assert( op->o_tag == LDAP_REQ_SEARCH ); + + switch ( rs->sr_type ) { + case REP_SEARCH: + ((int *)op->o_callback->sc_private)[0] = (int)op->o_private; + break; + + case REP_SEARCHREF: + case REP_RESULT: + break; + + default: + return rs->sr_err; + } + + return 0; +} + + +static int +meta_back_get_candidate( + Operation *op, + SlapReply *rs, + struct berval *ndn ) +{ + struct metainfo *li = ( struct metainfo * )op->o_bd->be_private; + int candidate; + + /* + * tries to get a unique candidate + * (takes care of default target) + */ + candidate = meta_back_select_unique_candidate( li, ndn ); + + /* + * if any is found, inits the connection + */ + if ( candidate == META_TARGET_NONE ) { + rs->sr_err = LDAP_NO_SUCH_OBJECT; + rs->sr_text = "no suitable candidate target found"; + + } else if ( candidate == META_TARGET_MULTIPLE ) { + Filter f = { 0 }; + Operation op2 = *op; + SlapReply rs2 = { 0 }; + slap_callback cb2 = { 0 }; + int rc; + + /* try to get a unique match for the request ndn + * among the multiple candidates available */ + op2.o_tag = LDAP_REQ_SEARCH; + op2.o_req_dn = *ndn; + op2.o_req_ndn = *ndn; + op2.ors_scope = LDAP_SCOPE_BASE; + op2.ors_deref = LDAP_DEREF_NEVER; + op2.ors_attrs = slap_anlist_no_attrs; + op2.ors_attrsonly = 0; + op2.ors_limit = NULL; + op2.ors_slimit = 1; + op2.ors_tlimit = SLAP_NO_LIMIT; + + f.f_choice = LDAP_FILTER_PRESENT; + f.f_desc = slap_schema.si_ad_objectClass; + op2.ors_filter = &f; + BER_BVSTR( &op2.ors_filterstr, "(objectClass=*)" ); + + op2.o_callback = &cb2; + cb2.sc_response = meta_back_conn_cb; + cb2.sc_private = (void *)&candidate; + + rc = op->o_bd->be_search( &op2, &rs2 ); + + switch ( rs2.sr_err ) { + case LDAP_SUCCESS: + default: + rs->sr_err = rs2.sr_err; + break; + + case LDAP_SIZELIMIT_EXCEEDED: + /* if multiple candidates can serve the operation, + * and a default target is defined, and it is + * a candidate, try using it (FIXME: YMMV) */ + if ( li->mi_defaulttarget != META_DEFAULT_TARGET_NONE + && meta_back_is_candidate( &li->mi_targets[ li->mi_defaulttarget ]->mt_nsuffix, ndn ) ) + { + candidate = li->mi_defaulttarget; + rs->sr_err = LDAP_SUCCESS; + rs->sr_text = NULL; + + } else { + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "cannot select unique candidate target"; + } + break; + } + } + + return candidate; +} + +static void +meta_back_candidate_keyfree( void *key, void *data ) +{ + ber_memfree_x( data, NULL ); +} + +char * +meta_back_candidates_get( Operation *op ) +{ + struct metainfo *li = ( struct metainfo * )op->o_bd->be_private; + void *data = NULL; + + if ( op->o_threadctx ) { + ldap_pvt_thread_pool_getkey( op->o_threadctx, + meta_back_candidate_keyfree, &data, NULL ); + } else { + data = (void *)li->mi_candidates; + } + + if ( data == NULL ) { + data = ber_memalloc_x( sizeof( char ) * li->mi_ntargets, NULL ); + if ( op->o_threadctx ) { + ldap_pvt_thread_pool_setkey( op->o_threadctx, + meta_back_candidate_keyfree, data, + meta_back_candidate_keyfree ); + + } else { + li->mi_candidates = (char *)data; + } + } + + return (char *)data; +} + /* * meta_back_getconn * * Prepares the connection structure * - * FIXME: This function needs to receive some info on the type of operation - * it is invoked by, so that only the correct pool of candidate targets - * is initialized in case no connection was available yet. - * - * At present a flag that says whether the candidate target must be unique - * is passed; eventually an operation agent will be used. + * RATIONALE: + * + * - determine what DN is being requested: + * + * op requires candidate checks + * + * add unique parent of o_req_ndn + * bind unique^*[/all] o_req_ndn [no check] + * compare unique^+ o_req_ndn + * delete unique o_req_ndn + * modify unique o_req_ndn + * search any o_req_ndn + * modrdn unique[, unique] o_req_ndn[, orr_nnewSup] + * + * - for ops that require the candidate to be unique, in case of multiple + * occurrences an internal search with sizeLimit=1 is performed + * if a unique candidate can actually be determined. If none is found, + * the operation aborts; if multiple are found, the default target + * is used if defined and candidate; otherwise the operation aborts. + * + * *^note: actually, the bind operation is handled much like a search; + * i.e. the bind is broadcast to all candidate targets. + * + * +^note: actually, the compare operation is handled much like a search; + * i.e. the compare is broadcast to all candidate targets, while checking + * that exactly none (noSuchObject) or one (TRUE/FALSE/UNDEFINED) is + * returned. */ struct metaconn * meta_back_getconn( Operation *op, SlapReply *rs, - int op_type, - struct berval *ndn, int *candidate, ldap_back_send_t sendok ) { @@ -405,32 +568,81 @@ meta_back_getconn( err = LDAP_SUCCESS, new_conn = 0; + meta_op_type op_type = META_OP_REQUIRE_SINGLE; + int parent = 0, + newparent = 0; + struct berval ndn = op->o_req_ndn; + + char *candidates = meta_back_candidates_get( op ); + /* Searches for a metaconn in the avl tree */ lc_curr.mc_conn = op->o_conn; - ldap_pvt_thread_mutex_lock( &li->conn_mutex ); - lc = (struct metaconn *)avl_find( li->conntree, + ldap_pvt_thread_mutex_lock( &li->mi_conn_mutex ); + lc = (struct metaconn *)avl_find( li->mi_conntree, (caddr_t)&lc_curr, meta_back_conn_cmp ); - ldap_pvt_thread_mutex_unlock( &li->conn_mutex ); + ldap_pvt_thread_mutex_unlock( &li->mi_conn_mutex ); + + switch ( op->o_tag ) { + case LDAP_REQ_ADD: + /* if we go to selection, the entry must not exist, + * and we must be able to resolve the parent */ + parent = 1; + dnParent( &ndn, &ndn ); + break; + + case LDAP_REQ_MODRDN: + /* if nnewSuperior is not NULL, it must resolve + * to the same candidate as the req_ndn */ + if ( op->orr_nnewSup ) { + newparent = 1; + } + break; - /* Looks like we didn't get a bind. Open a new session... */ - if ( !lc ) { - lc = metaconn_alloc( li->ntargets ); - lc->mc_conn = op->o_conn; - new_conn = 1; + case LDAP_REQ_BIND: + /* if bound as rootdn, the backend must bind to all targets + * with the administrative identity */ + if ( op->orb_method == LDAP_AUTH_SIMPLE && be_isroot_pw( op ) ) { + op_type = META_OP_REQUIRE_ALL; + } + break; + + case LDAP_REQ_DELETE: + case LDAP_REQ_MODIFY: + /* just a unique candidate */ + break; + + case LDAP_REQ_COMPARE: + case LDAP_REQ_SEARCH: + /* allow multiple candidates for the searchBase */ + op_type = META_OP_ALLOW_MULTIPLE; + break; + + default: + /* right now, just break (exop?) */ + break; } /* * require all connections ... */ if ( op_type == META_OP_REQUIRE_ALL ) { - for ( i = 0; i < li->ntargets; i++ ) { + + /* Looks like we didn't get a bind. Open a new session... */ + if ( !lc ) { + lc = metaconn_alloc( li->mi_ntargets ); + lc->mc_conn = op->o_conn; + new_conn = 1; + } + + for ( i = 0; i < li->mi_ntargets; i++ ) { /* * The target is activated; if needed, it is * also init'd */ - int lerr = init_one_conn( op, rs, li->targets[ i ], - &lc->mc_conns[ i ], sendok ); + int lerr = init_one_conn( op, rs, li->mi_targets[ i ], + &lc->mc_conns[ i ], &candidates[ i ], + sendok ); if ( lerr != LDAP_SUCCESS ) { /* @@ -438,7 +650,10 @@ meta_back_getconn( * be init'd, should the other ones * be tried? */ - ( void )meta_clear_one_candidate( &lc->mc_conns[ i ], 1 ); + candidates[ i ] = META_NOT_CANDIDATE; +#if 0 + ( void )meta_clear_one_candidate( &lc->mc_conns[ i ] ); +#endif err = lerr; continue; } @@ -449,48 +664,72 @@ meta_back_getconn( /* * looks in cache, if any */ - if ( li->cache.ttl != META_DNCACHE_DISABLED ) { - cached = i = meta_dncache_get_target( &li->cache, ndn ); + if ( li->mi_cache.ttl != META_DNCACHE_DISABLED ) { + cached = i = meta_dncache_get_target( &li->mi_cache, &op->o_req_ndn ); } if ( op_type == META_OP_REQUIRE_SINGLE ) { + memset( candidates, META_NOT_CANDIDATE, sizeof( char ) * li->mi_ntargets ); + /* * tries to get a unique candidate - * (takes care of default target + * (takes care of default target) */ if ( i == META_TARGET_NONE ) { - i = meta_back_select_unique_candidate( li, ndn ); - } + i = meta_back_get_candidate( op, rs, &ndn ); - /* - * if any is found, inits the connection - */ - if ( i == META_TARGET_NONE ) { - if ( new_conn ) { - metaconn_free( lc ); + if ( rs->sr_err != LDAP_SUCCESS ) { + if ( sendok & LDAP_BACK_SENDERR ) { + send_ldap_result( op, rs ); + rs->sr_text = NULL; + } + return NULL; } + } - rs->sr_err = LDAP_NO_SUCH_OBJECT; + if ( newparent && meta_back_get_candidate( op, rs, op->orr_nnewSup ) != i ) + { + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "cross-target rename not supported"; + if ( sendok & LDAP_BACK_SENDERR ) { + send_ldap_result( op, rs ); + rs->sr_text = NULL; + } return NULL; } - + Debug( LDAP_DEBUG_CACHE, "==>meta_back_getconn: got target %d for ndn=\"%s\" from cache\n", - i, ndn->bv_val, 0 ); + i, op->o_req_ndn.bv_val, 0 ); + + /* Retries searching for a metaconn in the avl tree */ + lc_curr.mc_conn = op->o_conn; + ldap_pvt_thread_mutex_lock( &li->mi_conn_mutex ); + lc = (struct metaconn *)avl_find( li->mi_conntree, + (caddr_t)&lc_curr, meta_back_conn_cmp ); + ldap_pvt_thread_mutex_unlock( &li->mi_conn_mutex ); + + /* Looks like we didn't get a bind. Open a new session... */ + if ( !lc ) { + lc = metaconn_alloc( li->mi_ntargets ); + lc->mc_conn = op->o_conn; + new_conn = 1; + } /* * Clear all other candidates */ - ( void )meta_clear_unused_candidates( li, lc, i, 0 ); + ( void )meta_clear_unused_candidates( op, lc, i ); /* * The target is activated; if needed, it is * also init'd. In case of error, init_one_conn * sends the appropriate result. */ - err = init_one_conn( op, rs, li->targets[ i ], - &lc->mc_conns[ i ], sendok ); + err = init_one_conn( op, rs, li->mi_targets[ i ], + &lc->mc_conns[ i ], &candidates[ i ], + sendok ); if ( err != LDAP_SUCCESS ) { /* @@ -498,8 +737,9 @@ meta_back_getconn( * be init'd, should the other ones * be tried? */ - ( void )meta_clear_one_candidate( &lc->mc_conns[ i ], 1 ); - if ( new_conn ) { + candidates[ i ] = META_NOT_CANDIDATE; + if ( new_conn ) { + ( void )meta_clear_one_candidate( &lc->mc_conns[ i ] ); metaconn_free( lc ); } return NULL; @@ -513,9 +753,18 @@ meta_back_getconn( * if no unique candidate ... */ } else { - for ( i = 0; i < li->ntargets; i++ ) { + + /* Looks like we didn't get a bind. Open a new session... */ + if ( !lc ) { + lc = metaconn_alloc( li->mi_ntargets ); + lc->mc_conn = op->o_conn; + new_conn = 1; + } + + for ( i = 0; i < li->mi_ntargets; i++ ) { if ( i == cached - || meta_back_is_candidate( &li->targets[ i ]->mt_nsuffix, ndn ) ) + || meta_back_is_candidate( &li->mi_targets[ i ]->mt_nsuffix, + &op->o_req_ndn ) ) { /* @@ -523,8 +772,10 @@ meta_back_getconn( * also init'd */ int lerr = init_one_conn( op, rs, - li->targets[ i ], - &lc->mc_conns[ i ], sendok ); + li->mi_targets[ i ], + &lc->mc_conns[ i ], + &candidates[ i ], + sendok ); if ( lerr != LDAP_SUCCESS ) { /* @@ -532,10 +783,16 @@ meta_back_getconn( * be init'd, should the other ones * be tried? */ - ( void )meta_clear_one_candidate( &lc->mc_conns[ i ], 1 ); + candidates[ i ] = META_NOT_CANDIDATE; +#if 0 + ( void )meta_clear_one_candidate( &lc->mc_conns[ i ] ); +#endif err = lerr; continue; } + + } else { + candidates[ i ] = META_NOT_CANDIDATE; } } } @@ -550,15 +807,15 @@ done:; /* * Inserts the newly created metaconn in the avl tree */ - ldap_pvt_thread_mutex_lock( &li->conn_mutex ); - err = avl_insert( &li->conntree, ( caddr_t )lc, + ldap_pvt_thread_mutex_lock( &li->mi_conn_mutex ); + err = avl_insert( &li->mi_conntree, ( caddr_t )lc, meta_back_conn_cmp, meta_back_conn_dup ); #if PRINT_CONNTREE > 0 - myprint( li->conntree ); + myprint( li->mi_conntree ); #endif /* PRINT_CONNTREE */ - ldap_pvt_thread_mutex_unlock( &li->conn_mutex ); + ldap_pvt_thread_mutex_unlock( &li->mi_conn_mutex ); Debug( LDAP_DEBUG_TRACE, "=>meta_back_getconn: conn %ld inserted\n", @@ -571,6 +828,10 @@ done:; rs->sr_err = LDAP_OTHER; rs->sr_text = "Internal server error"; metaconn_free( lc ); + if ( sendok & LDAP_BACK_SENDERR ) { + send_ldap_result( op, rs ); + rs->sr_text = NULL; + } return NULL; } diff --git a/servers/slapd/back-meta/delete.c b/servers/slapd/back-meta/delete.c index 646cbe8de6..a2387ea96c 100644 --- a/servers/slapd/back-meta/delete.c +++ b/servers/slapd/back-meta/delete.c @@ -40,8 +40,7 @@ meta_back_delete( Operation *op, SlapReply *rs ) struct berval mdn = BER_BVNULL; dncookie dc; - lc = meta_back_getconn( op, rs, META_OP_REQUIRE_SINGLE, - &op->o_req_ndn, &candidate, LDAP_BACK_SENDERR ); + lc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR ); if ( !lc || !meta_back_dobind( lc, op, LDAP_BACK_SENDERR ) ) { return rs->sr_err; } @@ -55,7 +54,7 @@ meta_back_delete( Operation *op, SlapReply *rs ) /* * Rewrite the compare dn, if needed */ - dc.rwmap = &li->targets[ candidate ]->mt_rwmap; + dc.rwmap = &li->mi_targets[ candidate ]->mt_rwmap; dc.conn = op->o_conn; dc.rs = rs; dc.ctx = "deleteDN"; @@ -73,6 +72,6 @@ meta_back_delete( Operation *op, SlapReply *rs ) BER_BVZERO( &mdn ); } - return meta_back_op_result( lc, op, rs ); + return meta_back_op_result( lc, op, rs, candidate ); } diff --git a/servers/slapd/back-meta/init.c b/servers/slapd/back-meta/init.c index e7883ce147..cb3cc111f6 100644 --- a/servers/slapd/back-meta/init.c +++ b/servers/slapd/back-meta/init.c @@ -78,16 +78,8 @@ meta_back_db_init( { struct metainfo *li; - struct rewrite_info *rwinfo; - - rwinfo = rewrite_info_init( REWRITE_MODE_USE_DEFAULT ); - if ( rwinfo == NULL ) { - return -1; - } - li = ch_calloc( 1, sizeof( struct metainfo ) ); if ( li == NULL ) { - rewrite_info_delete( &rwinfo ); return -1; } @@ -95,11 +87,10 @@ meta_back_db_init( * At present the default is no default target; * this may change */ - li->defaulttarget = META_DEFAULT_TARGET_NONE; - li->rwinfo = rwinfo; + li->mi_defaulttarget = META_DEFAULT_TARGET_NONE; - ldap_pvt_thread_mutex_init( &li->conn_mutex ); - ldap_pvt_thread_mutex_init( &li->cache.mutex ); + ldap_pvt_thread_mutex_init( &li->mi_conn_mutex ); + ldap_pvt_thread_mutex_init( &li->mi_cache.mutex ); be->be_private = li; return 0; @@ -189,33 +180,37 @@ meta_back_db_destroy( /* * Destroy the connection tree */ - ldap_pvt_thread_mutex_lock( &li->conn_mutex ); + ldap_pvt_thread_mutex_lock( &li->mi_conn_mutex ); - if ( li->conntree ) { - avl_free( li->conntree, conn_free ); + if ( li->mi_conntree ) { + avl_free( li->mi_conntree, conn_free ); } /* * Destroy the per-target stuff (assuming there's at * least one ...) */ - for ( i = 0; i < li->ntargets; i++ ) { - target_free( li->targets[ i ] ); - free( li->targets[ i ] ); + for ( i = 0; i < li->mi_ntargets; i++ ) { + target_free( li->mi_targets[ i ] ); + free( li->mi_targets[ i ] ); } - free( li->targets ); + free( li->mi_targets ); - ldap_pvt_thread_mutex_lock( &li->cache.mutex ); - if ( li->cache.tree ) { - avl_free( li->cache.tree, meta_dncache_free ); + ldap_pvt_thread_mutex_lock( &li->mi_cache.mutex ); + if ( li->mi_cache.tree ) { + avl_free( li->mi_cache.tree, meta_dncache_free ); } - ldap_pvt_thread_mutex_unlock( &li->cache.mutex ); - ldap_pvt_thread_mutex_destroy( &li->cache.mutex ); + ldap_pvt_thread_mutex_unlock( &li->mi_cache.mutex ); + ldap_pvt_thread_mutex_destroy( &li->mi_cache.mutex ); - ldap_pvt_thread_mutex_unlock( &li->conn_mutex ); - ldap_pvt_thread_mutex_destroy( &li->conn_mutex ); + ldap_pvt_thread_mutex_unlock( &li->mi_conn_mutex ); + ldap_pvt_thread_mutex_destroy( &li->mi_conn_mutex ); + + if ( li->mi_candidates != NULL ) { + ber_memfree_x( li->mi_candidates, NULL ); + } } free( be->be_private ); diff --git a/servers/slapd/back-meta/modify.c b/servers/slapd/back-meta/modify.c index e09b9c3566..5177132f91 100644 --- a/servers/slapd/back-meta/modify.c +++ b/servers/slapd/back-meta/modify.c @@ -46,8 +46,7 @@ meta_back_modify( Operation *op, SlapReply *rs ) struct berval mapped; dncookie dc; - lc = meta_back_getconn( op, rs, META_OP_REQUIRE_SINGLE, - &op->o_req_ndn, &candidate, LDAP_BACK_SENDERR ); + lc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR ); if ( !lc || !meta_back_dobind( lc, op, LDAP_BACK_SENDERR ) ) { return rs->sr_err; } @@ -61,7 +60,7 @@ meta_back_modify( Operation *op, SlapReply *rs ) /* * Rewrite the modify dn, if needed */ - dc.rwmap = &li->targets[ candidate ]->mt_rwmap; + dc.rwmap = &li->mi_targets[ candidate ]->mt_rwmap; dc.conn = op->o_conn; dc.rs = rs; dc.ctx = "modifyDN"; @@ -103,7 +102,7 @@ meta_back_modify( Operation *op, SlapReply *rs ) mapped = ml->sml_desc->ad_cname; } else { - ldap_back_map( &li->targets[ candidate ]->mt_rwmap.rwm_at, + ldap_back_map( &li->mi_targets[ candidate ]->mt_rwmap.rwm_at, &ml->sml_desc->ad_cname, &mapped, BACKLDAP_MAP ); if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) { @@ -130,11 +129,11 @@ meta_back_modify( Operation *op, SlapReply *rs ) for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); ) { struct ldapmapping *mapping; - ldap_back_mapping( &li->targets[ candidate ]->mt_rwmap.rwm_oc, + ldap_back_mapping( &li->mi_targets[ candidate ]->mt_rwmap.rwm_oc, &ml->sml_values[ j ], &mapping, BACKLDAP_MAP ); if ( mapping == NULL ) { - if ( li->targets[ candidate ]->mt_rwmap.rwm_oc.drop_missing ) { + if ( li->mi_targets[ candidate ]->mt_rwmap.rwm_oc.drop_missing ) { continue; } mods[ i ].mod_bvalues[ j ] = &ml->sml_values[ j ]; @@ -192,7 +191,7 @@ cleanup:; free( modv ); if ( rc != -1 ) { - return meta_back_op_result( lc, op, rs ); + return meta_back_op_result( lc, op, rs, candidate ); } send_ldap_result( op, rs ); diff --git a/servers/slapd/back-meta/modrdn.c b/servers/slapd/back-meta/modrdn.c index a0d7e408cc..6123fd2533 100644 --- a/servers/slapd/back-meta/modrdn.c +++ b/servers/slapd/back-meta/modrdn.c @@ -42,8 +42,7 @@ meta_back_modrdn( Operation *op, SlapReply *rs ) mnewSuperior = BER_BVNULL; dncookie dc; - lc = meta_back_getconn( op, rs, META_OP_REQUIRE_SINGLE, - &op->o_req_ndn, &candidate, LDAP_BACK_SENDERR ); + lc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR ); if ( !lc ) { return rs->sr_err; } @@ -64,37 +63,36 @@ meta_back_modrdn( Operation *op, SlapReply *rs ) dc.rs = rs; if ( op->orr_newSup ) { - int nsCandidate, version = LDAP_VERSION3; - - nsCandidate = meta_back_select_unique_candidate( li, - op->orr_nnewSup ); - - if ( nsCandidate != candidate ) { - /* - * FIXME: one possibility is to delete the entry - * from one target and add it to the other; - * unfortunately we'd need write access to both, - * which is nearly impossible; for administration - * needs, the rootdn of the metadirectory could - * be mapped to an administrative account on each - * target (the binddn?); we'll see. - */ - /* - * FIXME: is this the correct return code? - */ - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "cross-target rename not supported"; - rc = -1; - goto cleanup; - } + int version = LDAP_VERSION3; + + /* + * NOTE: the newParent, if defined, must be on the + * same target as the entry to be renamed. This check + * has been anticipated in meta_back_getconn() + */ + /* + * FIXME: one possibility is to delete the entry + * from one target and add it to the other; + * unfortunately we'd need write access to both, + * which is nearly impossible; for administration + * needs, the rootdn of the metadirectory could + * be mapped to an administrative account on each + * target (the binddn?); we'll see. + */ + /* + * NOTE: we need to port the identity assertion + * feature from back-ldap + */ - ldap_set_option( lc->mc_conns[ nsCandidate ].msc_ld, + /* newSuperior needs LDAPv3; if we got here, we can safely + * enforce it */ + ldap_set_option( lc->mc_conns[ candidate ].msc_ld, LDAP_OPT_PROTOCOL_VERSION, &version ); /* * Rewrite the new superior, if defined and required */ - dc.rwmap = &li->targets[ nsCandidate ]->mt_rwmap; + dc.rwmap = &li->mi_targets[ candidate ]->mt_rwmap; dc.ctx = "newSuperiorDN"; if ( ldap_back_dn_massage( &dc, op->orr_newSup, &mnewSuperior ) ) { rc = -1; @@ -105,7 +103,7 @@ meta_back_modrdn( Operation *op, SlapReply *rs ) /* * Rewrite the modrdn dn, if required */ - dc.rwmap = &li->targets[ candidate ]->mt_rwmap; + dc.rwmap = &li->mi_targets[ candidate ]->mt_rwmap; dc.ctx = "modrDN"; if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) { rc = -1; @@ -132,7 +130,7 @@ cleanup:; } if ( rc == 0 ) { - return meta_back_op_result( lc, op, rs ) == LDAP_SUCCESS + return meta_back_op_result( lc, op, rs, candidate ) == LDAP_SUCCESS ? 0 : 1; } /* else */ diff --git a/servers/slapd/back-meta/search.c b/servers/slapd/back-meta/search.c index 3dbd522a8b..36254eeee3 100644 --- a/servers/slapd/back-meta/search.c +++ b/servers/slapd/back-meta/search.c @@ -47,22 +47,27 @@ meta_send_entry( int meta_back_search( Operation *op, SlapReply *rs ) { - struct metainfo *li = ( struct metainfo * )op->o_bd->be_private; - struct metaconn *lc; - struct metasingleconn *lsc; - struct timeval tv = { 0, 0 }; - LDAPMessage *res = NULL, *e; - int rc = 0, *msgid, sres = LDAP_SUCCESS; - char *err = NULL; - struct berval match = BER_BVNULL, mmatch = BER_BVNULL; - BerVarray v2refs = NULL; + struct metainfo *li = ( struct metainfo * )op->o_bd->be_private; + struct metaconn *lc; + struct metasingleconn *lsc; + struct timeval tv = { 0, 0 }; + LDAPMessage *res = NULL, *e; + int rc = 0, *msgid, sres = LDAP_SUCCESS; + char *err = NULL; + struct berval match = BER_BVNULL, mmatch = BER_BVNULL; + BerVarray v2refs = NULL; - int i, last = 0, candidates = 0, initial_candidates = 0, - candidate_match = 0; - dncookie dc; + int i, last = 0, ncandidates = 0, + initial_candidates = 0, candidate_match = 0; + dncookie dc; + + int is_scope = 0, + is_filter = 0, + is_ok = 0; - int is_scope = 0, - is_filter = 0; + void *savepriv; + + char *candidates = meta_back_candidates_get( op ); /* * controls are set in ldap_back_dobind() @@ -70,8 +75,7 @@ meta_back_search( Operation *op, SlapReply *rs ) * FIXME: in case of values return filter, we might want * to map attrs and maybe rewrite value */ - lc = meta_back_getconn( op, rs, META_OP_ALLOW_MULTIPLE, - &op->o_req_ndn, NULL, LDAP_BACK_SENDERR ); + lc = meta_back_getconn( op, rs, NULL, LDAP_BACK_SENDERR ); if ( !lc || !meta_back_dobind( lc, op, LDAP_BACK_SENDERR ) ) { return rs->sr_err; } @@ -79,7 +83,7 @@ meta_back_search( Operation *op, SlapReply *rs ) /* * Array of message id of each target */ - msgid = ch_calloc( sizeof( int ), li->ntargets ); + msgid = ch_calloc( sizeof( int ), li->mi_ntargets ); if ( msgid == NULL ) { rs->sr_err = LDAP_OTHER; send_ldap_result( op, rs ); @@ -100,7 +104,7 @@ meta_back_search( Operation *op, SlapReply *rs ) struct berval mfilter = BER_BVNULL; char **mapped_attrs = NULL; - if ( lsc->msc_candidate != META_CANDIDATE ) { + if ( candidates[ i ] != META_CANDIDATE ) { msgid[ i ] = -1; continue; } @@ -119,12 +123,12 @@ meta_back_search( Operation *op, SlapReply *rs ) ( void * )&op->ors_slimit); } - dc.rwmap = &li->targets[ i ]->mt_rwmap; + dc.rwmap = &li->mi_targets[ i ]->mt_rwmap; /* * modifies the base according to the scope, if required */ - suffixlen = li->targets[ i ]->mt_nsuffix.bv_len; + suffixlen = li->mi_targets[ i ]->mt_nsuffix.bv_len; if ( suffixlen > op->o_req_ndn.bv_len ) { switch ( op->ors_scope ) { case LDAP_SCOPE_SUBTREE: @@ -134,9 +138,9 @@ meta_back_search( Operation *op, SlapReply *rs ) * illegal bases may be turned into * the suffix of the target. */ - if ( dnIsSuffix( &li->targets[ i ]->mt_nsuffix, + if ( dnIsSuffix( &li->mi_targets[ i ]->mt_nsuffix, &op->o_req_ndn ) ) { - realbase = li->targets[ i ]->mt_nsuffix; + realbase = li->mi_targets[ i ]->mt_nsuffix; is_scope++; } else { @@ -150,17 +154,17 @@ meta_back_search( Operation *op, SlapReply *rs ) case LDAP_SCOPE_ONELEVEL: { - struct berval rdn = li->targets[ i ]->mt_nsuffix; + struct berval rdn = li->mi_targets[ i ]->mt_nsuffix; rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," ); if ( dnIsOneLevelRDN( &rdn ) - && dnIsSuffix( &li->targets[ i ]->mt_nsuffix, &op->o_req_ndn ) ) + && dnIsSuffix( &li->mi_targets[ i ]->mt_nsuffix, &op->o_req_ndn ) ) { /* * if there is exactly one level, * make the target suffix the new * base, and make scope "base" */ - realbase = li->targets[ i ]->mt_nsuffix; + realbase = li->mi_targets[ i ]->mt_nsuffix; realscope = LDAP_SCOPE_BASE; is_scope++; break; @@ -235,7 +239,7 @@ meta_back_search( Operation *op, SlapReply *rs ) /* * Maps required attributes */ - rc = ldap_back_map_attrs( &li->targets[ i ]->mt_rwmap.rwm_at, + rc = ldap_back_map_attrs( &li->mi_targets[ i ]->mt_rwmap.rwm_at, op->ors_attrs, BACKLDAP_MAP, &mapped_attrs ); if ( rc != LDAP_SUCCESS ) { @@ -271,12 +275,12 @@ meta_back_search( Operation *op, SlapReply *rs ) continue; } - ++candidates; + ++ncandidates; new_candidate:; } - initial_candidates = candidates; + initial_candidates = ncandidates; /* We pull apart the ber result, stuff it into a slapd entry, and * let send_search_entry stuff it back into ber format. Slow & ugly, @@ -290,7 +294,7 @@ new_candidate:; * FIXME: we might use a queue, to balance the load * among the candidates */ - for ( rc = 0; candidates > 0; ) { + for ( rc = 0; ncandidates > 0; ) { int ab, gotit = 0; /* check for abandon */ @@ -308,10 +312,14 @@ new_candidate:; } if ( op->ors_slimit > 0 - && rs->sr_nentries == op->ors_slimit ) { + && rs->sr_nentries == op->ors_slimit ) + { rs->sr_err = LDAP_SIZELIMIT_EXCEEDED; rs->sr_v2ref = v2refs; + savepriv = op->o_private; + op->o_private = (void *)i; send_ldap_result( op, rs ); + op->o_private = savepriv; goto finish; } @@ -336,11 +344,14 @@ new_candidate:; } else if ( rc == -1 ) { really_bad:; /* something REALLY bad happened! */ - ( void )meta_clear_unused_candidates( li, - lc, -1, 0 ); + ( void )meta_clear_unused_candidates( op, + lc, -1 ); rs->sr_err = LDAP_OTHER; rs->sr_v2ref = v2refs; + savepriv = op->o_private; + op->o_private = (void *)i; send_ldap_result( op, rs ); + op->o_private = savepriv; /* anything else needs be done? */ @@ -350,8 +361,13 @@ really_bad:; goto finish; } else if ( rc == LDAP_RES_SEARCH_ENTRY ) { + is_ok++; + e = ldap_first_entry( lsc->msc_ld, res ); + savepriv = op->o_private; + op->o_private = (void *)i; meta_send_entry( op, rs, lc, i, e ); + op->o_private = savepriv; ldap_msgfree( res ); res = NULL; @@ -364,8 +380,9 @@ really_bad:; * entry that has the base DN */ if ( op->ors_scope == LDAP_SCOPE_BASE - && rs->sr_nentries > 0 ) { - candidates = 0; + && rs->sr_nentries > 0 ) + { + ncandidates = 0; sres = LDAP_SUCCESS; break; } @@ -376,6 +393,8 @@ really_bad:; char **references = NULL; int cnt; + is_ok++; + rc = ldap_parse_reference( lsc->msc_ld, res, &references, &rs->sr_ctrls, 1 ); res = NULL; @@ -408,7 +427,10 @@ really_bad:; if ( rs->sr_ref != NULL && !BER_BVISNULL( &rs->sr_ref[ 0 ] ) ) { /* ignore return value by now */ + savepriv = op->o_private; + op->o_private = (void *)i; ( void )send_search_reference( op, rs ); + op->o_private = savepriv; ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; @@ -435,16 +457,38 @@ really_bad:; res = NULL; sres = slap_map_api2result( rs ); + switch ( sres ) { + case LDAP_NO_SUCH_OBJECT: + /* is_ok is touched any time a valid + * (even intermediate) result is + * returned; as a consequence, if + * a candidate returns noSuchObject + * it is ignored and the candidate + * is simply demoted. */ + if ( is_ok ) { + sres = LDAP_SUCCESS; + } + break; + + case LDAP_SUCCESS: + is_ok++; + break; + } + if ( err != NULL ) { free( err ); } ldap_get_option( lsc->msc_ld, LDAP_OPT_ERROR_STRING, &err ); - if ( match.bv_val != NULL ) { + if ( !BER_BVISNULL( &match ) ) { free( match.bv_val ); + BER_BVZERO( &match ); } ldap_get_option( lsc->msc_ld, LDAP_OPT_MATCHED_DN, &match.bv_val ); + if ( !BER_BVISNULL( &match ) ) { + match.bv_len = strlen( match.bv_val ); + } Debug( LDAP_DEBUG_ANY, "=>meta_back_search [%d] " @@ -459,7 +503,7 @@ really_bad:; * the outer cycle finishes */ msgid[ i ] = -1; - --candidates; + --ncandidates; } } @@ -482,7 +526,7 @@ really_bad:; /* * FIXME: need a strategy to handle errors */ - rc = meta_back_op_result( lc, op, rs ); + rc = meta_back_op_result( lc, op, rs, META_TARGET_NONE ); goto finish; } @@ -492,12 +536,13 @@ really_bad:; * FIXME: only the last one gets caught! */ if ( candidate_match == initial_candidates - && match.bv_val != NULL && *match.bv_val ) { + && !BER_BVISNULL( &match ) && !BER_BVISEMPTY( &match ) ) + { dc.ctx = "matchedDN"; - dc.rwmap = &li->targets[ last ]->mt_rwmap; + dc.rwmap = &li->mi_targets[ last ]->mt_rwmap; if ( ldap_back_dn_massage( &dc, &match, &mmatch ) ) { - mmatch.bv_val = NULL; + BER_BVZERO( &mmatch ); } } @@ -518,14 +563,18 @@ really_bad:; rs->sr_err = sres; rs->sr_matched = mmatch.bv_val; rs->sr_v2ref = v2refs; + savepriv = op->o_private; + op->o_private = (void *)i; send_ldap_result( op, rs ); + op->o_private = savepriv; rs->sr_matched = NULL; rs->sr_v2ref = NULL; finish:; - if ( match.bv_val ) { - if ( mmatch.bv_val != match.bv_val ) { + if ( !BER_BVISNULL( &match ) ) { + if ( !BER_BVISNULL( &mmatch ) && mmatch.bv_val != match.bv_val ) + { free( mmatch.bv_val ); } free( match.bv_val ); @@ -567,7 +616,7 @@ meta_send_entry( /* * Rewrite the dn of the result, if needed */ - dc.rwmap = &li->targets[ target ]->mt_rwmap; + dc.rwmap = &li->mi_targets[ target ]->mt_rwmap; dc.conn = op->o_conn; dc.rs = rs; dc.ctx = "searchResult"; @@ -593,8 +642,8 @@ meta_send_entry( /* * cache dn */ - if ( li->cache.ttl != META_DNCACHE_DISABLED ) { - ( void )meta_dncache_update_entry( &li->cache, + if ( li->mi_cache.ttl != META_DNCACHE_DISABLED ) { + ( void )meta_dncache_update_entry( &li->mi_cache, &ent.e_nname, target ); } @@ -604,9 +653,9 @@ meta_send_entry( while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) { int last = 0; - ldap_back_map( &li->targets[ target ]->mt_rwmap.rwm_at, + ldap_back_map( &li->mi_targets[ target ]->mt_rwmap.rwm_at, &a, &mapped, BACKLDAP_REMAP ); - if ( mapped.bv_val == NULL || mapped.bv_val[0] == '\0' ) { + if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) { continue; } attr = ( Attribute * )ch_malloc( sizeof( Attribute ) ); @@ -651,19 +700,19 @@ meta_send_entry( } else if ( attr->a_desc == slap_schema.si_ad_objectClass || attr->a_desc == slap_schema.si_ad_structuralObjectClass ) { - for ( last = 0; attr->a_vals[ last ].bv_val; ++last ); + for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); ++last ); - for ( bv = attr->a_vals; bv->bv_val; bv++ ) { - ldap_back_map( &li->targets[ target ]->mt_rwmap.rwm_oc, + for ( bv = attr->a_vals; !BER_BVISNULL( bv ); bv++ ) { + ldap_back_map( &li->mi_targets[ target ]->mt_rwmap.rwm_oc, bv, &mapped, BACKLDAP_REMAP ); - if ( mapped.bv_val == NULL || mapped.bv_val[0] == '\0') { + if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0') { free( bv->bv_val ); - bv->bv_val = NULL; + BER_BVZERO( bv ); if ( --last < 0 ) { break; } *bv = attr->a_vals[ last ]; - attr->a_vals[ last ].bv_val = NULL; + BER_BVZERO( &attr->a_vals[ last ] ); bv--; } else if ( mapped.bv_val != bv->bv_val ) { @@ -704,8 +753,7 @@ meta_send_entry( &attr->a_vals[i], &attr->a_nvals[i], NULL ); } - attr->a_nvals[i].bv_val = NULL; - attr->a_nvals[i].bv_len = 0; + BER_BVZERO( &attr->a_nvals[i] ); } else { attr->a_nvals = attr->a_vals; } diff --git a/servers/slapd/back-meta/unbind.c b/servers/slapd/back-meta/unbind.c index 40350141c9..c60ee05f0b 100644 --- a/servers/slapd/back-meta/unbind.c +++ b/servers/slapd/back-meta/unbind.c @@ -47,14 +47,14 @@ meta_back_conn_destroy( lc_curr.mc_conn = conn; - ldap_pvt_thread_mutex_lock( &li->conn_mutex ); - lc = avl_delete( &li->conntree, ( caddr_t )&lc_curr, + ldap_pvt_thread_mutex_lock( &li->mi_conn_mutex ); + lc = avl_delete( &li->mi_conntree, ( caddr_t )&lc_curr, meta_back_conn_cmp ); - ldap_pvt_thread_mutex_unlock( &li->conn_mutex ); + ldap_pvt_thread_mutex_unlock( &li->mi_conn_mutex ); if ( lc ) { - int i; - + int i; + Debug( LDAP_DEBUG_TRACE, "=>meta_back_conn_destroy: destroying conn %ld\n", lc->mc_conn->c_connid, 0, 0 ); @@ -62,13 +62,13 @@ meta_back_conn_destroy( /* * Cleanup rewrite session */ - for ( i = 0; i < li->ntargets; ++i ) { + for ( i = 0; i < li->mi_ntargets; ++i ) { if ( lc->mc_conns[ i ].msc_ld == NULL ) { continue; } - rewrite_session_delete( li->targets[ i ]->mt_rwmap.rwm_rw, conn ); - meta_clear_one_candidate( &lc->mc_conns[ i ], 1 ); + rewrite_session_delete( li->mi_targets[ i ]->mt_rwmap.rwm_rw, conn ); + meta_clear_one_candidate( &lc->mc_conns[ i ] ); } free( lc->mc_conns );