]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/back-ldap/bind.c
ITS#5404
[openldap] / servers / slapd / back-ldap / bind.c
index b4f4529887a667dfa3410c5f97857f92d89e0b0c..8d69effb014a0026c10bc7e253e1513e3a196684 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 1999-2007 The OpenLDAP Foundation.
+ * Copyright 1999-2008 The OpenLDAP Foundation.
  * Portions Copyright 2000-2003 Pierangelo Masarati.
  * Portions Copyright 1999-2003 Howard Chu.
  * All rights reserved.
@@ -644,6 +644,7 @@ ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_
        ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
        if ( rs->sr_err != LDAP_SUCCESS ) {
                ldap_unbind_ext( ld, NULL, NULL );
+               rs->sr_text = "Start TLS failed";
                goto error_return;
 
        } else if ( li->li_idle_timeout ) {
@@ -670,10 +671,9 @@ error_return:;
                rs->sr_err = slap_map_api2result( rs );
                if ( sendok & LDAP_BACK_SENDERR ) {
                        if ( rs->sr_text == NULL ) {
-                               rs->sr_text = "ldap_initialize() failed";
+                               rs->sr_text = "Proxy connection initialization failed";
                        }
                        send_ldap_result( op, rs );
-                       rs->sr_text = NULL;
                }
 
        } else {
@@ -726,6 +726,7 @@ ldap_back_getconn(
                if ( dont_retry ) {
                        rs->sr_err = LDAP_UNAVAILABLE;
                        if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
+                               rs->sr_text = "Target is quarantined";
                                send_ldap_result( op, rs );
                        }
                        return NULL;
@@ -759,13 +760,13 @@ ldap_back_getconn(
                        op->o_ndn = op->o_req_ndn;
                }
                isproxyauthz = ldap_back_is_proxy_authz( op, rs, sendok, binddn, bindcred );
-               if ( isproxyauthz == -1 ) {
-                       return NULL;
-               }
                if ( op->o_tag == LDAP_REQ_BIND ) {
                        op->o_dn = save_o_dn;
                        op->o_ndn = save_o_ndn;
                }
+               if ( isproxyauthz == -1 ) {
+                       return NULL;
+               }
 
                lc_curr.lc_local_ndn = op->o_ndn;
                /* Explicit binds must not be shared;
@@ -1019,10 +1020,9 @@ retry_lock:
                                LDAP_BACK_CONN_CACHED_CLEAR( lc );
                                ldap_back_conn_free( lc );
                                rs->sr_err = LDAP_OTHER;
-                               rs->sr_text = "proxy bind collision";
+                               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;
                        }
@@ -1311,15 +1311,26 @@ retry_lock:;
 
                lutil_sasl_freedefs( defaults );
 
-               rs->sr_err = slap_map_api2result( rs );
-               if ( rs->sr_err != LDAP_SUCCESS ) {
+               switch ( rs->sr_err ) {
+               case LDAP_SUCCESS:
+                       LDAP_BACK_CONN_ISBOUND_SET( lc );
+                       break;
+
+               case LDAP_LOCAL_ERROR:
+                       /* list client API error codes that require
+                        * to taint the connection */
+                       /* FIXME: should actually retry? */
+                       LDAP_BACK_CONN_TAINTED_SET( lc );
+
+                       /* fallthru */
+
+               default:
                        LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
+                       rs->sr_err = slap_map_api2result( rs );
                        if ( sendok & LDAP_BACK_SENDERR ) {
                                send_ldap_result( op, rs );
                        }
-
-               } else {
-                       LDAP_BACK_CONN_ISBOUND_SET( lc );
+                       break;
                }
 
                if ( LDAP_BACK_QUARANTINE( li ) ) {
@@ -1350,6 +1361,7 @@ retry:;
                                /* lc here must be the regular lc, reset and ready for init */
                                rs->sr_err = ldap_back_prepare_conn( lc, op, rs, sendok );
                                if ( rs->sr_err != LDAP_SUCCESS ) {
+                                       sendok &= ~LDAP_BACK_SENDERR;
                                        lc->lc_refcnt = 0;
                                }
                        }
@@ -1379,6 +1391,7 @@ retry:;
                if ( rs->sr_err != LDAP_SUCCESS &&
                        ( sendok & LDAP_BACK_SENDERR ) )
                {
+                       rs->sr_text = "Internal proxy bind failure";
                        send_ldap_result( op, rs );
                }
 
@@ -1386,7 +1399,7 @@ retry:;
        }
 
        rc = ldap_back_op_result( lc, op, rs, msgid,
-               -1, (sendok|LDAP_BACK_BINDING) );
+               -1, ( sendok | LDAP_BACK_BINDING ) );
        if ( rc == LDAP_SUCCESS ) {
                LDAP_BACK_CONN_ISBOUND_SET( lc );
        }
@@ -1559,8 +1572,23 @@ retry:;
                                if ( sendok & LDAP_BACK_BINDING ) {
                                        ldap_unbind_ext( lc->lc_ld, NULL, NULL );
                                        lc->lc_ld = NULL;
+
+                                       /* 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, ">>> ldap_back_getconn(timeout)" );
+#endif /* LDAP_BACK_PRINT_CONNTREE */
+
+                                       (void)ldap_back_conn_delete( li, lc );
                                        LDAP_BACK_CONN_TAINTED_SET( 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 );
+
                                } else {
                                        (void)ldap_back_cancel( lc, op, rs, msgid, sendok );
                                }
@@ -1596,18 +1624,44 @@ retry:;
                        if ( rc != LDAP_SUCCESS ) {
                                rs->sr_err = rc;
                        }
-                       if ( refs != NULL ) {
-                               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 ] );
+
+                       /* 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 ldap_back_op_result: "
+                                               "got referrals with err=%d\n",
+                                               op->o_log_prefix,
+                                               rs->sr_err, 0 );
+
+                               } 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 ] );
+                                       }
+                                       BER_BVZERO( &rs->sr_ref[ i ] );
                                }
-                               BER_BVZERO( &rs->sr_ref[ i ] );
+
+                       } else if ( rs->sr_err == LDAP_REFERRAL ) {
+                               Debug( LDAP_DEBUG_ANY,
+                                       "%s ldap_back_op_result: "
+                                       "got err=%d with null "
+                                       "or empty referrals\n",
+                                       op->o_log_prefix,
+                                       rs->sr_err, 0 );
+
+                               rs->sr_err = LDAP_NO_SUCH_OBJECT;
                        }
+
                        if ( ctrls != NULL ) {
                                rs->sr_ctrls = ctrls;
                        }
@@ -1636,6 +1690,7 @@ retry:;
                                ldap_back_quarantine( op, rs );
                        }
                        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 );
                        }
                }
@@ -1661,12 +1716,14 @@ retry:;
        rs->sr_text = NULL;
 
        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 );
                ldap_controls_free( ctrls );
@@ -1681,8 +1738,7 @@ int
 ldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
 {
        ldapinfo_t      *li = (ldapinfo_t *)op->o_bd->be_private;
-       int             rc = 0,
-                       binding;
+       int             rc = 0;
 
        assert( lcp != NULL );
        assert( *lcp != NULL );
@@ -1690,7 +1746,7 @@ 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 );
+               int binding = LDAP_BACK_CONN_BINDING( *lcp );
 
                ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
                Debug( LDAP_DEBUG_ANY,
@@ -1739,9 +1795,9 @@ ldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_
                ldap_back_release_conn_lock( li, lcp, 0 );
                assert( *lcp == NULL );
 
-               if ( sendok ) {
+               if ( sendok & LDAP_BACK_SENDERR ) {
                        rs->sr_err = LDAP_UNAVAILABLE;
-                       rs->sr_text = "unable to retry";
+                       rs->sr_text = "Unable to retry";
                        send_ldap_result( op, rs );
                }
        }
@@ -1954,15 +2010,26 @@ ldap_back_proxy_authz_bind(
                                LDAP_SASL_QUIET, lutil_sasl_interact,
                                defaults );
 
-               rs->sr_err = slap_map_api2result( rs );
-               if ( rs->sr_err != LDAP_SUCCESS ) {
+               switch ( rs->sr_err ) {
+               case LDAP_SUCCESS:
+                       LDAP_BACK_CONN_ISBOUND_SET( lc );
+                       break;
+
+               case LDAP_LOCAL_ERROR:
+                       /* list client API error codes that require
+                        * to taint the connection */
+                       /* FIXME: should actually retry? */
+                       LDAP_BACK_CONN_TAINTED_SET( lc );
+
+                       /* fallthru */
+
+               default:
                        LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
+                       rs->sr_err = slap_map_api2result( rs );
                        if ( sendok & LDAP_BACK_SENDERR ) {
                                send_ldap_result( op, rs );
                        }
-
-               } else {
-                       LDAP_BACK_CONN_ISBOUND_SET( lc );
+                       break;
                }
 
                lutil_sasl_freedefs( defaults );
@@ -1986,7 +2053,7 @@ ldap_back_proxy_authz_bind(
                                binddn->bv_val, LDAP_SASL_SIMPLE,
                                bindcred, NULL, NULL, &msgid );
                rc = ldap_back_op_result( lc, op, rs, msgid,
-                       -1, (sendok|LDAP_BACK_BINDING) );
+                       -1, ( sendok | LDAP_BACK_BINDING ) );
                break;
 
        default:
@@ -2088,7 +2155,8 @@ ldap_back_proxy_authz_ctrl(
         * but if it is not set this test fails.  We need a different
         * means to detect if idassert is enabled */
        if ( ( BER_BVISNULL( &si->si_bc.sb_authcId ) || BER_BVISEMPTY( &si->si_bc.sb_authcId ) )
-                       && ( BER_BVISNULL( &si->si_bc.sb_binddn ) || BER_BVISEMPTY( &si->si_bc.sb_binddn ) ) )
+               && ( BER_BVISNULL( &si->si_bc.sb_binddn ) || BER_BVISEMPTY( &si->si_bc.sb_binddn ) )
+               && BER_BVISNULL( &si->si_bc.sb_saslmech ) )
        {
                goto done;
        }