Diff for /servers/slapd/back-ldap/chain.c between versions 1.52 and 1.52.2.22

version 1.52, 2006/04/02 21:47:13 version 1.52.2.22, 2011/03/24 02:09:19
Line 1 Line 1
 /* chain.c - chain LDAP operations */  /* chain.c - chain LDAP operations */
 /* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/chain.c,v 1.51 2006/03/26 22:31:38 ando Exp $ */  /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.  /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *   *
  * Copyright 2003-2006 The OpenLDAP Foundation.   * Copyright 2003-2011 The OpenLDAP Foundation.
  * Portions Copyright 2003 Howard Chu.   * Portions Copyright 2003 Howard Chu.
  * All rights reserved.   * All rights reserved.
  *   *
Line 27 Line 27
 #include <ac/string.h>  #include <ac/string.h>
 #include <ac/socket.h>  #include <ac/socket.h>
   
   #include "lutil.h"
 #include "slap.h"  #include "slap.h"
 #include "back-ldap.h"  #include "back-ldap.h"
   
 #include "config.h"  #include "config.h"
   
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR  #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
Line 58 Line 58
 static int              sc_chainingBehavior;  static int              sc_chainingBehavior;
 #endif /*  LDAP_CONTROL_X_CHAINING_BEHAVIOR */  #endif /*  LDAP_CONTROL_X_CHAINING_BEHAVIOR */
   
 #define LDAP_CH_NONE                    ((void *)(0))  typedef enum {
 #define LDAP_CH_RES                     ((void *)(1))          LDAP_CH_NONE = 0,
 #define LDAP_CH_ERR                     ((void *)(2))          LDAP_CH_RES,
           LDAP_CH_ERR
   } ldap_chain_status_t;
   
 static BackendInfo      *lback;  static BackendInfo      *lback;
   
Line 87  typedef struct ldap_chain_t { Line 89  typedef struct ldap_chain_t {
         /* tree of configured[/generated?] "uri" info */          /* tree of configured[/generated?] "uri" info */
         ldap_avl_info_t         lc_lai;          ldap_avl_info_t         lc_lai;
   
           /* max depth in nested referrals chaining */
           int                     lc_max_depth;
   
         unsigned                lc_flags;          unsigned                lc_flags;
 #define LDAP_CHAIN_F_NONE               (0x00U)  #define LDAP_CHAIN_F_NONE               (0x00U)
 #define LDAP_CHAIN_F_CHAINING           (0x01U)  #define LDAP_CHAIN_F_CHAINING           (0x01U)
 #define LDAP_CHAIN_F_CACHE_URI          (0x10U)  #define LDAP_CHAIN_F_CACHE_URI          (0x02U)
   #define LDAP_CHAIN_F_RETURN_ERR         (0x04U)
   
 #define LDAP_CHAIN_CHAINING( lc )       ( ( (lc)->lc_flags & LDAP_CHAIN_F_CHAINING ) == LDAP_CHAIN_F_CHAINING )  #define LDAP_CHAIN_ISSET(lc, f)         ( ( (lc)->lc_flags & (f) ) == (f) )
 #define LDAP_CHAIN_CACHE_URI( lc )      ( ( (lc)->lc_flags & LDAP_CHAIN_F_CACHE_URI ) == LDAP_CHAIN_F_CACHE_URI )  #define LDAP_CHAIN_CHAINING( lc )       LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CHAINING )
   #define LDAP_CHAIN_CACHE_URI( lc )      LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CACHE_URI )
   #define LDAP_CHAIN_RETURN_ERR( lc )     LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_RETURN_ERR )
   
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR  #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
         LDAPControl             lc_chaining_ctrl;          LDAPControl             lc_chaining_ctrl;
Line 103  typedef struct ldap_chain_t { Line 111  typedef struct ldap_chain_t {
   
 static int ldap_chain_db_init_common( BackendDB *be );  static int ldap_chain_db_init_common( BackendDB *be );
 static int ldap_chain_db_init_one( BackendDB *be );  static int ldap_chain_db_init_one( BackendDB *be );
 #define ldap_chain_db_open_one(be)      (lback)->bi_db_open( (be) )  static int ldap_chain_db_open_one( BackendDB *be );
 #define ldap_chain_db_close_one(be)     (0)  #define ldap_chain_db_close_one(be)     (0)
 #define ldap_chain_db_destroy_one(be)   (lback)->bi_db_destroy( (be) )  #define ldap_chain_db_destroy_one(be, rs)       (lback)->bi_db_destroy( (be), (rs) )
   
   typedef struct ldap_chain_cb_t {
           ldap_chain_status_t     lb_status;
           ldap_chain_t            *lb_lc;
           BI_op_func              *lb_op_f;
           int                     lb_depth;
   } ldap_chain_cb_t;
   
   static int
   ldap_chain_op(
           Operation       *op,
           SlapReply       *rs,
           BI_op_func      *op_f,
           BerVarray       ref,
           int             depth );
   
   static int
   ldap_chain_search(
           Operation       *op,
           SlapReply       *rs,
           BerVarray       ref,
           int             depth );
   
   static slap_overinst ldapchain;
   
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR  #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 static int  static int
Line 225  ldap_chain_uri_dup( void *c1, void *c2 ) Line 257  ldap_chain_uri_dup( void *c1, void *c2 )
 static int  static int
 ldap_chain_cb_search_response( Operation *op, SlapReply *rs )  ldap_chain_cb_search_response( Operation *op, SlapReply *rs )
 {  {
           ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
   
         assert( op->o_tag == LDAP_REQ_SEARCH );          assert( op->o_tag == LDAP_REQ_SEARCH );
   
         /* if in error, don't proceed any further */          /* if in error, don't proceed any further */
         if ( op->o_callback->sc_private == LDAP_CH_ERR ) {          if ( lb->lb_status == LDAP_CH_ERR ) {
                 return 0;                  return 0;
         }          }
   
Line 260  ldap_chain_cb_search_response( Operation Line 294  ldap_chain_cb_search_response( Operation
         } else if ( rs->sr_type == REP_SEARCHREF ) {          } else if ( rs->sr_type == REP_SEARCHREF ) {
                 /* if we get it here, it means the library was unable                  /* if we get it here, it means the library was unable
                  * to chase the referral... */                   * to chase the referral... */
                   if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) {
                           rs->sr_err = ldap_chain_search( op, rs, rs->sr_ref, lb->lb_depth );
                   }
   
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR  #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
                 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {                  if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
                         switch ( get_continuationBehavior( op ) ) {                          switch ( get_continuationBehavior( op ) ) {
                         case SLAP_CH_RESOLVE_CHAINING_REQUIRED:                          case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
                                 op->o_callback->sc_private = LDAP_CH_ERR;                                  lb->lb_status = LDAP_CH_ERR;
                                 return rs->sr_err = LDAP_X_CANNOT_CHAIN;                                  return rs->sr_err = LDAP_X_CANNOT_CHAIN;
   
                         default:                          default:
Line 276  ldap_chain_cb_search_response( Operation Line 313  ldap_chain_cb_search_response( Operation
                 return SLAP_CB_CONTINUE;                  return SLAP_CB_CONTINUE;
   
         } else if ( rs->sr_type == REP_RESULT ) {          } else if ( rs->sr_type == REP_RESULT ) {
                   if ( rs->sr_err == LDAP_REFERRAL
                           && lb->lb_depth < lb->lb_lc->lc_max_depth
                           && rs->sr_ref != NULL )
                   {
                           rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_f, rs->sr_ref, lb->lb_depth );
                   }
   
                 /* back-ldap tried to send result */                  /* back-ldap tried to send result */
                 op->o_callback->sc_private = LDAP_CH_RES;                  lb->lb_status = LDAP_CH_RES;
         }          }
   
         return 0;          return 0;
Line 290  ldap_chain_cb_search_response( Operation Line 334  ldap_chain_cb_search_response( Operation
 static int  static int
 ldap_chain_cb_response( Operation *op, SlapReply *rs )  ldap_chain_cb_response( Operation *op, SlapReply *rs )
 {  {
           ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
   
         /* if in error, don't proceed any further */          /* if in error, don't proceed any further */
         if ( op->o_callback->sc_private == LDAP_CH_ERR ) {          if ( lb->lb_status == LDAP_CH_ERR ) {
                 return 0;                  return 0;
         }          }
   
         if ( rs->sr_type == REP_RESULT ) {          if ( rs->sr_type == REP_RESULT ) {
   retry:;
                 switch ( rs->sr_err ) {                  switch ( rs->sr_err ) {
                 case LDAP_COMPARE_TRUE:                  case LDAP_COMPARE_TRUE:
                 case LDAP_COMPARE_FALSE:                  case LDAP_COMPARE_FALSE:
Line 305  ldap_chain_cb_response( Operation *op, S Line 352  ldap_chain_cb_response( Operation *op, S
                         /* fallthru */                          /* fallthru */
   
                 case LDAP_SUCCESS:                  case LDAP_SUCCESS:
                         op->o_callback->sc_private = LDAP_CH_RES;                          lb->lb_status = LDAP_CH_RES;
                         break;                          break;
   
                 case LDAP_REFERRAL:                  case LDAP_REFERRAL:
                           if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) {
                                   rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_f, rs->sr_ref, lb->lb_depth );
                                   goto retry;
                           }
   
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR  #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
                         if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {                          if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
                                 switch ( get_continuationBehavior( op ) ) {                                  switch ( get_continuationBehavior( op ) ) {
                                 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:                                  case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
                                         op->o_callback->sc_private = LDAP_CH_ERR;                                          lb->lb_status = LDAP_CH_ERR;
                                         return rs->sr_err = LDAP_X_CANNOT_CHAIN;                                          return rs->sr_err = LDAP_X_CANNOT_CHAIN;
   
                                 default:                                  default:
Line 341  ldap_chain_op( Line 393  ldap_chain_op(
         Operation       *op,          Operation       *op,
         SlapReply       *rs,          SlapReply       *rs,
         BI_op_func      *op_f,          BI_op_func      *op_f,
         BerVarray       ref )          BerVarray       ref,
           int             depth )
 {  {
         slap_overinst   *on = (slap_overinst *) op->o_bd->bd_info;          slap_overinst   *on = (slap_overinst *) op->o_bd->bd_info;
           ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
         ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;          ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
           struct berval   odn = op->o_req_dn,
                           ondn = op->o_req_ndn;
         ldapinfo_t      li = { 0 }, *lip = NULL;          ldapinfo_t      li = { 0 }, *lip = NULL;
         struct berval   bvuri[ 2 ] = { { 0 } };          struct berval   bvuri[ 2 ] = { { 0 } };
   
         /* NOTE: returned if ref is empty... */          /* NOTE: returned if ref is empty... */
         int             rc = LDAP_OTHER;          int             rc = LDAP_OTHER,
                           first_rc;
   
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR  #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
         LDAPControl     **ctrls = NULL;          LDAPControl     **ctrls = NULL;
Line 358  ldap_chain_op( Line 415  ldap_chain_op(
 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */  #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
   
         li.li_bvuri = bvuri;          li.li_bvuri = bvuri;
           first_rc = -1;
         for ( ; !BER_BVISNULL( ref ); ref++ ) {          for ( ; !BER_BVISNULL( ref ); ref++ ) {
                 LDAPURLDesc     *srv;                  SlapReply       rs2 = { 0 };
                 char            *save_dn;                  LDAPURLDesc     *srv = NULL;
                   req_search_s    save_oq_search = op->oq_search,
                                   tmp_oq_search = { 0 };
                   struct berval   dn = BER_BVNULL,
                                   pdn = odn,
                                   ndn = ondn;
                   char            *filter = NULL;
                 int             temporary = 0;                  int             temporary = 0;
                   int             free_dn = 0;
                                                   
                 /* We're setting the URI of the first referral;                  /* We're setting the URI of the first referral;
                  * what if there are more?                   * what if there are more?
   
 Document: draft-ietf-ldapbis-protocol-27.txt  Document: RFC 4511
   
 4.1.10. Referral   4.1.10. Referral 
    ...     ...
Line 381  Document: draft-ietf-ldapbis-protocol-27 Line 446  Document: draft-ietf-ldapbis-protocol-27
                   
                 /* parse reference and use                   /* parse reference and use 
                  * proto://[host][:port]/ only */                   * proto://[host][:port]/ only */
                 rc = ldap_url_parse_ext( ref->bv_val, &srv );                  rc = ldap_url_parse_ext( ref->bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
                 if ( rc != LDAP_URL_SUCCESS ) {                  if ( rc != LDAP_URL_SUCCESS ) {
                           Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: unable to parse ref=\"%s\"\n",
                                   op->o_log_prefix, ref->bv_val, 0 );
   
                         /* try next */                          /* try next */
                         rc = LDAP_OTHER;                          rc = LDAP_OTHER;
                         continue;                          continue;
                 }                  }
   
                 /* remove DN essentially because later on                   if ( op->o_tag == LDAP_REQ_SEARCH ) {
                  * ldap_initialize() will parse the URL                           if ( srv->lud_scope != LDAP_SCOPE_DEFAULT ) {
                  * as a comma-separated URL list */                                  /* RFC 4511: if scope is present, use it */
                 save_dn = srv->lud_dn;                                  tmp_oq_search.rs_scope = srv->lud_scope;
                 srv->lud_dn = "";  
                           } else {
                                   /* RFC 4511: if scope is absent, use original */
                                   tmp_oq_search.rs_scope = op->ors_scope;
                           }
                   }
   
                   rc = LDAP_SUCCESS;
                 srv->lud_scope = LDAP_SCOPE_DEFAULT;                  srv->lud_scope = LDAP_SCOPE_DEFAULT;
                 li.li_uri = ldap_url_desc2str( srv );                  dn.bv_val = srv->lud_dn;
                 srv->lud_dn = save_dn;                  filter = srv->lud_filter;
   
                   /* normalize DN */
                   if ( srv->lud_dn == NULL || srv->lud_dn[0] == '\0' ) {
                           if ( srv->lud_dn == NULL ) {
                                   srv->lud_dn = "";
                           }
   
                   } else {
                           ber_str2bv( srv->lud_dn, 0, 0, &dn );
                           rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
                           if ( rc == LDAP_SUCCESS ) {
                                   /* remove DN essentially because later on 
                                    * ldap_initialize() will parse the URL 
                                    * as a comma-separated URL list */
                                   srv->lud_dn = "";
                                   free_dn = 1;
                           }
                   }
   
                   /* prepare filter */
                   if ( rc == LDAP_SUCCESS && op->o_tag == LDAP_REQ_SEARCH ) {
                           /* filter */
                           if ( srv->lud_filter != NULL
                                   && srv->lud_filter[0] != '\0'
                                   && strcasecmp( srv->lud_filter, "(objectClass=*)" ) != 0 )
                           {
                                   /* RFC 4511: if filter is present, use it;
                                    * otherwise, use original */
                                   tmp_oq_search.rs_filter = str2filter_x( op, srv->lud_filter );
                                   if ( tmp_oq_search.rs_filter != NULL ) {
                                           filter2bv_x( op, tmp_oq_search.rs_filter, &tmp_oq_search.rs_filterstr );
   
                                   } else {
                                           Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\": unable to parse filter=\"%s\"\n",
                                                   op->o_log_prefix, ref->bv_val, srv->lud_filter );
                                           rc = LDAP_OTHER;
                                   }
                           }
                   }
                   srv->lud_filter = NULL;
   
                   if ( rc == LDAP_SUCCESS ) {
                           li.li_uri = ldap_url_desc2str( srv );
                   }
   
                   srv->lud_dn = dn.bv_val;
                   srv->lud_filter = filter;
                 ldap_free_urldesc( srv );                  ldap_free_urldesc( srv );
   
                   if ( rc != LDAP_SUCCESS ) {
                           /* try next */
                           rc = LDAP_OTHER;
                           continue;
                   }
   
                 if ( li.li_uri == NULL ) {                  if ( li.li_uri == NULL ) {
                           Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\" unable to reconstruct URI\n",
                                   op->o_log_prefix, ref->bv_val, 0 );
   
                         /* try next */                          /* try next */
                         rc = LDAP_OTHER;                          rc = LDAP_OTHER;
                           goto further_cleanup;
                   }
   
                   Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\" -> \"%s\"\n",
                           op->o_log_prefix, ref->bv_val, li.li_uri );
   
                   op->o_req_dn = pdn;
                   op->o_req_ndn = ndn;
   
                   if ( op->o_tag == LDAP_REQ_SEARCH ) {
                           op->ors_scope = tmp_oq_search.rs_scope;
                           if ( tmp_oq_search.rs_filter != NULL ) {
                                   op->ors_filter = tmp_oq_search.rs_filter;
                                   op->ors_filterstr = tmp_oq_search.rs_filterstr;
                           }
                   }
   
                   ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
   
                   /* Searches for a ldapinfo in the avl tree */
                   ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
                   lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree, 
                           (caddr_t)&li, ldap_chain_uri_cmp );
                   ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
   
                   if ( lip != NULL ) {
                           op->o_bd->be_private = (void *)lip;
   
                           Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\": URI=\"%s\" found in cache\n",
                                   op->o_log_prefix, ref->bv_val, li.li_uri );
   
                   } else {
                           rc = ldap_chain_db_init_one( op->o_bd );
                           if ( rc != 0 ) {
                                   Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\" unable to init back-ldap for URI=\"%s\"\n",
                                           op->o_log_prefix, ref->bv_val, li.li_uri );
                                   goto cleanup;
                           }
                           lip = (ldapinfo_t *)op->o_bd->be_private;
                           lip->li_uri = li.li_uri;
                           lip->li_bvuri = bvuri;
                           rc = ldap_chain_db_open_one( op->o_bd );
                           if ( rc != 0 ) {
                                   Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\" unable to open back-ldap for URI=\"%s\"\n",
                                           op->o_log_prefix, ref->bv_val, li.li_uri );
                                   lip->li_uri = NULL;
                                   lip->li_bvuri = NULL;
                                   (void)ldap_chain_db_destroy_one( op->o_bd, NULL);
                                   goto cleanup;
                           }
   
                           if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
                                   ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
                                   if ( avl_insert( &lc->lc_lai.lai_tree,
                                           (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
                                   {
                                           /* someone just inserted another;
                                            * don't bother, use this and then
                                            * just free it */
                                           temporary = 1;
                                   }
                                   ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
   
                           } else {
                                   temporary = 1;
                           }
   
                           Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\" %s\n",
                                   op->o_log_prefix, ref->bv_val, temporary ? "temporary" : "caching" );
                   }
   
                   lb->lb_op_f = op_f;
                   lb->lb_depth = depth + 1;
   
                   rc = op_f( op, &rs2 );
   
                   /* note the first error */
                   if ( first_rc == -1 ) {
                           first_rc = rc;
                   }
   
   cleanup:;
                   ldap_memfree( li.li_uri );
                   li.li_uri = NULL;
   
                   if ( temporary ) {
                           lip->li_uri = NULL;
                           lip->li_bvuri = NULL;
                           (void)ldap_chain_db_close_one( op->o_bd );
                           (void)ldap_chain_db_destroy_one( op->o_bd, NULL );
                   }
   
   further_cleanup:;
                   if ( free_dn ) {
                           op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
                           op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
                   }
           
                   if ( op->o_tag == LDAP_REQ_SEARCH ) {   
                           if ( tmp_oq_search.rs_filter != NULL ) {
                                   filter_free_x( op, tmp_oq_search.rs_filter, 1 );
                           }
   
                           if ( !BER_BVISNULL( &tmp_oq_search.rs_filterstr ) ) {
                                   slap_sl_free( tmp_oq_search.rs_filterstr.bv_val, op->o_tmpmemctx );
                           }
   
                           op->oq_search = save_oq_search;
                   }
   
                   if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) {
                           *rs = rs2;
                           break;
                   }
   
                   rc = rs2.sr_err;
           }
   
           op->o_req_dn = odn;
           op->o_req_ndn = ondn;
   
   #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
           (void)chaining_control_remove( op, &ctrls );
   #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
   
           if ( rc != LDAP_SUCCESS && first_rc > 0 ) {
                   rc = first_rc;
           }
   
           return rc;
   }
   
   static int
   ldap_chain_search(
           Operation       *op,
           SlapReply       *rs,
           BerVarray       ref,
           int             depth )
   
   {
           slap_overinst   *on = (slap_overinst *) op->o_bd->bd_info;
           ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
           ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
           ldapinfo_t      li = { 0 }, *lip = NULL;
           struct berval   bvuri[ 2 ] = { { 0 } };
   
           struct berval   odn = op->o_req_dn,
                           ondn = op->o_req_ndn;
           Entry           *save_entry = rs->sr_entry;
           slap_mask_t     save_flags = rs->sr_flags;
   
           int             rc = LDAP_OTHER,
                           first_rc = -1;
   
   #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
           LDAPControl     **ctrls = NULL;
           
           (void)chaining_control_add( lc, op, &ctrls );
   #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
   
           assert( rs->sr_type == REP_SEARCHREF );
   
           rs->sr_type = REP_SEARCH;
   
           /* if we parse the URI then by no means 
            * we can cache stuff or reuse connections, 
            * because in back-ldap there's no caching
            * based on the URI value, which is supposed
            * to be set once for all (correct?) */
           li.li_bvuri = bvuri;
           for ( ; !BER_BVISNULL( &ref[0] ); ref++ ) {
                   SlapReply       rs2 = { REP_RESULT };
                   LDAPURLDesc     *srv;
                   req_search_s    save_oq_search = op->oq_search,
                                   tmp_oq_search = { 0 };
                   struct berval   dn,
                                   pdn = op->o_req_dn,
                                   ndn = op->o_req_ndn;
                   char            *filter = NULL;
                   int             temporary = 0;
                   int             free_dn = 0;
   
                   /* parse reference and use
                    * proto://[host][:port]/ only */
                   rc = ldap_url_parse_ext( ref[0].bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
                   if ( rc != LDAP_URL_SUCCESS ) {
                           Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: unable to parse ref=\"%s\"\n",
                                   op->o_log_prefix, ref->bv_val, 0 );
   
                           /* try next */
                           rs->sr_err = LDAP_OTHER;
                         continue;                          continue;
                 }                  }
   
                   if ( srv->lud_scope != LDAP_SCOPE_DEFAULT ) {
                           /* RFC 4511: if scope is present, use it */
                           tmp_oq_search.rs_scope = srv->lud_scope;
   
                   } else {
                           /* RFC 4511: if scope is absent, use original */
                           /* Section 4.5.3: if scope is onelevel, use base */
                           if ( op->ors_scope == LDAP_SCOPE_ONELEVEL )
                                   tmp_oq_search.rs_scope = LDAP_SCOPE_BASE;
                           else
                                   tmp_oq_search.rs_scope = op->ors_scope;
                   }
   
                   rc = LDAP_SUCCESS;
                   srv->lud_scope = LDAP_SCOPE_DEFAULT;
                   dn.bv_val = srv->lud_dn;
                   filter = srv->lud_filter;
   
                   /* normalize DN */
                   if ( srv->lud_dn == NULL || srv->lud_dn[0] == '\0' ) {
                           if ( srv->lud_dn == NULL ) {
                                   srv->lud_dn = "";
                           }
   
                           if ( save_entry != NULL ) {
                                   /* use the "right" DN, if available */
                                   pdn = save_entry->e_name;
                                   ndn = save_entry->e_nname;
                           } /* else leave the original req DN in place, if any RFC 4511 */
                           
                   } else {
                           /* RFC 4511: if DN is present, use it */
                           ber_str2bv( srv->lud_dn, 0, 0, &dn );
                           rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
                           if ( rc == LDAP_SUCCESS ) {
                                   /* remove DN essentially because later on 
                                    * ldap_initialize() will parse the URL 
                                    * as a comma-separated URL list */
                                   srv->lud_dn = "";
                                   free_dn = 1;
                           }
                   }
   
                   /* prepare filter */
                   if ( rc == LDAP_SUCCESS ) {
                           /* filter */
                           if ( srv->lud_filter != NULL
                                   && srv->lud_filter[0] != '\0'
                                   && strcasecmp( srv->lud_filter, "(objectClass=*)" ) != 0 )
                           {
                                   /* RFC 4511: if filter is present, use it;
                                    * otherwise, use original */
                                   tmp_oq_search.rs_filter = str2filter_x( op, srv->lud_filter );
                                   if ( tmp_oq_search.rs_filter != NULL ) {
                                           filter2bv_x( op, tmp_oq_search.rs_filter, &tmp_oq_search.rs_filterstr );
   
                                   } else {
                                           Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\": unable to parse filter=\"%s\"\n",
                                                   op->o_log_prefix, ref->bv_val, srv->lud_filter );
                                           rc = LDAP_OTHER;
                                   }
                           }
                   }
                   srv->lud_filter = NULL;
   
                   if ( rc == LDAP_SUCCESS ) {
                           li.li_uri = ldap_url_desc2str( srv );
                   }
   
                   srv->lud_dn = dn.bv_val;
                   srv->lud_filter = filter;
                   ldap_free_urldesc( srv );
   
                   if ( rc != LDAP_SUCCESS || li.li_uri == NULL ) {
                           Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\" unable to reconstruct URI\n",
                                   op->o_log_prefix, ref->bv_val, 0 );
   
                           /* try next */
                           rc = LDAP_OTHER;
                           goto further_cleanup;
                   }
   
                   Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\" -> \"%s\"\n",
                           op->o_log_prefix, ref->bv_val, li.li_uri );
   
                   op->o_req_dn = pdn;
                   op->o_req_ndn = ndn;
                   op->ors_scope = tmp_oq_search.rs_scope;
                   if ( tmp_oq_search.rs_filter != NULL ) {
                           op->ors_filter = tmp_oq_search.rs_filter;
                           op->ors_filterstr = tmp_oq_search.rs_filterstr;
                   }
   
                 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );                  ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
   
                 /* Searches for a ldapinfo in the avl tree */                  /* Searches for a ldapinfo in the avl tree */
Line 415  Document: draft-ietf-ldapbis-protocol-27 Line 830  Document: draft-ietf-ldapbis-protocol-27
                 if ( lip != NULL ) {                  if ( lip != NULL ) {
                         op->o_bd->be_private = (void *)lip;                          op->o_bd->be_private = (void *)lip;
   
                           Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\": URI=\"%s\" found in cache\n",
                                   op->o_log_prefix, ref->bv_val, li.li_uri );
   
                 } else {                  } else {
                           /* if none is found, create a temporary... */
                         rc = ldap_chain_db_init_one( op->o_bd );                          rc = ldap_chain_db_init_one( op->o_bd );
                         if ( rc != 0 ) {                          if ( rc != 0 ) {
                                   Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\" unable to init back-ldap for URI=\"%s\"\n",
                                           op->o_log_prefix, ref->bv_val, li.li_uri );
                                 goto cleanup;                                  goto cleanup;
                         }                          }
                         lip = (ldapinfo_t *)op->o_bd->be_private;                          lip = (ldapinfo_t *)op->o_bd->be_private;
Line 425  Document: draft-ietf-ldapbis-protocol-27 Line 846  Document: draft-ietf-ldapbis-protocol-27
                         lip->li_bvuri = bvuri;                          lip->li_bvuri = bvuri;
                         rc = ldap_chain_db_open_one( op->o_bd );                          rc = ldap_chain_db_open_one( op->o_bd );
                         if ( rc != 0 ) {                          if ( rc != 0 ) {
                                 (void)ldap_chain_db_destroy_one( op->o_bd );                                  Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\" unable to open back-ldap for URI=\"%s\"\n",
                                           op->o_log_prefix, ref->bv_val, li.li_uri );
                                   lip->li_uri = NULL;
                                   lip->li_bvuri = NULL;
                                   (void)ldap_chain_db_destroy_one( op->o_bd, NULL );
                                 goto cleanup;                                  goto cleanup;
                         }                          }
   
Line 444  Document: draft-ietf-ldapbis-protocol-27 Line 869  Document: draft-ietf-ldapbis-protocol-27
                         } else {                          } else {
                                 temporary = 1;                                  temporary = 1;
                         }                          }
   
                           Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\" %s\n",
                                   op->o_log_prefix, ref->bv_val, temporary ? "temporary" : "caching" );
                 }                  }
   
                 rc = op_f( op, rs );                  lb->lb_op_f = lback->bi_op_search;
                   lb->lb_depth = depth + 1;
   
                   /* FIXME: should we also copy filter and scope?
                    * according to RFC3296, no */
                   rc = lback->bi_op_search( op, &rs2 );
                   if ( first_rc == -1 ) {
                           first_rc = rc;
                   }
   
 cleanup:;  cleanup:;
                 ldap_memfree( li.li_uri );                  ldap_memfree( li.li_uri );
Line 456  cleanup:; Line 892  cleanup:;
                         lip->li_uri = NULL;                          lip->li_uri = NULL;
                         lip->li_bvuri = NULL;                          lip->li_bvuri = NULL;
                         (void)ldap_chain_db_close_one( op->o_bd );                          (void)ldap_chain_db_close_one( op->o_bd );
                         (void)ldap_chain_db_destroy_one( op->o_bd );                          (void)ldap_chain_db_destroy_one( op->o_bd, NULL );
                   }
                   
   further_cleanup:;
                   if ( free_dn ) {
                           op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
                           op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
                   }
   
                   op->o_req_dn = odn;
                   op->o_req_ndn = ondn;
   
                   if ( tmp_oq_search.rs_filter != NULL ) {
                           filter_free_x( op, tmp_oq_search.rs_filter, 1 );
                   }
   
                   if ( !BER_BVISNULL( &tmp_oq_search.rs_filterstr ) ) {
                           slap_sl_free( tmp_oq_search.rs_filterstr.bv_val, op->o_tmpmemctx );
                 }                  }
   
                   op->oq_search = save_oq_search;
                                   
                 if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {                  if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) {
                           *rs = rs2;
                         break;                          break;
                 }                  }
   
                   rc = rs2.sr_err;
         }          }
   
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR  #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
         (void)chaining_control_remove( op, &ctrls );          (void)chaining_control_remove( op, &ctrls );
 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */  #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
   
           op->o_req_dn = odn;
           op->o_req_ndn = ondn;
           rs->sr_type = REP_SEARCHREF;
           rs->sr_entry = save_entry;
           rs->sr_flags = save_flags;
   
           if ( rc != LDAP_SUCCESS ) {
                   /* couldn't chase any of the referrals */
                   if ( first_rc != -1 ) {
                           rc = first_rc;
   
                   } else {
                           rc = SLAP_CB_CONTINUE;
                   }
           }
   
         return rc;          return rc;
 }  }
   
Line 475  static int Line 949  static int
 ldap_chain_response( Operation *op, SlapReply *rs )  ldap_chain_response( Operation *op, SlapReply *rs )
 {  {
         slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;          slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
         void            *private = op->o_bd->be_private;          ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
           BackendDB       db, *bd = op->o_bd;
           ldap_chain_cb_t lb = { 0 };
         slap_callback   *sc = op->o_callback,          slap_callback   *sc = op->o_callback,
                         sc2 = { 0 };                          sc2 = { 0 };
         int             rc = 0;          int             rc = 0;
           const char      *text = NULL;
         const char      *matched;          const char      *matched;
         BerVarray       ref;          BerVarray       ref;
         struct berval   ndn = op->o_ndn;          struct berval   ndn = op->o_ndn;
Line 530  ldap_chain_response( Operation *op, Slap Line 1007  ldap_chain_response( Operation *op, Slap
          *   e) what ssf           *   e) what ssf
          */           */
   
           db = *op->o_bd;
           SLAP_DBFLAGS( &db ) &= ~SLAP_DBFLAG_MONITORING;
           op->o_bd = &db;
   
           text = rs->sr_text;
           rs->sr_text = NULL;
         matched = rs->sr_matched;          matched = rs->sr_matched;
         rs->sr_matched = NULL;          rs->sr_matched = NULL;
         ref = rs->sr_ref;          ref = rs->sr_ref;
         rs->sr_ref = NULL;          rs->sr_ref = NULL;
   
         /* we need this to know if back-ldap returned any result */          /* we need this to know if back-ldap returned any result */
           lb.lb_lc = lc;
           sc2.sc_next = sc->sc_next;
           sc2.sc_private = &lb;
         sc2.sc_response = ldap_chain_cb_response;          sc2.sc_response = ldap_chain_cb_response;
         op->o_callback = &sc2;          op->o_callback = &sc2;
   
Line 556  ldap_chain_response( Operation *op, Slap Line 1042  ldap_chain_response( Operation *op, Slap
                 /* FIXME: can we really get a referral for binds? */                  /* FIXME: can we really get a referral for binds? */
                 op->o_req_ndn = slap_empty_bv;                  op->o_req_ndn = slap_empty_bv;
                 op->o_conn = NULL;                  op->o_conn = NULL;
                 rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref );                  rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref, 0 );
                 op->o_req_ndn = rndn;                  op->o_req_ndn = rndn;
                 op->o_conn = conn;                  op->o_conn = conn;
                 }                  }
                 break;                  break;
   
         case LDAP_REQ_ADD:          case LDAP_REQ_ADD:
                 rc = ldap_chain_op( op, rs, lback->bi_op_add, ref );                  rc = ldap_chain_op( op, rs, lback->bi_op_add, ref, 0 );
                 break;                  break;
   
         case LDAP_REQ_DELETE:          case LDAP_REQ_DELETE:
                 rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref );                  rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref, 0 );
                 break;                  break;
   
         case LDAP_REQ_MODRDN:          case LDAP_REQ_MODRDN:
                 rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref );                  rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref, 0 );
                 break;                  break;
   
         case LDAP_REQ_MODIFY:          case LDAP_REQ_MODIFY:
                 rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref );                  rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref, 0 );
                 break;                  break;
   
         case LDAP_REQ_COMPARE:          case LDAP_REQ_COMPARE:
                 rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref );                  rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref, 0 );
                 if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {                  if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {
                         rc = LDAP_SUCCESS;                          rc = LDAP_SUCCESS;
                 }                  }
Line 587  ldap_chain_response( Operation *op, Slap Line 1073  ldap_chain_response( Operation *op, Slap
   
         case LDAP_REQ_SEARCH:          case LDAP_REQ_SEARCH:
                 if ( rs->sr_type == REP_SEARCHREF ) {                  if ( rs->sr_type == REP_SEARCHREF ) {
                         ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;  
                         ldapinfo_t      li = { 0 }, *lip = NULL;  
                         struct berval   bvuri[ 2 ] = { { 0 } };  
   
                         struct berval   *curr = ref,  
                                         odn = op->o_req_dn,  
                                         ondn = op->o_req_ndn;  
   
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR  
                         LDAPControl     **ctrls = NULL;  
           
                         (void)chaining_control_add( lc, op, &ctrls );  
 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */  
   
                         rs->sr_type = REP_SEARCH;  
   
                         sc2.sc_response = ldap_chain_cb_search_response;                          sc2.sc_response = ldap_chain_cb_search_response;
                           rc = ldap_chain_search( op, rs, ref, 0 );
                         /* if we parse the URI then by no means   
                          * we can cache stuff or reuse connections,   
                          * because in back-ldap there's no caching  
                          * based on the URI value, which is supposed  
                          * to be set once for all (correct?) */  
                         li.li_bvuri = bvuri;  
                         for ( ; !BER_BVISNULL( &curr[0] ); curr++ ) {  
                                 LDAPURLDesc     *srv;  
                                 char            *save_dn;  
                                 int             temporary = 0;  
   
                                 /* parse reference and use  
                                  * proto://[host][:port]/ only */  
                                 rc = ldap_url_parse_ext( curr[0].bv_val, &srv );  
                                 if ( rc != LDAP_URL_SUCCESS ) {  
                                         /* try next */  
                                         rs->sr_err = LDAP_OTHER;  
                                         continue;  
                                 }  
   
                                 /* remove DN essentially because later on   
                                  * ldap_initialize() will parse the URL   
                                  * as a comma-separated URL list */  
                                 save_dn = srv->lud_dn;  
                                 srv->lud_dn = "";  
                                 srv->lud_scope = LDAP_SCOPE_DEFAULT;  
                                 li.li_uri = ldap_url_desc2str( srv );  
                                 if ( li.li_uri != NULL ) {  
                                         ber_str2bv_x( save_dn, 0, 1, &op->o_req_dn,  
                                                         op->o_tmpmemctx );  
                                         ber_dupbv_x( &op->o_req_ndn, &op->o_req_dn,  
                                                         op->o_tmpmemctx );  
                                 }  
   
                                 srv->lud_dn = save_dn;  
                                 ldap_free_urldesc( srv );  
   
                                 if ( li.li_uri == NULL ) {  
                                         /* try next */  
                                         rs->sr_err = LDAP_OTHER;  
                                         continue;  
                                 }  
   
                                 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );  
   
                                 /* Searches for a ldapinfo in the avl tree */  
                                 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );  
                                 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,   
                                         (caddr_t)&li, ldap_chain_uri_cmp );  
                                 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );  
   
                                 if ( lip != NULL ) {  
                                         op->o_bd->be_private = (void *)lip;  
   
                                 } else {  
                                         /* if none is found, create a temporary... */  
                                         rc = ldap_chain_db_init_one( op->o_bd );  
                                         if ( rc != 0 ) {  
                                                 goto cleanup;  
                                         }  
                                         lip = (ldapinfo_t *)op->o_bd->be_private;  
                                         lip->li_uri = li.li_uri;  
                                         lip->li_bvuri = bvuri;  
                                         rc = ldap_chain_db_open_one( op->o_bd );  
                                         if ( rc != 0 ) {  
                                                 (void)ldap_chain_db_destroy_one( op->o_bd );  
                                                 goto cleanup;  
                                         }  
   
                                         if ( LDAP_CHAIN_CACHE_URI( lc ) ) {  
                                                 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );  
                                                 if ( avl_insert( &lc->lc_lai.lai_tree,  
                                                         (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )  
                                                 {  
                                                         /* someone just inserted another;  
                                                          * don't bother, use this and then  
                                                          * just free it */  
                                                         temporary = 1;  
                                                 }  
                                                 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );  
                   
                                         } else {  
                                                 temporary = 1;  
                                         }  
                                 }  
   
                                 /* FIXME: should we also copy filter and scope?  
                                  * according to RFC3296, no */  
                                 rc = lback->bi_op_search( op, rs );  
   
 cleanup:;  
                                 ldap_memfree( li.li_uri );  
                                 li.li_uri = NULL;  
   
                                 op->o_tmpfree( op->o_req_dn.bv_val,  
                                                 op->o_tmpmemctx );  
                                 op->o_tmpfree( op->o_req_ndn.bv_val,  
                                                 op->o_tmpmemctx );  
   
                                 if ( temporary ) {  
                                         lip->li_uri = NULL;  
                                         lip->li_bvuri = NULL;  
                                         (void)ldap_chain_db_close_one( op->o_bd );  
                                         (void)ldap_chain_db_destroy_one( op->o_bd );  
                                 }  
                   
                                 if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {  
                                         break;  
                                 }  
   
                                 rc = rs->sr_err;  
                         }  
   
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR  
                         (void)chaining_control_remove( op, &ctrls );  
 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */  
   
                         op->o_req_dn = odn;  
                         op->o_req_ndn = ondn;  
                         rs->sr_type = REP_SEARCHREF;  
                         rs->sr_entry = NULL;  
   
                         if ( rc != LDAP_SUCCESS ) {  
                                 /* couldn't chase any of the referrals */  
                                 rc = SLAP_CB_CONTINUE;  
                         }  
                                                   
                 } else {                  } else {
                         /* we might get here before any database actually                           /* we might get here before any database actually 
Line 738  cleanup:; Line 1082  cleanup:;
                          * to check limits, to make sure safe defaults                           * to check limits, to make sure safe defaults
                          * are in place */                           * are in place */
                         if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) {                          if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) {
                                 rc = ldap_chain_op( op, rs, lback->bi_op_search, ref );                                  rc = ldap_chain_op( op, rs, lback->bi_op_search, ref, 0 );
   
                         } else {                          } else {
                                 rc = SLAP_CB_CONTINUE;                                  rc = SLAP_CB_CONTINUE;
Line 747  cleanup:; Line 1091  cleanup:;
                 break;                  break;
   
         case LDAP_REQ_EXTENDED:          case LDAP_REQ_EXTENDED:
                 rc = ldap_chain_op( op, rs, lback->bi_extended, ref );                  rc = ldap_chain_op( op, rs, lback->bi_extended, ref, 0 );
                 /* FIXME: ldap_back_extended() by design                   /* FIXME: ldap_back_extended() by design 
                  * doesn't send result; frontend is expected                   * doesn't send result; frontend is expected
                  * to send it... */                   * to send it... */
                 /* FIXME: what about chaining? */                  /* FIXME: what about chaining? */
                 if ( rc != SLAPD_ABANDON ) {                  if ( rc != SLAPD_ABANDON ) {
                           rs->sr_err = rc;
                         send_ldap_extended( op, rs );                          send_ldap_extended( op, rs );
                         rc = LDAP_SUCCESS;                          rc = LDAP_SUCCESS;
                 }                  }
                 sc2.sc_private = LDAP_CH_RES;                  lb.lb_status = LDAP_CH_RES;
                 break;                  break;
   
         default:          default:
Line 770  cleanup:; Line 1115  cleanup:;
   
         case LDAP_SUCCESS:          case LDAP_SUCCESS:
         case LDAP_REFERRAL:          case LDAP_REFERRAL:
                   sr_err = rs->sr_err;
                 /* slapd-ldap sent response */                  /* slapd-ldap sent response */
                 if ( !op->o_abandon && sc2.sc_private != LDAP_CH_RES ) {                  if ( !op->o_abandon && lb.lb_status != LDAP_CH_RES ) {
                         /* FIXME: should we send response? */                          /* FIXME: should we send response? */
                         Debug( LDAP_DEBUG_ANY,                          Debug( LDAP_DEBUG_ANY,
                                 "%s: ldap_chain_response: "                                  "%s: ldap_chain_response: "
Line 782  cleanup:; Line 1128  cleanup:;
   
         default:          default:
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR  #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
                 if ( sc2.sc_private == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {                  if ( lb.lb_status == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
                         goto cannot_chain;                          goto cannot_chain;
                 }                  }
   
Line 796  cannot_chain:; Line 1142  cannot_chain:;
   
                 default:                  default:
 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */  #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
                         rc = SLAP_CB_CONTINUE;                          if ( LDAP_CHAIN_RETURN_ERR( lc ) ) {
                         rs->sr_err = sr_err;                                  sr_err = rs->sr_err = rc;
                         rs->sr_type = sr_type;                                  rs->sr_type = sr_type;
                         rs->sr_matched = matched;  
                         rs->sr_ref = ref;                          } else {
                                   rc = SLAP_CB_CONTINUE;
                                   rs->sr_err = sr_err;
                                   rs->sr_type = sr_type;
                                   rs->sr_text = text;
                                   rs->sr_matched = matched;
                                   rs->sr_ref = ref;
                           }
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR  #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
                         break;                          break;
                 }                  }
 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */  #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
         }          }
   
         if ( sc2.sc_private == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {          if ( lb.lb_status == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {
                 op->o_callback = NULL;                  /* give the remaining callbacks a chance */
                   op->o_callback = sc->sc_next;
                 rc = rs->sr_err = slap_map_api2result( rs );                  rc = rs->sr_err = slap_map_api2result( rs );
                 send_ldap_result( op, rs );                  send_ldap_result( op, rs );
         }          }
Line 816  cannot_chain:; Line 1170  cannot_chain:;
 dont_chain:;  dont_chain:;
         rs->sr_err = sr_err;          rs->sr_err = sr_err;
         rs->sr_type = sr_type;          rs->sr_type = sr_type;
           rs->sr_text = text;
         rs->sr_matched = matched;          rs->sr_matched = matched;
         rs->sr_ref = ref;          rs->sr_ref = ref;
         op->o_bd->be_private = private;          op->o_bd = bd;
         op->o_callback = sc;          op->o_callback = sc;
         op->o_ndn = ndn;          op->o_ndn = ndn;
   
Line 858  str2chain( const char *s ) Line 1213  str2chain( const char *s )
   
 enum {  enum {
         CH_CHAINING = 1,          CH_CHAINING = 1,
         CH_CACHE_URI = 2,          CH_CACHE_URI,
           CH_MAX_DEPTH,
           CH_RETURN_ERR,
   
         CH_LAST          CH_LAST
 };  };
Line 877  static ConfigTable chaincfg[] = { Line 1234  static ConfigTable chaincfg[] = {
 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */  #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
         { "chain-cache-uri", "TRUE/FALSE",          { "chain-cache-uri", "TRUE/FALSE",
                 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen,                  2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen,
                 "( OLcfgOvAt:3.2 NAME 'olcCacheURI' "                  "( OLcfgOvAt:3.2 NAME 'olcChainCacheURI' "
                         "DESC 'Enables caching of URIs not present in configuration' "                          "DESC 'Enables caching of URIs not present in configuration' "
                         "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },                          "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
           { "chain-max-depth", "args",
                   2, 2, 0, ARG_MAGIC|ARG_INT|CH_MAX_DEPTH, chain_cf_gen,
                   "( OLcfgOvAt:3.3 NAME 'olcChainMaxReferralDepth' "
                           "DESC 'max referral depth' "
                           "SYNTAX OMsInteger "
                           "EQUALITY integerMatch "
                           "SINGLE-VALUE )", NULL, NULL },
           { "chain-return-error", "TRUE/FALSE",
                   2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_RETURN_ERR, chain_cf_gen,
                   "( OLcfgOvAt:3.4 NAME 'olcChainReturnError' "
                           "DESC 'Errors are returned instead of the original referral' "
                           "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
         { NULL, NULL, 0, 0, 0, ARG_IGNORED }          { NULL, NULL, 0, 0, 0, ARG_IGNORED }
 };  };
   
Line 892  static ConfigOCs chainocs[] = { Line 1261  static ConfigOCs chainocs[] = {
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR  #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
                         "olcChainingBehavior $ "                          "olcChainingBehavior $ "
 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */  #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
                         "olcCacheURI "                          "olcChainCacheURI $ "
                           "olcChainMaxReferralDepth $ "
                           "olcChainReturnError "
                         ") )",                          ") )",
                 Cft_Overlay, chaincfg, NULL, chain_cfadd },                  Cft_Overlay, chaincfg, NULL, chain_cfadd },
         { "( OLcfgOvOc:3.2 "          { "( OLcfgOvOc:3.2 "
                 "NAME 'olcChainDatabase' "                  "NAME 'olcChainDatabase' "
                 "DESC 'Chain remote server configuration' "                  "DESC 'Chain remote server configuration' "
                 "AUXILIARY )",                  "SUP olcLDAPConfig )",
                 Cft_Misc, chaincfg, chain_ldadd },                  Cft_Misc, olcDatabaseDummy, chain_ldadd },
         { NULL, 0, NULL }          { NULL, 0, NULL }
 };  };
   
Line 936  chain_ldadd( CfEntryInfo *p, Entry *e, C Line 1307  chain_ldadd( CfEntryInfo *p, Entry *e, C
         assert( rc == LDAP_SUCCESS );          assert( rc == LDAP_SUCCESS );
   
         at = attr_find( e->e_attrs, ad );          at = attr_find( e->e_attrs, ad );
   #if 0
         if ( lc->lc_common_li == NULL && at != NULL ) {          if ( lc->lc_common_li == NULL && at != NULL ) {
                 /* FIXME: we should generate an empty default entry                  /* FIXME: we should generate an empty default entry
                  * if none is supplied */                   * if none is supplied */
Line 946  chain_ldadd( CfEntryInfo *p, Entry *e, C Line 1318  chain_ldadd( CfEntryInfo *p, Entry *e, C
                 rc = LDAP_CONSTRAINT_VIOLATION;                  rc = LDAP_CONSTRAINT_VIOLATION;
                 goto done;                  goto done;
   
         } else if ( lc->lc_common_li != NULL && at == NULL ) {          } else
   #endif
           if ( lc->lc_common_li != NULL && at == NULL ) {
                 /* FIXME: we should generate an empty default entry                  /* FIXME: we should generate an empty default entry
                  * if none is supplied */                   * if none is supplied */
                 Debug( LDAP_DEBUG_ANY, "slapd-chain: "                  Debug( LDAP_DEBUG_ANY, "slapd-chain: "
Line 976  chain_ldadd( CfEntryInfo *p, Entry *e, C Line 1350  chain_ldadd( CfEntryInfo *p, Entry *e, C
         if ( lc->lc_common_li == NULL ) {          if ( lc->lc_common_li == NULL ) {
                 lc->lc_common_li = li;                  lc->lc_common_li = li;
   
         } else if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,          } else {
                 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )                  li->li_uri = ch_strdup( at->a_vals[ 0 ].bv_val );
         {                  value_add_one( &li->li_bvuri, &at->a_vals[ 0 ] );
                 Debug( LDAP_DEBUG_ANY, "slapd-chain: "                  if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
                         "database \"%s\" insert failed.\n",                          ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
                         e->e_name.bv_val, 0, 0 );                  {
                 rc = LDAP_CONSTRAINT_VIOLATION;                          Debug( LDAP_DEBUG_ANY, "slapd-chain: "
                 goto done;                                  "database \"%s\" insert failed.\n",
                                   e->e_name.bv_val, 0, 0 );
                           rc = LDAP_CONSTRAINT_VIOLATION;
                           goto done;
                   }
         }          }
   
           ca->ca_private = on;
   
 done:;  done:;
         if ( rc != LDAP_SUCCESS ) {          if ( rc != LDAP_SUCCESS ) {
                 (void)ldap_chain_db_destroy_one( ca->be );                  (void)ldap_chain_db_destroy_one( ca->be, NULL );
                 ch_free( ca->be );                  ch_free( ca->be );
                 ca->be = NULL;                  ca->be = NULL;
         }          }
Line 1013  ldap_chain_cfadd_apply( void *datum, voi Line 1393  ldap_chain_cfadd_apply( void *datum, voi
         struct berval                   bv;          struct berval                   bv;
   
         /* FIXME: should not hardcode "olcDatabase" here */          /* FIXME: should not hardcode "olcDatabase" here */
         bv.bv_len = snprintf( lca->ca->msg, sizeof( lca->ca->msg ),          bv.bv_len = snprintf( lca->ca->cr_msg, sizeof( lca->ca->cr_msg ),
                 "olcDatabase={%d}%s", lca->count, lback->bi_type );                  "olcDatabase={%d}%s", lca->count, lback->bi_type );
         bv.bv_val = lca->ca->msg;          bv.bv_val = lca->ca->cr_msg;
   
         lca->ca->be->be_private = (void *)li;          lca->ca->be->be_private = (void *)li;
         config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,          config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
Line 1110  chain_cf_gen( ConfigArgs *c ) Line 1490  chain_cf_gen( ConfigArgs *c )
                         c->value_int = LDAP_CHAIN_CACHE_URI( lc );                          c->value_int = LDAP_CHAIN_CACHE_URI( lc );
                         break;                          break;
   
                   case CH_MAX_DEPTH:
                           c->value_int = lc->lc_max_depth;
                           break;
   
                   case CH_RETURN_ERR:
                           c->value_int = LDAP_CHAIN_RETURN_ERR( lc );
                           break;
   
                 default:                  default:
                         assert( 0 );                          assert( 0 );
                         rc = 1;                          rc = 1;
Line 1125  chain_cf_gen( ConfigArgs *c ) Line 1513  chain_cf_gen( ConfigArgs *c )
                         lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;                          lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
                         break;                          break;
   
                   case CH_MAX_DEPTH:
                           c->value_int = 0;
                           break;
   
                   case CH_RETURN_ERR:
                           lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
                           break;
   
                 default:                  default:
                         return 1;                          return 1;
                 }                  }
Line 1257  chain_cf_gen( ConfigArgs *c ) Line 1653  chain_cf_gen( ConfigArgs *c )
                 }                  }
                 break;                  break;
   
           case CH_MAX_DEPTH:
                   if ( c->value_int < 0 ) {
                           snprintf( c->cr_msg, sizeof( c->cr_msg ),
                                   "<%s> invalid max referral depth %d",
                                   c->argv[0], c->value_int );
                           Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
                                   c->log, c->cr_msg, 0 );
                           rc = 1;
                           break;
                   }
                   lc->lc_max_depth = c->value_int;
   
           case CH_RETURN_ERR:
                   if ( c->value_int ) {
                           lc->lc_flags |= LDAP_CHAIN_F_RETURN_ERR;
                   } else {
                           lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
                   }
                   break;
   
         default:          default:
                 assert( 0 );                  assert( 0 );
                 return 1;                  return 1;
Line 1266  chain_cf_gen( ConfigArgs *c ) Line 1682  chain_cf_gen( ConfigArgs *c )
   
 static int  static int
 ldap_chain_db_init(  ldap_chain_db_init(
         BackendDB *be )          BackendDB *be,
           ConfigReply *cr )
 {  {
         slap_overinst   *on = (slap_overinst *)be->bd_info;          slap_overinst   *on = (slap_overinst *)be->bd_info;
         ldap_chain_t    *lc = NULL;          ldap_chain_t    *lc = NULL;
Line 1284  ldap_chain_db_init( Line 1701  ldap_chain_db_init(
                 return 1;                  return 1;
         }          }
         memset( lc, 0, sizeof( ldap_chain_t ) );          memset( lc, 0, sizeof( ldap_chain_t ) );
           lc->lc_max_depth = 1;
         ldap_pvt_thread_mutex_init( &lc->lc_lai.lai_mutex );          ldap_pvt_thread_mutex_init( &lc->lc_lai.lai_mutex );
   
         on->on_bi.bi_private = (void *)lc;          on->on_bi.bi_private = (void *)lc;
Line 1303  ldap_chain_db_config( Line 1721  ldap_chain_db_config(
         ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;          ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
   
         int             rc = SLAP_CONF_UNKNOWN;          int             rc = SLAP_CONF_UNKNOWN;
                   
         if ( lc->lc_common_li == NULL ) {          if ( lc->lc_common_li == NULL ) {
                 void    *be_private = be->be_private;                  BackendDB db = *be;
                 ldap_chain_db_init_common( be );                  ldap_chain_db_init_common( &db );
                 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;                  lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)db.be_private;
                 be->be_private = be_private;  
         }          }
   
         /* Something for the chain database? */          /* Something for the chain database? */
         if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) {          if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) {
                 char            *save_argv0 = argv[ 0 ];                  char            *save_argv0 = argv[ 0 ];
                 BackendInfo     *bd_info = be->bd_info;                  BackendDB       db = *be;
                 void            *be_private = be->be_private;  
                 ConfigOCs       *be_cf_ocs = be->be_cf_ocs;  
                 static char     *allowed_argv[] = {                  static char     *allowed_argv[] = {
                         /* special: put URI here, so in the meanwhile                          /* special: put URI here, so in the meanwhile
                          * it detects whether a new URI is being provided */                           * it detects whether a new URI is being provided */
Line 1355  ldap_chain_db_config( Line 1770  ldap_chain_db_config(
                 }                  }
   
                 if ( which_argv == 0 ) {                  if ( which_argv == 0 ) {
                         rc = ldap_chain_db_init_one( be );                          rc = ldap_chain_db_init_one( &db );
                         if ( rc != 0 ) {                          if ( rc != 0 ) {
                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: "                                  Debug( LDAP_DEBUG_ANY, "%s: line %d: "
                                         "underlying slapd-ldap initialization failed.\n.",                                          "underlying slapd-ldap initialization failed.\n.",
                                         fname, lineno, 0 );                                          fname, lineno, 0 );
                                 return 1;                                  return 1;
                         }                          }
                         lc->lc_cfg_li = be->be_private;                          lc->lc_cfg_li = db.be_private;
                 }                  }
   
                 /* TODO: add checks on what other slapd-ldap(5) args                  /* TODO: add checks on what other slapd-ldap(5) args
Line 1372  ldap_chain_db_config( Line 1787  ldap_chain_db_config(
                  * be warned.                   * be warned.
                  */                   */
   
                 be->bd_info = lback;                  db.bd_info = lback;
                 be->be_private = (void *)lc->lc_cfg_li;                  db.be_private = (void *)lc->lc_cfg_li;
                 be->be_cf_ocs = lback->bi_cf_ocs;                  db.be_cf_ocs = lback->bi_cf_ocs;
   
                 rc = config_generic_wrapper( be, fname, lineno, argc, argv );                  rc = config_generic_wrapper( &db, fname, lineno, argc, argv );
   
                 argv[ 0 ] = save_argv0;                  argv[ 0 ] = save_argv0;
                 be->be_cf_ocs = be_cf_ocs;  
                 be->be_private = be_private;  
                 be->bd_info = bd_info;  
   
                 if ( which_argv == 0 ) {                  if ( which_argv == 0 ) {
 private_destroy:;  private_destroy:;
                         if ( rc != 0 ) {                          if ( rc != 0 ) {
                                 BackendDB               db = *be;  
   
                                 db.bd_info = lback;                                  db.bd_info = lback;
                                 db.be_private = (void *)lc->lc_cfg_li;                                  db.be_private = (void *)lc->lc_cfg_li;
                                 ldap_chain_db_destroy_one( &db );                                  ldap_chain_db_destroy_one( &db, NULL );
                                 lc->lc_cfg_li = NULL;                                  lc->lc_cfg_li = NULL;
   
                         } else {                          } else {
                                 if ( lc->lc_cfg_li->li_bvuri == NULL                                  if ( lc->lc_cfg_li->li_bvuri == NULL
                                         || BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )                                          || BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )
Line 1418  private_destroy:; Line 1827  private_destroy:;
                         }                          }
                 }                  }
         }          }
           
         return rc;          return rc;
 }  }
   
Line 1443  ldap_chain_db_apply( void *datum, void * Line 1852  ldap_chain_db_apply( void *datum, void *
   
         lca->be->be_private = (void *)li;          lca->be->be_private = (void *)li;
   
         return lca->func( lca->be );          return lca->func( lca->be, NULL );
 }  }
   
 static int  static int
Line 1466  ldap_chain_db_func( Line 1875  ldap_chain_db_func(
                         db.bd_info = lback;                          db.bd_info = lback;
                         db.be_private = lc->lc_common_li;                          db.be_private = lc->lc_common_li;
   
                         rc = func( &db );                          rc = func( &db, NULL );
   
                         if ( rc != 0 ) {                          if ( rc != 0 ) {
                                 return rc;                                  return rc;
Line 1490  ldap_chain_db_func( Line 1899  ldap_chain_db_func(
   
 static int  static int
 ldap_chain_db_open(  ldap_chain_db_open(
         BackendDB       *be )          BackendDB       *be,
           ConfigReply     *cr )
 {  {
         slap_overinst   *on = (slap_overinst *) be->bd_info;          slap_overinst   *on = (slap_overinst *) be->bd_info;
         ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;          ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
           slap_mask_t     monitoring;
           int             rc = 0;
   
 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR  #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
         int     rc = 0;  
   
         rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );          rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
         if ( rc != 0 ) {          if ( rc != 0 ) {
                 return rc;                  return rc;
Line 1511  ldap_chain_db_open( Line 1921  ldap_chain_db_open(
                 be->be_private = be_private;                  be->be_private = be_private;
         }          }
   
         return ldap_chain_db_func( be, db_open );          /* filter out and restore monitoring */
           monitoring = ( SLAP_DBFLAGS( be ) & SLAP_DBFLAG_MONITORING );
           SLAP_DBFLAGS( be ) &= ~SLAP_DBFLAG_MONITORING;
           rc = ldap_chain_db_func( be, db_open );
           SLAP_DBFLAGS( be ) |= monitoring;
   
           return rc;
 }  }
   
 static int  static int
 ldap_chain_db_close(  ldap_chain_db_close(
         BackendDB       *be )          BackendDB       *be,
           ConfigReply     *cr )
 {  {
         return ldap_chain_db_func( be, db_close );          return ldap_chain_db_func( be, db_close );
 }  }
   
 static int  static int
 ldap_chain_db_destroy(  ldap_chain_db_destroy(
         BackendDB       *be )          BackendDB       *be,
           ConfigReply     *cr )
 {  {
         slap_overinst   *on = (slap_overinst *) be->bd_info;          slap_overinst   *on = (slap_overinst *) be->bd_info;
         ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;          ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
Line 1550  ldap_chain_db_init_common( Line 1968  ldap_chain_db_init_common(
         BackendDB       *be )          BackendDB       *be )
 {  {
         BackendInfo     *bi = be->bd_info;          BackendInfo     *bi = be->bd_info;
         int             t;          ldapinfo_t      *li;
           int             rc;
   
         be->bd_info = lback;          be->bd_info = lback;
         be->be_private = NULL;          be->be_private = NULL;
         t = lback->bi_db_init( be );          rc = lback->bi_db_init( be, NULL );
         if ( t != 0 ) {          if ( rc != 0 ) {
                 return t;                  return rc;
         }          }
           li = (ldapinfo_t *)be->be_private;
           li->li_urllist_f = NULL;
           li->li_urllist_p = NULL;
   
         be->bd_info = bi;          be->bd_info = bi;
   
         return 0;          return 0;
Line 1581  ldap_chain_db_init_one( Line 2004  ldap_chain_db_init_one(
         BackendInfo     *bi = be->bd_info;          BackendInfo     *bi = be->bd_info;
         ldapinfo_t      *li;          ldapinfo_t      *li;
   
         int             t;          slap_op_t       t;
   
         be->bd_info = lback;          be->bd_info = lback;
         be->be_private = NULL;          be->be_private = NULL;
         t = lback->bi_db_init( be );          t = lback->bi_db_init( be, NULL );
         if ( t != 0 ) {          if ( t != 0 ) {
                 return t;                  return t;
         }          }
         li = (ldapinfo_t *)be->be_private;          li = (ldapinfo_t *)be->be_private;
           li->li_urllist_f = NULL;
           li->li_urllist_p = NULL;
   
         /* copy common data */          /* copy common data */
         li->li_nretries = lc->lc_common_li->li_nretries;          li->li_nretries = lc->lc_common_li->li_nretries;
         li->li_flags = lc->lc_common_li->li_flags;          li->li_flags = lc->lc_common_li->li_flags;
         li->li_version = lc->lc_common_li->li_version;          li->li_version = lc->lc_common_li->li_version;
         for ( t = 0; t < LDAP_BACK_OP_LAST; t++ ) {          for ( t = 0; t < SLAP_OP_LAST; t++ ) {
                 li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];                  li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
         }          }
         be->bd_info = bi;          be->bd_info = bi;
Line 1603  ldap_chain_db_init_one( Line 2028  ldap_chain_db_init_one(
         return 0;          return 0;
 }  }
   
   static int
   ldap_chain_db_open_one(
           BackendDB       *be )
   {
           if ( SLAP_DBMONITORING( be ) ) {
                   ldapinfo_t      *li = (ldapinfo_t *)be->be_private;
   
                   if ( li->li_uri == NULL ) {
                           ber_str2bv( "cn=Common Connections", 0, 1,
                                   &li->li_monitor_info.lmi_rdn );
   
                   } else {
                           char            *ptr;
   
                           li->li_monitor_info.lmi_rdn.bv_len
                                   = STRLENOF( "cn=" ) + strlen( li->li_uri );
                           ptr = li->li_monitor_info.lmi_rdn.bv_val
                                   = ch_malloc( li->li_monitor_info.lmi_rdn.bv_len + 1 );
                           ptr = lutil_strcopy( ptr, "cn=" );
                           ptr = lutil_strcopy( ptr, li->li_uri );
                           ptr[ 0 ] = '\0';
                   }
           }
   
           return lback->bi_db_open( be, NULL );
   }
   
 typedef struct ldap_chain_conn_apply_t {  typedef struct ldap_chain_conn_apply_t {
         BackendDB       *be;          BackendDB       *be;
         Connection      *conn;          Connection      *conn;
Line 1771  ldap_chain_parse_ctrl( Line 2223  ldap_chain_parse_ctrl(
 }  }
 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */  #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
   
 static slap_overinst ldapchain;  
   
 int  int
 chain_initialize( void )  chain_initialize( void )
 {  {
         int     rc;          int rc;
   
         /* Make sure we don't exceed the bits reserved for userland */          /* Make sure we don't exceed the bits reserved for userland */
         config_check_userland( CH_LAST );          config_check_userland( CH_LAST );

Removed from v.1.52  
changed lines
  Added in v.1.52.2.22


______________
© Copyright 1998-2020, OpenLDAP Foundation, info@OpenLDAP.org