]> git.sur5r.net Git - openldap/commitdiff
a) implement a new candidate selection procedure, based on target naming
authorPierangelo Masarati <ando@openldap.org>
Sat, 16 Apr 2005 02:25:41 +0000 (02:25 +0000)
committerPierangelo Masarati <ando@openldap.org>
Sat, 16 Apr 2005 02:25:41 +0000 (02:25 +0000)
   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

13 files changed:
servers/slapd/back-meta/add.c
servers/slapd/back-meta/back-meta.h
servers/slapd/back-meta/bind.c
servers/slapd/back-meta/candidates.c
servers/slapd/back-meta/compare.c
servers/slapd/back-meta/config.c
servers/slapd/back-meta/conn.c
servers/slapd/back-meta/delete.c
servers/slapd/back-meta/init.c
servers/slapd/back-meta/modify.c
servers/slapd/back-meta/modrdn.c
servers/slapd/back-meta/search.c
servers/slapd/back-meta/unbind.c

index 857ce7ec5f452c6b3a158990fb38faa6a1b978bd..870c92ef5574214f957cb0a61e0888cbea7cc59e 100644 (file)
@@ -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 );
 }
 
index 6df5a58e5c7149be6def00eac32c788fd781a0cd..8b2f8a15e196b087537d28bd652825f7f8776f80 100644 (file)
@@ -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 <back-ldap/back-ldap.h>
+#if 0
+/* defined in <back-ldap/back-ldap.h> */
 #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,
index 69fe2ea995ea527d5f127a425f0484a6123dad0f..11093f2e6b070ba2a955d5e5431586faf17066b1 100644 (file)
@@ -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;
index a018588d9c83a3b6422f718508053cd2f3fc6f6b..96f0f2236470bbea9fd2b14c1f5fc3697775e862 100644 (file)
  * 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;
index ee15d1495d459409ef229e72c45721aecfee50ac..c9fc9fb137b7dac7c3eb0e38012a1a62f82fdda5 100644 (file)
@@ -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 );
index a7a6fa1805f6049f67ba74f6a9519c65bffd0d15..e9bd33fff091d3c87269030b61a6f20bd211ca44 100644 (file)
@@ -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 <protocol>://<server>[:port]/<naming context>\" 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 <protocol>://<server>[:port]/<naming context>\" 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: <naming context> of URI does not refer to current backend"
        " in \"uri <protocol>://<server>[:port]/<naming context>\" 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: <naming context> of URI does not resolve to a backend"
        " in \"uri <protocol>://<server>[:port]/<naming context>\" 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 <protocol>://<server>[:port]/<naming context>\" 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 {
index 3b31118c3fabdcb1d155c366c1409b7c0bac59aa..cfabeb17534f1b3dba1618e19cd48b425ae0a1d0 100644 (file)
@@ -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;
                }
 
index 646cbe8de646ad16823aeec17392017e11ab3be6..a2387ea96c28cfb8a22a630969dbff6a98afb0c3 100644 (file)
@@ -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 );
 }
 
index e7883ce14738fb4077c9eda321983e02961997d3..cb3cc111f6b63293eaf6118822a79a2442dc7100 100644 (file)
@@ -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 );
index e09b9c35666347c744093e4da5a41ad4b6ca7f9c..5177132f91c7e053ddfd36effcbe1f0b1babc1f3 100644 (file)
@@ -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 );
index a0d7e408ccd443925aa01126eb17465e8dc9f864..6123fd25331667edacc385ad96634a4476ff6dc5 100644 (file)
@@ -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 */
 
index 3dbd522a8be9a3b305032280a155caaef129ed33..36254eeee3a483a0d9e185890f5a848890041559 100644 (file)
@@ -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;
                }
index 40350141c9db3570b59056c68b2332c6af269ad3..c60ee05f0be248daad5425a6c0c0841a6cdab68f 100644 (file)
@@ -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 );