Back to index

openldap  2.4.31
bind.c
Go to the documentation of this file.
00001 /* bind.c - ldap backend bind function */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 1999-2012 The OpenLDAP Foundation.
00006  * Portions Copyright 2000-2003 Pierangelo Masarati.
00007  * Portions Copyright 1999-2003 Howard Chu.
00008  * All rights reserved.
00009  *
00010  * Redistribution and use in source and binary forms, with or without
00011  * modification, are permitted only as authorized by the OpenLDAP
00012  * Public License.
00013  *
00014  * A copy of this license is available in the file LICENSE in the
00015  * top-level directory of the distribution or, alternatively, at
00016  * <http://www.OpenLDAP.org/license.html>.
00017  */
00018 /* ACKNOWLEDGEMENTS:
00019  * This work was initially developed by Howard Chu for inclusion
00020  * in OpenLDAP Software and subsequently enhanced by Pierangelo
00021  * Masarati.
00022  */
00023 
00024 #include "portable.h"
00025 
00026 #include <stdio.h>
00027 
00028 #include <ac/errno.h>
00029 #include <ac/socket.h>
00030 #include <ac/string.h>
00031 
00032 #define AVL_INTERNAL
00033 #include "slap.h"
00034 #include "back-ldap.h"
00035 #include "lutil.h"
00036 #include "lutil_ldap.h"
00037 
00038 #define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ "2.16.840.1.113730.3.4.12"
00039 
00040 #ifdef LDAP_DEVEL
00041 #define SLAP_AUTH_DN 1
00042 #endif
00043 
00044 #if LDAP_BACK_PRINT_CONNTREE > 0
00045 
00046 static const struct {
00047        slap_mask_t   f;
00048        char          c;
00049 } flagsmap[] = {
00050        { LDAP_BACK_FCONN_ISBOUND,  'B' },
00051        { LDAP_BACK_FCONN_ISANON,   'A' },
00052        { LDAP_BACK_FCONN_ISPRIV,   'P' },
00053        { LDAP_BACK_FCONN_ISTLS,    'T' },
00054        { LDAP_BACK_FCONN_BINDING,  'X' },
00055        { LDAP_BACK_FCONN_TAINTED,  'E' },
00056        { LDAP_BACK_FCONN_ABANDON,  'N' },
00057        { LDAP_BACK_FCONN_ISIDASR,  'S' },
00058        { LDAP_BACK_FCONN_CACHED,   'C' },
00059        { 0,                        '\0' }
00060 };
00061 
00062 static void
00063 ldap_back_conn_print( ldapconn_t *lc, const char *avlstr )
00064 {
00065        char buf[ SLAP_TEXT_BUFLEN ];
00066        char fbuf[ sizeof("BAPTIENSC") ];
00067        int i;
00068 
00069        ldap_back_conn2str( &lc->lc_base, buf, sizeof( buf ) );
00070        for ( i = 0; flagsmap[ i ].c != '\0'; i++ ) {
00071               if ( lc->lc_lcflags & flagsmap[i].f ) {
00072                      fbuf[i] = flagsmap[i].c;
00073 
00074               } else {
00075                      fbuf[i] = '.';
00076               }
00077        }
00078        fbuf[i] = '\0';
00079        
00080        fprintf( stderr, "lc=%p %s %s flags=0x%08x (%s)\n",
00081               (void *)lc, buf, avlstr, lc->lc_lcflags, fbuf );
00082 }
00083 
00084 static void
00085 ldap_back_ravl_print( Avlnode *root, int depth )
00086 {
00087        int           i;
00088        ldapconn_t    *lc;
00089        
00090        if ( root == 0 ) {
00091               return;
00092        }
00093        
00094        ldap_back_ravl_print( root->avl_right, depth+1 );
00095        
00096        for ( i = 0; i < depth; i++ ) {
00097               fprintf( stderr, "-" );
00098        }
00099 
00100        lc = root->avl_data;
00101        ldap_back_conn_print( lc, avl_bf2str( root->avl_bf ) );
00102 
00103        ldap_back_ravl_print( root->avl_left, depth + 1 );
00104 }
00105 
00106 static char* priv2str[] = {
00107        "privileged",
00108        "privileged/TLS",
00109        "anonymous",
00110        "anonymous/TLS",
00111        "bind",
00112        "bind/TLS",
00113        NULL
00114 };
00115 
00116 void
00117 ldap_back_print_conntree( ldapinfo_t *li, char *msg )
00118 {
00119        int    c;
00120 
00121        fprintf( stderr, "========> %s\n", msg );
00122 
00123        for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) {
00124               int           i = 0;
00125               ldapconn_t    *lc;
00126 
00127               fprintf( stderr, "  %s[%d]\n", priv2str[ c ], li->li_conn_priv[ c ].lic_num );
00128 
00129               LDAP_TAILQ_FOREACH( lc, &li->li_conn_priv[ c ].lic_priv, lc_q )
00130               {
00131                      fprintf( stderr, "    [%d] ", i );
00132                      ldap_back_conn_print( lc, "" );
00133                      i++;
00134               }
00135        }
00136        
00137        if ( li->li_conninfo.lai_tree == 0 ) {
00138               fprintf( stderr, "\t(empty)\n" );
00139 
00140        } else {
00141               ldap_back_ravl_print( li->li_conninfo.lai_tree, 0 );
00142        }
00143        
00144        fprintf( stderr, "<======== %s\n", msg );
00145 }
00146 #endif /* LDAP_BACK_PRINT_CONNTREE */
00147 
00148 static int
00149 ldap_back_freeconn( ldapinfo_t *li, ldapconn_t *lc, int dolock );
00150 
00151 static ldapconn_t *
00152 ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
00153        struct berval *binddn, struct berval *bindcred );
00154 
00155 static int
00156 ldap_back_is_proxy_authz( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
00157        struct berval *binddn, struct berval *bindcred );
00158 
00159 static int
00160 ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs,
00161        ldap_back_send_t sendok, struct berval *binddn, struct berval *bindcred );
00162 
00163 static int
00164 ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs,
00165        ldap_back_send_t sendok );
00166 
00167 static int
00168 ldap_back_conndnlc_cmp( const void *c1, const void *c2 );
00169 
00170 ldapconn_t *
00171 ldap_back_conn_delete( ldapinfo_t *li, ldapconn_t *lc )
00172 {
00173        if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
00174               if ( LDAP_BACK_CONN_CACHED( lc ) ) {
00175                      assert( lc->lc_q.tqe_prev != NULL );
00176                      assert( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num > 0 );
00177                      li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num--;
00178                      LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
00179                      LDAP_TAILQ_ENTRY_INIT( lc, lc_q );
00180                      LDAP_BACK_CONN_CACHED_CLEAR( lc );
00181 
00182               } else {
00183                      assert( LDAP_BACK_CONN_TAINTED( lc ) );
00184                      assert( lc->lc_q.tqe_prev == NULL );
00185               }
00186 
00187        } else {
00188               ldapconn_t    *tmplc = NULL;
00189 
00190               if ( LDAP_BACK_CONN_CACHED( lc ) ) {
00191                      assert( !LDAP_BACK_CONN_TAINTED( lc ) );
00192                      tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
00193                             ldap_back_conndnlc_cmp );
00194                      assert( tmplc == lc );
00195                      LDAP_BACK_CONN_CACHED_CLEAR( lc );
00196               }
00197 
00198               assert( LDAP_BACK_CONN_TAINTED( lc ) || tmplc == lc );
00199        }
00200 
00201        return lc;
00202 }
00203 
00204 int
00205 ldap_back_bind( Operation *op, SlapReply *rs )
00206 {
00207        ldapinfo_t           *li = (ldapinfo_t *) op->o_bd->be_private;
00208        ldapconn_t           *lc;
00209 
00210        LDAPControl          **ctrls = NULL;
00211        struct berval        save_o_dn;
00212        int                  save_o_do_not_cache,
00213                             rc = 0;
00214        ber_int_t            msgid;
00215        ldap_back_send_t     retrying = LDAP_BACK_RETRYING;
00216 
00217        /* allow rootdn as a means to auth without the need to actually
00218         * contact the proxied DSA */
00219        switch ( be_rootdn_bind( op, rs ) ) {
00220        case SLAP_CB_CONTINUE:
00221               break;
00222 
00223        default:
00224               return rs->sr_err;
00225        }
00226 
00227        lc = ldap_back_getconn( op, rs, LDAP_BACK_BIND_SERR, NULL, NULL );
00228        if ( !lc ) {
00229               return rs->sr_err;
00230        }
00231 
00232        /* we can do (almost) whatever we want with this conn,
00233         * because either it's temporary, or it's marked as binding */
00234        if ( !BER_BVISNULL( &lc->lc_bound_ndn ) ) {
00235               ch_free( lc->lc_bound_ndn.bv_val );
00236               BER_BVZERO( &lc->lc_bound_ndn );
00237        }
00238        if ( !BER_BVISNULL( &lc->lc_cred ) ) {
00239               memset( lc->lc_cred.bv_val, 0, lc->lc_cred.bv_len );
00240               ch_free( lc->lc_cred.bv_val );
00241               BER_BVZERO( &lc->lc_cred );
00242        }
00243        LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
00244 
00245        /* don't add proxyAuthz; set the bindDN */
00246        save_o_dn = op->o_dn;
00247        save_o_do_not_cache = op->o_do_not_cache;
00248        op->o_dn = op->o_req_dn;
00249        op->o_do_not_cache = 1;
00250 
00251        ctrls = op->o_ctrls;
00252        rc = ldap_back_controls_add( op, rs, lc, &ctrls );
00253        op->o_dn = save_o_dn;
00254        op->o_do_not_cache = save_o_do_not_cache;
00255        if ( rc != LDAP_SUCCESS ) {
00256               send_ldap_result( op, rs );
00257               ldap_back_release_conn( li, lc );
00258               return( rc );
00259        }
00260 
00261 retry:;
00262        /* method is always LDAP_AUTH_SIMPLE if we got here */
00263        rs->sr_err = ldap_sasl_bind( lc->lc_ld, op->o_req_dn.bv_val,
00264                      LDAP_SASL_SIMPLE,
00265                      &op->orb_cred, ctrls, NULL, &msgid );
00266        /* FIXME: should we always retry, or only when piping the bind
00267         * in the "override" connection pool? */
00268        rc = ldap_back_op_result( lc, op, rs, msgid,
00269               li->li_timeout[ SLAP_OP_BIND ],
00270               LDAP_BACK_BIND_SERR | retrying );
00271        if ( rc == LDAP_UNAVAILABLE && retrying ) {
00272               retrying &= ~LDAP_BACK_RETRYING;
00273               if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_BIND_SERR ) ) {
00274                      goto retry;
00275               }
00276        }
00277 
00278        ldap_back_controls_free( op, rs, &ctrls );
00279 
00280        if ( rc == LDAP_SUCCESS ) {
00281               op->o_conn->c_authz_cookie = op->o_bd->be_private;
00282 
00283               /* If defined, proxyAuthz will be used also when
00284                * back-ldap is the authorizing backend; for this
00285                * purpose, after a successful bind the connection
00286                * is left for further binds, and further operations 
00287                * on this client connection will use a default
00288                * connection with identity assertion */
00289               /* NOTE: use with care */
00290               if ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
00291                      ldap_back_release_conn( li, lc );
00292                      return( rc );
00293               }
00294 
00295               /* rebind is now done inside ldap_back_proxy_authz_bind()
00296                * in case of success */
00297               LDAP_BACK_CONN_ISBOUND_SET( lc );
00298               ber_dupbv( &lc->lc_bound_ndn, &op->o_req_ndn );
00299 
00300               if ( !BER_BVISNULL( &lc->lc_cred ) ) {
00301                      memset( lc->lc_cred.bv_val, 0,
00302                                    lc->lc_cred.bv_len );
00303               }
00304 
00305               if ( LDAP_BACK_SAVECRED( li ) ) {
00306                      ber_bvreplace( &lc->lc_cred, &op->orb_cred );
00307                      ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
00308 
00309               } else {
00310                      lc->lc_cred.bv_len = 0;
00311               }
00312        }
00313 
00314        /* must re-insert if local DN changed as result of bind */
00315        if ( !LDAP_BACK_CONN_ISBOUND( lc )
00316               || ( !dn_match( &op->o_req_ndn, &lc->lc_local_ndn )
00317                      && !LDAP_BACK_PCONN_ISPRIV( lc ) ) )
00318        {
00319               int           lerr = -1;
00320               ldapconn_t    *tmplc;
00321 
00322               /* wait for all other ops to release the connection */
00323 retry_lock:;
00324               ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
00325               if ( lc->lc_refcnt > 1 ) {
00326                      ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
00327                      ldap_pvt_thread_yield();
00328                      goto retry_lock;
00329               }
00330 
00331 #if LDAP_BACK_PRINT_CONNTREE > 0
00332               ldap_back_print_conntree( li, ">>> ldap_back_bind" );
00333 #endif /* LDAP_BACK_PRINT_CONNTREE */
00334 
00335               assert( lc->lc_refcnt == 1 );
00336               ldap_back_conn_delete( li, lc );
00337 
00338               /* delete all cached connections with the current connection */
00339               if ( LDAP_BACK_SINGLECONN( li ) ) {
00340                      while ( ( tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc, ldap_back_conn_cmp ) ) != NULL )
00341                      {
00342                             assert( !LDAP_BACK_PCONN_ISPRIV( lc ) );
00343                             Debug( LDAP_DEBUG_TRACE,
00344                                    "=>ldap_back_bind: destroying conn %lu (refcnt=%u)\n",
00345                                    lc->lc_conn->c_connid, lc->lc_refcnt, 0 );
00346 
00347                             if ( tmplc->lc_refcnt != 0 ) {
00348                                    /* taint it */
00349                                    LDAP_BACK_CONN_TAINTED_SET( tmplc );
00350                                    LDAP_BACK_CONN_CACHED_CLEAR( tmplc );
00351 
00352                             } else {
00353                                    /*
00354                                     * Needs a test because the handler may be corrupted,
00355                                     * and calling ldap_unbind on a corrupted header results
00356                                     * in a segmentation fault
00357                                     */
00358                                    ldap_back_conn_free( tmplc );
00359                             }
00360                      }
00361               }
00362 
00363               if ( LDAP_BACK_CONN_ISBOUND( lc ) ) {
00364                      ber_bvreplace( &lc->lc_local_ndn, &op->o_req_ndn );
00365                      if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) {
00366                             LDAP_BACK_PCONN_ROOTDN_SET( lc, op );
00367                      }
00368                      lerr = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
00369                             ldap_back_conndn_cmp, ldap_back_conndn_dup );
00370               }
00371 
00372 #if LDAP_BACK_PRINT_CONNTREE > 0
00373               ldap_back_print_conntree( li, "<<< ldap_back_bind" );
00374 #endif /* LDAP_BACK_PRINT_CONNTREE */
00375        
00376               ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
00377               switch ( lerr ) {
00378               case 0:
00379                      LDAP_BACK_CONN_CACHED_SET( lc );
00380                      break;
00381 
00382               case -1:
00383                      /* duplicate; someone else successfully bound
00384                       * on the same connection with the same identity;
00385                       * we can do this because lc_refcnt == 1 */
00386                      ldap_back_conn_free( lc );
00387                      lc = NULL;
00388               }
00389        }
00390 
00391        if ( lc != NULL ) {
00392               ldap_back_release_conn( li, lc );
00393        }
00394 
00395        return( rc );
00396 }
00397 
00398 /*
00399  * ldap_back_conndn_cmp
00400  *
00401  * compares two ldapconn_t based on the value of the conn pointer
00402  * and of the local DN; used by avl stuff for insert, lookup
00403  * and direct delete
00404  */
00405 int
00406 ldap_back_conndn_cmp( const void *c1, const void *c2 )
00407 {
00408        const ldapconn_t     *lc1 = (const ldapconn_t *)c1;
00409        const ldapconn_t     *lc2 = (const ldapconn_t *)c2;
00410        int rc;
00411 
00412        /* If local DNs don't match, it is definitely not a match */
00413        /* For shared sessions, conn is NULL. Only explicitly
00414         * bound sessions will have non-NULL conn.
00415         */
00416        rc = SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
00417        if ( rc == 0 ) {
00418               rc = ber_bvcmp( &lc1->lc_local_ndn, &lc2->lc_local_ndn );
00419        }
00420 
00421        return rc;
00422 }
00423 
00424 /*
00425  * ldap_back_conndnlc_cmp
00426  *
00427  * compares two ldapconn_t based on the value of the conn pointer,
00428  * the local DN and the lc pointer; used by avl stuff for insert, lookup
00429  * and direct delete
00430  */
00431 static int
00432 ldap_back_conndnlc_cmp( const void *c1, const void *c2 )
00433 {
00434        const ldapconn_t     *lc1 = (const ldapconn_t *)c1;
00435        const ldapconn_t     *lc2 = (const ldapconn_t *)c2;
00436        int rc;
00437 
00438        /* If local DNs don't match, it is definitely not a match */
00439        /* For shared sessions, conn is NULL. Only explicitly
00440         * bound sessions will have non-NULL conn.
00441         */
00442        rc = SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
00443        if ( rc == 0 ) {
00444               rc = ber_bvcmp( &lc1->lc_local_ndn, &lc2->lc_local_ndn );
00445               if ( rc == 0 ) {
00446                      rc = SLAP_PTRCMP( lc1, lc2 );
00447               }
00448        }
00449 
00450        return rc;
00451 }
00452 
00453 /*
00454  * ldap_back_conn_cmp
00455  *
00456  * compares two ldapconn_t based on the value of the conn pointer;
00457  * used by avl stuff for delete of all conns with the same connid
00458  */
00459 int
00460 ldap_back_conn_cmp( const void *c1, const void *c2 )
00461 {
00462        const ldapconn_t     *lc1 = (const ldapconn_t *)c1;
00463        const ldapconn_t     *lc2 = (const ldapconn_t *)c2;
00464 
00465        /* For shared sessions, conn is NULL. Only explicitly
00466         * bound sessions will have non-NULL conn.
00467         */
00468        return SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
00469 }
00470 
00471 /*
00472  * ldap_back_conndn_dup
00473  *
00474  * returns -1 in case a duplicate ldapconn_t has been inserted;
00475  * used by avl stuff
00476  */
00477 int
00478 ldap_back_conndn_dup( void *c1, void *c2 )
00479 {
00480        ldapconn_t    *lc1 = (ldapconn_t *)c1;
00481        ldapconn_t    *lc2 = (ldapconn_t *)c2;
00482 
00483        /* Cannot have more than one shared session with same DN */
00484        if ( lc1->lc_conn == lc2->lc_conn &&
00485               dn_match( &lc1->lc_local_ndn, &lc2->lc_local_ndn ) )
00486        {
00487               return -1;
00488        }
00489               
00490        return 0;
00491 }
00492 
00493 static int
00494 ldap_back_freeconn( ldapinfo_t *li, ldapconn_t *lc, int dolock )
00495 {
00496        if ( dolock ) {
00497               ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
00498        }
00499 
00500 #if LDAP_BACK_PRINT_CONNTREE > 0
00501        ldap_back_print_conntree( li, ">>> ldap_back_freeconn" );
00502 #endif /* LDAP_BACK_PRINT_CONNTREE */
00503 
00504        (void)ldap_back_conn_delete( li, lc );
00505 
00506        if ( lc->lc_refcnt == 0 ) {
00507               ldap_back_conn_free( (void *)lc );
00508        }
00509 
00510 #if LDAP_BACK_PRINT_CONNTREE > 0
00511        ldap_back_print_conntree( li, "<<< ldap_back_freeconn" );
00512 #endif /* LDAP_BACK_PRINT_CONNTREE */
00513 
00514        if ( dolock ) {
00515               ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
00516        }
00517 
00518        return 0;
00519 }
00520 
00521 #ifdef HAVE_TLS
00522 static int
00523 ldap_back_start_tls(
00524        LDAP          *ld,
00525        int           protocol,
00526        int           *is_tls,
00527        const char    *url,
00528        unsigned      flags,
00529        int           retries,
00530        const char    **text )
00531 {
00532        int           rc = LDAP_SUCCESS;
00533 
00534        /* start TLS ("tls-[try-]{start,propagate}" statements) */
00535        if ( ( LDAP_BACK_USE_TLS_F( flags ) || ( *is_tls && LDAP_BACK_PROPAGATE_TLS_F( flags ) ) )
00536                             && !ldap_is_ldaps_url( url ) )
00537        {
00538 #ifdef SLAP_STARTTLS_ASYNCHRONOUS
00539               /*
00540                * use asynchronous StartTLS
00541                * in case, chase referral (not implemented yet)
00542                */
00543               int           msgid;
00544 
00545               if ( protocol == 0 ) {
00546                      ldap_get_option( ld, LDAP_OPT_PROTOCOL_VERSION,
00547                                    (void *)&protocol );
00548               }
00549 
00550               if ( protocol < LDAP_VERSION3 ) {
00551                      /* we should rather bail out... */
00552                      rc = LDAP_UNWILLING_TO_PERFORM;
00553                      *text = "invalid protocol version";
00554               }
00555 
00556               if ( rc == LDAP_SUCCESS ) {
00557                      rc = ldap_start_tls( ld, NULL, NULL, &msgid );
00558               }
00559 
00560               if ( rc == LDAP_SUCCESS ) {
00561                      LDAPMessage   *res = NULL;
00562                      struct timeval       tv;
00563 
00564                      LDAP_BACK_TV_SET( &tv );
00565 
00566 retry:;
00567                      rc = ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res );
00568                      if ( rc < 0 ) {
00569                             rc = LDAP_UNAVAILABLE;
00570 
00571                      } else if ( rc == 0 ) {
00572                             if ( retries != LDAP_BACK_RETRY_NEVER ) {
00573                                    ldap_pvt_thread_yield();
00574                                    if ( retries > 0 ) {
00575                                           retries--;
00576                                    }
00577                                    LDAP_BACK_TV_SET( &tv );
00578                                    goto retry;
00579                             }
00580                             rc = LDAP_UNAVAILABLE;
00581 
00582                      } else if ( rc == LDAP_RES_EXTENDED ) {
00583                             struct berval *data = NULL;
00584 
00585                             rc = ldap_parse_extended_result( ld, res,
00586                                           NULL, &data, 0 );
00587                             if ( rc == LDAP_SUCCESS ) {
00588                                    SlapReply rs;
00589                                    rc = ldap_parse_result( ld, res, &rs.sr_err,
00590                                           NULL, NULL, NULL, NULL, 1 );
00591                                    if ( rc != LDAP_SUCCESS ) {
00592                                           rs.sr_err = rc;
00593                                    }
00594                                    rc = slap_map_api2result( &rs );
00595                                    res = NULL;
00596                                    
00597                                    /* FIXME: in case a referral 
00598                                     * is returned, should we try
00599                                     * using it instead of the 
00600                                     * configured URI? */
00601                                    if ( rc == LDAP_SUCCESS ) {
00602                                           rc = ldap_install_tls( ld );
00603 
00604                                    } else if ( rc == LDAP_REFERRAL ) {
00605                                           rc = LDAP_UNWILLING_TO_PERFORM;
00606                                           *text = "unwilling to chase referral returned by Start TLS exop";
00607                                    }
00608 
00609                                    if ( data ) {
00610                                           if ( data->bv_val ) {
00611                                                  ber_memfree( data->bv_val );
00612                                           }
00613                                           ber_memfree( data );
00614                                    }
00615                             }
00616 
00617                      } else {
00618                             rc = LDAP_OTHER;
00619                      }
00620 
00621                      if ( res != NULL ) {
00622                             ldap_msgfree( res );
00623                      }
00624               }
00625 #else /* ! SLAP_STARTTLS_ASYNCHRONOUS */
00626               /*
00627                * use synchronous StartTLS
00628                */
00629               rc = ldap_start_tls_s( ld, NULL, NULL );
00630 #endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */
00631 
00632               /* if StartTLS is requested, only attempt it if the URL
00633                * is not "ldaps://"; this may occur not only in case
00634                * of misconfiguration, but also when used in the chain 
00635                * overlay, where the "uri" can be parsed out of a referral */
00636               switch ( rc ) {
00637               case LDAP_SUCCESS:
00638                      *is_tls = 1;
00639                      break;
00640 
00641               case LDAP_SERVER_DOWN:
00642                      break;
00643 
00644               default:
00645                      if ( LDAP_BACK_TLS_CRITICAL_F( flags ) ) {
00646                             *text = "could not start TLS";
00647                             break;
00648                      }
00649 
00650                      /* in case Start TLS is not critical */
00651                      *is_tls = 0;
00652                      rc = LDAP_SUCCESS;
00653                      break;
00654               }
00655 
00656        } else {
00657               *is_tls = 0;
00658        }
00659 
00660        return rc;
00661 }
00662 #endif /* HAVE_TLS */
00663 
00664 static int
00665 ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
00666 {
00667        ldapinfo_t    *li = (ldapinfo_t *)op->o_bd->be_private;
00668        int           version;
00669        LDAP          *ld = NULL;
00670 #ifdef HAVE_TLS
00671        int           is_tls = op->o_conn->c_is_tls;
00672        int           flags = li->li_flags;
00673        time_t        lctime = (time_t)(-1);
00674        slap_bindconf *sb;
00675 #endif /* HAVE_TLS */
00676 
00677        ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
00678        rs->sr_err = ldap_initialize( &ld, li->li_uri );
00679        ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
00680        if ( rs->sr_err != LDAP_SUCCESS ) {
00681               goto error_return;
00682        }
00683 
00684        if ( li->li_urllist_f ) {
00685               ldap_set_urllist_proc( ld, li->li_urllist_f, li->li_urllist_p );
00686        }
00687 
00688        /* Set LDAP version. This will always succeed: If the client
00689         * bound with a particular version, then so can we.
00690         */
00691        if ( li->li_version != 0 ) {
00692               version = li->li_version;
00693 
00694        } else if ( op->o_protocol != 0 ) {
00695               version = op->o_protocol;
00696 
00697        } else {
00698               /* assume it's an internal op; set to LDAPv3 */
00699               version = LDAP_VERSION3;
00700        }
00701        ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&version );
00702 
00703        /* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */
00704        ldap_set_option( ld, LDAP_OPT_REFERRALS,
00705               LDAP_BACK_CHASE_REFERRALS( li ) ? LDAP_OPT_ON : LDAP_OPT_OFF );
00706 
00707        if ( li->li_network_timeout > 0 ) {
00708               struct timeval              tv;
00709 
00710               tv.tv_sec = li->li_network_timeout;
00711               tv.tv_usec = 0;
00712               ldap_set_option( ld, LDAP_OPT_NETWORK_TIMEOUT, (const void *)&tv );
00713        }
00714 
00715 #ifdef HAVE_TLS
00716        if ( LDAP_BACK_CONN_ISPRIV( lc ) ) {
00717               /* See "rationale" comment in ldap_back_getconn() */
00718               if ( li->li_acl_authmethod == LDAP_AUTH_NONE &&
00719                       li->li_idassert_authmethod != LDAP_AUTH_NONE )
00720                      sb = &li->li_idassert.si_bc;
00721               else
00722                      sb = &li->li_acl;
00723 
00724        } else if ( LDAP_BACK_CONN_ISIDASSERT( lc ) ) {
00725               sb = &li->li_idassert.si_bc;
00726 
00727        } else {
00728               sb = &li->li_tls;
00729        }
00730 
00731        if ( sb->sb_tls_do_init ) {
00732               bindconf_tls_set( sb, ld );
00733        } else if ( sb->sb_tls_ctx ) {
00734               ldap_set_option( ld, LDAP_OPT_X_TLS_CTX, sb->sb_tls_ctx );
00735        }
00736 
00737        /* if required by the bindconf configuration, force TLS */
00738        if ( ( sb == &li->li_acl || sb == &li->li_idassert.si_bc ) &&
00739               sb->sb_tls_ctx )
00740        {
00741               flags |= LDAP_BACK_F_USE_TLS;
00742        }
00743 
00744        ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
00745        assert( li->li_uri_mutex_do_not_lock == 0 );
00746        li->li_uri_mutex_do_not_lock = 1;
00747        rs->sr_err = ldap_back_start_tls( ld, op->o_protocol, &is_tls,
00748                      li->li_uri, flags, li->li_nretries, &rs->sr_text );
00749        li->li_uri_mutex_do_not_lock = 0;
00750        ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
00751        if ( rs->sr_err != LDAP_SUCCESS ) {
00752               ldap_unbind_ext( ld, NULL, NULL );
00753               rs->sr_text = "Start TLS failed";
00754               goto error_return;
00755 
00756        } else if ( li->li_idle_timeout ) {
00757               /* only touch when activity actually took place... */
00758               lctime = op->o_time;
00759        }
00760 #endif /* HAVE_TLS */
00761 
00762        lc->lc_ld = ld;
00763        lc->lc_refcnt = 1;
00764 #ifdef HAVE_TLS
00765        if ( is_tls ) {
00766               LDAP_BACK_CONN_ISTLS_SET( lc );
00767        } else {
00768               LDAP_BACK_CONN_ISTLS_CLEAR( lc );
00769        }
00770        if ( lctime != (time_t)(-1) ) {
00771               lc->lc_time = lctime;
00772        }
00773 #endif /* HAVE_TLS */
00774 
00775 error_return:;
00776        if ( rs->sr_err != LDAP_SUCCESS ) {
00777               rs->sr_err = slap_map_api2result( rs );
00778               if ( sendok & LDAP_BACK_SENDERR ) {
00779                      if ( rs->sr_text == NULL ) {
00780                             rs->sr_text = "Proxy connection initialization failed";
00781                      }
00782                      send_ldap_result( op, rs );
00783               }
00784 
00785        } else {
00786               if ( li->li_conn_ttl > 0 ) {
00787                      lc->lc_create_time = op->o_time;
00788               }
00789        }
00790 
00791        return rs->sr_err;
00792 }
00793 
00794 static ldapconn_t *
00795 ldap_back_getconn(
00796        Operation            *op,
00797        SlapReply            *rs,
00798        ldap_back_send_t     sendok,
00799        struct berval        *binddn,
00800        struct berval        *bindcred )
00801 {
00802        ldapinfo_t    *li = (ldapinfo_t *)op->o_bd->be_private;
00803        ldapconn_t    *lc = NULL,
00804                      lc_curr = {{ 0 }};
00805        int           refcnt = 1,
00806                      lookupconn = !( sendok & LDAP_BACK_BINDING );
00807 
00808        /* if the server is quarantined, and
00809         * - the current interval did not expire yet, or
00810         * - no more retries should occur,
00811         * don't return the connection */
00812        if ( li->li_isquarantined ) {
00813               slap_retry_info_t    *ri = &li->li_quarantine;
00814               int                  dont_retry = 1;
00815 
00816               if ( li->li_quarantine.ri_interval ) {
00817                      ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex );
00818                      if ( li->li_isquarantined == LDAP_BACK_FQ_YES ) {
00819                             dont_retry = ( ri->ri_num[ ri->ri_idx ] == SLAP_RETRYNUM_TAIL
00820                                    || slap_get_time() < ri->ri_last + ri->ri_interval[ ri->ri_idx ] );
00821                             if ( !dont_retry ) {
00822                                    Debug( LDAP_DEBUG_ANY,
00823                                           "%s: ldap_back_getconn quarantine "
00824                                           "retry block #%d try #%d.\n",
00825                                           op->o_log_prefix, ri->ri_idx, ri->ri_count );
00826                                    li->li_isquarantined = LDAP_BACK_FQ_RETRYING;
00827                             }
00828                      }
00829                      ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
00830               }
00831 
00832               if ( dont_retry ) {
00833                      rs->sr_err = LDAP_UNAVAILABLE;
00834                      if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
00835                             rs->sr_text = "Target is quarantined";
00836                             send_ldap_result( op, rs );
00837                      }
00838                      return NULL;
00839               }
00840        }
00841 
00842        /* Internal searches are privileged and shared. So is root. */
00843        if ( op->o_do_not_cache || be_isroot( op ) ) {
00844               LDAP_BACK_CONN_ISPRIV_SET( &lc_curr );
00845               lc_curr.lc_local_ndn = op->o_bd->be_rootndn;
00846               LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
00847 
00848        } else {
00849               struct berval tmpbinddn,
00850                             tmpbindcred,
00851                             save_o_dn,
00852                             save_o_ndn;
00853               int           isproxyauthz;
00854 
00855               /* need cleanup */
00856               if ( binddn == NULL ) {
00857                      binddn = &tmpbinddn;
00858               }      
00859               if ( bindcred == NULL ) {
00860                      bindcred = &tmpbindcred;
00861               }
00862               if ( op->o_tag == LDAP_REQ_BIND ) {
00863                      save_o_dn = op->o_dn;
00864                      save_o_ndn = op->o_ndn;
00865                      op->o_dn = op->o_req_dn;
00866                      op->o_ndn = op->o_req_ndn;
00867               }
00868               isproxyauthz = ldap_back_is_proxy_authz( op, rs, sendok, binddn, bindcred );
00869               if ( op->o_tag == LDAP_REQ_BIND ) {
00870                      op->o_dn = save_o_dn;
00871                      op->o_ndn = save_o_ndn;
00872               }
00873               if ( isproxyauthz == -1 ) {
00874                      return NULL;
00875               }
00876 
00877               lc_curr.lc_local_ndn = op->o_ndn;
00878               /* Explicit binds must not be shared;
00879                * however, explicit binds are piped in a special connection
00880                * when idassert is to occur with "override" set */
00881               if ( op->o_tag == LDAP_REQ_BIND && !isproxyauthz ) {
00882                      lc_curr.lc_conn = op->o_conn;
00883 
00884               } else {
00885                      if ( isproxyauthz && !( sendok & LDAP_BACK_BINDING ) ) {
00886                             lc_curr.lc_local_ndn = *binddn;
00887                             LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
00888                             LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );
00889 
00890                      } else if ( isproxyauthz && ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) {
00891                             lc_curr.lc_local_ndn = slap_empty_bv;
00892                             LDAP_BACK_PCONN_BIND_SET( &lc_curr, op );
00893                             LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );
00894                             lookupconn = 1;
00895 
00896                      } else if ( SLAP_IS_AUTHZ_BACKEND( op ) ) {
00897                             lc_curr.lc_conn = op->o_conn;
00898 
00899                      } else {
00900                             LDAP_BACK_PCONN_ANON_SET( &lc_curr, op );
00901                      }
00902               }
00903        }
00904 
00905        /* Explicit Bind requests always get their own conn */
00906        if ( lookupconn ) {
00907 retry_lock:
00908               ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
00909               if ( LDAP_BACK_PCONN_ISPRIV( &lc_curr ) ) {
00910                      /* lookup a conn that's not binding */
00911                      LDAP_TAILQ_FOREACH( lc,
00912                             &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv,
00913                             lc_q )
00914                      {
00915                             if ( !LDAP_BACK_CONN_BINDING( lc ) && lc->lc_refcnt == 0 ) {
00916                                    break;
00917                             }
00918                      }
00919 
00920                      if ( lc != NULL ) {
00921                             if ( lc != LDAP_TAILQ_LAST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
00922                                    ldapconn_t, lc_q ) )
00923                             {
00924                                    LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
00925                                           lc, lc_q );
00926                                    LDAP_TAILQ_ENTRY_INIT( lc, lc_q );
00927                                    LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
00928                                           lc, lc_q );
00929                             }
00930 
00931                      } else if ( !LDAP_BACK_USE_TEMPORARIES( li )
00932                             && li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_num == li->li_conn_priv_max )
00933                      {
00934                             lc = LDAP_TAILQ_FIRST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv );
00935                      }
00936                      
00937               } else {
00938 
00939                      /* Searches for a ldapconn in the avl tree */
00940                      lc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree, 
00941                                    (caddr_t)&lc_curr, ldap_back_conndn_cmp );
00942               }
00943 
00944               if ( lc != NULL ) {
00945                      /* Don't reuse connections while they're still binding */
00946                      if ( LDAP_BACK_CONN_BINDING( lc ) ) {
00947                             if ( !LDAP_BACK_USE_TEMPORARIES( li ) ) {
00948                                    ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
00949 
00950                                    ldap_pvt_thread_yield();
00951                                    goto retry_lock;
00952                             }
00953                             lc = NULL;
00954                      }
00955 
00956                      if ( lc != NULL ) {
00957                             if ( op->o_tag == LDAP_REQ_BIND ) {
00958                                    /* right now, this is the only possible case */
00959                                    assert( ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) );
00960                                    LDAP_BACK_CONN_BINDING_SET( lc );
00961                             }
00962 
00963                             refcnt = ++lc->lc_refcnt;
00964                      }
00965               }
00966               ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
00967        }
00968 
00969        /* Looks like we didn't get a bind. Open a new session... */
00970        if ( lc == NULL ) {
00971               lc = (ldapconn_t *)ch_calloc( 1, sizeof( ldapconn_t ) );
00972               lc->lc_flags = li->li_flags;
00973               lc->lc_lcflags = lc_curr.lc_lcflags;
00974               if ( ldap_back_prepare_conn( lc, op, rs, sendok ) != LDAP_SUCCESS ) {
00975                      ch_free( lc );
00976                      return NULL;
00977               }
00978 
00979               if ( sendok & LDAP_BACK_BINDING ) {
00980                      LDAP_BACK_CONN_BINDING_SET( lc );
00981               }
00982 
00983               lc->lc_conn = lc_curr.lc_conn;
00984               ber_dupbv( &lc->lc_local_ndn, &lc_curr.lc_local_ndn );
00985 
00986               /*
00987                * the rationale is: connections as the rootdn are privileged,
00988                * so li_acl is to be used; however, in some cases
00989                * one already configured identity assertion with a highly
00990                * privileged idassert_authcDN, so if li_acl is not configured
00991                * and idassert is, use idassert instead.
00992                *
00993                * might change in the future, because it's preferable
00994                * to make clear what identity is being used, since
00995                * the only drawback is that one risks to configure
00996                * the same identity twice...
00997                */
00998               if ( LDAP_BACK_CONN_ISPRIV( &lc_curr ) ) {
00999                      if ( li->li_acl_authmethod == LDAP_AUTH_NONE &&
01000                              li->li_idassert_authmethod != LDAP_AUTH_NONE ) {
01001                             ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN );
01002                             ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd );
01003 
01004                      } else {
01005                             ber_dupbv( &lc->lc_bound_ndn, &li->li_acl_authcDN );
01006                             ber_dupbv( &lc->lc_cred, &li->li_acl_passwd );
01007                      }
01008                      LDAP_BACK_CONN_ISPRIV_SET( lc );
01009 
01010               } else if ( LDAP_BACK_CONN_ISIDASSERT( &lc_curr ) ) {
01011                      if ( !LDAP_BACK_PCONN_ISBIND( &lc_curr ) ) {
01012                             ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN );
01013                             ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd );
01014                      }
01015                      LDAP_BACK_CONN_ISIDASSERT_SET( lc );
01016 
01017               } else {
01018                      BER_BVZERO( &lc->lc_cred );
01019                      BER_BVZERO( &lc->lc_bound_ndn );
01020                      if ( !BER_BVISEMPTY( &op->o_ndn )
01021                             && SLAP_IS_AUTHZ_BACKEND( op ) )
01022                      {
01023                             ber_dupbv( &lc->lc_bound_ndn, &op->o_ndn );
01024                      }
01025               }
01026 
01027 #ifdef HAVE_TLS
01028               /* if start TLS failed but it was not mandatory,
01029                * check if the non-TLS connection was already
01030                * in cache; in case, destroy the newly created
01031                * connection and use the existing one */
01032               if ( LDAP_BACK_PCONN_ISTLS( lc ) 
01033                             && !ldap_tls_inplace( lc->lc_ld ) )
01034               {
01035                      ldapconn_t    *tmplc = NULL;
01036                      int           idx = LDAP_BACK_CONN2PRIV( &lc_curr ) - 1;
01037                      
01038                      ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
01039                      LDAP_TAILQ_FOREACH( tmplc,
01040                             &li->li_conn_priv[ idx ].lic_priv,
01041                             lc_q )
01042                      {
01043                             if ( !LDAP_BACK_CONN_BINDING( tmplc ) ) {
01044                                    break;
01045                             }
01046                      }
01047 
01048                      if ( tmplc != NULL ) {
01049                             refcnt = ++tmplc->lc_refcnt;
01050                             ldap_back_conn_free( lc );
01051                             lc = tmplc;
01052                      }
01053                      ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
01054 
01055                      if ( tmplc != NULL ) {
01056                             goto done;
01057                      }
01058               }
01059 #endif /* HAVE_TLS */
01060 
01061               /* Inserts the newly created ldapconn in the avl tree */
01062               ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
01063 
01064               LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
01065 
01066               assert( lc->lc_refcnt == 1 );
01067 
01068 #if LDAP_BACK_PRINT_CONNTREE > 0
01069               ldap_back_print_conntree( li, ">>> ldap_back_getconn(insert)" );
01070 #endif /* LDAP_BACK_PRINT_CONNTREE */
01071        
01072               if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
01073                      if ( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num < li->li_conn_priv_max ) {
01074                             LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
01075                             li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num++;
01076                             LDAP_BACK_CONN_CACHED_SET( lc );
01077 
01078                      } else {
01079                             LDAP_BACK_CONN_TAINTED_SET( lc );
01080                      }
01081                      rs->sr_err = 0;
01082 
01083               } else {
01084                      rs->sr_err = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
01085                             ldap_back_conndn_cmp, ldap_back_conndn_dup );
01086                      LDAP_BACK_CONN_CACHED_SET( lc );
01087               }
01088 
01089 #if LDAP_BACK_PRINT_CONNTREE > 0
01090               ldap_back_print_conntree( li, "<<< ldap_back_getconn(insert)" );
01091 #endif /* LDAP_BACK_PRINT_CONNTREE */
01092        
01093               ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
01094 
01095               if ( LogTest( LDAP_DEBUG_TRACE ) ) {
01096                      char   buf[ SLAP_TEXT_BUFLEN ];
01097 
01098                      snprintf( buf, sizeof( buf ),
01099                             "lc=%p inserted refcnt=%u rc=%d",
01100                             (void *)lc, refcnt, rs->sr_err );
01101                             
01102                      Debug( LDAP_DEBUG_TRACE,
01103                             "=>ldap_back_getconn: %s: %s\n",
01104                             op->o_log_prefix, buf, 0 );
01105               }
01106        
01107               if ( !LDAP_BACK_PCONN_ISPRIV( lc ) ) {
01108                      /* Err could be -1 in case a duplicate ldapconn is inserted */
01109                      switch ( rs->sr_err ) {
01110                      case 0:
01111                             break;
01112 
01113                      case -1:
01114                             LDAP_BACK_CONN_CACHED_CLEAR( lc );
01115                             if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( li ) ) {
01116                                    /* duplicate: free and try to get the newly created one */
01117                                    ldap_back_conn_free( lc );
01118                                    lc = NULL;
01119                                    goto retry_lock;
01120                             }
01121 
01122                             /* taint connection, so that it'll be freed when released */
01123                             LDAP_BACK_CONN_TAINTED_SET( lc );
01124                             break;
01125 
01126                      default:
01127                             LDAP_BACK_CONN_CACHED_CLEAR( lc );
01128                             ldap_back_conn_free( lc );
01129                             rs->sr_err = LDAP_OTHER;
01130                             rs->sr_text = "Proxy bind collision";
01131                             if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
01132                                    send_ldap_result( op, rs );
01133                             }
01134                             return NULL;
01135                      }
01136               }
01137 
01138        } else {
01139               int    expiring = 0;
01140 
01141               if ( ( li->li_idle_timeout != 0 && op->o_time > lc->lc_time + li->li_idle_timeout )
01142                      || ( li->li_conn_ttl != 0 && op->o_time > lc->lc_create_time + li->li_conn_ttl ) )
01143               {
01144                      expiring = 1;
01145 
01146                      /* let it be used, but taint/delete it so that 
01147                       * no-one else can look it up any further */
01148                      ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
01149 
01150 #if LDAP_BACK_PRINT_CONNTREE > 0
01151                      ldap_back_print_conntree( li, ">>> ldap_back_getconn(timeout)" );
01152 #endif /* LDAP_BACK_PRINT_CONNTREE */
01153 
01154                      (void)ldap_back_conn_delete( li, lc );
01155                      LDAP_BACK_CONN_TAINTED_SET( lc );
01156 
01157 #if LDAP_BACK_PRINT_CONNTREE > 0
01158                      ldap_back_print_conntree( li, "<<< ldap_back_getconn(timeout)" );
01159 #endif /* LDAP_BACK_PRINT_CONNTREE */
01160 
01161                      ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
01162               }
01163 
01164               if ( LogTest( LDAP_DEBUG_TRACE ) ) {
01165                      char   buf[ SLAP_TEXT_BUFLEN ];
01166 
01167                      snprintf( buf, sizeof( buf ),
01168                             "conn %p fetched refcnt=%u%s",
01169                             (void *)lc, refcnt,
01170                             expiring ? " expiring" : "" );
01171                      Debug( LDAP_DEBUG_TRACE,
01172                             "=>ldap_back_getconn: %s.\n", buf, 0, 0 );
01173               }
01174        }
01175 
01176 #ifdef HAVE_TLS
01177 done:;
01178 #endif /* HAVE_TLS */
01179 
01180        return lc;
01181 }
01182 
01183 void
01184 ldap_back_release_conn_lock(
01185        ldapinfo_t           *li,
01186        ldapconn_t           **lcp,
01187        int                  dolock )
01188 {
01189 
01190        ldapconn_t    *lc = *lcp;
01191 
01192        if ( dolock ) {
01193               ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
01194        }
01195        assert( lc->lc_refcnt > 0 );
01196        LDAP_BACK_CONN_BINDING_CLEAR( lc );
01197        lc->lc_refcnt--;
01198        if ( LDAP_BACK_CONN_TAINTED( lc ) ) {
01199               ldap_back_freeconn( li, lc, 0 );
01200               *lcp = NULL;
01201        }
01202        if ( dolock ) {
01203               ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
01204        }
01205 }
01206 
01207 void
01208 ldap_back_quarantine(
01209        Operation     *op,
01210        SlapReply     *rs )
01211 {
01212        ldapinfo_t           *li = (ldapinfo_t *)op->o_bd->be_private;
01213 
01214        slap_retry_info_t    *ri = &li->li_quarantine;
01215 
01216        ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex );
01217 
01218        if ( rs->sr_err == LDAP_UNAVAILABLE ) {
01219               time_t        new_last = slap_get_time();
01220 
01221               switch ( li->li_isquarantined ) {
01222               case LDAP_BACK_FQ_NO:
01223                      if ( ri->ri_last == new_last ) {
01224                             goto done;
01225                      }
01226 
01227                      Debug( LDAP_DEBUG_ANY,
01228                             "%s: ldap_back_quarantine enter.\n",
01229                             op->o_log_prefix, 0, 0 );
01230 
01231                      ri->ri_idx = 0;
01232                      ri->ri_count = 0;
01233                      break;
01234 
01235               case LDAP_BACK_FQ_RETRYING:
01236                      Debug( LDAP_DEBUG_ANY,
01237                             "%s: ldap_back_quarantine block #%d try #%d failed.\n",
01238                             op->o_log_prefix, ri->ri_idx, ri->ri_count );
01239 
01240                      ++ri->ri_count;
01241                      if ( ri->ri_num[ ri->ri_idx ] != SLAP_RETRYNUM_FOREVER
01242                             && ri->ri_count == ri->ri_num[ ri->ri_idx ] )
01243                      {
01244                             ri->ri_count = 0;
01245                             ++ri->ri_idx;
01246                      }
01247                      break;
01248 
01249               default:
01250                      break;
01251               }
01252 
01253               li->li_isquarantined = LDAP_BACK_FQ_YES;
01254               ri->ri_last = new_last;
01255 
01256        } else if ( li->li_isquarantined != LDAP_BACK_FQ_NO ) {
01257               if ( ri->ri_last == slap_get_time() ) {
01258                      goto done;
01259               }
01260 
01261               Debug( LDAP_DEBUG_ANY,
01262                      "%s: ldap_back_quarantine exit (%d) err=%d.\n",
01263                      op->o_log_prefix, li->li_isquarantined, rs->sr_err );
01264 
01265               if ( li->li_quarantine_f ) {
01266                      (void)li->li_quarantine_f( li, li->li_quarantine_p );
01267               }
01268 
01269               ri->ri_count = 0;
01270               ri->ri_idx = 0;
01271               li->li_isquarantined = LDAP_BACK_FQ_NO;
01272        }
01273 
01274 done:;
01275        ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
01276 }
01277 
01278 static int
01279 ldap_back_dobind_cb(
01280        Operation *op,
01281        SlapReply *rs
01282 )
01283 {
01284        ber_tag_t *tptr = op->o_callback->sc_private;
01285        op->o_tag = *tptr;
01286        rs->sr_tag = slap_req2res( op->o_tag );
01287 
01288        return SLAP_CB_CONTINUE;
01289 }
01290 
01291 /*
01292  * ldap_back_dobind_int
01293  *
01294  * Note: dolock indicates whether li->li_conninfo.lai_mutex must be locked or not
01295  */
01296 static int
01297 ldap_back_dobind_int(
01298        ldapconn_t           **lcp,
01299        Operation            *op,
01300        SlapReply            *rs,
01301        ldap_back_send_t     sendok,
01302        int                  retries,
01303        int                  dolock )
01304 {      
01305        ldapinfo_t    *li = (ldapinfo_t *)op->o_bd->be_private;
01306 
01307        ldapconn_t    *lc;
01308        struct berval binddn = slap_empty_bv,
01309                      bindcred = slap_empty_bv;
01310 
01311        int           rc = 0,
01312                      isbound,
01313                      binding = 0;
01314        ber_int_t     msgid;
01315        ber_tag_t     o_tag = op->o_tag;
01316        slap_callback cb = {0};
01317        char          *tmp_dn;
01318 
01319        assert( lcp != NULL );
01320        assert( retries >= 0 );
01321 
01322        if ( sendok & LDAP_BACK_GETCONN ) {
01323               assert( *lcp == NULL );
01324 
01325               lc = ldap_back_getconn( op, rs, sendok, &binddn, &bindcred );
01326               if ( lc == NULL ) {
01327                      return 0;
01328               }
01329               *lcp = lc;
01330 
01331        } else {
01332               lc = *lcp;
01333        }
01334 
01335        assert( lc != NULL );
01336 
01337 retry_lock:;
01338        if ( dolock ) {
01339               ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
01340        }
01341 
01342        if ( binding == 0 ) {
01343               /* check if already bound */
01344               rc = isbound = LDAP_BACK_CONN_ISBOUND( lc );
01345               if ( isbound ) {
01346                      if ( dolock ) {
01347                             ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
01348                      }
01349                      return rc;
01350               }
01351 
01352               if ( LDAP_BACK_CONN_BINDING( lc ) ) {
01353                      /* if someone else is about to bind it, give up and retry */
01354                      if ( dolock ) {
01355                             ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
01356                      }
01357                      ldap_pvt_thread_yield();
01358                      goto retry_lock;
01359 
01360               } else {
01361                      /* otherwise this thread will bind it */
01362                      LDAP_BACK_CONN_BINDING_SET( lc );
01363                      binding = 1;
01364               }
01365        }
01366 
01367        if ( dolock ) {
01368               ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
01369        }
01370 
01371        /*
01372         * FIXME: we need to let clients use proxyAuthz
01373         * otherwise we cannot do symmetric pools of servers;
01374         * we have to live with the fact that a user can
01375         * authorize itself as any ID that is allowed
01376         * by the authzTo directive of the "proxyauthzdn".
01377         */
01378        /*
01379         * NOTE: current Proxy Authorization specification
01380         * and implementation do not allow proxy authorization
01381         * control to be provided with Bind requests
01382         */
01383        /*
01384         * if no bind took place yet, but the connection is bound
01385         * and the "idassert-authcDN" (or other ID) is set, 
01386         * then bind as the asserting identity and explicitly 
01387         * add the proxyAuthz control to every operation with the
01388         * dn bound to the connection as control value.
01389         * This is done also if this is the authorizing backend,
01390         * but the "override" flag is given to idassert.
01391         * It allows to use SASL bind and yet proxyAuthz users
01392         */
01393        op->o_tag = LDAP_REQ_BIND;
01394        cb.sc_next = op->o_callback;
01395        cb.sc_private = &o_tag;
01396        cb.sc_response = ldap_back_dobind_cb;
01397        op->o_callback = &cb;
01398 
01399        if ( LDAP_BACK_CONN_ISIDASSERT( lc ) ) {
01400               if ( BER_BVISEMPTY( &binddn ) && BER_BVISEMPTY( &bindcred ) ) {
01401                      /* if we got here, it shouldn't return result */
01402                      rc = ldap_back_is_proxy_authz( op, rs,
01403                             LDAP_BACK_DONTSEND, &binddn, &bindcred );
01404                      assert( rc == 1 );
01405               }
01406               rc = ldap_back_proxy_authz_bind( lc, op, rs, sendok, &binddn, &bindcred );
01407               goto done;
01408        }
01409 
01410 #ifdef HAVE_CYRUS_SASL
01411        if ( LDAP_BACK_CONN_ISPRIV( lc )) {
01412        slap_bindconf *sb;
01413        if ( li->li_acl_authmethod != LDAP_AUTH_NONE )
01414               sb = &li->li_acl;
01415        else
01416               sb = &li->li_idassert.si_bc;
01417 
01418        if ( sb->sb_method == LDAP_AUTH_SASL ) {
01419               void          *defaults = NULL;
01420 
01421               if ( sb->sb_secprops != NULL ) {
01422                      rc = ldap_set_option( lc->lc_ld,
01423                             LDAP_OPT_X_SASL_SECPROPS, sb->sb_secprops );
01424 
01425                      if ( rc != LDAP_OPT_SUCCESS ) {
01426                             Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option "
01427                                    "(SECPROPS,\"%s\") failed!\n",
01428                                    sb->sb_secprops, 0, 0 );
01429                             goto done;
01430                      }
01431               }
01432 
01433               defaults = lutil_sasl_defaults( lc->lc_ld,
01434                             sb->sb_saslmech.bv_val,
01435                             sb->sb_realm.bv_val,
01436                             sb->sb_authcId.bv_val,
01437                             sb->sb_cred.bv_val,
01438                             NULL );
01439               if ( defaults == NULL ) {
01440                      rs->sr_err = LDAP_OTHER;
01441                      LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
01442                      if ( sendok & LDAP_BACK_SENDERR ) {
01443                             send_ldap_result( op, rs );
01444                      }
01445                      goto done;
01446               }
01447 
01448               rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld,
01449                             sb->sb_binddn.bv_val,
01450                             sb->sb_saslmech.bv_val, NULL, NULL,
01451                             LDAP_SASL_QUIET, lutil_sasl_interact,
01452                             defaults );
01453 
01454               lutil_sasl_freedefs( defaults );
01455 
01456               switch ( rs->sr_err ) {
01457               case LDAP_SUCCESS:
01458                      LDAP_BACK_CONN_ISBOUND_SET( lc );
01459                      break;
01460 
01461               case LDAP_LOCAL_ERROR:
01462                      /* list client API error codes that require
01463                       * to taint the connection */
01464                      /* FIXME: should actually retry? */
01465                      LDAP_BACK_CONN_TAINTED_SET( lc );
01466 
01467                      /* fallthru */
01468 
01469               default:
01470                      LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
01471                      rs->sr_err = slap_map_api2result( rs );
01472                      if ( sendok & LDAP_BACK_SENDERR ) {
01473                             send_ldap_result( op, rs );
01474                      }
01475                      break;
01476               }
01477 
01478               if ( LDAP_BACK_QUARANTINE( li ) ) {
01479                      ldap_back_quarantine( op, rs );
01480               }
01481 
01482               goto done;
01483        }
01484        }
01485 #endif /* HAVE_CYRUS_SASL */
01486 
01487 retry:;
01488        if ( BER_BVISNULL( &lc->lc_cred ) ) {
01489               tmp_dn = "";
01490               if ( !BER_BVISNULL( &lc->lc_bound_ndn ) && !BER_BVISEMPTY( &lc->lc_bound_ndn ) ) {
01491                      Debug( LDAP_DEBUG_ANY, "%s ldap_back_dobind_int: DN=\"%s\" without creds, binding anonymously",
01492                             op->o_log_prefix, lc->lc_bound_ndn.bv_val, 0 );
01493               }
01494 
01495        } else {
01496               tmp_dn = lc->lc_bound_ndn.bv_val;
01497        }
01498        rs->sr_err = ldap_sasl_bind( lc->lc_ld,
01499                      tmp_dn,
01500                      LDAP_SASL_SIMPLE, &lc->lc_cred,
01501                      NULL, NULL, &msgid );
01502 
01503        if ( rs->sr_err == LDAP_SERVER_DOWN ) {
01504               if ( retries != LDAP_BACK_RETRY_NEVER ) {
01505                      if ( dolock ) {
01506                             ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
01507                      }
01508 
01509                      assert( lc->lc_refcnt > 0 );
01510                      if ( lc->lc_refcnt == 1 ) {
01511                             ldap_unbind_ext( lc->lc_ld, NULL, NULL );
01512                             lc->lc_ld = NULL;
01513 
01514                             /* lc here must be the regular lc, reset and ready for init */
01515                             rs->sr_err = ldap_back_prepare_conn( lc, op, rs, sendok );
01516                             if ( rs->sr_err != LDAP_SUCCESS ) {
01517                                    sendok &= ~LDAP_BACK_SENDERR;
01518                                    lc->lc_refcnt = 0;
01519                             }
01520                      }
01521 
01522                      if ( dolock ) {
01523                             ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
01524                      }
01525 
01526                      if ( rs->sr_err == LDAP_SUCCESS ) {
01527                             if ( retries > 0 ) {
01528                                    retries--;
01529                             }
01530                             goto retry;
01531                      }
01532               }
01533 
01534               assert( lc->lc_refcnt == 1 );
01535               lc->lc_refcnt = 0;
01536               ldap_back_freeconn( li, lc, dolock );
01537               *lcp = NULL;
01538               rs->sr_err = slap_map_api2result( rs );
01539 
01540               if ( LDAP_BACK_QUARANTINE( li ) ) {
01541                      ldap_back_quarantine( op, rs );
01542               }
01543 
01544               if ( rs->sr_err != LDAP_SUCCESS &&
01545                      ( sendok & LDAP_BACK_SENDERR ) )
01546               {
01547                      if ( op->o_callback == &cb )
01548                             op->o_callback = cb.sc_next;
01549                      op->o_tag = o_tag;
01550                      rs->sr_text = "Proxy can't contact remote server";
01551                      send_ldap_result( op, rs );
01552               }
01553 
01554               rc = 0;
01555               goto func_leave;
01556        }
01557 
01558        rc = ldap_back_op_result( lc, op, rs, msgid,
01559               -1, ( sendok | LDAP_BACK_BINDING ) );
01560        if ( rc == LDAP_SUCCESS ) {
01561               op->o_conn->c_authz_cookie = op->o_bd->be_private;
01562               LDAP_BACK_CONN_ISBOUND_SET( lc );
01563        }
01564 
01565 done:;
01566        LDAP_BACK_CONN_BINDING_CLEAR( lc );
01567        rc = LDAP_BACK_CONN_ISBOUND( lc );
01568        if ( !rc ) {
01569               ldap_back_release_conn_lock( li, lcp, dolock );
01570 
01571        } else if ( LDAP_BACK_SAVECRED( li ) ) {
01572               ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
01573        }
01574 
01575 func_leave:;
01576        if ( op->o_callback == &cb )
01577               op->o_callback = cb.sc_next;
01578        op->o_tag = o_tag;
01579 
01580        return rc;
01581 }
01582 
01583 /*
01584  * ldap_back_dobind
01585  *
01586  * Note: dolock indicates whether li->li_conninfo.lai_mutex must be locked or not
01587  */
01588 int
01589 ldap_back_dobind( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
01590 {
01591        ldapinfo_t    *li = (ldapinfo_t *)op->o_bd->be_private;
01592 
01593        return ldap_back_dobind_int( lcp, op, rs,
01594               ( sendok | LDAP_BACK_GETCONN ), li->li_nretries, 1 );
01595 }
01596 
01597 /*
01598  * ldap_back_default_rebind
01599  *
01600  * This is a callback used for chasing referrals using the same
01601  * credentials as the original user on this session.
01602  */
01603 int 
01604 ldap_back_default_rebind( LDAP *ld, LDAP_CONST char *url, ber_tag_t request,
01605        ber_int_t msgid, void *params )
01606 {
01607        ldapconn_t    *lc = (ldapconn_t *)params;
01608 
01609 #ifdef HAVE_TLS
01610        /* ... otherwise we couldn't get here */
01611        assert( lc != NULL );
01612 
01613        if ( !ldap_tls_inplace( ld ) ) {
01614               int           is_tls = LDAP_BACK_CONN_ISTLS( lc ),
01615                             rc;
01616               const char    *text = NULL;
01617 
01618               rc = ldap_back_start_tls( ld, 0, &is_tls, url, lc->lc_flags,
01619                      LDAP_BACK_RETRY_DEFAULT, &text );
01620               if ( rc != LDAP_SUCCESS ) {
01621                      return rc;
01622               }
01623        }
01624 #endif /* HAVE_TLS */
01625 
01626        /* FIXME: add checks on the URL/identity? */
01627 
01628        return ldap_sasl_bind_s( ld,
01629                      BER_BVISNULL( &lc->lc_cred ) ? "" : lc->lc_bound_ndn.bv_val,
01630                      LDAP_SASL_SIMPLE, &lc->lc_cred, NULL, NULL, NULL );
01631 }
01632 
01633 /*
01634  * ldap_back_default_urllist
01635  */
01636 int 
01637 ldap_back_default_urllist(
01638        LDAP          *ld,
01639        LDAPURLDesc   **urllist,
01640        LDAPURLDesc   **url,
01641        void          *params )
01642 {
01643        ldapinfo_t    *li = (ldapinfo_t *)params;
01644        LDAPURLDesc   **urltail;
01645 
01646        if ( urllist == url ) {
01647               return LDAP_SUCCESS;
01648        }
01649 
01650        for ( urltail = &(*url)->lud_next; *urltail; urltail = &(*urltail)->lud_next )
01651               /* count */ ;
01652 
01653        *urltail = *urllist;
01654        *urllist = *url;
01655        *url = NULL;
01656 
01657        if ( !li->li_uri_mutex_do_not_lock ) {
01658               ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
01659        }
01660 
01661        if ( li->li_uri ) {
01662               ch_free( li->li_uri );
01663        }
01664 
01665        ldap_get_option( ld, LDAP_OPT_URI, (void *)&li->li_uri );
01666 
01667        if ( !li->li_uri_mutex_do_not_lock ) {
01668               ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
01669        }
01670 
01671        return LDAP_SUCCESS;
01672 }
01673 
01674 int
01675 ldap_back_cancel(
01676               ldapconn_t           *lc,
01677               Operation            *op,
01678               SlapReply            *rs,
01679               ber_int_t            msgid,
01680               ldap_back_send_t     sendok )
01681 {
01682        ldapinfo_t    *li = (ldapinfo_t *)op->o_bd->be_private;
01683 
01684        /* default behavior */
01685        if ( LDAP_BACK_ABANDON( li ) ) {
01686               return ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL );
01687        }
01688 
01689        if ( LDAP_BACK_IGNORE( li ) ) {
01690               return ldap_pvt_discard( lc->lc_ld, msgid );
01691        }
01692 
01693        if ( LDAP_BACK_CANCEL( li ) ) {
01694               /* FIXME: asynchronous? */
01695               return ldap_cancel_s( lc->lc_ld, msgid, NULL, NULL );
01696        }
01697 
01698        assert( 0 );
01699 
01700        return LDAP_OTHER;
01701 }
01702 
01703 int
01704 ldap_back_op_result(
01705               ldapconn_t           *lc,
01706               Operation            *op,
01707               SlapReply            *rs,
01708               ber_int_t            msgid,
01709               time_t               timeout,
01710               ldap_back_send_t     sendok )
01711 {
01712        ldapinfo_t    *li = (ldapinfo_t *)op->o_bd->be_private;
01713 
01714        char          *match = NULL;
01715        char          *text = NULL;
01716        char          **refs = NULL;
01717        LDAPControl   **ctrls = NULL;
01718 
01719        rs->sr_text = NULL;
01720        rs->sr_matched = NULL;
01721        rs->sr_ref = NULL;
01722        rs->sr_ctrls = NULL;
01723 
01724        /* if the error recorded in the reply corresponds
01725         * to a successful state, get the error from the
01726         * remote server response */
01727        if ( LDAP_ERR_OK( rs->sr_err ) ) {
01728               int           rc;
01729               struct timeval       tv;
01730               LDAPMessage   *res = NULL;
01731               time_t        stoptime = (time_t)(-1);
01732               int           timeout_err = op->o_protocol >= LDAP_VERSION3 ?
01733                                    LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
01734               const char    *timeout_text = "Operation timed out";
01735 
01736               /* if timeout is not specified, compute and use
01737                * the one specific to the ongoing operation */
01738               if ( timeout == (time_t)(-1) ) {
01739                      slap_op_t     opidx = slap_req2op( op->o_tag );
01740 
01741                      if ( opidx == SLAP_OP_SEARCH ) {
01742                             if ( op->ors_tlimit <= 0 ) {
01743                                    timeout = 0;
01744 
01745                             } else {
01746                                    timeout = op->ors_tlimit;
01747                                    timeout_err = LDAP_TIMELIMIT_EXCEEDED;
01748                                    timeout_text = NULL;
01749                             }
01750 
01751                      } else {
01752                             timeout = li->li_timeout[ opidx ];
01753                      }
01754               }
01755 
01756               /* better than nothing :) */
01757               if ( timeout == 0 ) {
01758                      if ( li->li_idle_timeout ) {
01759                             timeout = li->li_idle_timeout;
01760 
01761                      } else if ( li->li_conn_ttl ) {
01762                             timeout = li->li_conn_ttl;
01763                      }
01764               }
01765 
01766               if ( timeout ) {
01767                      stoptime = op->o_time + timeout;
01768               }
01769 
01770               LDAP_BACK_TV_SET( &tv );
01771 
01772 retry:;
01773               /* if result parsing fails, note the failure reason */
01774               rc = ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
01775               switch ( rc ) {
01776               case 0:
01777                      if ( timeout && slap_get_time() > stoptime ) {
01778                             if ( sendok & LDAP_BACK_BINDING ) {
01779                                    ldap_unbind_ext( lc->lc_ld, NULL, NULL );
01780                                    lc->lc_ld = NULL;
01781 
01782                                    /* let it be used, but taint/delete it so that 
01783                                     * no-one else can look it up any further */
01784                                    ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
01785 
01786 #if LDAP_BACK_PRINT_CONNTREE > 0
01787                                    ldap_back_print_conntree( li, ">>> ldap_back_getconn(timeout)" );
01788 #endif /* LDAP_BACK_PRINT_CONNTREE */
01789 
01790                                    (void)ldap_back_conn_delete( li, lc );
01791                                    LDAP_BACK_CONN_TAINTED_SET( lc );
01792 
01793 #if LDAP_BACK_PRINT_CONNTREE > 0
01794                                    ldap_back_print_conntree( li, "<<< ldap_back_getconn(timeout)" );
01795 #endif /* LDAP_BACK_PRINT_CONNTREE */
01796                                    ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
01797 
01798                             } else {
01799                                    (void)ldap_back_cancel( lc, op, rs, msgid, sendok );
01800                             }
01801                             rs->sr_err = timeout_err;
01802                             rs->sr_text = timeout_text;
01803                             break;
01804                      }
01805 
01806                      /* timeout == 0 */
01807                      LDAP_BACK_TV_SET( &tv );
01808                      ldap_pvt_thread_yield();
01809                      goto retry;
01810 
01811               case -1:
01812                      ldap_get_option( lc->lc_ld, LDAP_OPT_ERROR_NUMBER,
01813                                    &rs->sr_err );
01814                      break;
01815 
01816 
01817               /* otherwise get the result; if it is not
01818                * LDAP_SUCCESS, record it in the reply
01819                * structure (this includes 
01820                * LDAP_COMPARE_{TRUE|FALSE}) */
01821               default:
01822                      /* only touch when activity actually took place... */
01823                      if ( li->li_idle_timeout && lc ) {
01824                             lc->lc_time = op->o_time;
01825                      }
01826 
01827                      rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err,
01828                                    &match, &text, &refs, &ctrls, 1 );
01829                      if ( rc == LDAP_SUCCESS ) {
01830                             rs->sr_text = text;
01831                      } else {
01832                             rs->sr_err = rc;
01833                      }
01834                      rs->sr_err = slap_map_api2result( rs );
01835 
01836                      /* RFC 4511: referrals can only appear
01837                       * if result code is LDAP_REFERRAL */
01838                      if ( refs != NULL
01839                             && refs[ 0 ] != NULL
01840                             && refs[ 0 ][ 0 ] != '\0' )
01841                      {
01842                             if ( rs->sr_err != LDAP_REFERRAL ) {
01843                                    Debug( LDAP_DEBUG_ANY,
01844                                           "%s ldap_back_op_result: "
01845                                           "got referrals with err=%d\n",
01846                                           op->o_log_prefix,
01847                                           rs->sr_err, 0 );
01848 
01849                             } else {
01850                                    int    i;
01851 
01852                                    for ( i = 0; refs[ i ] != NULL; i++ )
01853                                           /* count */ ;
01854                                    rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ),
01855                                           op->o_tmpmemctx );
01856                                    for ( i = 0; refs[ i ] != NULL; i++ ) {
01857                                           ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] );
01858                                    }
01859                                    BER_BVZERO( &rs->sr_ref[ i ] );
01860                             }
01861 
01862                      } else if ( rs->sr_err == LDAP_REFERRAL ) {
01863                             Debug( LDAP_DEBUG_ANY,
01864                                    "%s ldap_back_op_result: "
01865                                    "got err=%d with null "
01866                                    "or empty referrals\n",
01867                                    op->o_log_prefix,
01868                                    rs->sr_err, 0 );
01869 
01870                             rs->sr_err = LDAP_NO_SUCH_OBJECT;
01871                      }
01872 
01873                      if ( ctrls != NULL ) {
01874                             rs->sr_ctrls = ctrls;
01875                      }
01876               }
01877        }
01878 
01879        /* if the error in the reply structure is not
01880         * LDAP_SUCCESS, try to map it from client 
01881         * to server error */
01882        if ( !LDAP_ERR_OK( rs->sr_err ) ) {
01883               rs->sr_err = slap_map_api2result( rs );
01884 
01885               /* internal ops ( op->o_conn == NULL ) 
01886                * must not reply to client */
01887               if ( op->o_conn && !op->o_do_not_cache && match ) {
01888 
01889                      /* record the (massaged) matched
01890                       * DN into the reply structure */
01891                      rs->sr_matched = match;
01892               }
01893        }
01894 
01895        if ( rs->sr_err == LDAP_UNAVAILABLE ) {
01896               if ( !( sendok & LDAP_BACK_RETRYING ) ) {
01897                      if ( LDAP_BACK_QUARANTINE( li ) ) {
01898                             ldap_back_quarantine( op, rs );
01899                      }
01900                      if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
01901                             if ( rs->sr_text == NULL ) rs->sr_text = "Proxy operation retry failed";
01902                             send_ldap_result( op, rs );
01903                      }
01904               }
01905 
01906        } else if ( op->o_conn &&
01907               ( ( ( sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) )
01908                      || ( ( sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) )
01909        {
01910               send_ldap_result( op, rs );
01911        }
01912 
01913        if ( text ) {
01914               ldap_memfree( text );
01915        }
01916        rs->sr_text = NULL;
01917 
01918        /* there can't be refs with a (successful) bind */
01919        if ( rs->sr_ref ) {
01920               op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
01921               rs->sr_ref = NULL;
01922        }
01923 
01924        if ( refs ) {
01925               ber_memvfree( (void **)refs );
01926        }
01927 
01928        /* match should not be possible with a successful bind */
01929        if ( match ) {
01930               if ( rs->sr_matched != match ) {
01931                      free( (char *)rs->sr_matched );
01932               }
01933               rs->sr_matched = NULL;
01934               ldap_memfree( match );
01935        }
01936 
01937        if ( ctrls != NULL ) {
01938               if ( op->o_tag == LDAP_REQ_BIND && rs->sr_err == LDAP_SUCCESS ) {
01939                      int i;
01940 
01941                      for ( i = 0; ctrls[i] != NULL; i++ );
01942 
01943                      rs->sr_ctrls = op->o_tmpalloc( sizeof( LDAPControl * )*( i + 1 ),
01944                             op->o_tmpmemctx );
01945                      for ( i = 0; ctrls[ i ] != NULL; i++ ) {
01946                             char *ptr;
01947                             ber_len_t oidlen = strlen( ctrls[i]->ldctl_oid );
01948                             ber_len_t size = sizeof( LDAPControl )
01949                                    + oidlen + 1
01950                                    + ctrls[i]->ldctl_value.bv_len + 1;
01951        
01952                             rs->sr_ctrls[ i ] = op->o_tmpalloc( size, op->o_tmpmemctx );
01953                             rs->sr_ctrls[ i ]->ldctl_oid = (char *)&rs->sr_ctrls[ i ][ 1 ];
01954                             lutil_strcopy( rs->sr_ctrls[ i ]->ldctl_oid, ctrls[i]->ldctl_oid );
01955                             rs->sr_ctrls[ i ]->ldctl_value.bv_val
01956                                           = (char *)&rs->sr_ctrls[ i ]->ldctl_oid[oidlen + 1];
01957                             rs->sr_ctrls[ i ]->ldctl_value.bv_len
01958                                    = ctrls[i]->ldctl_value.bv_len;
01959                             ptr = lutil_memcopy( rs->sr_ctrls[ i ]->ldctl_value.bv_val,
01960                                    ctrls[i]->ldctl_value.bv_val, ctrls[i]->ldctl_value.bv_len );
01961                             *ptr = '\0';
01962                      }
01963                      rs->sr_ctrls[ i ] = NULL;
01964                      rs->sr_flags |= REP_CTRLS_MUSTBEFREED;
01965 
01966               } else {
01967                      assert( rs->sr_ctrls != NULL );
01968                      rs->sr_ctrls = NULL;
01969               }
01970 
01971               ldap_controls_free( ctrls );
01972        }
01973 
01974        return( LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err );
01975 }
01976 
01977 /* return true if bound, false if failed */
01978 int
01979 ldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
01980 {
01981        ldapinfo_t    *li = (ldapinfo_t *)op->o_bd->be_private;
01982        int           rc = 0;
01983 
01984        assert( lcp != NULL );
01985        assert( *lcp != NULL );
01986 
01987        ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
01988 
01989        if ( (*lcp)->lc_refcnt == 1 ) {
01990               int binding = LDAP_BACK_CONN_BINDING( *lcp );
01991 
01992               ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
01993               Debug( LDAP_DEBUG_ANY,
01994                      "%s ldap_back_retry: retrying URI=\"%s\" DN=\"%s\"\n",
01995                      op->o_log_prefix, li->li_uri,
01996                      BER_BVISNULL( &(*lcp)->lc_bound_ndn ) ?
01997                             "" : (*lcp)->lc_bound_ndn.bv_val );
01998               ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
01999 
02000               ldap_unbind_ext( (*lcp)->lc_ld, NULL, NULL );
02001               (*lcp)->lc_ld = NULL;
02002               LDAP_BACK_CONN_ISBOUND_CLEAR( (*lcp) );
02003 
02004               /* lc here must be the regular lc, reset and ready for init */
02005               rc = ldap_back_prepare_conn( *lcp, op, rs, sendok );
02006               if ( rc != LDAP_SUCCESS ) {
02007                      /* freeit, because lc_refcnt == 1 */
02008                      (*lcp)->lc_refcnt = 0;
02009                      (void)ldap_back_freeconn( li, *lcp, 0 );
02010                      *lcp = NULL;
02011                      rc = 0;
02012 
02013               } else if ( ( sendok & LDAP_BACK_BINDING ) ) {
02014                      if ( binding ) {
02015                             LDAP_BACK_CONN_BINDING_SET( *lcp );
02016                      }
02017                      rc = 1;
02018 
02019               } else {
02020                      rc = ldap_back_dobind_int( lcp, op, rs, sendok, 0, 0 );
02021                      if ( rc == 0 && *lcp != NULL ) {
02022                             /* freeit, because lc_refcnt == 1 */
02023                             (*lcp)->lc_refcnt = 0;
02024                             LDAP_BACK_CONN_TAINTED_SET( *lcp );
02025                             (void)ldap_back_freeconn( li, *lcp, 0 );
02026                             *lcp = NULL;
02027                      }
02028               }
02029 
02030        } else {
02031               Debug( LDAP_DEBUG_TRACE,
02032                      "ldap_back_retry: conn %p refcnt=%u unable to retry.\n",
02033                      (void *)(*lcp), (*lcp)->lc_refcnt, 0 );
02034 
02035               LDAP_BACK_CONN_TAINTED_SET( *lcp );
02036               ldap_back_release_conn_lock( li, lcp, 0 );
02037               assert( *lcp == NULL );
02038 
02039               if ( sendok & LDAP_BACK_SENDERR ) {
02040                      rs->sr_err = LDAP_UNAVAILABLE;
02041                      rs->sr_text = "Unable to retry";
02042                      send_ldap_result( op, rs );
02043               }
02044        }
02045 
02046        ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
02047 
02048        return rc;
02049 }
02050 
02051 static int
02052 ldap_back_is_proxy_authz( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
02053        struct berval *binddn, struct berval *bindcred )
02054 {
02055        ldapinfo_t    *li = (ldapinfo_t *)op->o_bd->be_private;
02056        struct berval ndn;
02057        int           dobind = 0;
02058 
02059        if ( op->o_conn == NULL || op->o_do_not_cache ) {
02060               goto done;
02061        }
02062 
02063        /* don't proxyAuthz if protocol is not LDAPv3 */
02064        switch ( li->li_version ) {
02065        case LDAP_VERSION3:
02066               break;
02067 
02068        case 0:
02069               if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
02070                      break;
02071               }
02072               /* fall thru */
02073 
02074        default:
02075               rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
02076               if ( sendok & LDAP_BACK_SENDERR ) {
02077                      send_ldap_result( op, rs );
02078                      dobind = -1;
02079               }
02080               goto done;
02081        }
02082 
02083        /* safe default */
02084        *binddn = slap_empty_bv;
02085        *bindcred = slap_empty_bv;
02086 
02087        if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
02088               ndn = op->o_conn->c_ndn;
02089 
02090        } else {
02091               ndn = op->o_ndn;
02092        }
02093 
02094        switch ( li->li_idassert_mode ) {
02095        case LDAP_BACK_IDASSERT_LEGACY:
02096               if ( !BER_BVISNULL( &ndn ) && !BER_BVISEMPTY( &ndn ) ) {
02097                      if ( !BER_BVISNULL( &li->li_idassert_authcDN ) && !BER_BVISEMPTY( &li->li_idassert_authcDN ) )
02098                      {
02099                             *binddn = li->li_idassert_authcDN;
02100                             *bindcred = li->li_idassert_passwd;
02101                             dobind = 1;
02102                      }
02103               }
02104               break;
02105 
02106        default:
02107               /* NOTE: rootdn can always idassert */
02108               if ( BER_BVISNULL( &ndn )
02109                      && li->li_idassert_authz == NULL
02110                      && !( li->li_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) )
02111               {
02112                      if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
02113                             rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
02114                             if ( sendok & LDAP_BACK_SENDERR ) {
02115                                    send_ldap_result( op, rs );
02116                                    dobind = -1;
02117                             }
02118 
02119                      } else {
02120                             rs->sr_err = LDAP_SUCCESS;
02121                             *binddn = slap_empty_bv;
02122                             *bindcred = slap_empty_bv;
02123                             break;
02124                      }
02125 
02126                      goto done;
02127 
02128               } else if ( !be_isroot( op ) ) {
02129                      if ( li->li_idassert_passthru ) {
02130                             struct berval authcDN;
02131 
02132                             if ( BER_BVISNULL( &ndn ) ) {
02133                                    authcDN = slap_empty_bv;
02134 
02135                             } else {
02136                                    authcDN = ndn;
02137                             }      
02138                             rs->sr_err = slap_sasl_matches( op, li->li_idassert_passthru,
02139                                           &authcDN, &authcDN );
02140                             if ( rs->sr_err == LDAP_SUCCESS ) {
02141                                    dobind = 0;
02142                                    break;
02143                             }
02144                      }
02145 
02146                      if ( li->li_idassert_authz ) {
02147                             struct berval authcDN;
02148 
02149                             if ( BER_BVISNULL( &ndn ) ) {
02150                                    authcDN = slap_empty_bv;
02151 
02152                             } else {
02153                                    authcDN = ndn;
02154                             }      
02155                             rs->sr_err = slap_sasl_matches( op, li->li_idassert_authz,
02156                                           &authcDN, &authcDN );
02157                             if ( rs->sr_err != LDAP_SUCCESS ) {
02158                                    if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
02159                                           if ( sendok & LDAP_BACK_SENDERR ) {
02160                                                  send_ldap_result( op, rs );
02161                                                  dobind = -1;
02162                                           }
02163 
02164                                    } else {
02165                                           rs->sr_err = LDAP_SUCCESS;
02166                                           *binddn = slap_empty_bv;
02167                                           *bindcred = slap_empty_bv;
02168                                           break;
02169                                    }
02170 
02171                                    goto done;
02172                             }
02173                      }
02174               }
02175 
02176               *binddn = li->li_idassert_authcDN;
02177               *bindcred = li->li_idassert_passwd;
02178               dobind = 1;
02179               break;
02180        }
02181 
02182 done:;
02183        return dobind;
02184 }
02185 
02186 static int
02187 ldap_back_proxy_authz_bind(
02188        ldapconn_t           *lc,
02189        Operation            *op,
02190        SlapReply            *rs,
02191        ldap_back_send_t     sendok,
02192        struct berval        *binddn,
02193        struct berval        *bindcred )
02194 {
02195        ldapinfo_t    *li = (ldapinfo_t *)op->o_bd->be_private;
02196        struct berval ndn;
02197        int           msgid;
02198        int           rc;
02199 
02200        if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
02201               ndn = op->o_conn->c_ndn;
02202 
02203        } else {
02204               ndn = op->o_ndn;
02205        }
02206 
02207        if ( li->li_idassert_authmethod == LDAP_AUTH_SASL ) {
02208 #ifdef HAVE_CYRUS_SASL
02209               void          *defaults = NULL;
02210               struct berval authzID = BER_BVNULL;
02211               int           freeauthz = 0;
02212               LDAPControl **ctrlsp = NULL;
02213               LDAPMessage *result = NULL;
02214               const char *rmech = NULL;
02215               const char *save_text = rs->sr_text;
02216 
02217 #ifdef SLAP_AUTH_DN
02218               LDAPControl ctrl, *ctrls[2];
02219               int msgid;
02220 #endif /* SLAP_AUTH_DN */
02221 
02222               /* if SASL supports native authz, prepare for it */
02223               if ( ( !op->o_do_not_cache || !op->o_is_auth_check ) &&
02224                             ( li->li_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) )
02225               {
02226                      switch ( li->li_idassert_mode ) {
02227                      case LDAP_BACK_IDASSERT_OTHERID:
02228                      case LDAP_BACK_IDASSERT_OTHERDN:
02229                             authzID = li->li_idassert_authzID;
02230                             break;
02231 
02232                      case LDAP_BACK_IDASSERT_ANONYMOUS:
02233                             BER_BVSTR( &authzID, "dn:" );
02234                             break;
02235 
02236                      case LDAP_BACK_IDASSERT_SELF:
02237                             if ( BER_BVISNULL( &ndn ) ) {
02238                                    /* connection is not authc'd, so don't idassert */
02239                                    BER_BVSTR( &authzID, "dn:" );
02240                                    break;
02241                             }
02242                             authzID.bv_len = STRLENOF( "dn:" ) + ndn.bv_len;
02243                             authzID.bv_val = slap_sl_malloc( authzID.bv_len + 1, op->o_tmpmemctx );
02244                             AC_MEMCPY( authzID.bv_val, "dn:", STRLENOF( "dn:" ) );
02245                             AC_MEMCPY( authzID.bv_val + STRLENOF( "dn:" ),
02246                                           ndn.bv_val, ndn.bv_len + 1 );
02247                             freeauthz = 1;
02248                             break;
02249 
02250                      default:
02251                             break;
02252                      }
02253               }
02254 
02255               if ( li->li_idassert_secprops != NULL ) {
02256                      rs->sr_err = ldap_set_option( lc->lc_ld,
02257                             LDAP_OPT_X_SASL_SECPROPS,
02258                             (void *)li->li_idassert_secprops );
02259 
02260                      if ( rs->sr_err != LDAP_OPT_SUCCESS ) {
02261                             rs->sr_err = LDAP_OTHER;
02262                             if ( sendok & LDAP_BACK_SENDERR ) {
02263                                    send_ldap_result( op, rs );
02264                             }
02265                             LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
02266                             goto done;
02267                      }
02268               }
02269 
02270               defaults = lutil_sasl_defaults( lc->lc_ld,
02271                             li->li_idassert_sasl_mech.bv_val,
02272                             li->li_idassert_sasl_realm.bv_val,
02273                             li->li_idassert_authcID.bv_val,
02274                             li->li_idassert_passwd.bv_val,
02275                             authzID.bv_val );
02276               if ( defaults == NULL ) {
02277                      rs->sr_err = LDAP_OTHER;
02278                      LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
02279                      if ( sendok & LDAP_BACK_SENDERR ) {
02280                             send_ldap_result( op, rs );
02281                      }
02282                      goto done;
02283               }
02284 
02285 #ifdef SLAP_AUTH_DN
02286               if ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_AUTHZID ) {
02287                      assert( BER_BVISNULL( binddn ) );
02288 
02289                      ctrl.ldctl_oid = LDAP_CONTROL_AUTHZID_REQUEST;
02290                      ctrl.ldctl_iscritical = 0;
02291                      BER_BVZERO( &ctrl.ldctl_value );
02292                      ctrls[0] = &ctrl;
02293                      ctrls[1] = NULL;
02294                      ctrlsp = ctrls;
02295               }
02296 #endif /* SLAP_AUTH_DN */
02297 
02298               do {
02299                      rs->sr_err = ldap_sasl_interactive_bind( lc->lc_ld, binddn->bv_val,
02300                             li->li_idassert_sasl_mech.bv_val, 
02301                             ctrlsp, NULL, LDAP_SASL_QUIET, lutil_sasl_interact, defaults,
02302                             result, &rmech, &msgid );
02303 
02304                      if ( rs->sr_err != LDAP_SASL_BIND_IN_PROGRESS )
02305                             break;
02306 
02307                      ldap_msgfree( result );
02308 
02309                      if ( ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) {
02310                             ldap_get_option( lc->lc_ld, LDAP_OPT_RESULT_CODE, (void*)&rs->sr_err );
02311                             ldap_get_option( lc->lc_ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*)&rs->sr_text );
02312                             break;
02313                      }
02314               } while ( rs->sr_err == LDAP_SASL_BIND_IN_PROGRESS );
02315 
02316               switch ( rs->sr_err ) {
02317               case LDAP_SUCCESS:
02318 #ifdef SLAP_AUTH_DN
02319                      /* FIXME: right now, the only reason to check
02320                       * response controls is RFC 3829 authzid */
02321                      if ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_AUTHZID ) {
02322                             ctrlsp = NULL;
02323                             rc = ldap_parse_result( lc->lc_ld, result, NULL, NULL, NULL, NULL,
02324                                    &ctrlsp, 0 );
02325                             if ( rc == LDAP_SUCCESS && ctrlsp ) {
02326                                    LDAPControl *ctrl;
02327               
02328                                    ctrl = ldap_control_find( LDAP_CONTROL_AUTHZID_RESPONSE,
02329                                           ctrlsp, NULL );
02330                                    if ( ctrl ) {
02331                                           Debug( LDAP_DEBUG_TRACE, "%s: ldap_back_proxy_authz_bind: authzID=\"%s\" (authzid)\n",
02332                                                  op->o_log_prefix, ctrl->ldctl_value.bv_val, 0 );
02333                                           if ( ctrl->ldctl_value.bv_len > STRLENOF("dn:") &&
02334                                                  strncasecmp( ctrl->ldctl_value.bv_val, "dn:", STRLENOF("dn:") ) == 0 )
02335                                           {
02336                                                  struct berval bv;
02337                                                  bv.bv_val = &ctrl->ldctl_value.bv_val[STRLENOF("dn:")];
02338                                                  bv.bv_len = ctrl->ldctl_value.bv_len - STRLENOF("dn:");
02339                                                  ber_bvreplace( &lc->lc_bound_ndn, &bv );
02340                                           }
02341                                    }
02342                             }
02343 
02344                             ldap_controls_free( ctrlsp );
02345 
02346                      } else if ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_WHOAMI ) {
02347                             struct berval *val = NULL;
02348                             rc = ldap_whoami_s( lc->lc_ld, &val, NULL, NULL );
02349                             if ( rc == LDAP_SUCCESS && val != NULL ) {
02350                                    Debug( LDAP_DEBUG_TRACE, "%s: ldap_back_proxy_authz_bind: authzID=\"%s\" (whoami)\n",
02351                                           op->o_log_prefix, val->bv_val, 0 );
02352                                    if ( val->bv_len > STRLENOF("dn:") &&
02353                                           strncasecmp( val->bv_val, "dn:", STRLENOF("dn:") ) == 0 )
02354                                    {
02355                                           struct berval bv;
02356                                           bv.bv_val = &val->bv_val[STRLENOF("dn:")];
02357                                           bv.bv_len = val->bv_len - STRLENOF("dn:");
02358                                           ber_bvreplace( &lc->lc_bound_ndn, &bv );
02359                                    }
02360                                    ber_bvfree( val );
02361                             }
02362                      }
02363 
02364                      if ( ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_MASK ) &&
02365                             BER_BVISNULL( &lc->lc_bound_ndn ) )
02366                      {
02367                             /* all in all, we only need it to be non-null */
02368                             /* FIXME: should this be configurable? */
02369                             static struct berval bv = BER_BVC("cn=authzdn");
02370                             ber_bvreplace( &lc->lc_bound_ndn, &bv );
02371                      }
02372 #endif /* SLAP_AUTH_DN */
02373                      op->o_conn->c_authz_cookie = op->o_bd->be_private;
02374                      LDAP_BACK_CONN_ISBOUND_SET( lc );
02375                      break;
02376 
02377               case LDAP_LOCAL_ERROR:
02378                      /* list client API error codes that require
02379                       * to taint the connection */
02380                      /* FIXME: should actually retry? */
02381                      LDAP_BACK_CONN_TAINTED_SET( lc );
02382 
02383                      /* fallthru */
02384 
02385               default:
02386                      LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
02387                      rs->sr_err = slap_map_api2result( rs );
02388                      if ( sendok & LDAP_BACK_SENDERR ) {
02389                             send_ldap_result( op, rs );
02390                      }
02391                      break;
02392               }
02393 
02394               if ( save_text != rs->sr_text ) {
02395                      ldap_memfree( (char *)rs->sr_text );
02396                      rs->sr_text = save_text;
02397               }
02398 
02399               ldap_msgfree( result );
02400 
02401               lutil_sasl_freedefs( defaults );
02402               if ( freeauthz ) {
02403                      slap_sl_free( authzID.bv_val, op->o_tmpmemctx );
02404               }
02405 
02406               goto done;
02407 #endif /* HAVE_CYRUS_SASL */
02408        }
02409 
02410        switch ( li->li_idassert_authmethod ) {
02411        case LDAP_AUTH_NONE:
02412               /* FIXME: do we really need this? */
02413               BER_BVSTR( binddn, "" );
02414               BER_BVSTR( bindcred, "" );
02415               /* fallthru */
02416 
02417        case LDAP_AUTH_SIMPLE:
02418               rs->sr_err = ldap_sasl_bind( lc->lc_ld,
02419                             binddn->bv_val, LDAP_SASL_SIMPLE,
02420                             bindcred, NULL, NULL, &msgid );
02421               rc = ldap_back_op_result( lc, op, rs, msgid,
02422                      -1, ( sendok | LDAP_BACK_BINDING ) );
02423               break;
02424 
02425        default:
02426               /* unsupported! */
02427               LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
02428               rs->sr_err = LDAP_AUTH_METHOD_NOT_SUPPORTED;
02429               if ( sendok & LDAP_BACK_SENDERR ) {
02430                      send_ldap_result( op, rs );
02431               }
02432               goto done;
02433        }
02434 
02435        if ( rc == LDAP_SUCCESS ) {
02436               /* set rebind stuff in case of successful proxyAuthz bind,
02437                * so that referral chasing is attempted using the right
02438                * identity */
02439               LDAP_BACK_CONN_ISBOUND_SET( lc );
02440               op->o_conn->c_authz_cookie = op->o_bd->be_private;
02441               if ( !BER_BVISNULL( binddn ) ) {
02442                      ber_bvreplace( &lc->lc_bound_ndn, binddn );
02443               }
02444 
02445               if ( !BER_BVISNULL( &lc->lc_cred ) ) {
02446                      memset( lc->lc_cred.bv_val, 0,
02447                                    lc->lc_cred.bv_len );
02448               }
02449 
02450               if ( LDAP_BACK_SAVECRED( li ) ) {
02451                      if ( !BER_BVISNULL( bindcred ) ) {
02452                             ber_bvreplace( &lc->lc_cred, bindcred );
02453                             ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
02454                      }
02455 
02456               } else {
02457                      lc->lc_cred.bv_len = 0;
02458               }
02459        }
02460 
02461 done:;
02462        return LDAP_BACK_CONN_ISBOUND( lc );
02463 }
02464 
02465 /*
02466  * ldap_back_proxy_authz_ctrl() prepends a proxyAuthz control
02467  * to existing server-side controls if required; if not,
02468  * the existing server-side controls are placed in *pctrls.
02469  * The caller, after using the controls in client API 
02470  * operations, if ( *pctrls != op->o_ctrls ), should
02471  * free( (*pctrls)[ 0 ] ) and free( *pctrls ).
02472  * The function returns success if the control could
02473  * be added if required, or if it did nothing; in the future,
02474  * it might return some error if it failed.
02475  * 
02476  * if no bind took place yet, but the connection is bound
02477  * and the "proxyauthzdn" is set, then bind as "proxyauthzdn" 
02478  * and explicitly add proxyAuthz the control to every operation
02479  * with the dn bound to the connection as control value.
02480  *
02481  * If no server-side controls are defined for the operation,
02482  * simply add the proxyAuthz control; otherwise, if the
02483  * proxyAuthz control is not already set, add it as
02484  * the first one
02485  *
02486  * FIXME: is controls order significant for security?
02487  * ANSWER: controls ordering and interoperability
02488  * must be indicated by the specs of each control; if none
02489  * is specified, the order is irrelevant.
02490  */
02491 int
02492 ldap_back_proxy_authz_ctrl(
02493               Operation     *op,
02494               SlapReply     *rs,
02495               struct berval *bound_ndn,
02496               int           version,
02497               slap_idassert_t      *si,
02498               LDAPControl   *ctrl )
02499 {
02500        slap_idassert_mode_t mode;
02501        struct berval        assertedID,
02502                             ndn;
02503        int                  isroot = 0;
02504 
02505        rs->sr_err = SLAP_CB_CONTINUE;
02506 
02507        /* FIXME: SASL/EXTERNAL over ldapi:// doesn't honor the authcID,
02508         * but if it is not set this test fails.  We need a different
02509         * means to detect if idassert is enabled */
02510        if ( ( BER_BVISNULL( &si->si_bc.sb_authcId ) || BER_BVISEMPTY( &si->si_bc.sb_authcId ) )
02511               && ( BER_BVISNULL( &si->si_bc.sb_binddn ) || BER_BVISEMPTY( &si->si_bc.sb_binddn ) )
02512               && BER_BVISNULL( &si->si_bc.sb_saslmech ) )
02513        {
02514               goto done;
02515        }
02516 
02517        if ( !op->o_conn || op->o_do_not_cache || ( isroot = be_isroot( op ) ) ) {
02518               goto done;
02519        }
02520 
02521        if ( op->o_tag == LDAP_REQ_BIND ) {
02522               ndn = op->o_req_ndn;
02523 
02524        } else if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
02525               ndn = op->o_conn->c_ndn;
02526 
02527        } else {
02528               ndn = op->o_ndn;
02529        }
02530 
02531        if ( si->si_mode == LDAP_BACK_IDASSERT_LEGACY ) {
02532               if ( op->o_proxy_authz ) {
02533                      /*
02534                       * FIXME: we do not want to perform proxyAuthz
02535                       * on behalf of the client, because this would
02536                       * be performed with "proxyauthzdn" privileges.
02537                       *
02538                       * This might actually be too strict, since
02539                       * the "proxyauthzdn" authzTo, and each entry's
02540                       * authzFrom attributes may be crafted
02541                       * to avoid unwanted proxyAuthz to take place.
02542                       */
02543 #if 0
02544                      rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
02545                      rs->sr_text = "proxyAuthz not allowed within namingContext";
02546 #endif
02547                      goto done;
02548               }
02549 
02550               if ( !BER_BVISNULL( bound_ndn ) ) {
02551                      goto done;
02552               }
02553 
02554               if ( BER_BVISNULL( &ndn ) ) {
02555                      goto done;
02556               }
02557 
02558               if ( BER_BVISNULL( &si->si_bc.sb_binddn ) ) {
02559                      goto done;
02560               }
02561 
02562        } else if ( si->si_bc.sb_method == LDAP_AUTH_SASL ) {
02563               if ( ( si->si_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) )
02564               {
02565                      /* already asserted in SASL via native authz */
02566                      goto done;
02567               }
02568 
02569        } else if ( si->si_authz && !isroot ) {
02570               int           rc;
02571               struct berval authcDN;
02572 
02573               if ( BER_BVISNULL( &ndn ) ) {
02574                      authcDN = slap_empty_bv;
02575               } else {
02576                      authcDN = ndn;
02577               }
02578               rc = slap_sasl_matches( op, si->si_authz,
02579                             &authcDN, &authcDN );
02580               if ( rc != LDAP_SUCCESS ) {
02581                      if ( si->si_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
02582                             /* ndn is not authorized
02583                              * to use idassert */
02584                             rs->sr_err = rc;
02585                      }
02586                      goto done;
02587               }
02588        }
02589 
02590        if ( op->o_proxy_authz ) {
02591               /*
02592                * FIXME: we can:
02593                * 1) ignore the already set proxyAuthz control
02594                * 2) leave it in place, and don't set ours
02595                * 3) add both
02596                * 4) reject the operation
02597                *
02598                * option (4) is very drastic
02599                * option (3) will make the remote server reject
02600                * the operation, thus being equivalent to (4)
02601                * option (2) will likely break the idassert
02602                * assumptions, so we cannot accept it;
02603                * option (1) means that we are contradicting
02604                * the client's reques.
02605                *
02606                * I think (4) is the only correct choice.
02607                */
02608               rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
02609               rs->sr_text = "proxyAuthz not allowed within namingContext";
02610        }
02611 
02612        if ( op->o_is_auth_check ) {
02613               mode = LDAP_BACK_IDASSERT_NOASSERT;
02614 
02615        } else {
02616               mode = si->si_mode;
02617        }
02618 
02619        switch ( mode ) {
02620        case LDAP_BACK_IDASSERT_LEGACY:
02621               /* original behavior:
02622                * assert the client's identity */
02623        case LDAP_BACK_IDASSERT_SELF:
02624               assertedID = ndn;
02625               break;
02626 
02627        case LDAP_BACK_IDASSERT_ANONYMOUS:
02628               /* assert "anonymous" */
02629               assertedID = slap_empty_bv;
02630               break;
02631 
02632        case LDAP_BACK_IDASSERT_NOASSERT:
02633               /* don't assert; bind as proxyauthzdn */
02634               goto done;
02635 
02636        case LDAP_BACK_IDASSERT_OTHERID:
02637        case LDAP_BACK_IDASSERT_OTHERDN:
02638               /* assert idassert DN */
02639               assertedID = si->si_bc.sb_authzId;
02640               break;
02641 
02642        default:
02643               assert( 0 );
02644        }
02645 
02646        /* if we got here, "" is allowed to proxyAuthz */
02647        if ( BER_BVISNULL( &assertedID ) ) {
02648               assertedID = slap_empty_bv;
02649        }
02650 
02651        /* don't idassert the bound DN (ITS#4497) */
02652        if ( dn_match( &assertedID, bound_ndn ) ) {
02653               goto done;
02654        }
02655 
02656        ctrl->ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
02657        ctrl->ldctl_iscritical = ( ( si->si_flags & LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL ) == LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL );
02658 
02659        switch ( si->si_mode ) {
02660        /* already in u:ID or dn:DN form */
02661        case LDAP_BACK_IDASSERT_OTHERID:
02662        case LDAP_BACK_IDASSERT_OTHERDN:
02663               ber_dupbv_x( &ctrl->ldctl_value, &assertedID, op->o_tmpmemctx );
02664               rs->sr_err = LDAP_SUCCESS;
02665               break;
02666 
02667        /* needs the dn: prefix */
02668        default:
02669               ctrl->ldctl_value.bv_len = assertedID.bv_len + STRLENOF( "dn:" );
02670               ctrl->ldctl_value.bv_val = op->o_tmpalloc( ctrl->ldctl_value.bv_len + 1,
02671                             op->o_tmpmemctx );
02672               AC_MEMCPY( ctrl->ldctl_value.bv_val, "dn:", STRLENOF( "dn:" ) );
02673               AC_MEMCPY( &ctrl->ldctl_value.bv_val[ STRLENOF( "dn:" ) ],
02674                             assertedID.bv_val, assertedID.bv_len + 1 );
02675               rs->sr_err = LDAP_SUCCESS;
02676               break;
02677        }
02678 
02679        /* Older versions of <draft-weltman-ldapv3-proxy> required
02680         * to encode the value of the authzID (and called it proxyDN);
02681         * this hack provides compatibility with those DSAs that
02682         * implement it this way */
02683        if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) {
02684               struct berval        authzID = ctrl->ldctl_value;
02685               BerElementBuffer     berbuf;
02686               BerElement           *ber = (BerElement *)&berbuf;
02687               ber_tag_t            tag;
02688 
02689               ber_init2( ber, 0, LBER_USE_DER );
02690               ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
02691 
02692               tag = ber_printf( ber, "O", &authzID );
02693               if ( tag == LBER_ERROR ) {
02694                      rs->sr_err = LDAP_OTHER;
02695                      goto free_ber;
02696               }
02697 
02698               if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) {
02699                      rs->sr_err = LDAP_OTHER;
02700                      goto free_ber;
02701               }
02702 
02703               rs->sr_err = LDAP_SUCCESS;
02704 
02705 free_ber:;
02706               op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx );
02707               ber_free_buf( ber );
02708 
02709               if ( rs->sr_err != LDAP_SUCCESS ) {
02710                      goto done;
02711               }
02712 
02713        } else if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) {
02714               struct berval        authzID = ctrl->ldctl_value,
02715                                    tmp;
02716               BerElementBuffer     berbuf;
02717               BerElement           *ber = (BerElement *)&berbuf;
02718               ber_tag_t            tag;
02719 
02720               if ( strncasecmp( authzID.bv_val, "dn:", STRLENOF( "dn:" ) ) != 0 ) {
02721                      rs->sr_err = LDAP_PROTOCOL_ERROR;
02722                      goto done;
02723               }
02724 
02725               tmp = authzID;
02726               tmp.bv_val += STRLENOF( "dn:" );
02727               tmp.bv_len -= STRLENOF( "dn:" );
02728 
02729               ber_init2( ber, 0, LBER_USE_DER );
02730               ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
02731 
02732               /* apparently, Mozilla API encodes this
02733                * as "SEQUENCE { LDAPDN }" */
02734               tag = ber_printf( ber, "{O}", &tmp );
02735               if ( tag == LBER_ERROR ) {
02736                      rs->sr_err = LDAP_OTHER;
02737                      goto free_ber2;
02738               }
02739 
02740               if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) {
02741                      rs->sr_err = LDAP_OTHER;
02742                      goto free_ber2;
02743               }
02744 
02745               ctrl->ldctl_oid = LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ;
02746               rs->sr_err = LDAP_SUCCESS;
02747 
02748 free_ber2:;
02749               op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx );
02750               ber_free_buf( ber );
02751 
02752               if ( rs->sr_err != LDAP_SUCCESS ) {
02753                      goto done;
02754               }
02755        }
02756 
02757 done:;
02758 
02759        return rs->sr_err;
02760 }
02761 
02762 /*
02763  * Add controls;
02764  *
02765  * if any needs to be added, it is prepended to existing ones,
02766  * in a newly allocated array.  The companion function
02767  * ldap_back_controls_free() must be used to restore the original
02768  * status of op->o_ctrls.
02769  */
02770 int
02771 ldap_back_controls_add(
02772               Operation     *op,
02773               SlapReply     *rs,
02774               ldapconn_t    *lc,
02775               LDAPControl   ***pctrls )
02776 {
02777        ldapinfo_t    *li = (ldapinfo_t *)op->o_bd->be_private;
02778 
02779        LDAPControl   **ctrls = NULL;
02780        /* set to the maximum number of controls this backend can add */
02781        LDAPControl   c[ 2 ] = { { 0 } };
02782        int           n = 0, i, j1 = 0, j2 = 0;
02783 
02784        *pctrls = NULL;
02785 
02786        rs->sr_err = LDAP_SUCCESS;
02787 
02788        /* don't add controls if protocol is not LDAPv3 */
02789        switch ( li->li_version ) {
02790        case LDAP_VERSION3:
02791               break;
02792 
02793        case 0:
02794               if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
02795                      break;
02796               }
02797               /* fall thru */
02798 
02799        default:
02800               goto done;
02801        }
02802 
02803        /* put controls that go __before__ existing ones here */
02804 
02805        /* proxyAuthz for identity assertion */
02806        switch ( ldap_back_proxy_authz_ctrl( op, rs, &lc->lc_bound_ndn,
02807               li->li_version, &li->li_idassert, &c[ j1 ] ) )
02808        {
02809        case SLAP_CB_CONTINUE:
02810               break;
02811 
02812        case LDAP_SUCCESS:
02813               j1++;
02814               break;
02815 
02816        default:
02817               goto done;
02818        }
02819 
02820        /* put controls that go __after__ existing ones here */
02821 
02822 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
02823        /* FIXME: according to <draft-wahl-ldap-session>, 
02824         * the server should check if the control can be added
02825         * based on the identity of the client and so */
02826 
02827        /* session tracking */
02828        if ( LDAP_BACK_ST_REQUEST( li ) ) {
02829               switch ( slap_ctrl_session_tracking_request_add( op, rs, &c[ j1 + j2 ] ) ) {
02830               case SLAP_CB_CONTINUE:
02831                      break;
02832 
02833               case LDAP_SUCCESS:
02834                      j2++;
02835                      break;
02836 
02837               default:
02838                      goto done;
02839               }
02840        }
02841 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
02842 
02843        if ( rs->sr_err == SLAP_CB_CONTINUE ) {
02844               rs->sr_err = LDAP_SUCCESS;
02845        }
02846 
02847        /* if nothing to do, just bail out */
02848        if ( j1 == 0 && j2 == 0 ) {
02849               goto done;
02850        }
02851 
02852        assert( j1 + j2 <= (int) (sizeof( c )/sizeof( c[0] )) );
02853 
02854        if ( op->o_ctrls ) {
02855               for ( n = 0; op->o_ctrls[ n ]; n++ )
02856                      /* just count ctrls */ ;
02857        }
02858 
02859        ctrls = op->o_tmpalloc( (n + j1 + j2 + 1) * sizeof( LDAPControl * ) + ( j1 + j2 ) * sizeof( LDAPControl ),
02860                      op->o_tmpmemctx );
02861        if ( j1 ) {
02862               ctrls[ 0 ] = (LDAPControl *)&ctrls[ n + j1 + j2 + 1 ];
02863               *ctrls[ 0 ] = c[ 0 ];
02864               for ( i = 1; i < j1; i++ ) {
02865                      ctrls[ i ] = &ctrls[ 0 ][ i ];
02866                      *ctrls[ i ] = c[ i ];
02867               }
02868        }
02869 
02870        i = 0;
02871        if ( op->o_ctrls ) {
02872               for ( i = 0; op->o_ctrls[ i ]; i++ ) {
02873                      ctrls[ i + j1 ] = op->o_ctrls[ i ];
02874               }
02875        }
02876 
02877        n += j1;
02878        if ( j2 ) {
02879               ctrls[ n ] = (LDAPControl *)&ctrls[ n + j2 + 1 ] + j1;
02880               *ctrls[ n ] = c[ j1 ];
02881               for ( i = 1; i < j2; i++ ) {
02882                      ctrls[ n + i ] = &ctrls[ n ][ i ];
02883                      *ctrls[ n + i ] = c[ i ];
02884               }
02885        }
02886 
02887        ctrls[ n + j2 ] = NULL;
02888 
02889 done:;
02890        if ( ctrls == NULL ) {
02891               ctrls = op->o_ctrls;
02892        }
02893 
02894        *pctrls = ctrls;
02895        
02896        return rs->sr_err;
02897 }
02898 
02899 int
02900 ldap_back_controls_free( Operation *op, SlapReply *rs, LDAPControl ***pctrls )
02901 {
02902        LDAPControl   **ctrls = *pctrls;
02903 
02904        /* we assume that the controls added by the proxy come first,
02905         * so as soon as we find op->o_ctrls[ 0 ] we can stop */
02906        if ( ctrls && ctrls != op->o_ctrls ) {
02907               int           i = 0, n = 0, n_added;
02908               LDAPControl   *lower, *upper;
02909 
02910               assert( ctrls[ 0 ] != NULL );
02911 
02912               for ( n = 0; ctrls[ n ] != NULL; n++ )
02913                      /* count 'em */ ;
02914 
02915               if ( op->o_ctrls ) {
02916                      for ( i = 0; op->o_ctrls[ i ] != NULL; i++ )
02917                             /* count 'em */ ;
02918               }
02919 
02920               n_added = n - i;
02921               lower = (LDAPControl *)&ctrls[ n ];
02922               upper = &lower[ n_added ];
02923 
02924               for ( i = 0; ctrls[ i ] != NULL; i++ ) {
02925                      if ( ctrls[ i ] < lower || ctrls[ i ] >= upper ) {
02926                             /* original; don't touch */
02927                             continue;
02928                      }
02929 
02930                      if ( !BER_BVISNULL( &ctrls[ i ]->ldctl_value ) ) {
02931                             op->o_tmpfree( ctrls[ i ]->ldctl_value.bv_val, op->o_tmpmemctx );
02932                      }
02933               }
02934 
02935               op->o_tmpfree( ctrls, op->o_tmpmemctx );
02936        } 
02937 
02938        *pctrls = NULL;
02939 
02940        return 0;
02941 }
02942 
02943 int
02944 ldap_back_conn2str( const ldapconn_base_t *lc, char *buf, ber_len_t buflen )
02945 {
02946        char tbuf[ SLAP_TEXT_BUFLEN ];
02947        char *ptr = buf, *end = buf + buflen;
02948        int len;
02949 
02950        if ( ptr + sizeof("conn=") > end ) return -1;
02951        ptr = lutil_strcopy( ptr, "conn=" );
02952 
02953        len = ldap_back_connid2str( lc, ptr, (ber_len_t)(end - ptr) );
02954        ptr += len;
02955        if ( ptr >= end ) return -1;
02956 
02957        if ( !BER_BVISNULL( &lc->lcb_local_ndn ) ) {
02958               if ( ptr + sizeof(" DN=\"\"") + lc->lcb_local_ndn.bv_len > end ) return -1;
02959               ptr = lutil_strcopy( ptr, " DN=\"" );
02960               ptr = lutil_strncopy( ptr, lc->lcb_local_ndn.bv_val, lc->lcb_local_ndn.bv_len );
02961               *ptr++ = '"';
02962        }
02963 
02964        if ( lc->lcb_create_time != 0 ) {
02965               len = snprintf( tbuf, sizeof(tbuf), "%ld", lc->lcb_create_time );
02966               if ( ptr + sizeof(" created=") + len >= end ) return -1;
02967               ptr = lutil_strcopy( ptr, " created=" );
02968               ptr = lutil_strcopy( ptr, tbuf );
02969        }
02970 
02971        if ( lc->lcb_time != 0 ) {
02972               len = snprintf( tbuf, sizeof(tbuf), "%ld", lc->lcb_time );
02973               if ( ptr + sizeof(" modified=") + len >= end ) return -1;
02974               ptr = lutil_strcopy( ptr, " modified=" );
02975               ptr = lutil_strcopy( ptr, tbuf );
02976        }
02977 
02978        len = snprintf( tbuf, sizeof(tbuf), "%u", lc->lcb_refcnt );
02979        if ( ptr + sizeof(" refcnt=") + len >= end ) return -1;
02980        ptr = lutil_strcopy( ptr, " refcnt=" );
02981        ptr = lutil_strcopy( ptr, tbuf );
02982 
02983        return ptr - buf;
02984 }
02985 
02986 int
02987 ldap_back_connid2str( const ldapconn_base_t *lc, char *buf, ber_len_t buflen )
02988 {
02989        static struct berval conns[] = {
02990               BER_BVC("ROOTDN"),
02991               BER_BVC("ROOTDN-TLS"),
02992               BER_BVC("ANON"),
02993               BER_BVC("ANON-TLS"),
02994               BER_BVC("BIND"),
02995               BER_BVC("BIND-TLS"),
02996               BER_BVNULL
02997        };
02998 
02999        int len = 0;
03000 
03001        if ( LDAP_BACK_PCONN_ISPRIV( (const ldapconn_t *)lc ) ) {
03002               long cid;
03003               struct berval *bv;
03004 
03005               cid = (long)lc->lcb_conn;
03006               assert( cid >= LDAP_BACK_PCONN_FIRST && cid < LDAP_BACK_PCONN_LAST );
03007 
03008               bv = &conns[ cid ];
03009 
03010               if ( bv->bv_len >= buflen ) {
03011                      return bv->bv_len + 1;
03012               }
03013 
03014               len = bv->bv_len;
03015               lutil_strncopy( buf, bv->bv_val, bv->bv_len + 1 );
03016 
03017        } else {
03018               len = snprintf( buf, buflen, "%lu", lc->lcb_conn->c_connid );
03019        }
03020 
03021        return len;
03022 }