]> git.sur5r.net Git - openldap/commitdiff
- add support for "use-temporary-conn" much like back-ldap
authorPierangelo Masarati <ando@openldap.org>
Sun, 17 Dec 2006 23:52:23 +0000 (23:52 +0000)
committerPierangelo Masarati <ando@openldap.org>
Sun, 17 Dec 2006 23:52:23 +0000 (23:52 +0000)
- fix various connection creation/setup concurrency issues
- use shared connection when always idasserting (similar to ITS#4781)
- reduce the impact of schema mapping when not used (tnx to gprof)
- fix temporary/tainted connection leak in abnormal conditions

doc/man/man5/slapd-meta.5
servers/slapd/back-meta/back-meta.h
servers/slapd/back-meta/bind.c
servers/slapd/back-meta/candidates.c
servers/slapd/back-meta/config.c
servers/slapd/back-meta/conn.c
servers/slapd/back-meta/init.c
servers/slapd/back-meta/map.c
servers/slapd/back-meta/search.c

index fd15479b0cb1587e4dd4a4b25697f4bbf031ac41..7fc1ac3b28fee7ab6a56977d318ad8d93d43c12c 100644 (file)
@@ -176,6 +176,13 @@ is set to
 .B single\-conn {NO|yes}
 Discards current cached connection when the client rebinds.
 
+.TP
+.B use-temporary-conn {NO|yes}
+when set to 
+.BR yes ,
+create a temporary connection whenever competing with other threads
+for a shared one; otherwise, wait until the shared connection is available.
+
 .SH TARGET SPECIFICATION
 Target specification starts with a "uri" directive:
 
index 4d367674fc84cea279a460fbee5ca51edcc94045..945d54623f0bd22bcda21401f55d0d54ec661b88 100644 (file)
@@ -160,6 +160,35 @@ ldap_dnattr_result_rewrite(
 
 /* (end of) from back-ldap.h before rwm removal */
 
+/*
+ * A metasingleconn_t can be in the following, mutually exclusive states:
+ *
+ *     - none                  (0x0U)
+ *     - creating              META_BACK_FCONN_CREATING
+ *     - initialized           META_BACK_FCONN_INITED
+ *     - binding               LDAP_BACK_FCONN_BINDING
+ *     - bound/anonymous       LDAP_BACK_FCONN_ISBOUND/LDAP_BACK_FCONN_ISANON
+ *
+ * possible modifiers are:
+ *
+ *     - privileged            LDAP_BACK_FCONN_ISPRIV
+ *     - privileged, TLS       LDAP_BACK_FCONN_ISTLS
+ *     - subjected to idassert LDAP_BACK_FCONN_ISIDASR
+ *     - tainted               LDAP_BACK_FCONN_TAINTED
+ */
+
+#define META_BACK_FCONN_INITED         (0x00100000U)
+#define META_BACK_FCONN_CREATING       (0x00200000U)
+
+#define        META_BACK_CONN_INITED(lc)               LDAP_BACK_CONN_ISSET((lc), META_BACK_FCONN_INITED)
+#define        META_BACK_CONN_INITED_SET(lc)           LDAP_BACK_CONN_SET((lc), META_BACK_FCONN_INITED)
+#define        META_BACK_CONN_INITED_CLEAR(lc)         LDAP_BACK_CONN_CLEAR((lc), META_BACK_FCONN_INITED)
+#define        META_BACK_CONN_INITED_CPY(lc, mlc)      LDAP_BACK_CONN_CPY((lc), META_BACK_FCONN_INITED, (mlc))
+#define        META_BACK_CONN_CREATING(lc)             LDAP_BACK_CONN_ISSET((lc), META_BACK_FCONN_CREATING)
+#define        META_BACK_CONN_CREATING_SET(lc)         LDAP_BACK_CONN_SET((lc), META_BACK_FCONN_CREATING)
+#define        META_BACK_CONN_CREATING_CLEAR(lc)       LDAP_BACK_CONN_CLEAR((lc), META_BACK_FCONN_CREATING)
+#define        META_BACK_CONN_CREATING_CPY(lc, mlc)    LDAP_BACK_CONN_CPY((lc), META_BACK_FCONN_CREATING, (mlc))
+
 struct metainfo_t;
 
 #define        META_NOT_CANDIDATE              ((ber_tag_t)0x0)
@@ -329,16 +358,18 @@ typedef struct metainfo_t {
        unsigned                mi_flags;
 #define        li_flags                mi_flags
 /* uses flags as defined in <back-ldap/back-ldap.h> */
-#define        META_BACK_F_ONERR_STOP          (0x00010000U)
-#define        META_BACK_F_ONERR_REPORT        (0x00020000U)
+#define        META_BACK_F_ONERR_STOP          (0x00100000U)
+#define        META_BACK_F_ONERR_REPORT        (0x00200000U)
 #define        META_BACK_F_ONERR_MASK          (META_BACK_F_ONERR_STOP|META_BACK_F_ONERR_REPORT)
-#define        META_BACK_F_DEFER_ROOTDN_BIND   (0x00040000U)
+#define        META_BACK_F_DEFER_ROOTDN_BIND   (0x00400000U)
+#define        META_BACK_F_PROXYAUTHZ_ALWAYS   (0x00800000U)
 
 #define        META_BACK_ONERR_STOP(mi)        ( (mi)->mi_flags & META_BACK_F_ONERR_STOP )
 #define        META_BACK_ONERR_REPORT(mi)      ( (mi)->mi_flags & META_BACK_F_ONERR_REPORT )
 #define        META_BACK_ONERR_CONTINUE(mi)    ( !( (mi)->mi_flags & META_BACK_F_ONERR_MASK ) )
 
 #define META_BACK_DEFER_ROOTDN_BIND(mi)        ( (mi)->mi_flags & META_BACK_F_DEFER_ROOTDN_BIND )
+#define META_BACK_PROXYAUTHZ_ALWAYS(mi)        ( (mi)->mi_flags & META_BACK_F_PROXYAUTHZ_ALWAYS )
 
        int                     mi_version;
        time_t                  mi_network_timeout;
@@ -397,7 +428,8 @@ meta_back_init_one_conn(
        metaconn_t              *mc,
        int                     candidate,
        int                     ispriv,
-       ldap_back_send_t        sendok );
+       ldap_back_send_t        sendok,
+       int                     dolock );
 
 extern void
 meta_back_quarantine(
index e648dee09825b093bc570d53a2d32b7265728eee..3880e06e548f0864c8da87d5015c3f8e4705eef3 100644 (file)
@@ -399,9 +399,7 @@ retry:;
                                op->o_log_prefix, candidate, (void *)msc->msc_ld );
 #endif /* DEBUG_205 */
 
-                       ldap_unbind_ext( msc->msc_ld, NULL, NULL );
-                       msc->msc_ld = NULL;
-                       LDAP_BACK_CONN_BINDING_CLEAR( msc );
+                       meta_clear_one_candidate( op, mc, candidate );
                        ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
 
                        rs->sr_err = timeout_err;
@@ -683,7 +681,8 @@ retry_binding:;
                        ++bound;
                        continue;
 
-               } else if ( LDAP_BACK_CONN_BINDING( msc ) ) {
+               } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) )
+               {
                        ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
                        ldap_pvt_thread_yield();
                        goto retry_binding;
@@ -710,7 +709,7 @@ retry_binding:;
 
 
                        if ( rc == LDAP_UNAVAILABLE ) {
-                               /* FIXME: meta_back_retry() already calls
+                               /* FIXME: meta_back_retry() already re-calls
                                 * meta_back_single_dobind() */
                                if ( meta_back_retry( op, rs, &mc, i, sendok ) ) {
                                        goto retry_ok;
@@ -720,6 +719,7 @@ retry_binding:;
                                        ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
                                        LDAP_BACK_CONN_BINDING_CLEAR( msc );
                                        ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+                                       meta_back_release_conn( op, mc );
                                }
 
                                return 0;
index 4a7ba3b3e267a5d87d0abe3f23516557d3f96f59..e0c0116af62cad98a419ea7624fb0285df40ab7e 100644 (file)
@@ -187,7 +187,7 @@ meta_clear_one_candidate(
 {
        metasingleconn_t        *msc = &mc->mc_conns[ candidate ];
 
-       if ( msc->msc_ld ) {
+       if ( msc->msc_ld != NULL ) {
 
 #ifdef DEBUG_205
                char    buf[ BUFSIZ ];
@@ -213,6 +213,8 @@ meta_clear_one_candidate(
                BER_BVZERO( &msc->msc_cred );
        }
 
+       msc->msc_mscflags = 0;
+
        return 0;
 }
 
index 6ae4b3ba5fb21091eb3e43e8010a66921abcf377..6bdc63e90e0372eebde753f16d164bd1a91c5edc 100644 (file)
@@ -38,7 +38,6 @@ static int
 meta_back_new_target( 
        metatarget_t    **mtp )
 {
-        struct ldapmapping     *mapping;
        char                    *rargv[ 3 ];
        metatarget_t            *mt;
 
@@ -52,7 +51,6 @@ meta_back_new_target(
                return -1;
        }
 
-
        /*
         * the filter rewrite as a string must be disabled
         * by default; it can be re-enabled by adding rules;
@@ -68,8 +66,6 @@ meta_back_new_target(
        rargv[ 2 ] = NULL;
        rewrite_parse( mt->mt_rwmap.rwm_rw, "<suffix massage>", 1, 2, rargv );
 
-       ldap_back_map_init( &mt->mt_rwmap.rwm_at, &mapping );
-
        ldap_pvt_thread_mutex_init( &mt->mt_uri_mutex );
 
        mt->mt_idassert_mode = LDAP_BACK_IDASSERT_LEGACY;
@@ -849,6 +845,38 @@ meta_back_db_config(
                        return 1;
                }
 
+       /* use-temporaries? */
+       } else if ( strcasecmp( argv[ 0 ], "use-temporary-conn" ) == 0 ) {
+               if ( argc != 2 ) {
+                       Debug( LDAP_DEBUG_ANY,
+       "%s: line %d: \"use-temporary-conn {FALSE|true}\" takes 1 argument\n",
+                               fname, lineno, 0 );
+                       return( 1 );
+               }
+
+               if ( mi->mi_ntargets > 0 ) {
+                       Debug( LDAP_DEBUG_ANY,
+       "%s: line %d: \"use-temporary-conn\" must appear before target definitions\n",
+                               fname, lineno, 0 );
+                       return( 1 );
+               }
+
+               switch ( check_true_false( argv[ 1 ] ) ) {
+               case 0:
+                       mi->mi_flags &= ~LDAP_BACK_F_USE_TEMPORARIES;
+                       break;
+
+               case 1:
+                       mi->mi_flags |= LDAP_BACK_F_USE_TEMPORARIES;
+                       break;
+
+               default:
+                       Debug( LDAP_DEBUG_ANY,
+       "%s: line %d: \"use-temporary-conn {FALSE|true}\": invalid arg \"%s\".\n",
+                               fname, lineno, argv[ 1 ] );
+                       return 1;
+               }
+
        } else if ( strcasecmp( argv[ 0 ], "cancel" ) == 0 ) {
                unsigned        flag = 0;
                unsigned        *flagsp = mi->mi_ntargets ?
@@ -1402,7 +1430,7 @@ ldap_back_map_config(
        if ( strcmp( argv[ 2 ], "*" ) == 0 ) {
                if ( argc < 4 || strcmp( argv[ 3 ], "*" ) == 0 ) {
                        map->drop_missing = ( argc < 4 );
-                       return 0;
+                       goto success_return;
                }
                src = dst = argv[ 3 ];
 
@@ -1416,7 +1444,7 @@ ldap_back_map_config(
        }
 
        if ( ( map == at_map )
-                       && ( strcasecmp( src, "objectclass" ) == 0
+               && ( strcasecmp( src, "objectclass" ) == 0
                        || strcasecmp( dst, "objectclass" ) == 0 ) )
        {
                Debug( LDAP_DEBUG_ANY,
@@ -1544,6 +1572,12 @@ ldap_back_map_config(
        avl_insert( &map->remap, (caddr_t)&mapping[ 1 ],
                                mapping_cmp, mapping_dup );
 
+success_return:;
+       if ( !is_oc && map->map == NULL ) {
+               /* only init if required */
+               ldap_back_map_init( map, &mapping );
+       }
+
        return 0;
 
 error_return:;
index b1c4cc5724bb0d9d64b2f979202d70150ce5a2b0..9758cf1cd07ad8185e4aa837f7d650a169089f98 100644 (file)
@@ -202,7 +202,7 @@ metaconn_alloc(
 
        /* malloc all in one */
        mc = ( metaconn_t * )ch_calloc( 1, sizeof( metaconn_t )
-                       + sizeof( metasingleconn_t ) * ntargets );
+               + sizeof( metasingleconn_t ) * ( ntargets - 1 ) );
        if ( mc == NULL ) {
                return NULL;
        }
@@ -227,7 +227,8 @@ meta_back_init_one_conn(
        metaconn_t              *mc,
        int                     candidate,
        int                     ispriv,
-       ldap_back_send_t        sendok )
+       ldap_back_send_t        sendok,
+       int                     dolock )
 {
        metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
        metatarget_t            *mt = mi->mi_targets[ candidate ];
@@ -235,6 +236,7 @@ meta_back_init_one_conn(
        int                     version;
        dncookie                dc;
        int                     isauthz = ( candidate == mc->mc_authz_target );
+       int                     do_return = 0;
 #ifdef HAVE_TLS
        int                     is_ldaps = 0;
 #endif /* HAVE_TLS */
@@ -275,14 +277,62 @@ meta_back_init_one_conn(
                }
        }
 
+retry_lock:;
+       if ( dolock ) {
+               ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+       }
+
        /*
         * Already init'ed
         */
-       if ( msc->msc_ld != NULL ) {
-               return rs->sr_err = LDAP_SUCCESS;
+       if ( LDAP_BACK_CONN_ISBOUND( msc )
+               || LDAP_BACK_CONN_ISANON( msc ) )
+       {
+               assert( msc->msc_ld != NULL );
+               rs->sr_err = LDAP_SUCCESS;
+               do_return = 1;
+
+       } else if ( META_BACK_CONN_CREATING( msc )
+               || LDAP_BACK_CONN_BINDING( msc ) )
+       {
+               if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) {
+                       if ( dolock ) {
+                               ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+                       }
+
+                       ldap_pvt_thread_yield();
+                       goto retry_lock;
+               }
+
+               /* sounds more appropriate */
+               rs->sr_err = LDAP_BUSY;
+               do_return = 1;
+
+       } else if ( META_BACK_CONN_INITED( msc ) ) {
+               assert( msc->msc_ld != NULL );
+               rs->sr_err = LDAP_SUCCESS;
+               do_return = 1;
+
+       } else {
+               /*
+                * creating...
+                */
+               META_BACK_CONN_CREATING_SET( msc );
+       }
+
+       if ( dolock ) {
+               ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+       }
+
+       if ( do_return ) {
+               if ( rs->sr_err != LDAP_SUCCESS && op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
+                       send_ldap_result( op, rs );
+               }
+
+               return rs->sr_err;
        }
 
-       msc->msc_mscflags = 0;
+       assert( msc->msc_ld == NULL );
        
        /*
         * Attempts to initialize the connection to the target ds
@@ -430,8 +480,8 @@ retry:;
                                op->o_log_prefix, candidate, (void *)msc->msc_ld );
 #endif /* DEBUG_205 */
 
-                       ldap_unbind_ext( msc->msc_ld, NULL, NULL );
-                       msc->msc_ld = NULL;
+                       /* need to trash a failed Start TLS */
+                       meta_clear_one_candidate( op, mc, candidate );
                        goto error_return;
                }
        }
@@ -500,8 +550,8 @@ retry:;
                                        op->o_log_prefix, candidate, (void *)msc->msc_ld );
 #endif /* DEBUG_205 */
 
-                               ldap_unbind_ext( msc->msc_ld, NULL, NULL );
-                               msc->msc_ld = NULL;
+                               /* need to trash a connection not fully established */
+                               meta_clear_one_candidate( op, mc, candidate );
                                goto error_return;
                        }
                        
@@ -510,6 +560,8 @@ retry:;
                                ber_dupbv( &msc->msc_bound_ndn, &op->o_conn->c_dn );
                        }
 
+                       assert( !BER_BVISNULL( &msc->msc_bound_ndn ) );
+
                } else {
                        ber_dupbv( &msc->msc_bound_ndn, (struct berval *)&slap_empty_bv );
                }
@@ -518,13 +570,22 @@ retry:;
        assert( !BER_BVISNULL( &msc->msc_bound_ndn ) );
 
 error_return:;
+       if ( dolock ) {
+               ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+       }
+       META_BACK_CONN_CREATING_CLEAR( msc );
        if ( rs->sr_err == LDAP_SUCCESS ) {
                /*
                 * Sets a cookie for the rewrite session
                 */
                ( void )rewrite_session_init( mt->mt_rwmap.rwm_rw, op->o_conn );
+               META_BACK_CONN_INITED_SET( msc );
+       }
+       if ( dolock ) {
+               ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+       }
 
-       } else {
+       if ( rs->sr_err != LDAP_SUCCESS ) {
                rs->sr_err = slap_map_api2result( rs );
                if ( sendok & LDAP_BACK_SENDERR ) {
                        send_ldap_result( op, rs );
@@ -556,13 +617,18 @@ meta_back_retry(
                                binding;
 
        ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+
+       assert( !META_BACK_CONN_CREATING( msc ) );
        binding = LDAP_BACK_CONN_BINDING( msc );
+       LDAP_BACK_CONN_BINDING_CLEAR( msc );
 
        assert( mc->mc_refcnt > 0 );
        if ( mc->mc_refcnt == 1 ) {
                if ( LogTest( LDAP_DEBUG_ANY ) ) {
                        char    buf[ SLAP_TEXT_BUFLEN ];
 
+                       /* this lock is required; however,
+                        * it's invoked only when logging is on */
                        ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
                        snprintf( buf, sizeof( buf ),
                                "retrying URI=\"%s\" DN=\"%s\"",
@@ -583,7 +649,7 @@ meta_back_retry(
 
                /* mc here must be the regular mc, reset and ready for init */
                rc = meta_back_init_one_conn( op, rs, mc, candidate,
-                       LDAP_BACK_CONN_ISPRIV( mc ), sendok );
+                       LDAP_BACK_CONN_ISPRIV( mc ), sendok, 0 );
 
                /* restore the "binding" flag, in case */
                if ( binding ) {
@@ -614,6 +680,9 @@ meta_back_retry(
                                }
                        }
                }
+
+               /* don't send twice */
+               sendok &= ~LDAP_BACK_SENDERR;
        }
 
        if ( rc != LDAP_SUCCESS ) {
@@ -622,9 +691,13 @@ meta_back_retry(
                candidates[ candidate ].sr_err = rc;
 
                if ( *mcp != NULL ) {
-                       if ( binding ) {
-                               LDAP_BACK_CONN_BINDING_CLEAR( msc );
+                       if ( mc->mc_refcnt == 1 ) {
+                               if ( binding ) {
+                                       LDAP_BACK_CONN_BINDING_CLEAR( msc );
+                               }
+                               (void)meta_clear_one_candidate( op, mc, candidate );
                        }
+
                        LDAP_BACK_CONN_TAINTED_SET( mc );
                        /* only release if mandatory; otherwise
                         * let the caller do what's best before
@@ -632,10 +705,21 @@ meta_back_retry(
                        if ( META_BACK_ONERR_STOP( mi ) ) {
                                meta_back_release_conn_lock( op, mc, 0 );
                                *mcp = NULL;
+
+                       } else {
+#if META_BACK_PRINT_CONNTREE > 0
+                               meta_back_print_conntree( mi->mi_conninfo.lai_tree, ">>> meta_back_retry" );
+#endif /* META_BACK_PRINT_CONNTREE */
+                               /* FIXME: could be done better, reworking meta_back_release_conn_lock() */
+                               (void)avl_delete( &mi->mi_conninfo.lai_tree,
+                                       ( caddr_t )mc, meta_back_conndnmc_cmp );
+#if META_BACK_PRINT_CONNTREE > 0
+                               meta_back_print_conntree( mi->mi_conninfo.lai_tree, "<<< meta_back_retry" );
+#endif /* META_BACK_PRINT_CONNTREE */
                        }
                }
 
-               if ( sendok ) {
+               if ( sendok & LDAP_BACK_SENDERR ) {
                        rs->sr_err = rc;
                        rs->sr_text = NULL;
                        send_ldap_result( op, rs );
@@ -882,8 +966,8 @@ meta_back_getconn(
        SlapReply       *candidates = meta_back_candidates_get( op );
 
        /* Internal searches are privileged and shared. So is root. */
-       /* FIXME: there seem to be concurrency issues */
-       if ( op->o_do_not_cache || be_isroot( op ) ) {
+       /* FIXME: there seems to be concurrency issues */
+       if ( META_BACK_PROXYAUTHZ_ALWAYS( mi ) || op->o_do_not_cache || be_isroot( op ) ) {
                mc_curr.mc_local_ndn = op->o_bd->be_rootndn;
                LDAP_BACK_CONN_ISPRIV_SET( &mc_curr );
                mc_curr.mc_conn = LDAP_BACK_PCONN_SET( op );
@@ -908,33 +992,45 @@ retry_lock:;
                mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree, 
                        (caddr_t)&mc_curr, meta_back_conndn_cmp );
                if ( mc ) {
-                       if ( ( mi->mi_conn_ttl != 0 && op->o_time > mc->mc_create_time + mi->mi_conn_ttl )
-                               || ( mi->mi_idle_timeout != 0 && op->o_time > mc->mc_time + mi->mi_idle_timeout ) )
-                       {
+                       /* catch taint errors */
+                       assert( !LDAP_BACK_CONN_TAINTED( mc ) );
+
+                       /* Don't reuse connections while they're still binding
+                        * NOTE: only makes sense for binds */
+                       if ( LDAP_BACK_CONN_BINDING( mc ) ) {
+                               if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) {
+                                       ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+
+                                       ldap_pvt_thread_yield();
+                                       goto retry_lock;
+                               }
+
+                               /* release conn, and create a temporary */
+                               mc = NULL;
+
+                       } else {
+                               if ( ( mi->mi_conn_ttl != 0 && op->o_time > mc->mc_create_time + mi->mi_conn_ttl )
+                                       || ( mi->mi_idle_timeout != 0 && op->o_time > mc->mc_time + mi->mi_idle_timeout ) )
+                               {
 #if META_BACK_PRINT_CONNTREE > 0
-                               meta_back_print_conntree( mi->mi_conninfo.lai_tree, ">>> meta_back_getconn" );
+                                       meta_back_print_conntree( mi->mi_conninfo.lai_tree,
+                                               ">>> meta_back_getconn(expired)" );
 #endif /* META_BACK_PRINT_CONNTREE */
-                               /* don't let anyone else use this expired connection */
-                               (void)avl_delete( &mi->mi_conninfo.lai_tree,
-                                       (caddr_t)mc, meta_back_conndnmc_cmp );
+                                       /* don't let anyone else use this expired connection */
+                                       (void)avl_delete( &mi->mi_conninfo.lai_tree,
+                                               (caddr_t)mc, meta_back_conndnmc_cmp );
 #if META_BACK_PRINT_CONNTREE > 0
-                               meta_back_print_conntree( mi->mi_conninfo.lai_tree, "<<< meta_back_getconn" );
+                                       meta_back_print_conntree( mi->mi_conninfo.lai_tree,
+                                               "<<< meta_back_getconn(expired)" );
 #endif /* META_BACK_PRINT_CONNTREE */
-                               LDAP_BACK_CONN_TAINTED_SET( mc );
+                                       LDAP_BACK_CONN_TAINTED_SET( mc );
 
-                               Debug( LDAP_DEBUG_TRACE, "%s meta_back_getconn: mc=%p conn=%ld expired.\n",
-                                       op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc ) );
-                       }
+                                       Debug( LDAP_DEBUG_TRACE, "%s meta_back_getconn: mc=%p conn=%ld expired (tainted).\n",
+                                               op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc ) );
+                               }
 
-                       /* Don't reuse connections while they're still binding
-                        * NOTE: only makes sense for binds */
-                       if ( LDAP_BACK_CONN_BINDING( mc ) ) {
-                               ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
-                               ldap_pvt_thread_yield();
-                               goto retry_lock;
+                               mc->mc_refcnt++;
                        }
-
-                       mc->mc_refcnt++;
                }
                ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
        }
@@ -1010,7 +1106,7 @@ retry_lock:;
                         */
                        candidates[ i ].sr_err = meta_back_init_one_conn( op,
                                rs, mc, i, LDAP_BACK_CONN_ISPRIV( &mc_curr ),
-                               sendok );
+                               LDAP_BACK_DONTSEND, !new_conn );
                        if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
                                META_CANDIDATE_SET( &candidates[ i ] );
                                ncandidates++;
@@ -1131,13 +1227,24 @@ retry_lock2:;
                                mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree, 
                                        (caddr_t)&mc_curr, meta_back_conndn_cmp );
                                if ( mc != NULL ) {
+                                       /* catch taint errors */
+                                       assert( !LDAP_BACK_CONN_TAINTED( mc ) );
+
                                        /* Don't reuse connections while they're still binding */
-                                       if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ) {
-                                               ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
-                                               ldap_pvt_thread_yield();
-                                               goto retry_lock2;
+                                       if ( META_BACK_CONN_CREATING( &mc->mc_conns[ i ] )
+                                               || LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) )
+                                       {
+                                               if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) {
+                                                       ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+                                                       ldap_pvt_thread_yield();
+                                                       goto retry_lock2;
+                                               }
+
+                                               mc = NULL;
+
+                                       } else {
+                                               mc->mc_refcnt++;
                                        }
-                                       mc->mc_refcnt++;
                                }
                                ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
                        }
@@ -1172,7 +1279,7 @@ retry_lock2:;
                 * sends the appropriate result.
                 */
                err = meta_back_init_one_conn( op, rs, mc, i,
-                       LDAP_BACK_CONN_ISPRIV( &mc_curr ), sendok );
+                       LDAP_BACK_CONN_ISPRIV( &mc_curr ), sendok, !new_conn );
                if ( err != LDAP_SUCCESS ) {
                        /*
                         * FIXME: in case one target cannot
@@ -1230,7 +1337,8 @@ retry_lock2:;
                                 * also init'd
                                 */
                                int lerr = meta_back_init_one_conn( op, rs, mc, i,
-                                       LDAP_BACK_CONN_ISPRIV( &mc_curr ), LDAP_BACK_DONTSEND );
+                                       LDAP_BACK_CONN_ISPRIV( &mc_curr ),
+                                       LDAP_BACK_DONTSEND, !new_conn );
                                if ( lerr == LDAP_SUCCESS ) {
                                        META_CANDIDATE_SET( &candidates[ i ] );
                                        candidates[ i ].sr_err = LDAP_SUCCESS;
@@ -1262,11 +1370,11 @@ retry_lock2:;
                                        err = lerr;
 
                                        if ( lerr == LDAP_UNAVAILABLE && mt->mt_isquarantined != LDAP_BACK_FQ_NO ) {
-                                               Debug( LDAP_DEBUG_TRACE, "%s: meta_back_getconn[%d] quarantined%d\n",
+                                               Debug( LDAP_DEBUG_TRACE, "%s: meta_back_getconn[%d] quarantined err=%d\n",
                                                        op->o_log_prefix, i, lerr );
 
                                        } else {
-                                               Debug( LDAP_DEBUG_ANY, "%s: meta_back_getconn[%d] failed%d\n",
+                                               Debug( LDAP_DEBUG_ANY, "%s: meta_back_getconn[%d] failed err=%d\n",
                                                        op->o_log_prefix, i, lerr );
                                        }
 
@@ -1362,10 +1470,14 @@ done:;
 
                case -1:
                        /* duplicate: free and try to get the newly created one */
-                       if ( !( sendok & LDAP_BACK_BINDING ) ) {
+                       if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( mi ) ) {
+                               mc->mc_refcnt = 0;      
+                               meta_back_conn_free( mc );
+
                                new_conn = 0;
                                goto retry_lock;
                        }
+
                        LDAP_BACK_CONN_TAINTED_SET( mc );
                        break;
 
@@ -1398,7 +1510,7 @@ done:;
                        op->o_log_prefix, ncandidates,
                        LDAP_BACK_PCONN_ID( mc ) );
        }
-       
+
        return mc;
 }
 
@@ -1424,27 +1536,34 @@ meta_back_release_conn_lock(
         * the connection space (and eat up resources).  Maybe this
         * should be configurable... */
        if ( LDAP_BACK_CONN_TAINTED( mc ) || 
-               ( !LDAP_BACK_CONN_ISPRIV( mc ) &&
-                       LDAP_BACK_PCONN_ISPRIV( mc ) && 
-                       mc->mc_refcnt == 0 ) )
+               ( !LDAP_BACK_CONN_ISPRIV( mc ) && LDAP_BACK_PCONN_ISPRIV( mc ) && mc->mc_refcnt == 0 ) )
        {
+               metaconn_t      *tmpmc;
+
                Debug( LDAP_DEBUG_TRACE, "%s meta_back_release_conn: mc=%p conn=%ld tainted.\n",
                        op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc ) );
 #if META_BACK_PRINT_CONNTREE > 0
                meta_back_print_conntree( mi->mi_conninfo.lai_tree, ">>> meta_back_release_conn" );
 #endif /* META_BACK_PRINT_CONNTREE */
-               (void)avl_delete( &mi->mi_conninfo.lai_tree,
+               tmpmc = avl_delete( &mi->mi_conninfo.lai_tree,
                        ( caddr_t )mc, meta_back_conndnmc_cmp );
 #if META_BACK_PRINT_CONNTREE > 0
                meta_back_print_conntree( mi->mi_conninfo.lai_tree, "<<< meta_back_release_conn" );
 #endif /* META_BACK_PRINT_CONNTREE */
+               if ( tmpmc == NULL ) {
+                       Debug( LDAP_DEBUG_TRACE, "%s: meta_back_release_conn: unable to find mc=%p\n",
+                               op->o_log_prefix, (void *)mc, 0 );
+               } else {
+                       assert( tmpmc == mc );
+               }
+
                if ( mc->mc_refcnt == 0 ) {
                        meta_back_conn_free( mc );
                        mc = NULL;
                }
        }
 
-       if ( mc != NULL ) {
+       if ( mc != NULL && LDAP_BACK_CONN_BINDING( mc ) ) {
                LDAP_BACK_CONN_BINDING_CLEAR( mc );
        }
 
index 46f18cb20075ffb0e06d214124d2dd5c08c6a912..2b0c41835c47bef2263494be3d133cdf8c2e7203 100644 (file)
@@ -125,7 +125,9 @@ meta_back_db_open(
 {
        metainfo_t      *mi = (metainfo_t *)be->be_private;
 
-       int             i, rc;
+       int             i,
+                       not_always = 0,
+                       rc;
 
        for ( i = 0; i < mi->mi_ntargets; i++ ) {
                slap_bindconf   sb = { 0 };
@@ -153,6 +155,18 @@ meta_back_db_open(
                                mt->mt_flags |= LDAP_BACK_F_CANCEL_EXOP;
                        }
                }
+
+               if ( not_always == 0 ) {
+                       if ( !( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE )
+                               || !( mt->mt_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) )
+                       {
+                               not_always = 1;
+                       }
+               }
+       }
+
+       if ( not_always == 0 ) {
+               mi->mi_flags |= META_BACK_F_PROXYAUTHZ_ALWAYS;
        }
 
        return 0;
@@ -175,7 +189,6 @@ meta_back_conn_free(
        assert( mc->mc_refcnt == 0 );
 
        /* at least one must be present... */
-       assert( mc->mc_conns != NULL );
        ntargets = mc->mc_info->mi_ntargets;
        assert( ntargets > 0 );
 
index 0f01e6bfc553eec7114d1cfda86e7c9afb41fe47..379094350a2569b931b7ea26e3561ce22a851a57 100644 (file)
@@ -90,19 +90,19 @@ ldap_back_map_init ( struct ldapmap *lm, struct ldapmapping **m )
        assert( m != NULL );
 
        *m = NULL;
-       
+
        mapping = (struct ldapmapping *)ch_calloc( 2, 
                        sizeof( struct ldapmapping ) );
        if ( mapping == NULL ) {
                return;
        }
 
-       ber_str2bv( "objectclass", sizeof("objectclass")-1, 1, &mapping->src);
-       ber_dupbv( &mapping->dst, &mapping->src );
-       mapping[1].src = mapping->src;
-       mapping[1].dst = mapping->dst;
+       ber_str2bv( "objectclass", STRLENOF("objectclass"), 1, &mapping[0].src);
+       ber_dupbv( &mapping[0].dst, &mapping[0].src );
+       mapping[1].src = mapping[0].src;
+       mapping[1].dst = mapping[0].dst;
 
-       avl_insert( &lm->map, (caddr_t)mapping
+       avl_insert( &lm->map, (caddr_t)&mapping[0]
                        mapping_cmp, mapping_dup );
        avl_insert( &lm->remap, (caddr_t)&mapping[1], 
                        mapping_cmp, mapping_dup );
@@ -120,6 +120,7 @@ ldap_back_mapping ( struct ldapmap *map, struct berval *s, struct ldapmapping **
 
        if ( remap == BACKLDAP_REMAP ) {
                tree = map->remap;
+
        } else {
                tree = map->map;
        }
@@ -139,6 +140,13 @@ ldap_back_map ( struct ldapmap *map, struct berval *s, struct berval *bv,
 {
        struct ldapmapping *mapping;
 
+       /* map->map may be NULL when mapping is configured,
+        * but map->remap can't */
+       if ( map->remap == NULL ) {
+               *bv = *s;
+               return;
+       }
+
        BER_BVZERO( bv );
        ( void )ldap_back_mapping( map, s, &mapping, remap );
        if ( mapping != NULL ) {
index c5627d56d1e6e1a66073c96e2906e9521b528ce7..149a6c38377e97110bb3f94d71bf5002b876c069 100644 (file)
@@ -108,7 +108,7 @@ meta_search_dobind_init(
                        bound = 1;
                }
 
-               snprintf( buf, sizeof( buf ), " mc=%p lc=%p%s DN=\"%s\"",
+               snprintf( buf, sizeof( buf ), " mc=%p ld=%p%s DN=\"%s\"",
                        (void *)mc, (void *)msc->msc_ld,
                        bound ? " bound" : " anonymous",
                        bound == 0 ? "" : msc->msc_bound_ndn.bv_val );
@@ -118,13 +118,13 @@ meta_search_dobind_init(
 
                retcode = META_SEARCH_CANDIDATE;
 
-       } else if ( LDAP_BACK_CONN_BINDING( msc ) ) {
+       } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) ) {
                /* another thread is binding the target for this conn; wait */
 
 #ifdef DEBUG_205
                char    buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
 
-               snprintf( buf, sizeof( buf ), " mc=%p lc=%p needbind",
+               snprintf( buf, sizeof( buf ), " mc=%p ld=%p needbind",
                        (void *)mc, (void *)msc->msc_ld );
                Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
                        op->o_log_prefix, candidate, buf );
@@ -145,6 +145,32 @@ meta_search_dobind_init(
                        op->o_log_prefix, candidate, buf );
 #endif /* DEBUG_205 */
 
+               if ( msc->msc_ld == NULL ) {
+                       /* for some reason (e.g. because formerly in "binding"
+                        * state, with eventual connection expiration or invalidation)
+                        * it was not initialized as expected */
+
+                       Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p ld=NULL\n",
+                               op->o_log_prefix, candidate, (void *)mc );
+
+                       rc = meta_back_init_one_conn( op, rs, *mcp, candidate,
+                               LDAP_BACK_CONN_ISPRIV( *mcp ), LDAP_BACK_DONTSEND, 0 );
+                       switch ( rc ) {
+                       case LDAP_SUCCESS:
+                               assert( msc->msc_ld != NULL );
+                               break;
+
+                       case LDAP_SERVER_DOWN:
+                       case LDAP_UNAVAILABLE:
+                               ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+                               goto down;
+       
+                       default:
+                               ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+                               goto other;
+                       }
+               }
+
                LDAP_BACK_CONN_BINDING_SET( msc );
        }
 
@@ -154,29 +180,6 @@ meta_search_dobind_init(
                return retcode;
        }
 
-       if ( msc->msc_ld == NULL ) {
-               /* for some reason (e.g. because formerly in "binding"
-                * state, with eventual connection expiration or invalidation)
-                * it was not initialized as expected */
-
-               Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p ld=NULL\n",
-                       op->o_log_prefix, candidate, (void *)mc );
-
-               rc = meta_back_init_one_conn( op, rs, *mcp, candidate,
-                       LDAP_BACK_CONN_ISPRIV( *mcp ), LDAP_BACK_DONTSEND );
-               switch ( rc ) {
-               case LDAP_SUCCESS:
-                       assert( msc->msc_ld != NULL );
-                       break;
-
-               case LDAP_SERVER_DOWN:
-                       goto down;
-
-               default:
-                       goto other;
-               }
-       }
-
        /* NOTE: this obsoletes pseudorootdn */
        if ( op->o_conn != NULL &&
                !op->o_do_not_cache &&
@@ -268,7 +271,7 @@ other:;
                rc = slap_map_api2result( rs );
 
                ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
-               LDAP_BACK_CONN_BINDING_CLEAR( msc );
+               meta_clear_one_candidate( op, mc, candidate );
                if ( META_BACK_ONERR_STOP( mi ) ) {
                        LDAP_BACK_CONN_TAINTED_SET( mc );
                        meta_back_release_conn_lock( op, mc, 0 );
@@ -315,14 +318,17 @@ meta_search_dobind_result(
                NULL, NULL, NULL, NULL, 0 );
        if ( rc != LDAP_SUCCESS ) {
                candidates[ candidate ].sr_err = rc;
+
+       } else {
+               rc = slap_map_api2result( &candidates[ candidate ] );
        }
-       rc = slap_map_api2result( &candidates[ candidate ] );
 
        ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
        LDAP_BACK_CONN_BINDING_CLEAR( msc );
        if ( rc != LDAP_SUCCESS ) {
                if ( META_BACK_ONERR_STOP( mi ) ) {
                        LDAP_BACK_CONN_TAINTED_SET( mc );
+                       meta_clear_one_candidate( op, mc, candidate );
                        meta_back_release_conn_lock( op, mc, 0 );
                        *mcp = NULL;
                        retcode = META_SEARCH_ERR;
@@ -796,9 +802,8 @@ getconn:;
         */
        for ( rc = 0; ncandidates > 0; ) {
                int     gotit = 0,
-                       doabandon = 0;
-
-               needbind = ncandidates;
+                       doabandon = 0,
+                       alreadybound = ncandidates;
 
                /* check time limit */
                if ( op->ors_tlimit != SLAP_NO_LIMIT
@@ -834,7 +839,7 @@ getconn:;
 
                                switch ( retcode ) {
                                case META_SEARCH_NEED_BIND:
-                                       needbind--;
+                                       alreadybound--;
                                        /* fallthru */
 
                                case META_SEARCH_BINDING:
@@ -918,11 +923,12 @@ getconn:;
 
                                ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
                                snprintf( buf, sizeof( buf ),
-                                       "%s meta_back_search[%ld] mc=%p msgid=%d%s%s\n",
+                                       "%s meta_back_search[%ld] mc=%p msgid=%d%s%s%s\n",
                                        op->o_log_prefix, (long)i, (void *)mc,
                                        candidates[ i ].sr_msgid,
                                        META_IS_BINDING( &candidates[ i ] ) ? " binding" : "",
-                                       LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ? " connbinding" : "" );
+                                       LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ? " connbinding" : "",
+                                       META_BACK_CONN_CREATING( &mc->mc_conns[ i ] ) ? " conncreating" : "" );
                                ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
                                        
                                Debug( LDAP_DEBUG_ANY, "!!! %s\n", buf, 0, 0 );
@@ -1376,9 +1382,7 @@ really_bad:;
                                                        Debug( LDAP_DEBUG_ANY, "### %s\n", buf, 0, 0 );
 #endif /* DEBUG_205 */
 
-                                                       ldap_unbind_ext( mc->mc_conns[ i ].msc_ld, NULL, NULL );
-                                                       mc->mc_conns[ i ].msc_ld = NULL;
-                                                       LDAP_BACK_CONN_BINDING_CLEAR( &mc->mc_conns[ i ] );
+                                                       meta_clear_one_candidate( op, mc, i );
                                                }
                                                ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
                                                META_BINDING_CLEAR( &candidates[ i ] );
@@ -1439,7 +1443,7 @@ really_bad:;
                        }
 #endif
 
-                       if ( needbind == 0 ) {
+                       if ( alreadybound == 0 ) {
 #if 0
                                Debug( LDAP_DEBUG_TRACE, "### %s select(%ld.%06ld)\n",
                                        op->o_log_prefix, save_tv.tv_sec, save_tv.tv_usec );
@@ -1622,9 +1626,7 @@ finish:;
 #endif /* DEBUG_205 */
 
                                /* if still binding, destroy */
-                               ldap_unbind_ext( mc->mc_conns[ i ].msc_ld, NULL, NULL );
-                               mc->mc_conns[ i ].msc_ld = NULL;
-                               LDAP_BACK_CONN_BINDING_CLEAR( &mc->mc_conns[ i ] );
+                               meta_clear_one_candidate( op, mc, i );
                        }
                        ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
                        META_BINDING_CLEAR( &candidates[ i ] );