pool privileged connections (ITS#4791)

This commit is contained in:
Pierangelo Masarati 2006-12-24 18:23:36 +00:00
parent 1939ed3fc2
commit 7e8242d50d
12 changed files with 693 additions and 198 deletions

View file

@ -44,22 +44,57 @@ typedef struct ldap_monitor_info_t {
struct berval lmi_more_filter;
} ldap_monitor_info_t;
enum {
/* even numbers are connection types */
LDAP_BACK_PCONN_FIRST = 0,
LDAP_BACK_PCONN_ROOTDN = LDAP_BACK_PCONN_FIRST,
LDAP_BACK_PCONN_ANON = 2,
LDAP_BACK_PCONN_BIND = 4,
/* add the TLS bit */
LDAP_BACK_PCONN_TLS = 0x1U,
LDAP_BACK_PCONN_ROOTDN_TLS = (LDAP_BACK_PCONN_ROOTDN|LDAP_BACK_PCONN_TLS),
LDAP_BACK_PCONN_ANON_TLS = (LDAP_BACK_PCONN_ANON|LDAP_BACK_PCONN_TLS),
LDAP_BACK_PCONN_BIND_TLS = (LDAP_BACK_PCONN_BIND|LDAP_BACK_PCONN_TLS),
LDAP_BACK_PCONN_LAST
};
typedef struct ldapconn_t {
Connection *lc_conn;
#define LDAP_BACK_PCONN ((void *)0x0)
#define LDAP_BACK_PCONN_TLS ((void *)0x1)
#define LDAP_BACK_PCONN_BIND ((void *)0x2)
#define LDAP_BACK_PCONN_BIND_TLS ((void *)0x3)
#define LDAP_BACK_PCONN_LAST ((void *)0x4)
#define LDAP_BACK_PCONN_ISPRIV(lc) ((void *)(lc)->lc_conn < LDAP_BACK_PCONN_LAST)
#define LDAP_BACK_PCONN_ID(lc) (LDAP_BACK_PCONN_ISPRIV((lc)) ? ( -1 - (long)(lc)->lc_conn ): (lc)->lc_conn->c_connid )
#define LDAP_BACK_CONN2PRIV(lc) ((unsigned long)(lc)->lc_conn)
#define LDAP_BACK_PCONN_ISPRIV(lc) ((void *)(lc)->lc_conn >= (void *)LDAP_BACK_PCONN_FIRST \
&& (void *)(lc)->lc_conn < (void *)LDAP_BACK_PCONN_LAST)
#define LDAP_BACK_PCONN_ISROOTDN(lc) (LDAP_BACK_PCONN_ISPRIV((lc)) \
&& (LDAP_BACK_CONN2PRIV((lc)) < LDAP_BACK_PCONN_ANON))
#define LDAP_BACK_PCONN_ISANON(lc) (LDAP_BACK_PCONN_ISPRIV((lc)) \
&& (LDAP_BACK_CONN2PRIV((lc)) < LDAP_BACK_PCONN_BIND) \
&& (LDAP_BACK_CONN2PRIV((lc)) >= LDAP_BACK_PCONN_ANON))
#define LDAP_BACK_PCONN_ISBIND(lc) (LDAP_BACK_PCONN_ISPRIV((lc)) \
&& (LDAP_BACK_CONN2PRIV((lc)) >= LDAP_BACK_PCONN_BIND))
#define LDAP_BACK_PCONN_ISTLS(lc) (LDAP_BACK_PCONN_ISPRIV((lc)) \
&& (LDAP_BACK_CONN2PRIV((lc)) & LDAP_BACK_PCONN_TLS))
#define LDAP_BACK_PCONN_ID(lc) (LDAP_BACK_PCONN_ISPRIV((lc)) ? \
( -1 - (long)(lc)->lc_conn ) : (lc)->lc_conn->c_connid )
#ifdef HAVE_TLS
#define LDAP_BACK_PCONN_SET(op) ((op)->o_conn->c_is_tls ? LDAP_BACK_PCONN_TLS : LDAP_BACK_PCONN)
#define LDAP_BACK_PCONN_BIND_SET(op) ((op)->o_conn->c_is_tls ? LDAP_BACK_PCONN_BIND_TLS : LDAP_BACK_PCONN_BIND)
#define LDAP_BACK_PCONN_ROOTDN_SET(lc, op) \
((lc)->lc_conn = (void *)((op)->o_conn->c_is_tls ? LDAP_BACK_PCONN_ROOTDN_TLS : LDAP_BACK_PCONN_ROOTDN))
#define LDAP_BACK_PCONN_ANON_SET(lc, op) \
((lc)->lc_conn = (void *)((op)->o_conn->c_is_tls ? LDAP_BACK_PCONN_ANON_TLS : LDAP_BACK_PCONN_ANON))
#define LDAP_BACK_PCONN_BIND_SET(lc, op) \
((lc)->lc_conn = (void *)((op)->o_conn->c_is_tls ? LDAP_BACK_PCONN_BIND_TLS : LDAP_BACK_PCONN_BIND))
#else /* ! HAVE_TLS */
#define LDAP_BACK_PCONN_SET(op) (LDAP_BACK_PCONN)
#define LDAP_BACK_PCONN_BIND_SET(op) (LDAP_BACK_PCONN_BIND)
#define LDAP_BACK_PCONN_ROOTDN_SET(lc, op) \
((lc)->lc_conn = (void *)LDAP_BACK_PCONN_ROOTDN)
#define LDAP_BACK_PCONN_ANON_SET(lc, op) \
((lc)->lc_conn = (void *)LDAP_BACK_PCONN_ANON)
#define LDAP_BACK_PCONN_BIND_SET(lc, op) \
((lc)->lc_conn = (void *)LDAP_BACK_PCONN_BIND)
#endif /* ! HAVE_TLS */
#define LDAP_BACK_PCONN_SET(lc, op) \
(BER_BVISEMPTY(&(op)->o_ndn) ? \
LDAP_BACK_PCONN_ANON_SET((lc), (op)) : LDAP_BACK_PCONN_ROOTDN_SET((lc), (op)))
LDAP *lc_ld;
struct berval lc_cred;
@ -93,6 +128,7 @@ typedef struct ldapconn_t {
#define LDAP_BACK_FCONN_BINDING (0x00000010U)
#define LDAP_BACK_FCONN_TAINTED (0x00000020U)
#define LDAP_BACK_FCONN_ISIDASR (0x00000040U)
#define LDAP_BACK_FCONN_CACHED (0x00000080U)
#define LDAP_BACK_CONN_ISBOUND(lc) LDAP_BACK_CONN_ISSET((lc), LDAP_BACK_FCONN_ISBOUND)
#define LDAP_BACK_CONN_ISBOUND_SET(lc) LDAP_BACK_CONN_SET((lc), LDAP_BACK_FCONN_ISBOUND)
@ -120,12 +156,17 @@ typedef struct ldapconn_t {
#define LDAP_BACK_CONN_ISIDASSERT_SET(lc) LDAP_BACK_CONN_SET((lc), LDAP_BACK_FCONN_ISIDASR)
#define LDAP_BACK_CONN_ISIDASSERT_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), LDAP_BACK_FCONN_ISIDASR)
#define LDAP_BACK_CONN_ISIDASSERT_CPY(lc, mlc) LDAP_BACK_CONN_CPY((lc), LDAP_BACK_FCONN_ISIDASR, (mlc))
#define LDAP_BACK_CONN_CACHED(lc) LDAP_BACK_CONN_ISSET((lc), LDAP_BACK_FCONN_CACHED)
#define LDAP_BACK_CONN_CACHED_SET(lc) LDAP_BACK_CONN_SET((lc), LDAP_BACK_FCONN_CACHED)
#define LDAP_BACK_CONN_CACHED_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), LDAP_BACK_FCONN_CACHED)
unsigned lc_refcnt;
unsigned lc_binding;
unsigned lc_flags;
time_t lc_create_time;
time_t lc_time;
LDAP_TAILQ_ENTRY(ldapconn_t) lc_q;
} ldapconn_t;
typedef struct ldap_avl_info_t {
@ -259,8 +300,11 @@ typedef struct ldapinfo_t {
#define LDAP_BACK_F_CANCEL_MASK (LDAP_BACK_F_CANCEL_IGNORE|LDAP_BACK_F_CANCEL_EXOP)
#define LDAP_BACK_F_CANCEL_MASK2 (LDAP_BACK_F_CANCEL_MASK|LDAP_BACK_F_CANCEL_EXOP_DISCOVER)
#define LDAP_BACK_ISSET(li,f) ( ( (li)->li_flags & (f) ) == (f) )
#define LDAP_BACK_ISMASK(li,m,f) ( ( (li)->li_flags & (m) ) == (f) )
#define LDAP_BACK_ISSET_F(ff,f) ( ( (ff) & (f) ) == (f) )
#define LDAP_BACK_ISMASK_F(ff,m,f) ( ( (ff) & (m) ) == (f) )
#define LDAP_BACK_ISSET(li,f) LDAP_BACK_ISSET_F( (li)->li_flags, (f) )
#define LDAP_BACK_ISMASK(li,m,f) LDAP_BACK_ISMASK_F( (li)->li_flags, (m), (f) )
#define LDAP_BACK_SAVECRED(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_SAVECRED )
#define LDAP_BACK_USE_TLS(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_USE_TLS )
@ -269,6 +313,10 @@ typedef struct ldapinfo_t {
#define LDAP_BACK_CHASE_REFERRALS(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_CHASE_REFERRALS )
#define LDAP_BACK_PROXY_WHOAMI(li) LDAP_BACK_ISSET( (li), LDAP_BACK_F_PROXY_WHOAMI )
#define LDAP_BACK_USE_TLS_F(ff) LDAP_BACK_ISSET_F( (ff), LDAP_BACK_F_USE_TLS )
#define LDAP_BACK_PROPAGATE_TLS_F(ff) LDAP_BACK_ISSET_F( (ff), LDAP_BACK_F_PROPAGATE_TLS )
#define LDAP_BACK_TLS_CRITICAL_F(ff) LDAP_BACK_ISSET_F( (ff), LDAP_BACK_F_TLS_CRITICAL )
#define LDAP_BACK_T_F(li) LDAP_BACK_ISMASK( (li), LDAP_BACK_F_T_F_MASK, LDAP_BACK_F_T_F )
#define LDAP_BACK_T_F_DISCOVER(li) LDAP_BACK_ISMASK( (li), LDAP_BACK_F_T_F_MASK2, LDAP_BACK_F_T_F_DISCOVER )
@ -285,10 +333,23 @@ typedef struct ldapinfo_t {
int li_version;
/* cached connections;
* special conns are in tailq rather than in tree */
ldap_avl_info_t li_conninfo;
ldap_monitor_info_t li_monitor_info;
struct {
int lic_num;
LDAP_TAILQ_HEAD(lc_conn_priv_q, ldapconn_t) lic_priv;
} li_conn_priv[ LDAP_BACK_PCONN_LAST ];
int li_conn_priv_max;
#define LDAP_BACK_CONN_PRIV_MIN (1)
#define LDAP_BACK_CONN_PRIV_MAX (256)
/* must be between LDAP_BACK_CONN_PRIV_MIN
* and LDAP_BACK_CONN_PRIV_MAX ! */
#define LDAP_BACK_CONN_PRIV_DEFAULT (16)
sig_atomic_t li_isquarantined;
#define LDAP_BACK_FQ_NO (0)
#define LDAP_BACK_FQ_YES (1)

View file

@ -41,7 +41,7 @@
#if LDAP_BACK_PRINT_CONNTREE > 0
static void
ravl_print( Avlnode *root, int depth )
ldap_back_ravl_print( Avlnode *root, int depth )
{
int i;
ldapconn_t *lc;
@ -50,38 +50,70 @@ ravl_print( Avlnode *root, int depth )
return;
}
ravl_print( root->avl_right, depth+1 );
ldap_back_ravl_print( root->avl_right, depth+1 );
for ( i = 0; i < depth; i++ ) {
fprintf( stderr, "-" );
}
lc = root->avl_data;
fprintf( stderr, "lc=%p local=\"%s\" conn=%p %s refcnt=%d\n",
fprintf( stderr, "lc=%p local=\"%s\" conn=%p %s refcnt=%d flags=0x%08x\n",
(void *)lc,
lc->lc_local_ndn.bv_val ? lc->lc_local_ndn.bv_val : "",
(void *)lc->lc_conn,
avl_bf2str( root->avl_bf ), lc->lc_refcnt );
avl_bf2str( root->avl_bf ), lc->lc_refcnt, lc->lc_lcflags );
ravl_print( root->avl_left, depth+1 );
ldap_back_ravl_print( root->avl_left, depth+1 );
}
static char* priv2str[] = {
"privileged",
"privileged/TLS",
"anonymous",
"anonymous/TLS",
"bind",
"bind/TLS",
NULL
};
void
ldap_back_print_conntree( Avlnode *root, char *msg )
ldap_back_print_conntree( ldapinfo_t *li, char *msg )
{
int c;
fprintf( stderr, "========> %s\n", msg );
for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) {
int i = 0;
ldapconn_t *lc;
fprintf( stderr, " %s[%d]\n", priv2str[ c ], li->li_conn_priv[ c ].lic_num );
LDAP_TAILQ_FOREACH( lc, &li->li_conn_priv[ c ].lic_priv, lc_q )
{
fprintf( stderr, " [%d] lc=%p local=\"%s\" conn=%p refcnt=%d flags=0x%08x\n",
i,
(void *)lc,
lc->lc_local_ndn.bv_val ? lc->lc_local_ndn.bv_val : "",
(void *)lc->lc_conn, lc->lc_refcnt, lc->lc_lcflags );
i++;
}
}
if ( root == 0 ) {
if ( li->li_conninfo.lai_tree == 0 ) {
fprintf( stderr, "\t(empty)\n" );
} else {
ravl_print( root, 0 );
ldap_back_ravl_print( li->li_conninfo.lai_tree, 0 );
}
fprintf( stderr, "<======== %s\n", msg );
}
#endif /* LDAP_BACK_PRINT_CONNTREE */
static int
ldap_back_freeconn( Operation *op, ldapconn_t *lc, int dolock );
static ldapconn_t *
ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
struct berval *binddn, struct berval *bindcred );
@ -116,10 +148,17 @@ ldap_back_bind( Operation *op, SlapReply *rs )
return rs->sr_err;
}
/* we can do (almost) whatever we want with this conn,
* because either it's temporary, or it's marked as binding */
if ( !BER_BVISNULL( &lc->lc_bound_ndn ) ) {
ch_free( lc->lc_bound_ndn.bv_val );
BER_BVZERO( &lc->lc_bound_ndn );
}
if ( !BER_BVISNULL( &lc->lc_cred ) ) {
memset( lc->lc_cred.bv_val, 0, lc->lc_cred.bv_len );
ch_free( lc->lc_cred.bv_val );
BER_BVZERO( &lc->lc_cred );
}
LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
retry:;
@ -159,13 +198,17 @@ retry:;
LDAP_BACK_CONN_ISBOUND_SET( lc );
ber_dupbv( &lc->lc_bound_ndn, &op->o_req_ndn );
if ( !BER_BVISNULL( &lc->lc_cred ) ) {
memset( lc->lc_cred.bv_val, 0,
lc->lc_cred.bv_len );
}
if ( LDAP_BACK_SAVECRED( li ) ) {
if ( !BER_BVISNULL( &lc->lc_cred ) ) {
memset( lc->lc_cred.bv_val, 0,
lc->lc_cred.bv_len );
}
ber_bvreplace( &lc->lc_cred, &op->orb_cred );
ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
} else {
lc->lc_cred.bv_len = 0;
}
}
@ -174,8 +217,8 @@ retry:;
/* must re-insert if local DN changed as result of bind */
if ( !LDAP_BACK_CONN_ISBOUND( lc )
|| ( LDAP_BACK_CONN_ISBOUND( lc )
&& !dn_match( &op->o_req_ndn, &lc->lc_local_ndn ) ) )
|| ( !dn_match( &op->o_req_ndn, &lc->lc_local_ndn )
&& !LDAP_BACK_PCONN_ISPRIV( lc ) ) )
{
int lerr = -1;
ldapconn_t *tmplc;
@ -190,13 +233,31 @@ retry_lock:;
}
#if LDAP_BACK_PRINT_CONNTREE > 0
ldap_back_print_conntree( li->li_conninfo.lai_tree, ">>> ldap_back_bind" );
ldap_back_print_conntree( li, ">>> ldap_back_bind" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
assert( lc->lc_refcnt == 1 );
tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
ldap_back_conndnlc_cmp );
assert( tmplc == NULL || lc == tmplc );
if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
/* this can happen, for example, if the bind fails
* for some reason... */
if ( lc->lc_q.tqe_prev != NULL ) {
assert( LDAP_BACK_CONN_CACHED( lc ) );
assert( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num > 0 );
LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num--;
lc->lc_q.tqe_prev = NULL;
lc->lc_q.tqe_next = NULL;
} else {
assert( !LDAP_BACK_CONN_CACHED( lc ) );
}
} else {
tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
ldap_back_conndnlc_cmp );
assert( ( LDAP_BACK_CONN_TAINTED( lc ) && tmplc == NULL ) || lc == tmplc );
}
LDAP_BACK_CONN_CACHED_CLEAR( lc );
/* delete all cached connections with the current connection */
if ( LDAP_BACK_SINGLECONN( li ) ) {
@ -209,6 +270,7 @@ retry_lock:;
if ( tmplc->lc_refcnt != 0 ) {
/* taint it */
LDAP_BACK_CONN_TAINTED_SET( tmplc );
LDAP_BACK_CONN_CACHED_CLEAR( tmplc );
} else {
/*
@ -224,19 +286,20 @@ retry_lock:;
if ( LDAP_BACK_CONN_ISBOUND( lc ) ) {
ber_bvreplace( &lc->lc_local_ndn, &op->o_req_ndn );
if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) {
lc->lc_conn = LDAP_BACK_PCONN_SET( op );
LDAP_BACK_PCONN_ROOTDN_SET( lc, op );
}
lerr = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
ldap_back_conndn_cmp, ldap_back_conndn_dup );
}
#if LDAP_BACK_PRINT_CONNTREE > 0
ldap_back_print_conntree( li->li_conninfo.lai_tree, "<<< ldap_back_bind" );
ldap_back_print_conntree( li, "<<< ldap_back_bind" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
switch ( lerr ) {
case 0:
LDAP_BACK_CONN_CACHED_SET( lc );
break;
case -1:
@ -350,29 +413,51 @@ ldap_back_conndn_dup( void *c1, void *c2 )
return 0;
}
int
static int
ldap_back_freeconn( Operation *op, ldapconn_t *lc, int dolock )
{
ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private;
ldapconn_t *tmplc;
if ( dolock ) {
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
}
#if LDAP_BACK_PRINT_CONNTREE > 0
ldap_back_print_conntree( li->li_conninfo.lai_tree, ">>> ldap_back_freeconn" );
ldap_back_print_conntree( li, ">>> ldap_back_freeconn" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
ldap_back_conndnlc_cmp );
assert( LDAP_BACK_CONN_TAINTED( lc ) || tmplc == lc );
if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
if ( lc->lc_q.tqe_prev != NULL ) {
assert( LDAP_BACK_CONN_CACHED( lc ) );
assert( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num > 0 );
li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num--;
LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
LDAP_BACK_CONN_CACHED_CLEAR( lc );
} else {
assert( !LDAP_BACK_CONN_CACHED( lc ) );
}
lc->lc_q.tqe_prev = NULL;
lc->lc_q.tqe_next = NULL;
} else {
ldapconn_t *tmplc = NULL;
if ( LDAP_BACK_CONN_CACHED( lc ) ) {
tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
ldap_back_conndnlc_cmp );
assert( tmplc == lc );
LDAP_BACK_CONN_CACHED_CLEAR( lc );
}
assert( LDAP_BACK_CONN_TAINTED( lc ) || tmplc == lc );
}
if ( lc->lc_refcnt == 0 ) {
ldap_back_conn_free( (void *)lc );
}
#if LDAP_BACK_PRINT_CONNTREE > 0
ldap_back_print_conntree( li->li_conninfo.lai_tree, "<<< ldap_back_freeconn" );
ldap_back_print_conntree( li, "<<< ldap_back_freeconn" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
if ( dolock ) {
@ -394,13 +479,9 @@ ldap_back_start_tls(
const char **text )
{
int rc = LDAP_SUCCESS;
ldapinfo_t dummy;
/* this is ridiculous... */
dummy.li_flags = flags;
/* start TLS ("tls-[try-]{start,propagate}" statements) */
if ( ( LDAP_BACK_USE_TLS( &dummy ) || ( *is_tls && LDAP_BACK_PROPAGATE_TLS( &dummy ) ) )
if ( ( LDAP_BACK_USE_TLS_F( flags ) || ( *is_tls && LDAP_BACK_PROPAGATE_TLS_F( flags ) ) )
&& !ldap_is_ldaps_url( url ) )
{
#ifdef SLAP_STARTTLS_ASYNCHRONOUS
@ -509,7 +590,7 @@ retry:;
break;
default:
if ( LDAP_BACK_TLS_CRITICAL( &dummy ) ) {
if ( LDAP_BACK_TLS_CRITICAL_F( flags ) ) {
*text = "could not start TLS";
break;
}
@ -655,19 +736,21 @@ ldap_back_getconn(
slap_retry_info_t *ri = &li->li_quarantine;
int dont_retry = 1;
ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex );
if ( li->li_isquarantined == LDAP_BACK_FQ_YES ) {
dont_retry = ( ri->ri_num[ ri->ri_idx ] == SLAP_RETRYNUM_TAIL
|| slap_get_time() < ri->ri_last + ri->ri_interval[ ri->ri_idx ] );
if ( !dont_retry ) {
Debug( LDAP_DEBUG_ANY,
"%s: ldap_back_getconn quarantine "
"retry block #%d try #%d.\n",
op->o_log_prefix, ri->ri_idx, ri->ri_count );
li->li_isquarantined = LDAP_BACK_FQ_RETRYING;
if ( li->li_quarantine.ri_interval ) {
ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex );
if ( li->li_isquarantined == LDAP_BACK_FQ_YES ) {
dont_retry = ( ri->ri_num[ ri->ri_idx ] == SLAP_RETRYNUM_TAIL
|| slap_get_time() < ri->ri_last + ri->ri_interval[ ri->ri_idx ] );
if ( !dont_retry ) {
Debug( LDAP_DEBUG_ANY,
"%s: ldap_back_getconn quarantine "
"retry block #%d try #%d.\n",
op->o_log_prefix, ri->ri_idx, ri->ri_count );
li->li_isquarantined = LDAP_BACK_FQ_RETRYING;
}
}
ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
}
ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
if ( dont_retry ) {
rs->sr_err = LDAP_UNAVAILABLE;
@ -682,7 +765,7 @@ ldap_back_getconn(
if ( op->o_do_not_cache || be_isroot( op ) ) {
LDAP_BACK_CONN_ISPRIV_SET( &lc_curr );
lc_curr.lc_local_ndn = op->o_bd->be_rootndn;
lc_curr.lc_conn = LDAP_BACK_PCONN_SET( op );
LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
} else {
struct berval tmpbinddn,
@ -723,12 +806,12 @@ ldap_back_getconn(
} else {
if ( isproxyauthz && !( sendok & LDAP_BACK_BINDING ) ) {
lc_curr.lc_local_ndn = *binddn;
lc_curr.lc_conn = LDAP_BACK_PCONN_SET( op );
LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );
} else if ( isproxyauthz && ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) {
lc_curr.lc_local_ndn = slap_empty_bv;
lc_curr.lc_conn = LDAP_BACK_PCONN_BIND_SET( op );
LDAP_BACK_PCONN_BIND_SET( &lc_curr, op );
LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );
lookupconn = 1;
@ -736,19 +819,51 @@ ldap_back_getconn(
lc_curr.lc_conn = op->o_conn;
} else {
lc_curr.lc_conn = LDAP_BACK_PCONN_SET( op );
LDAP_BACK_PCONN_ANON_SET( &lc_curr, op );
}
}
}
/* Explicit Bind requests always get their own conn */
if ( lookupconn ) {
/* Searches for a ldapconn in the avl tree */
retry_lock:
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
if ( LDAP_BACK_PCONN_ISPRIV( &lc_curr ) ) {
/* lookup a conn that's not binding */
LDAP_TAILQ_FOREACH( lc,
&li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv,
lc_q )
{
if ( !LDAP_BACK_CONN_BINDING( lc ) && lc->lc_refcnt == 0 ) {
break;
}
}
if ( lc != NULL ) {
if ( lc != LDAP_TAILQ_LAST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
ldapconn_t, lc_q ) )
{
LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
lc, lc_q );
lc->lc_q.tqe_prev = NULL;
lc->lc_q.tqe_next = NULL;
LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
lc, lc_q );
}
} else if ( !LDAP_BACK_USE_TEMPORARIES( li )
&& li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_num == li->li_conn_priv_max )
{
lc = LDAP_TAILQ_FIRST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv );
}
} else {
/* Searches for a ldapconn in the avl tree */
lc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree,
(caddr_t)&lc_curr, ldap_back_conndn_cmp );
}
lc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree,
(caddr_t)&lc_curr, ldap_back_conndn_cmp );
if ( lc != NULL ) {
/* Don't reuse connections while they're still binding */
if ( LDAP_BACK_CONN_BINDING( lc ) ) {
@ -758,11 +873,10 @@ retry_lock:
ldap_pvt_thread_yield();
goto retry_lock;
}
lc = NULL;
}
} else {
if ( lc != NULL ) {
if ( op->o_tag == LDAP_REQ_BIND ) {
/* right now, this is the only possible case */
assert( ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) );
@ -813,8 +927,10 @@ retry_lock:
LDAP_BACK_CONN_ISPRIV_SET( lc );
} else if ( LDAP_BACK_CONN_ISIDASSERT( &lc_curr ) ) {
ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN );
ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd );
if ( !LDAP_BACK_PCONN_ISBIND( &lc_curr ) ) {
ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN );
ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd );
}
LDAP_BACK_CONN_ISIDASSERT_SET( lc );
} else {
@ -832,15 +948,22 @@ retry_lock:
* check if the non-TLS connection was already
* in cache; in case, destroy the newly created
* connection and use the existing one */
if ( lc->lc_conn == LDAP_BACK_PCONN_TLS
if ( LDAP_BACK_PCONN_ISTLS( lc )
&& !ldap_tls_inplace( lc->lc_ld ) )
{
ldapconn_t *tmplc;
ldapconn_t *tmplc = NULL;
int idx = LDAP_BACK_CONN2PRIV( &lc_curr ) - 1;
lc_curr.lc_conn = LDAP_BACK_PCONN;
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
tmplc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree,
(caddr_t)&lc_curr, ldap_back_conndn_cmp );
LDAP_TAILQ_FOREACH( tmplc,
&li->li_conn_priv[ idx ].lic_priv,
lc_q )
{
if ( !LDAP_BACK_CONN_BINDING( tmplc ) ) {
break;
}
}
if ( tmplc != NULL ) {
refcnt = ++tmplc->lc_refcnt;
binding = ++tmplc->lc_binding;
@ -855,56 +978,83 @@ retry_lock:
}
#endif /* HAVE_TLS */
LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
/* Inserts the newly created ldapconn in the avl tree */
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
#if LDAP_BACK_PRINT_CONNTREE > 0
ldap_back_print_conntree( li->li_conninfo.lai_tree, ">>> ldap_back_getconn(insert)" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
assert( lc->lc_refcnt == 1 );
assert( lc->lc_binding == 1 );
rs->sr_err = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
ldap_back_conndn_cmp, ldap_back_conndn_dup );
#if LDAP_BACK_PRINT_CONNTREE > 0
ldap_back_print_conntree( li->li_conninfo.lai_tree, "<<< ldap_back_getconn(insert)" );
ldap_back_print_conntree( li, ">>> ldap_back_getconn(insert)" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
if ( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num < li->li_conn_priv_max ) {
LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num++;
LDAP_BACK_CONN_CACHED_SET( lc );
} else {
LDAP_BACK_CONN_TAINTED_SET( lc );
}
rs->sr_err = 0;
} else {
rs->sr_err = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
ldap_back_conndn_cmp, ldap_back_conndn_dup );
LDAP_BACK_CONN_CACHED_SET( lc );
}
#if LDAP_BACK_PRINT_CONNTREE > 0
ldap_back_print_conntree( li, "<<< ldap_back_getconn(insert)" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
Debug( LDAP_DEBUG_TRACE,
"=>ldap_back_getconn: conn %p inserted refcnt=%u binding=%u\n",
(void *)lc, refcnt, binding );
if ( LogTest( LDAP_DEBUG_TRACE ) ) {
char buf[ SLAP_TEXT_BUFLEN ];
snprintf( buf, sizeof( buf ),
"lc=%p inserted refcnt=%u binding=%u rc=%d",
(void *)lc, refcnt, binding, rs->sr_err );
Debug( LDAP_DEBUG_TRACE,
"=>ldap_back_getconn: %s: %s\n",
op->o_log_prefix, buf, 0 );
}
/* Err could be -1 in case a duplicate ldapconn is inserted */
switch ( rs->sr_err ) {
case 0:
break;
if ( !LDAP_BACK_PCONN_ISPRIV( lc ) ) {
/* Err could be -1 in case a duplicate ldapconn is inserted */
switch ( rs->sr_err ) {
case 0:
break;
case -1:
if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( li ) ) {
/* duplicate: free and try to get the newly created one */
case -1:
LDAP_BACK_CONN_CACHED_CLEAR( lc );
if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( li ) ) {
/* duplicate: free and try to get the newly created one */
ldap_back_conn_free( lc );
lc = NULL;
goto retry_lock;
}
/* taint connection, so that it'll be freed when released */
LDAP_BACK_CONN_TAINTED_SET( lc );
break;
default:
LDAP_BACK_CONN_CACHED_CLEAR( lc );
ldap_back_conn_free( lc );
lc = NULL;
goto retry_lock;
rs->sr_err = LDAP_OTHER;
rs->sr_text = "proxy bind collision";
if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
send_ldap_result( op, rs );
rs->sr_text = NULL;
}
return NULL;
}
/* taint connection, so that it'll be freed when released */
LDAP_BACK_CONN_TAINTED_SET( lc );
break;
default:
ldap_back_conn_free( lc );
rs->sr_err = LDAP_OTHER;
rs->sr_text = "proxy bind collision";
if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
send_ldap_result( op, rs );
rs->sr_text = NULL;
}
return NULL;
}
} else {
@ -918,16 +1068,37 @@ retry_lock:
/* let it be used, but taint/delete it so that
* no-one else can look it up any further */
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
#if LDAP_BACK_PRINT_CONNTREE > 0
ldap_back_print_conntree( li->li_conninfo.lai_tree, ">>> ldap_back_getconn(timeout)" );
ldap_back_print_conntree( li, ">>> ldap_back_getconn(timeout)" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
(void *)avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
if ( lc->lc_q.tqe_prev != NULL ) {
assert( LDAP_BACK_CONN_CACHED( lc ) );
assert( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num > 0 );
LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
lc, lc_q );
li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num--;
lc->lc_q.tqe_prev = NULL;
lc->lc_q.tqe_next = NULL;
} else {
assert( !LDAP_BACK_CONN_CACHED( lc ) );
}
} else {
(void)avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
ldap_back_conndnlc_cmp );
#if LDAP_BACK_PRINT_CONNTREE > 0
ldap_back_print_conntree( li->li_conninfo.lai_tree, "<<< ldap_back_getconn(timeout)" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
}
LDAP_BACK_CONN_TAINTED_SET( lc );
LDAP_BACK_CONN_CACHED_CLEAR( lc );
#if LDAP_BACK_PRINT_CONNTREE > 0
ldap_back_print_conntree( li, "<<< ldap_back_getconn(timeout)" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
}
if ( LogTest( LDAP_DEBUG_TRACE ) ) {
@ -1620,8 +1791,9 @@ retry:;
int
ldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
{
int rc = 0;
ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
int rc = 0,
binding;
assert( lcp != NULL );
assert( *lcp != NULL );
@ -1629,6 +1801,8 @@ ldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
if ( (*lcp)->lc_refcnt == 1 ) {
binding = LDAP_BACK_CONN_BINDING( *lcp );
ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
Debug( LDAP_DEBUG_ANY,
"%s ldap_back_retry: retrying URI=\"%s\" DN=\"%s\"\n",
@ -1651,6 +1825,9 @@ ldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_
rc = 0;
} else if ( ( sendok & LDAP_BACK_BINDING ) ) {
if ( binding ) {
LDAP_BACK_CONN_BINDING_SET( *lcp );
}
rc = 1;
} else {
@ -1937,13 +2114,17 @@ ldap_back_proxy_authz_bind(
LDAP_BACK_CONN_ISBOUND_SET( lc );
ber_bvreplace( &lc->lc_bound_ndn, binddn );
if ( !BER_BVISNULL( &lc->lc_cred ) ) {
memset( lc->lc_cred.bv_val, 0,
lc->lc_cred.bv_len );
}
if ( LDAP_BACK_SAVECRED( li ) ) {
if ( !BER_BVISNULL( &lc->lc_cred ) ) {
memset( lc->lc_cred.bv_val, 0,
lc->lc_cred.bv_len );
}
ber_bvreplace( &lc->lc_cred, bindcred );
ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
} else {
lc->lc_cred.bv_len = 0;
}
}
done:;

View file

@ -66,6 +66,7 @@ enum {
LDAP_BACK_CFG_VERSION,
LDAP_BACK_CFG_SINGLECONN,
LDAP_BACK_CFG_USETEMP,
LDAP_BACK_CFG_CONNPOOLMAX,
LDAP_BACK_CFG_CANCEL,
LDAP_BACK_CFG_QUARANTINE,
LDAP_BACK_CFG_REWRITE,
@ -286,6 +287,14 @@ static ConfigTable ldapcfg[] = {
"SYNTAX OMsBoolean "
"SINGLE-VALUE )",
NULL, NULL },
{ "conn-pool-max", "<n>", 2, 0, 0,
ARG_MAGIC|ARG_INT|LDAP_BACK_CFG_CONNPOOLMAX,
ldap_back_cf_gen, "( OLcfgDbAt:3.23 "
"NAME 'olcDbConnectionPoolMax' "
"DESC 'Max size of privileged connections pool' "
"SYNTAX OMsInteger "
"SINGLE-VALUE )",
NULL, NULL },
{ "suffixmassage", "[virtual]> <real", 2, 3, 0,
ARG_STRING|ARG_MAGIC|LDAP_BACK_CFG_REWRITE,
ldap_back_cf_gen, NULL, NULL, NULL },
@ -324,6 +333,7 @@ static ConfigOCs ldapocs[] = {
"$ olcDbCancel "
"$ olcDbQuarantine "
"$ olcDbUseTemporaryConn "
"$ olcDbConnectionPoolMax "
") )",
Cft_Database, ldapcfg},
{ NULL, 0, NULL }
@ -1060,6 +1070,10 @@ ldap_back_cf_gen( ConfigArgs *c )
c->value_int = LDAP_BACK_USE_TEMPORARIES( li );
break;
case LDAP_BACK_CFG_CONNPOOLMAX:
c->value_int = li->li_conn_priv_max;
break;
case LDAP_BACK_CFG_CANCEL: {
slap_mask_t mask = LDAP_BACK_F_CANCEL_MASK2;
@ -1190,6 +1204,10 @@ ldap_back_cf_gen( ConfigArgs *c )
li->li_flags &= ~LDAP_BACK_F_USE_TEMPORARIES;
break;
case LDAP_BACK_CFG_CONNPOOLMAX:
li->li_conn_priv_max = LDAP_BACK_CONN_PRIV_MIN;
break;
case LDAP_BACK_CFG_QUARANTINE:
if ( !LDAP_BACK_QUARANTINE( li ) ) {
break;
@ -1744,6 +1762,24 @@ done_url:;
}
break;
case LDAP_BACK_CFG_CONNPOOLMAX:
if ( c->value_int < LDAP_BACK_CONN_PRIV_MIN
|| c->value_int > LDAP_BACK_CONN_PRIV_MAX )
{
snprintf( c->msg, sizeof( c->msg ),
"invalid max size " "of privileged "
"connections pool \"%s\" "
"in \"conn-pool-max <n> "
"(must be between %d and %d)\"",
c->argv[ 1 ],
LDAP_BACK_CONN_PRIV_MIN,
LDAP_BACK_CONN_PRIV_MAX );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
return 1;
}
li->li_conn_priv_max = c->value_int;
break;
case LDAP_BACK_CFG_CANCEL: {
slap_mask_t mask;

View file

@ -102,6 +102,7 @@ ldap_back_db_init( Backend *be )
{
ldapinfo_t *li;
int rc;
unsigned i;
li = (ldapinfo_t *)ch_calloc( 1, sizeof( ldapinfo_t ) );
if ( li == NULL ) {
@ -146,6 +147,12 @@ ldap_back_db_init( Backend *be )
ldap_pvt_thread_mutex_init( &li->li_conninfo.lai_mutex );
for ( i = LDAP_BACK_PCONN_FIRST; i < LDAP_BACK_PCONN_LAST; i++ ) {
li->li_conn_priv[ i ].lic_num = 0;
LDAP_TAILQ_INIT( &li->li_conn_priv[ i ].lic_priv );
}
li->li_conn_priv_max = LDAP_BACK_CONN_PRIV_DEFAULT;
be->be_private = li;
SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_NOLASTMOD;
@ -244,6 +251,8 @@ ldap_back_conn_free( void *v_lc )
if ( !BER_BVISNULL( &lc->lc_local_ndn ) ) {
ch_free( lc->lc_local_ndn.bv_val );
}
lc->lc_q.tqe_prev = NULL;
lc->lc_q.tqe_next = NULL;
ch_free( lc );
}
@ -264,6 +273,7 @@ ldap_back_db_destroy( Backend *be )
{
if ( be->be_private ) {
ldapinfo_t *li = ( ldapinfo_t * )be->be_private;
unsigned i;
(void)ldap_back_monitor_db_destroy( be );
@ -328,6 +338,14 @@ ldap_back_db_destroy( Backend *be )
if ( li->li_conninfo.lai_tree ) {
avl_free( li->li_conninfo.lai_tree, ldap_back_conn_free );
}
for ( i = LDAP_BACK_PCONN_FIRST; i < LDAP_BACK_PCONN_LAST; i++ ) {
while ( !LDAP_TAILQ_EMPTY( &li->li_conn_priv[ i ].lic_priv ) ) {
ldapconn_t *lc = LDAP_TAILQ_FIRST( &li->li_conn_priv[ i ].lic_priv );
LDAP_TAILQ_REMOVE( &li->li_conn_priv[ i ].lic_priv, lc, lc_q );
ldap_back_conn_free( lc );
}
}
if ( LDAP_BACK_QUARANTINE( li ) ) {
slap_retry_info_destroy( &li->li_quarantine );
ldap_pvt_thread_mutex_destroy( &li->li_quarantine_mutex );

View file

@ -45,7 +45,6 @@ extern BI_connection_destroy ldap_back_conn_destroy;
extern BI_entry_get_rw ldap_back_entry_get;
int ldap_back_freeconn( Operation *op, ldapconn_t *lc, int dolock );
void ldap_back_release_conn_lock( Operation *op, SlapReply *rs, ldapconn_t **lcp, int dolock );
#define ldap_back_release_conn(op, rs, lc) ldap_back_release_conn_lock((op), (rs), &(lc), 1)
int ldap_back_dobind( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok );
@ -83,7 +82,7 @@ ldap_back_quarantine(
#ifdef LDAP_BACK_PRINT_CONNTREE
extern void
ldap_back_print_conntree( Avlnode *root, char *msg );
ldap_back_print_conntree( ldapinfo_t *li, char *msg );
#endif /* LDAP_BACK_PRINT_CONNTREE */
extern void slap_retry_info_destroy( slap_retry_info_t *ri );

View file

@ -49,7 +49,7 @@ ldap_back_conn_destroy(
ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
#if LDAP_BACK_PRINT_CONNTREE > 0
ldap_back_print_conntree( li->li_conninfo.lai_tree, ">>> ldap_back_conn_destroy" );
ldap_back_print_conntree( li, ">>> ldap_back_conn_destroy" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
while ( ( lc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)&lc_curr, ldap_back_conn_cmp ) ) != NULL )
{
@ -67,7 +67,7 @@ ldap_back_conn_destroy(
ldap_back_conn_free( lc );
}
#if LDAP_BACK_PRINT_CONNTREE > 0
ldap_back_print_conntree( li->li_conninfo.lai_tree, "<<< ldap_back_conn_destroy" );
ldap_back_print_conntree( li, "<<< ldap_back_conn_destroy" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );

View file

@ -241,6 +241,8 @@ typedef struct metaconn_t {
struct metainfo_t *mc_info;
LDAP_TAILQ_ENTRY(metaconn_t) mc_q;
/* supersedes the connection stuff */
metasingleconn_t mc_conns[ 1 ];
/* NOTE: mc_conns must be last, because
@ -346,7 +348,14 @@ typedef struct metainfo_t {
metadncache_t mi_cache;
/* cached connections;
* special conns are in tailq rather than in tree */
ldap_avl_info_t mi_conninfo;
struct {
int mic_num;
LDAP_TAILQ_HEAD(mc_conn_priv_q, metaconn_t) mic_priv;
} mi_conn_priv[ LDAP_BACK_PCONN_LAST ];
int mi_conn_priv_max;
/* NOTE: quarantine uses the connection mutex */
slap_retry_info_t mi_quarantine;
@ -417,7 +426,7 @@ meta_back_conn_free(
#if META_BACK_PRINT_CONNTREE > 0
extern void
meta_back_print_conntree(
Avlnode *root,
metainfo_t *mi,
char *msg );
#endif

View file

@ -220,7 +220,7 @@ retry_lock:;
assert( mc->mc_refcnt == 1 );
#if META_BACK_PRINT_CONNTREE > 0
meta_back_print_conntree( mi->mi_conninfo.lai_tree, ">>> meta_back_bind" );
meta_back_print_conntree( mi, ">>> meta_back_bind" );
#endif /* META_BACK_PRINT_CONNTREE */
tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
meta_back_conndn_cmp );
@ -252,12 +252,12 @@ retry_lock:;
ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn );
if ( isroot ) {
LDAP_BACK_CONN_ISPRIV_SET( mc );
mc->mc_conn = LDAP_BACK_PCONN_SET( op );
LDAP_BACK_PCONN_SET( mc, op );
}
lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
meta_back_conndn_cmp, meta_back_conndn_dup );
#if META_BACK_PRINT_CONNTREE > 0
meta_back_print_conntree( mi->mi_conninfo.lai_tree, "<<< meta_back_bind" );
meta_back_print_conntree( mi, "<<< meta_back_bind" );
#endif /* META_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
if ( lerr == -1 ) {

View file

@ -877,6 +877,32 @@ meta_back_db_config(
return 1;
}
/* privileged connections pool max size ? */
} else if ( strcasecmp( argv[ 0 ], "conn-pool-max" ) == 0 ) {
if ( argc != 2 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: \"conn-pool-max <n>\" takes 1 argument\n",
fname, lineno, 0 );
return( 1 );
}
if ( mi->mi_ntargets > 0 ) {
Debug( LDAP_DEBUG_ANY,
"%s: line %d: \"conn-pool-max\" must appear before target definitions\n",
fname, lineno, 0 );
return( 1 );
}
if ( lutil_atoi( &mi->mi_conn_priv_max, argv[1] )
|| mi->mi_conn_priv_max < LDAP_BACK_CONN_PRIV_MIN
|| mi->mi_conn_priv_max > LDAP_BACK_CONN_PRIV_MAX )
{
Debug( LDAP_DEBUG_ANY,
"%s: line %d: \"conn-pool-max <n>\": 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 ?

View file

@ -140,7 +140,7 @@ meta_back_conndn_dup(
*/
#if META_BACK_PRINT_CONNTREE > 0
static void
ravl_print( Avlnode *root, int depth )
meta_back_ravl_print( Avlnode *root, int depth )
{
int i;
metaconn_t *mc;
@ -149,7 +149,7 @@ ravl_print( Avlnode *root, int depth )
return;
}
ravl_print( root->avl_right, depth + 1 );
meta_back_ravl_print( root->avl_right, depth + 1 );
for ( i = 0; i < depth; i++ ) {
fprintf( stderr, "-" );
@ -163,19 +163,49 @@ ravl_print( Avlnode *root, int depth )
avl_bf2str( root->avl_bf ), mc->mc_refcnt,
LDAP_BACK_CONN_TAINTED( mc ) ? " tainted" : "" );
ravl_print( root->avl_left, depth + 1 );
meta_back_ravl_print( root->avl_left, depth + 1 );
}
/* NOTE: duplicate from back-ldap/bind.c */
static char* priv2str[] = {
"privileged",
"privileged/TLS",
"anonymous",
"anonymous/TLS",
"bind",
"bind/TLS",
NULL
};
void
meta_back_print_conntree( Avlnode *root, char *msg )
meta_back_print_conntree( metainfo_t *mi, char *msg )
{
int c;
fprintf( stderr, "========> %s\n", msg );
if ( root == 0 ) {
for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) {
int i = 0;
metaconn_t *mc;
fprintf( stderr, " %s[%d]\n", priv2str[ c ], mi->mi_conn_priv[ c ].mic_num );
LDAP_TAILQ_FOREACH( mc, &mi->mi_conn_priv[ c ].mic_priv, mc_q )
{
fprintf( stderr, " [%d] mc=%p local=\"%s\" conn=%p refcnt=%d flags=0x%08x\n",
i,
(void *)mc,
mc->mc_local_ndn.bv_val ? mc->mc_local_ndn.bv_val : "",
(void *)mc->mc_conn, mc->mc_refcnt, mc->msc_mscflags );
i++;
}
}
if ( mi->mi_conninfo.lai_tree == NULL ) {
fprintf( stderr, "\t(empty)\n" );
} else {
ravl_print( root, 0 );
meta_back_ravl_print( mi->mi_conninfo.lai_tree, 0 );
}
fprintf( stderr, "<======== %s\n", msg );
@ -708,13 +738,33 @@ meta_back_retry(
} else {
#if META_BACK_PRINT_CONNTREE > 0
meta_back_print_conntree( mi->mi_conninfo.lai_tree, ">>> meta_back_retry" );
meta_back_print_conntree( mi, ">>> 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 ( LDAP_BACK_PCONN_ISPRIV( mc ) ) {
if ( mc->mc_q.tqe_prev != NULL ) {
assert( LDAP_BACK_CONN_CACHED( mc ) );
assert( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num > 0 );
LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv,
mc, mc_q );
mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num--;
mc->mc_q.tqe_prev = NULL;
mc->mc_q.tqe_next = NULL;
} else {
assert( !LDAP_BACK_CONN_CACHED( mc ) );
}
} else {
/* FIXME: check if in tree, for consistency? */
(void)avl_delete( &mi->mi_conninfo.lai_tree,
( caddr_t )mc, meta_back_conndnmc_cmp );
}
LDAP_BACK_CONN_CACHED_CLEAR( mc );
#if META_BACK_PRINT_CONNTREE > 0
meta_back_print_conntree( mi->mi_conninfo.lai_tree, "<<< meta_back_retry" );
meta_back_print_conntree( mi, "<<< meta_back_retry" );
#endif /* META_BACK_PRINT_CONNTREE */
}
}
@ -970,7 +1020,7 @@ meta_back_getconn(
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 );
LDAP_BACK_PCONN_ROOTDN_SET( &mc_curr, op );
} else {
mc_curr.mc_local_ndn = op->o_ndn;
@ -980,7 +1030,8 @@ meta_back_getconn(
mc_curr.mc_conn = op->o_conn;
} else {
mc_curr.mc_conn = LDAP_BACK_PCONN_SET( op );
LDAP_BACK_CONN_ISANON_SET( &mc_curr );
LDAP_BACK_PCONN_ANON_SET( &mc_curr, op );
}
}
@ -989,8 +1040,41 @@ meta_back_getconn(
/* Searches for a metaconn in the avl tree */
retry_lock:;
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree,
(caddr_t)&mc_curr, meta_back_conndn_cmp );
if ( LDAP_BACK_PCONN_ISPRIV( &mc_curr ) ) {
/* lookup a conn that's not binding */
LDAP_TAILQ_FOREACH( mc,
&mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( &mc_curr ) ].mic_priv,
mc_q )
{
if ( !LDAP_BACK_CONN_BINDING( mc ) && mc->mc_refcnt == 0 ) {
break;
}
}
if ( mc != NULL ) {
if ( mc != LDAP_TAILQ_LAST( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv,
metaconn_t, mc_q ) )
{
LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv,
mc, mc_q );
mc->mc_q.tqe_prev = NULL;
mc->mc_q.tqe_next = NULL;
LDAP_TAILQ_INSERT_TAIL( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv,
mc, mc_q );
}
} else if ( !LDAP_BACK_USE_TEMPORARIES( mi )
&& mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( &mc_curr ) ].mic_num == mi->mi_conn_priv_max )
{
mc = LDAP_TAILQ_FIRST( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( &mc_curr ) ].mic_priv );
}
} else {
mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree,
(caddr_t)&mc_curr, meta_back_conndn_cmp );
}
if ( mc ) {
/* catch taint errors */
assert( !LDAP_BACK_CONN_TAINTED( mc ) );
@ -1013,17 +1097,36 @@ retry_lock:;
|| ( 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_print_conntree( mi,
">>> 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 );
if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) {
if ( mc->mc_q.tqe_prev != NULL ) {
assert( LDAP_BACK_CONN_CACHED( mc ) );
assert( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num > 0 );
LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv,
mc, mc_q );
mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num--;
mc->mc_q.tqe_prev = NULL;
mc->mc_q.tqe_next = NULL;
} else {
assert( !LDAP_BACK_CONN_CACHED( mc ) );
}
} else {
(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_print_conntree( mi,
"<<< meta_back_getconn(expired)" );
#endif /* META_BACK_PRINT_CONNTREE */
LDAP_BACK_CONN_TAINTED_SET( mc );
LDAP_BACK_CONN_CACHED_CLEAR( 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 ) );
@ -1092,6 +1195,9 @@ retry_lock:;
}
if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) {
LDAP_BACK_CONN_ISPRIV_SET( mc );
} else if ( LDAP_BACK_CONN_ISANON( &mc_curr ) ) {
LDAP_BACK_CONN_ISANON_SET( mc );
}
} else if ( 0 ) {
@ -1261,6 +1367,9 @@ retry_lock2:;
}
if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) {
LDAP_BACK_CONN_ISPRIV_SET( mc );
} else if ( LDAP_BACK_CONN_ISANON( &mc_curr ) ) {
LDAP_BACK_CONN_ISANON_SET( mc );
}
}
}
@ -1319,6 +1428,9 @@ retry_lock2:;
new_conn = 1;
if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) {
LDAP_BACK_CONN_ISPRIV_SET( mc );
} else if ( LDAP_BACK_CONN_ISANON( &mc_curr ) ) {
LDAP_BACK_CONN_ISANON_SET( mc );
}
}
@ -1452,51 +1564,71 @@ done:;
*/
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
#if META_BACK_PRINT_CONNTREE > 0
meta_back_print_conntree( mi->mi_conninfo.lai_tree, ">>> meta_back_getconn" );
meta_back_print_conntree( mi, ">>> meta_back_getconn" );
#endif /* META_BACK_PRINT_CONNTREE */
err = avl_insert( &mi->mi_conninfo.lai_tree, ( caddr_t )mc,
if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) {
if ( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num < mi->mi_conn_priv_max ) {
LDAP_TAILQ_INSERT_TAIL( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, mc, mc_q );
mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num++;
LDAP_BACK_CONN_CACHED_SET( mc );
} else {
LDAP_BACK_CONN_TAINTED_SET( mc );
}
rs->sr_err = 0;
} else {
err = avl_insert( &mi->mi_conninfo.lai_tree, ( caddr_t )mc,
meta_back_conndn_cmp, meta_back_conndn_dup );
LDAP_BACK_CONN_CACHED_SET( mc );
}
#if META_BACK_PRINT_CONNTREE > 0
meta_back_print_conntree( mi->mi_conninfo.lai_tree, ">>> meta_back_getconn" );
meta_back_print_conntree( mi, ">>> meta_back_getconn" );
#endif /* META_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
/*
* Err could be -1 in case a duplicate metaconn is inserted
*/
switch ( err ) {
case 0:
break;
if ( !LDAP_BACK_PCONN_ISPRIV( mc ) ) {
/*
* Err could be -1 in case a duplicate metaconn is inserted
*/
switch ( err ) {
case 0:
break;
case -1:
/* duplicate: free and try to get the newly created one */
if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( mi ) ) {
case -1:
LDAP_BACK_CONN_CACHED_CLEAR( mc );
/* duplicate: free and try to get the newly created one */
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;
default:
LDAP_BACK_CONN_CACHED_CLEAR( mc );
Debug( LDAP_DEBUG_ANY,
"%s meta_back_getconn: candidates=%d conn=%ld insert failed\n",
op->o_log_prefix, ncandidates,
LDAP_BACK_PCONN_ID( mc ) );
mc->mc_refcnt = 0;
meta_back_conn_free( mc );
new_conn = 0;
goto retry_lock;
rs->sr_err = LDAP_OTHER;
rs->sr_text = "proxy bind collision";
if ( sendok & LDAP_BACK_SENDERR ) {
send_ldap_result( op, rs );
rs->sr_text = NULL;
}
return NULL;
}
LDAP_BACK_CONN_TAINTED_SET( mc );
break;
default:
Debug( LDAP_DEBUG_ANY,
"%s meta_back_getconn: candidates=%d conn=%ld insert failed\n",
op->o_log_prefix, ncandidates,
LDAP_BACK_PCONN_ID( mc ) );
mc->mc_refcnt = 0;
meta_back_conn_free( mc );
rs->sr_err = LDAP_OTHER;
rs->sr_text = "proxy bind collision";
if ( sendok & LDAP_BACK_SENDERR ) {
send_ldap_result( op, rs );
rs->sr_text = NULL;
}
return NULL;
}
Debug( LDAP_DEBUG_TRACE,
@ -1535,28 +1667,46 @@ meta_back_release_conn_lock(
* that are not privileged would live forever and pollute
* 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 ) )
{
metaconn_t *tmpmc;
if ( LDAP_BACK_CONN_TAINTED( mc ) ) {
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" );
meta_back_print_conntree( mi, ">>> meta_back_release_conn" );
#endif /* META_BACK_PRINT_CONNTREE */
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 );
if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) {
if ( mc->mc_q.tqe_prev != NULL ) {
assert( LDAP_BACK_CONN_CACHED( mc ) );
assert( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num > 0 );
mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num--;
LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, mc, mc_q );
} else {
assert( !LDAP_BACK_CONN_CACHED( mc ) );
}
mc->mc_q.tqe_prev = NULL;
mc->mc_q.tqe_next = NULL;
} else {
assert( tmpmc == mc );
metaconn_t *tmpmc;
tmpmc = avl_delete( &mi->mi_conninfo.lai_tree,
( caddr_t )mc, meta_back_conndnmc_cmp );
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 );
}
}
LDAP_BACK_CONN_CACHED_CLEAR( mc );
#if META_BACK_PRINT_CONNTREE > 0
meta_back_print_conntree( mi, "<<< meta_back_release_conn" );
#endif /* META_BACK_PRINT_CONNTREE */
if ( mc->mc_refcnt == 0 ) {
meta_back_conn_free( mc );
mc = NULL;

View file

@ -90,6 +90,7 @@ meta_back_db_init(
Backend *be )
{
metainfo_t *mi;
int i;
mi = ch_calloc( 1, sizeof( metainfo_t ) );
if ( mi == NULL ) {
@ -113,6 +114,12 @@ meta_back_db_init(
/* safe default */
mi->mi_nretries = META_RETRY_DEFAULT;
mi->mi_version = LDAP_VERSION3;
for ( i = LDAP_BACK_PCONN_FIRST; i < LDAP_BACK_PCONN_LAST; i++ ) {
mi->mi_conn_priv[ i ].mic_num = 0;
LDAP_TAILQ_INIT( &mi->mi_conn_priv[ i ].mic_priv );
}
mi->mi_conn_priv_max = LDAP_BACK_CONN_PRIV_DEFAULT;
be->be_private = mi;
@ -298,6 +305,14 @@ meta_back_db_destroy(
if ( mi->mi_conninfo.lai_tree ) {
avl_free( mi->mi_conninfo.lai_tree, meta_back_conn_free );
}
for ( i = LDAP_BACK_PCONN_FIRST; i < LDAP_BACK_PCONN_LAST; i++ ) {
while ( !LDAP_TAILQ_EMPTY( &mi->mi_conn_priv[ i ].mic_priv ) ) {
metaconn_t *mc = LDAP_TAILQ_FIRST( &mi->mi_conn_priv[ i ].mic_priv );
LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ i ].mic_priv, mc, mc_q );
meta_back_conn_free( mc );
}
}
/*
* Destroy the per-target stuff (assuming there's at

View file

@ -52,7 +52,7 @@ meta_back_conn_destroy(
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
#if META_BACK_PRINT_CONNTREE > 0
meta_back_print_conntree( mi->mi_conninfo.lai_tree, ">>> meta_back_conn_destroy" );
meta_back_print_conntree( mi, ">>> meta_back_conn_destroy" );
#endif /* META_BACK_PRINT_CONNTREE */
while ( ( mc = avl_delete( &mi->mi_conninfo.lai_tree, ( caddr_t )&mc_curr, meta_back_conn_cmp ) ) != NULL )
{
@ -65,7 +65,7 @@ meta_back_conn_destroy(
meta_back_conn_free( mc );
}
#if META_BACK_PRINT_CONNTREE > 0
meta_back_print_conntree( mi->mi_conninfo.lai_tree, "<<< meta_back_conn_destroy" );
meta_back_print_conntree( mi, "<<< meta_back_conn_destroy" );
#endif /* META_BACK_PRINT_CONNTREE */
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );