+ 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 ] );
+
+ /* 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_search: ref=\"%s\": URI=\"%s\" found in cache\n",
+ op->o_log_prefix, ref->bv_val, li.li_uri );
+
+ } else {
+ /* if none is found, create a temporary... */
+ rc = ldap_chain_db_init_one( op->o_bd );
+ 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;
+ }
+ 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_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;
+ }
+
+ 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_search: ref=\"%s\" %s\n",
+ op->o_log_prefix, ref->bv_val, temporary ? "temporary" : "caching" );
+ }
+
+ 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:;
+ 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 );
+ }
+
+ 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;