X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=servers%2Fslapd%2Fback-meta%2Fbind.c;h=acfc69577cecd577ba97c1279eae8e2f31d6dccb;hb=caf751fbb20fbccf535b900df1dabef0f40e0222;hp=f0297d4a1b6c07db2b275c7d262d1290cf8e751a;hpb=3c5068bc1fa84fc5daf1e50d4f1a929cec91b7e9;p=openldap diff --git a/servers/slapd/back-meta/bind.c b/servers/slapd/back-meta/bind.c index f0297d4a1b..acfc69577c 100644 --- a/servers/slapd/back-meta/bind.c +++ b/servers/slapd/back-meta/bind.c @@ -1,7 +1,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1999-2007 The OpenLDAP Foundation. + * Copyright 1999-2012 The OpenLDAP Foundation. * Portions Copyright 2001-2003 Pierangelo Masarati. * Portions Copyright 1999-2003 Howard Chu. * All rights reserved. @@ -33,8 +33,6 @@ #include "slap.h" #include "../back-ldap/back-ldap.h" #include "back-meta.h" -#undef ldap_debug /* silence a warning in ldap-int.h */ -#include "../../../libraries/libldap/ldap-int.h" #include "lutil_ldap.h" @@ -44,7 +42,8 @@ meta_back_proxy_authz_bind( int candidate, Operation *op, SlapReply *rs, - ldap_back_send_t sendok ); + ldap_back_send_t sendok, + int dolock ); static int meta_back_single_bind( @@ -64,7 +63,7 @@ meta_back_bind( Operation *op, SlapReply *rs ) gotit = 0, isroot = 0; - SlapReply *candidates = meta_back_candidates_get( op ); + SlapReply *candidates; rs->sr_err = LDAP_SUCCESS; @@ -72,24 +71,22 @@ meta_back_bind( Operation *op, SlapReply *rs ) op->o_log_prefix, op->o_req_dn.bv_val, 0 ); /* the test on the bind method should be superfluous */ - if ( op->orb_method == LDAP_AUTH_SIMPLE - && be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) - { - if ( !be_isroot_pw( op ) ) { - rs->sr_err = LDAP_INVALID_CREDENTIALS; - rs->sr_text = NULL; - send_ldap_result( op, rs ); - return rs->sr_err; - } - + switch ( be_rootdn_bind( op, rs ) ) { + case LDAP_SUCCESS: if ( META_BACK_DEFER_ROOTDN_BIND( mi ) ) { - rs->sr_err = LDAP_SUCCESS; - rs->sr_text = NULL; /* frontend will return success */ return rs->sr_err; } isroot = 1; + /* fallthru */ + + case SLAP_CB_CONTINUE: + break; + + default: + /* be_rootdn_bind() sent result */ + return rs->sr_err; } /* we need meta_back_getconn() not send result even on error, @@ -124,6 +121,8 @@ meta_back_bind( Operation *op, SlapReply *rs ) return rs->sr_err; } + candidates = meta_back_candidates_get( op ); + /* * Each target is scanned ... */ @@ -145,7 +144,7 @@ meta_back_bind( Operation *op, SlapReply *rs ) rc = LDAP_SUCCESS; gotit = 1; - } else if ( isroot == 0 ) { + } else if ( !isroot ) { /* * A bind operation is expected to have * ONE CANDIDATE ONLY! @@ -180,7 +179,7 @@ meta_back_bind( Operation *op, SlapReply *rs ) } - (void)meta_back_proxy_authz_bind( mc, i, op, rs, LDAP_BACK_DONTSEND ); + (void)meta_back_proxy_authz_bind( mc, i, op, rs, LDAP_BACK_DONTSEND, 1 ); lerr = rs->sr_err; } else { @@ -189,6 +188,7 @@ meta_back_bind( Operation *op, SlapReply *rs ) if ( lerr != LDAP_SUCCESS ) { rc = rs->sr_err = lerr; + /* FIXME: in some cases (e.g. unavailable) * do not assume it's not candidate; rather * mark this as an error to be eventually @@ -202,39 +202,30 @@ meta_back_bind( Operation *op, SlapReply *rs ) if ( rc == LDAP_SUCCESS ) { if ( isroot ) { mc->mc_authz_target = META_BOUND_ALL; - ber_dupbv( &op->orb_edn, be_root_dn( op->o_bd ) ); } if ( !LDAP_BACK_PCONN_ISPRIV( mc ) && !dn_match( &op->o_req_ndn, &mc->mc_local_ndn ) ) { - metaconn_t *tmpmc; int lerr; /* wait for all other ops to release the connection */ -retry_lock:; ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); - if ( mc->mc_refcnt > 1 ) { - ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); - ldap_pvt_thread_yield(); - goto retry_lock; - } - assert( mc->mc_refcnt == 1 ); #if META_BACK_PRINT_CONNTREE > 0 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 ); - assert( tmpmc == mc ); /* delete all cached connections with the current connection */ if ( LDAP_BACK_SINGLECONN( mi ) ) { + metaconn_t *tmpmc; + while ( ( tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conn_cmp ) ) != NULL ) { + assert( !LDAP_BACK_PCONN_ISPRIV( mc ) ); Debug( LDAP_DEBUG_TRACE, - "=>meta_back_bind: destroying conn %ld (refcnt=%u)\n", - LDAP_BACK_PCONN_ID( mc ), mc->mc_refcnt, 0 ); + "=>meta_back_bind: destroying conn %lu (refcnt=%u)\n", + mc->mc_conn->c_connid, mc->mc_refcnt, 0 ); if ( tmpmc->mc_refcnt != 0 ) { /* taint it */ @@ -252,23 +243,27 @@ retry_lock:; } ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn ); - if ( isroot ) { - LDAP_BACK_CONN_ISPRIV_SET( mc ); - 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, "<<< meta_back_bind" ); #endif /* META_BACK_PRINT_CONNTREE */ - ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); - if ( lerr == -1 ) { - /* we can do this because mc_refcnt == 1 */ - assert( mc->mc_refcnt == 1 ); - mc->mc_refcnt = 0; - meta_back_conn_free( mc ); - mc = NULL; + if ( lerr == 0 ) { +#if 0 + /* NOTE: a connection cannot be privileged + * and be in the avl tree at the same time + */ + if ( isroot ) { + LDAP_BACK_CONN_ISPRIV_SET( mc ); + LDAP_BACK_PCONN_SET( mc, op ); + } +#endif + LDAP_BACK_CONN_CACHED_SET( mc ); + + } else { + LDAP_BACK_CONN_CACHED_CLEAR( mc ); } + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); } } @@ -311,7 +306,8 @@ meta_back_bind_op_result( metaconn_t *mc, int candidate, int msgid, - 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 ]; @@ -326,6 +322,9 @@ meta_back_bind_op_result( ">>> %s meta_back_bind_op_result[%d]\n", op->o_log_prefix, candidate, 0 ); + /* make sure this is clean */ + assert( rs->sr_ctrls == NULL ); + if ( rs->sr_err == LDAP_SUCCESS ) { time_t stoptime = (time_t)(-1), timeout; @@ -387,7 +386,9 @@ retry:; /* don't let anyone else use this handler, * because there's a pending bind that will not * be acknowledged */ - ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); + if ( dolock) { + ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); + } assert( LDAP_BACK_CONN_BINDING( msc ) ); #ifdef DEBUG_205 @@ -396,7 +397,9 @@ retry:; #endif /* DEBUG_205 */ meta_clear_one_candidate( op, mc, candidate ); - ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + if ( dolock ) { + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + } rs->sr_err = timeout_err; rs->sr_text = timeout_text; @@ -426,6 +429,7 @@ retry:; if ( rc != LDAP_SUCCESS ) { rs->sr_err = rc; } + rs->sr_err = slap_map_api2result( rs ); break; } } @@ -457,6 +461,9 @@ meta_back_single_bind( metasingleconn_t *msc = &mc->mc_conns[ candidate ]; int msgid; dncookie dc; + struct berval save_o_dn; + int save_o_do_not_cache; + LDAPControl **ctrls = NULL; if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) { ch_free( msc->msc_bound_ndn.bv_val ); @@ -484,6 +491,20 @@ meta_back_single_bind( return rs->sr_err; } + /* don't add proxyAuthz; set the bindDN */ + save_o_dn = op->o_dn; + save_o_do_not_cache = op->o_do_not_cache; + op->o_do_not_cache = 1; + op->o_dn = op->o_req_dn; + + ctrls = op->o_ctrls; + rs->sr_err = meta_back_controls_add( op, rs, mc, candidate, &ctrls ); + op->o_dn = save_o_dn; + op->o_do_not_cache = save_o_do_not_cache; + if ( rs->sr_err != LDAP_SUCCESS ) { + goto return_results; + } + /* FIXME: this fixes the bind problem right now; we need * to use the asynchronous version to get the "matched" * and more in case of failure ... */ @@ -492,13 +513,16 @@ meta_back_single_bind( for (;;) { rs->sr_err = ldap_sasl_bind( msc->msc_ld, mdn.bv_val, LDAP_SASL_SIMPLE, &op->orb_cred, - op->o_ctrls, NULL, &msgid ); + ctrls, NULL, &msgid ); if ( rs->sr_err != LDAP_X_CONNECTING ) { break; } ldap_pvt_thread_yield(); } - meta_back_bind_op_result( op, rs, mc, candidate, msgid, LDAP_BACK_DONTSEND ); + + mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); + + meta_back_bind_op_result( op, rs, mc, candidate, msgid, LDAP_BACK_DONTSEND, 1 ); if ( rs->sr_err != LDAP_SUCCESS ) { goto return_results; } @@ -509,7 +533,7 @@ meta_back_single_bind( * bind with the configured identity assertion */ /* NOTE: use with care */ if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) { - meta_back_proxy_authz_bind( mc, candidate, op, rs, LDAP_BACK_SENDERR ); + meta_back_proxy_authz_bind( mc, candidate, op, rs, LDAP_BACK_SENDERR, 1 ); if ( !LDAP_BACK_CONN_ISBOUND( msc ) ) { goto return_results; } @@ -520,7 +544,7 @@ meta_back_single_bind( LDAP_BACK_CONN_ISBOUND_SET( msc ); mc->mc_authz_target = candidate; - if ( LDAP_BACK_SAVECRED( mi ) ) { + if ( META_BACK_TGT_SAVECRED( mt ) ) { if ( !BER_BVISNULL( &msc->msc_cred ) ) { memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); @@ -566,7 +590,6 @@ meta_back_single_dobind( metatarget_t *mt = mi->mi_targets[ candidate ]; metaconn_t *mc = *mcp; metasingleconn_t *msc = &mc->mc_conns[ candidate ]; - static struct berval cred = BER_BVC( "" ); int msgid; assert( !LDAP_BACK_CONN_ISBOUND( msc ) ); @@ -579,15 +602,25 @@ meta_back_single_dobind( ( LDAP_BACK_CONN_ISPRIV( mc ) && dn_match( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN ) ) || ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) ) { - (void)meta_back_proxy_authz_bind( mc, candidate, op, rs, sendok ); + (void)meta_back_proxy_authz_bind( mc, candidate, op, rs, sendok, dolock ); } else { + char *binddn = ""; + struct berval cred = BER_BVC( "" ); + + /* use credentials if available */ + if ( !BER_BVISNULL( &msc->msc_bound_ndn ) + && !BER_BVISNULL( &msc->msc_cred ) ) + { + binddn = msc->msc_bound_ndn.bv_val; + cred = msc->msc_cred; + } /* FIXME: should we check if at least some of the op->o_ctrls * can/should be passed? */ for (;;) { rs->sr_err = ldap_sasl_bind( msc->msc_ld, - "", LDAP_SASL_SIMPLE, &cred, + binddn, LDAP_SASL_SIMPLE, &cred, NULL, NULL, &msgid ); if ( rs->sr_err != LDAP_X_CONNECTING ) { break; @@ -595,16 +628,30 @@ meta_back_single_dobind( ldap_pvt_thread_yield(); } - rs->sr_err = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok ); + rs->sr_err = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok, dolock ); + + /* if bind succeeded, but anonymous, clear msc_bound_ndn */ + if ( rs->sr_err != LDAP_SUCCESS || binddn[0] == '\0' ) { + if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) { + ber_memfree( msc->msc_bound_ndn.bv_val ); + BER_BVZERO( &msc->msc_bound_ndn ); + } + + if ( !BER_BVISNULL( &msc->msc_cred ) ) { + memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); + ber_memfree( msc->msc_cred.bv_val ); + BER_BVZERO( &msc->msc_cred ); + } + } } if ( rs->sr_err != LDAP_SUCCESS ) { if ( dolock ) { ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); } - LDAP_BACK_CONN_BINDING_CLEAR( msc ); + LDAP_BACK_CONN_BINDING_CLEAR( msc ); if ( META_BACK_ONERR_STOP( mi ) ) { - LDAP_BACK_CONN_TAINTED_SET( mc ); + LDAP_BACK_CONN_TAINTED_SET( mc ); meta_back_release_conn_lock( mi, mc, 0 ); *mcp = NULL; } @@ -636,17 +683,21 @@ meta_back_dobind( i, isroot = 0; - SlapReply *candidates = meta_back_candidates_get( op ); + SlapReply *candidates; if ( be_isroot( op ) ) { isroot = 1; } - Debug( LDAP_DEBUG_TRACE, - "%s meta_back_dobind: conn=%ld%s\n", - op->o_log_prefix, - LDAP_BACK_PCONN_ID( mc ), - isroot ? " (isroot)" : "" ); + if ( LogTest( LDAP_DEBUG_TRACE ) ) { + char buf[STRLENOF("4294967295U") + 1] = { 0 }; + mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) ); + + Debug( LDAP_DEBUG_TRACE, + "%s meta_back_dobind: conn=%s%s\n", + op->o_log_prefix, buf, + isroot ? " (isroot)" : "" ); + } /* * all the targets are bound as pseudoroot @@ -656,6 +707,8 @@ meta_back_dobind( goto done; } + candidates = meta_back_candidates_get( op ); + for ( i = 0; i < mi->mi_ntargets; i++ ) { metatarget_t *mt = mi->mi_targets[ i ]; metasingleconn_t *msc = &mc->mc_conns[ i ]; @@ -721,8 +774,8 @@ retry_binding:; if ( mc != NULL ) { ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); LDAP_BACK_CONN_BINDING_CLEAR( msc ); + meta_back_release_conn_lock( mi, mc, 0 ); ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); - meta_back_release_conn( mi, mc ); } return 0; @@ -776,9 +829,14 @@ retry_ok:; } done:; - Debug( LDAP_DEBUG_TRACE, - "%s meta_back_dobind: conn=%ld bound=%d\n", - op->o_log_prefix, LDAP_BACK_PCONN_ID( mc ), bound ); + if ( LogTest( LDAP_DEBUG_TRACE ) ) { + char buf[STRLENOF("4294967295U") + 1] = { 0 }; + mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) ); + + Debug( LDAP_DEBUG_TRACE, + "%s meta_back_dobind: conn=%s bound=%d\n", + op->o_log_prefix, buf, bound ); + } if ( bound == 0 ) { meta_back_release_conn( mi, mc ); @@ -933,9 +991,7 @@ meta_back_op_result( metatarget_t *mt = mi->mi_targets[ candidate ]; metasingleconn_t *msc = &mc->mc_conns[ candidate ]; -#define ERR_OK(err) ((err) == LDAP_SUCCESS || (err) == LDAP_COMPARE_FALSE || (err) == LDAP_COMPARE_TRUE) - - if ( ERR_OK( rs->sr_err ) ) { + if ( LDAP_ERR_OK( rs->sr_err ) ) { int rc; struct timeval tv; LDAPMessage *res = NULL; @@ -1014,22 +1070,50 @@ retry:; rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err, &matched, &text, &refs, &ctrls, 1 ); res = NULL; - rs->sr_text = text; - if ( rc != LDAP_SUCCESS ) { + if ( rc == LDAP_SUCCESS ) { + rs->sr_text = text; + } else { rs->sr_err = rc; } - if ( refs != NULL ) { - int i; + rs->sr_err = slap_map_api2result( rs ); + + /* RFC 4511: referrals can only appear + * if result code is LDAP_REFERRAL */ + if ( refs != NULL + && refs[ 0 ] != NULL + && refs[ 0 ][ 0 ] != '\0' ) + { + if ( rs->sr_err != LDAP_REFERRAL ) { + Debug( LDAP_DEBUG_ANY, + "%s meta_back_op_result[%d]: " + "got referrals with err=%d\n", + op->o_log_prefix, + candidate, rs->sr_err ); + + } else { + int i; - for ( i = 0; refs[ i ] != NULL; i++ ) - /* count */ ; - rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ), - op->o_tmpmemctx ); - for ( i = 0; refs[ i ] != NULL; i++ ) { - ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] ); + for ( i = 0; refs[ i ] != NULL; i++ ) + /* count */ ; + rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ), + op->o_tmpmemctx ); + for ( i = 0; refs[ i ] != NULL; i++ ) { + ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] ); + } + BER_BVZERO( &rs->sr_ref[ i ] ); } - BER_BVZERO( &rs->sr_ref[ i ] ); + + } else if ( rs->sr_err == LDAP_REFERRAL ) { + Debug( LDAP_DEBUG_ANY, + "%s meta_back_op_result[%d]: " + "got err=%d with null " + "or empty referrals\n", + op->o_log_prefix, + candidate, rs->sr_err ); + + rs->sr_err = LDAP_NO_SUCH_OBJECT; } + if ( ctrls != NULL ) { rs->sr_ctrls = ctrls; } @@ -1041,7 +1125,7 @@ retry:; /* if the error in the reply structure is not * LDAP_SUCCESS, try to map it from client * to server error */ - if ( !ERR_OK( rs->sr_err ) ) { + if ( !LDAP_ERR_OK( rs->sr_err ) ) { rs->sr_err = slap_map_api2result( rs ); /* internal ops ( op->o_conn == NULL ) @@ -1067,6 +1151,10 @@ retry:; char *xtext = NULL; char *xmatched = NULL; + if ( msc->msc_ld == NULL ) { + continue; + } + rs->sr_err = LDAP_SUCCESS; ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rs->sr_err ); @@ -1160,9 +1248,17 @@ retry:; rs->sr_matched = matched; } - if ( op->o_conn && - ( ( sendok & LDAP_BACK_SENDOK ) - || ( ( sendok & LDAP_BACK_SENDERR ) && rs->sr_err != LDAP_SUCCESS ) ) ) + if ( rs->sr_err == LDAP_UNAVAILABLE ) { + if ( !( sendok & LDAP_BACK_RETRYING ) ) { + if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) { + if ( rs->sr_text == NULL ) rs->sr_text = "Proxy operation retry failed"; + send_ldap_result( op, rs ); + } + } + + } else if ( op->o_conn && + ( ( ( sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) ) + || ( ( sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) ) { send_ldap_result( op, rs ); } @@ -1173,9 +1269,11 @@ retry:; ldap_memfree( text ); } if ( rs->sr_ref ) { - assert( refs != NULL ); - ber_memvfree( (void **)refs ); op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx ); + rs->sr_ref = NULL; + } + if ( refs ) { + ber_memvfree( (void **)refs ); } if ( ctrls ) { assert( rs->sr_ctrls != NULL ); @@ -1187,7 +1285,7 @@ retry:; rs->sr_ref = save_ref; rs->sr_ctrls = save_ctrls; - return( ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err ); + return( LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err ); } /* @@ -1242,6 +1340,7 @@ meta_back_proxy_authz_cred( } else { ndn = op->o_ndn; } + rs->sr_err = LDAP_SUCCESS; /* * FIXME: we need to let clients use proxyAuthz @@ -1392,6 +1491,14 @@ meta_back_proxy_authz_cred( mt->mt_idassert_authcID.bv_val, mt->mt_idassert_passwd.bv_val, authzID.bv_val ); + if ( defaults == NULL ) { + rs->sr_err = LDAP_OTHER; + LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); + if ( sendok & LDAP_BACK_SENDERR ) { + send_ldap_result( op, rs ); + } + goto done; + } rs->sr_err = ldap_sasl_interactive_bind_s( msc->msc_ld, binddn->bv_val, mt->mt_idassert_sasl_mech.bv_val, NULL, NULL, @@ -1439,11 +1546,22 @@ meta_back_proxy_authz_cred( } done:; + + if ( !BER_BVISEMPTY( binddn ) ) { + LDAP_BACK_CONN_ISIDASSERT_SET( msc ); + } + return rs->sr_err; } static int -meta_back_proxy_authz_bind( metaconn_t *mc, int candidate, Operation *op, SlapReply *rs, ldap_back_send_t sendok ) +meta_back_proxy_authz_bind( + metaconn_t *mc, + int candidate, + Operation *op, + SlapReply *rs, + ldap_back_send_t sendok, + int dolock ) { metainfo_t *mi = (metainfo_t *)op->o_bd->be_private; metatarget_t *mt = mi->mi_targets[ candidate ]; @@ -1469,7 +1587,7 @@ meta_back_proxy_authz_bind( metaconn_t *mc, int candidate, Operation *op, SlapRe } ldap_pvt_thread_yield(); } - rc = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok ); + rc = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok, dolock ); if ( rc == LDAP_SUCCESS ) { /* set rebind stuff in case of successful proxyAuthz bind, * so that referral chasing is attempted using the right @@ -1477,7 +1595,7 @@ meta_back_proxy_authz_bind( metaconn_t *mc, int candidate, Operation *op, SlapRe LDAP_BACK_CONN_ISBOUND_SET( msc ); ber_bvreplace( &msc->msc_bound_ndn, &binddn ); - if ( LDAP_BACK_SAVECRED( mi ) ) { + if ( META_BACK_TGT_SAVECRED( mt ) ) { if ( !BER_BVISNULL( &msc->msc_cred ) ) { memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); @@ -1496,3 +1614,140 @@ meta_back_proxy_authz_bind( metaconn_t *mc, int candidate, Operation *op, SlapRe return LDAP_BACK_CONN_ISBOUND( msc ); } + +/* + * Add controls; + * + * if any needs to be added, it is prepended to existing ones, + * in a newly allocated array. The companion function + * mi->mi_ldap_extra->controls_free() must be used to restore the original + * status of op->o_ctrls. + */ +int +meta_back_controls_add( + Operation *op, + SlapReply *rs, + metaconn_t *mc, + int candidate, + LDAPControl ***pctrls ) +{ + metainfo_t *mi = (metainfo_t *)op->o_bd->be_private; + metatarget_t *mt = mi->mi_targets[ candidate ]; + metasingleconn_t *msc = &mc->mc_conns[ candidate ]; + + LDAPControl **ctrls = NULL; + /* set to the maximum number of controls this backend can add */ + LDAPControl c[ 2 ] = {{ 0 }}; + int n = 0, i, j1 = 0, j2 = 0; + + *pctrls = NULL; + + rs->sr_err = LDAP_SUCCESS; + + /* don't add controls if protocol is not LDAPv3 */ + switch ( mt->mt_version ) { + case LDAP_VERSION3: + break; + + case 0: + if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) { + break; + } + /* fall thru */ + + default: + goto done; + } + + /* put controls that go __before__ existing ones here */ + + /* proxyAuthz for identity assertion */ + switch ( mi->mi_ldap_extra->proxy_authz_ctrl( op, rs, &msc->msc_bound_ndn, + mt->mt_version, &mt->mt_idassert, &c[ j1 ] ) ) + { + case SLAP_CB_CONTINUE: + break; + + case LDAP_SUCCESS: + j1++; + break; + + default: + goto done; + } + + /* put controls that go __after__ existing ones here */ + +#ifdef SLAP_CONTROL_X_SESSION_TRACKING + /* session tracking */ + if ( META_BACK_TGT_ST_REQUEST( mt ) ) { + switch ( slap_ctrl_session_tracking_request_add( op, rs, &c[ j1 + j2 ] ) ) { + case SLAP_CB_CONTINUE: + break; + + case LDAP_SUCCESS: + j2++; + break; + + default: + goto done; + } + } +#endif /* SLAP_CONTROL_X_SESSION_TRACKING */ + + if ( rs->sr_err == SLAP_CB_CONTINUE ) { + rs->sr_err = LDAP_SUCCESS; + } + + /* if nothing to do, just bail out */ + if ( j1 == 0 && j2 == 0 ) { + goto done; + } + + assert( j1 + j2 <= (int) (sizeof( c )/sizeof( c[0] )) ); + + if ( op->o_ctrls ) { + for ( n = 0; op->o_ctrls[ n ]; n++ ) + /* just count ctrls */ ; + } + + ctrls = op->o_tmpalloc( (n + j1 + j2 + 1) * sizeof( LDAPControl * ) + ( j1 + j2 ) * sizeof( LDAPControl ), + op->o_tmpmemctx ); + if ( j1 ) { + ctrls[ 0 ] = (LDAPControl *)&ctrls[ n + j1 + j2 + 1 ]; + *ctrls[ 0 ] = c[ 0 ]; + for ( i = 1; i < j1; i++ ) { + ctrls[ i ] = &ctrls[ 0 ][ i ]; + *ctrls[ i ] = c[ i ]; + } + } + + i = 0; + if ( op->o_ctrls ) { + for ( i = 0; op->o_ctrls[ i ]; i++ ) { + ctrls[ i + j1 ] = op->o_ctrls[ i ]; + } + } + + n += j1; + if ( j2 ) { + ctrls[ n ] = (LDAPControl *)&ctrls[ n + j2 + 1 ] + j1; + *ctrls[ n ] = c[ j1 ]; + for ( i = 1; i < j2; i++ ) { + ctrls[ n + i ] = &ctrls[ n ][ i ]; + *ctrls[ n + i ] = c[ i ]; + } + } + + ctrls[ n + j2 ] = NULL; + +done:; + if ( ctrls == NULL ) { + ctrls = op->o_ctrls; + } + + *pctrls = ctrls; + + return rs->sr_err; +} +