Back to index

openldap  2.4.31
search.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1999-2012 The OpenLDAP Foundation.
00005  * Portions Copyright 2001-2003 Pierangelo Masarati.
00006  * Portions Copyright 1999-2003 Howard Chu.
00007  * All rights reserved.
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted only as authorized by the OpenLDAP
00011  * Public License.
00012  *
00013  * A copy of this license is available in the file LICENSE in the
00014  * top-level directory of the distribution or, alternatively, at
00015  * <http://www.OpenLDAP.org/license.html>.
00016  */
00017 /* ACKNOWLEDGEMENTS:
00018  * This work was initially developed by the Howard Chu for inclusion
00019  * in OpenLDAP Software and subsequently enhanced by Pierangelo
00020  * Masarati.
00021  */
00022 
00023 #include "portable.h"
00024 
00025 #include <stdio.h>
00026 
00027 #include <ac/socket.h>
00028 #include <ac/string.h>
00029 #include <ac/time.h>
00030 
00031 #include "lutil.h"
00032 #include "slap.h"
00033 #include "../back-ldap/back-ldap.h"
00034 #include "back-meta.h"
00035 #include "../../../libraries/liblber/lber-int.h"
00036 
00037 /* IGNORE means that target does not (no longer) participate
00038  * in the search;
00039  * NOTREADY means the search on that target has not been initialized yet
00040  */
00041 #define       META_MSGID_IGNORE    (-1)
00042 #define       META_MSGID_NEED_BIND (-2)
00043 #define       META_MSGID_CONNECTING       (-3)
00044 
00045 static int
00046 meta_send_entry(
00047        Operation     *op,
00048        SlapReply     *rs,
00049        metaconn_t    *mc,
00050        int           i,
00051        LDAPMessage   *e );
00052 
00053 typedef enum meta_search_candidate_t {
00054        META_SEARCH_UNDEFINED = -2,
00055        META_SEARCH_ERR = -1,
00056        META_SEARCH_NOT_CANDIDATE,
00057        META_SEARCH_CANDIDATE,
00058        META_SEARCH_BINDING,
00059        META_SEARCH_NEED_BIND,
00060        META_SEARCH_CONNECTING
00061 } meta_search_candidate_t;
00062 
00063 /*
00064  * meta_search_dobind_init()
00065  *
00066  * initiates bind for a candidate target of a search.
00067  */
00068 static meta_search_candidate_t
00069 meta_search_dobind_init(
00070        Operation            *op,
00071        SlapReply            *rs,
00072        metaconn_t           **mcp,
00073        int                  candidate,
00074        SlapReply            *candidates )
00075 {
00076        metaconn_t           *mc = *mcp;
00077        metainfo_t           *mi = ( metainfo_t * )op->o_bd->be_private;
00078        metatarget_t         *mt = mi->mi_targets[ candidate ];
00079        metasingleconn_t     *msc = &mc->mc_conns[ candidate ];
00080 
00081        struct berval        binddn = msc->msc_bound_ndn,
00082                             cred = msc->msc_cred;
00083        int                  method;
00084 
00085        int                  rc;
00086 
00087        meta_search_candidate_t     retcode;
00088 
00089        Debug( LDAP_DEBUG_TRACE, "%s >>> meta_search_dobind_init[%d]\n",
00090               op->o_log_prefix, candidate, 0 );
00091 
00092        /*
00093         * all the targets are already bound as pseudoroot
00094         */
00095        if ( mc->mc_authz_target == META_BOUND_ALL ) {
00096               return META_SEARCH_CANDIDATE;
00097        }
00098 
00099        retcode = META_SEARCH_BINDING;
00100        ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
00101        if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
00102               /* already bound (or anonymous) */
00103 
00104 #ifdef DEBUG_205
00105               char   buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
00106               int    bound = 0;
00107 
00108               if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
00109                      bound = 1;
00110               }
00111 
00112               snprintf( buf, sizeof( buf ), " mc=%p ld=%p%s DN=\"%s\"",
00113                      (void *)mc, (void *)msc->msc_ld,
00114                      bound ? " bound" : " anonymous",
00115                      bound == 0 ? "" : msc->msc_bound_ndn.bv_val );
00116               Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
00117                      op->o_log_prefix, candidate, buf );
00118 #endif /* DEBUG_205 */
00119 
00120               retcode = META_SEARCH_CANDIDATE;
00121 
00122        } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) ) {
00123               /* another thread is binding the target for this conn; wait */
00124 
00125 #ifdef DEBUG_205
00126               char   buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
00127 
00128               snprintf( buf, sizeof( buf ), " mc=%p ld=%p needbind",
00129                      (void *)mc, (void *)msc->msc_ld );
00130               Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
00131                      op->o_log_prefix, candidate, buf );
00132 #endif /* DEBUG_205 */
00133 
00134               candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND;
00135               retcode = META_SEARCH_NEED_BIND;
00136 
00137        } else {
00138               /* we'll need to bind the target for this conn */
00139 
00140 #ifdef DEBUG_205
00141               char buf[ SLAP_TEXT_BUFLEN ];
00142 
00143               snprintf( buf, sizeof( buf ), " mc=%p ld=%p binding",
00144                      (void *)mc, (void *)msc->msc_ld );
00145               Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
00146                      op->o_log_prefix, candidate, buf );
00147 #endif /* DEBUG_205 */
00148 
00149               if ( msc->msc_ld == NULL ) {
00150                      /* for some reason (e.g. because formerly in "binding"
00151                       * state, with eventual connection expiration or invalidation)
00152                       * it was not initialized as expected */
00153 
00154                      Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p ld=NULL\n",
00155                             op->o_log_prefix, candidate, (void *)mc );
00156 
00157                      rc = meta_back_init_one_conn( op, rs, *mcp, candidate,
00158                             LDAP_BACK_CONN_ISPRIV( *mcp ), LDAP_BACK_DONTSEND, 0 );
00159                      switch ( rc ) {
00160                      case LDAP_SUCCESS:
00161                             assert( msc->msc_ld != NULL );
00162                             break;
00163 
00164                      case LDAP_SERVER_DOWN:
00165                      case LDAP_UNAVAILABLE:
00166                             ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
00167                             goto down;
00168        
00169                      default:
00170                             ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
00171                             goto other;
00172                      }
00173               }
00174 
00175               LDAP_BACK_CONN_BINDING_SET( msc );
00176        }
00177 
00178        ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
00179 
00180        if ( retcode != META_SEARCH_BINDING ) {
00181               return retcode;
00182        }
00183 
00184        /* NOTE: this obsoletes pseudorootdn */
00185        if ( op->o_conn != NULL &&
00186               !op->o_do_not_cache &&
00187               ( BER_BVISNULL( &msc->msc_bound_ndn ) ||
00188                      BER_BVISEMPTY( &msc->msc_bound_ndn ) ||
00189                      ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
00190        {
00191               rc = meta_back_proxy_authz_cred( mc, candidate, op, rs, LDAP_BACK_DONTSEND, &binddn, &cred, &method );
00192               switch ( rc ) {
00193               case LDAP_SUCCESS:
00194                      break;
00195               case LDAP_UNAVAILABLE:
00196                      goto down;
00197               default:
00198                      goto other;
00199               }
00200 
00201               /* NOTE: we copy things here, even if bind didn't succeed yet,
00202                * because the connection is not shared until bind is over */
00203               if ( !BER_BVISNULL( &binddn ) ) {
00204                      ber_bvreplace( &msc->msc_bound_ndn, &binddn );
00205                      if ( META_BACK_TGT_SAVECRED( mt ) && !BER_BVISNULL( &cred ) ) {
00206                             if ( !BER_BVISNULL( &msc->msc_cred ) ) {
00207                                    memset( msc->msc_cred.bv_val, 0,
00208                                           msc->msc_cred.bv_len );
00209                             }
00210                             ber_bvreplace( &msc->msc_cred, &cred );
00211                      }
00212               }
00213 
00214               if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
00215                      /* apparently, idassert was configured with SASL bind,
00216                       * so bind occurred inside meta_back_proxy_authz_cred() */
00217                      ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
00218                      LDAP_BACK_CONN_BINDING_CLEAR( msc );
00219                      ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
00220                      return META_SEARCH_CANDIDATE;
00221               }
00222 
00223               /* paranoid */
00224               switch ( method ) {
00225               case LDAP_AUTH_NONE:
00226               case LDAP_AUTH_SIMPLE:
00227                      /* do a simple bind with binddn, cred */
00228                      break;
00229 
00230               default:
00231                      assert( 0 );
00232                      break;
00233               }
00234        }
00235 
00236        assert( msc->msc_ld != NULL );
00237 
00238        /* connect must be async only the first time... */
00239        ldap_set_option( msc->msc_ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_ON );
00240 
00241 retry:;
00242        if ( !BER_BVISEMPTY( &binddn ) && BER_BVISEMPTY( &cred ) ) {
00243               /* bind anonymously? */
00244               Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p: "
00245                      "non-empty dn with empty cred; binding anonymously\n",
00246                      op->o_log_prefix, candidate, (void *)mc );
00247               cred = slap_empty_bv;
00248               
00249        } else if ( BER_BVISEMPTY( &binddn ) && !BER_BVISEMPTY( &cred ) ) {
00250               /* error */
00251               Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p: "
00252                      "empty dn with non-empty cred: error\n",
00253                      op->o_log_prefix, candidate, (void *)mc );
00254               goto other;
00255        }
00256 
00257        rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred,
00258                      NULL, NULL, &candidates[ candidate ].sr_msgid );
00259 
00260 #ifdef DEBUG_205
00261        {
00262               char buf[ SLAP_TEXT_BUFLEN ];
00263 
00264               snprintf( buf, sizeof( buf ), "meta_search_dobind_init[%d] mc=%p ld=%p rc=%d",
00265                      candidate, (void *)mc, (void *)mc->mc_conns[ candidate ].msc_ld, rc );
00266               Debug( LDAP_DEBUG_ANY, "### %s %s\n",
00267                      op->o_log_prefix, buf, 0 );
00268        }
00269 #endif /* DEBUG_205 */
00270 
00271        switch ( rc ) {
00272        case LDAP_SUCCESS:
00273               assert( candidates[ candidate ].sr_msgid >= 0 );
00274               META_BINDING_SET( &candidates[ candidate ] );
00275               return META_SEARCH_BINDING;
00276 
00277        case LDAP_X_CONNECTING:
00278               /* must retry, same conn */
00279               candidates[ candidate ].sr_msgid = META_MSGID_CONNECTING;
00280               ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
00281               LDAP_BACK_CONN_BINDING_CLEAR( msc );
00282               ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
00283               return META_SEARCH_CONNECTING;
00284 
00285        case LDAP_SERVER_DOWN:
00286 down:;
00287               /* This is the worst thing that could happen:
00288                * the search will wait until the retry is over. */
00289               if ( !META_IS_RETRYING( &candidates[ candidate ] ) ) {
00290                      META_RETRYING_SET( &candidates[ candidate ] );
00291 
00292                      ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
00293 
00294                      assert( mc->mc_refcnt > 0 );
00295                      if ( LogTest( LDAP_DEBUG_ANY ) ) {
00296                             char   buf[ SLAP_TEXT_BUFLEN ];
00297 
00298                             /* this lock is required; however,
00299                              * it's invoked only when logging is on */
00300                             ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
00301                             snprintf( buf, sizeof( buf ),
00302                                    "retrying URI=\"%s\" DN=\"%s\"",
00303                                    mt->mt_uri,
00304                                    BER_BVISNULL( &msc->msc_bound_ndn ) ?
00305                                           "" : msc->msc_bound_ndn.bv_val );
00306                             ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
00307 
00308                             Debug( LDAP_DEBUG_ANY,
00309                                    "%s meta_search_dobind_init[%d]: %s.\n",
00310                                    op->o_log_prefix, candidate, buf );
00311                      }
00312 
00313                      meta_clear_one_candidate( op, mc, candidate );
00314                      LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
00315 
00316                      ( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn );
00317 
00318                      /* mc here must be the regular mc, reset and ready for init */
00319                      rc = meta_back_init_one_conn( op, rs, mc, candidate,
00320                             LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 );
00321 
00322                      if ( rc == LDAP_SUCCESS ) {
00323                             LDAP_BACK_CONN_BINDING_SET( msc );
00324                      }
00325 
00326                      ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
00327 
00328                      if ( rc == LDAP_SUCCESS ) {
00329                             candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
00330                             binddn = msc->msc_bound_ndn;
00331                             cred = msc->msc_cred;
00332                             goto retry;
00333                      }
00334               }
00335 
00336               if ( *mcp == NULL ) {
00337                      retcode = META_SEARCH_ERR;
00338                      rs->sr_err = LDAP_UNAVAILABLE;
00339                      candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
00340                      break;
00341               }
00342               /* fall thru */
00343 
00344        default:
00345 other:;
00346               rs->sr_err = rc;
00347               rc = slap_map_api2result( rs );
00348 
00349               ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
00350               meta_clear_one_candidate( op, mc, candidate );
00351               candidates[ candidate ].sr_err = rc;
00352               if ( META_BACK_ONERR_STOP( mi ) ) {
00353                      LDAP_BACK_CONN_TAINTED_SET( mc );
00354                      meta_back_release_conn_lock( mi, mc, 0 );
00355                      *mcp = NULL;
00356                      rs->sr_err = rc;
00357 
00358                      retcode = META_SEARCH_ERR;
00359 
00360               } else {
00361                      retcode = META_SEARCH_NOT_CANDIDATE;
00362               }
00363               candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
00364               ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
00365               break;
00366        }
00367 
00368        return retcode;
00369 }
00370 
00371 static meta_search_candidate_t
00372 meta_search_dobind_result(
00373        Operation            *op,
00374        SlapReply            *rs,
00375        metaconn_t           **mcp,
00376        int                  candidate,
00377        SlapReply            *candidates,
00378        LDAPMessage          *res )
00379 {
00380        metainfo_t           *mi = ( metainfo_t * )op->o_bd->be_private;
00381        metatarget_t         *mt = mi->mi_targets[ candidate ];
00382        metaconn_t           *mc = *mcp;
00383        metasingleconn_t     *msc = &mc->mc_conns[ candidate ];
00384 
00385        meta_search_candidate_t     retcode = META_SEARCH_NOT_CANDIDATE;
00386        int                  rc;
00387 
00388        assert( msc->msc_ld != NULL );
00389 
00390        /* FIXME: matched? referrals? response controls? */
00391        rc = ldap_parse_result( msc->msc_ld, res,
00392               &candidates[ candidate ].sr_err,
00393               NULL, NULL, NULL, NULL, 0 );
00394        if ( rc != LDAP_SUCCESS ) {
00395               candidates[ candidate ].sr_err = rc;
00396        }
00397        rc = slap_map_api2result( &candidates[ candidate ] );
00398 
00399        ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
00400        LDAP_BACK_CONN_BINDING_CLEAR( msc );
00401        if ( rc != LDAP_SUCCESS ) {
00402               meta_clear_one_candidate( op, mc, candidate );
00403               candidates[ candidate ].sr_err = rc;
00404               if ( META_BACK_ONERR_STOP( mi ) ) {
00405                      LDAP_BACK_CONN_TAINTED_SET( mc );
00406                      meta_back_release_conn_lock( mi, mc, 0 );
00407                      *mcp = NULL;
00408                      retcode = META_SEARCH_ERR;
00409                      rs->sr_err = rc;
00410               }
00411 
00412        } else {
00413               /* FIXME: check if bound as idassert authcDN! */
00414               if ( BER_BVISNULL( &msc->msc_bound_ndn )
00415                      || BER_BVISEMPTY( &msc->msc_bound_ndn ) )
00416               {
00417                      LDAP_BACK_CONN_ISANON_SET( msc );
00418 
00419               } else {
00420                      if ( META_BACK_TGT_SAVECRED( mt ) &&
00421                             !BER_BVISNULL( &msc->msc_cred ) &&
00422                             !BER_BVISEMPTY( &msc->msc_cred ) )
00423                      {
00424                             ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
00425                      }
00426                      LDAP_BACK_CONN_ISBOUND_SET( msc );
00427               }
00428               retcode = META_SEARCH_CANDIDATE;
00429 
00430               /* connect must be async */
00431               ldap_set_option( msc->msc_ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_OFF );
00432        }
00433 
00434        candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
00435        META_BINDING_CLEAR( &candidates[ candidate ] );
00436 
00437        ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
00438 
00439        return retcode;
00440 }
00441 
00442 static meta_search_candidate_t
00443 meta_back_search_start(
00444        Operation            *op,
00445        SlapReply            *rs,
00446        dncookie             *dc,
00447        metaconn_t           **mcp,
00448        int                  candidate,
00449        SlapReply            *candidates,
00450        struct berval        *prcookie,
00451        ber_int_t            prsize )
00452 {
00453        metainfo_t           *mi = ( metainfo_t * )op->o_bd->be_private;
00454        metatarget_t         *mt = mi->mi_targets[ candidate ];
00455        metasingleconn_t     *msc = &(*mcp)->mc_conns[ candidate ];
00456        struct berval        realbase = op->o_req_dn;
00457        int                  realscope = op->ors_scope;
00458        struct berval        mbase = BER_BVNULL; 
00459        struct berval        mfilter = BER_BVNULL;
00460        char                 **mapped_attrs = NULL;
00461        int                  rc;
00462        meta_search_candidate_t     retcode;
00463        struct timeval              tv, *tvp = NULL;
00464        int                  nretries = 1;
00465        LDAPControl          **ctrls = NULL;
00466 #ifdef SLAPD_META_CLIENT_PR
00467        LDAPControl          **save_ctrls = NULL;
00468 #endif /* SLAPD_META_CLIENT_PR */
00469 
00470        /* this should not happen; just in case... */
00471        if ( msc->msc_ld == NULL ) {
00472               Debug( LDAP_DEBUG_ANY,
00473                      "%s: meta_back_search_start candidate=%d ld=NULL%s.\n",
00474                      op->o_log_prefix, candidate,
00475                      META_BACK_ONERR_STOP( mi ) ? "" : " (ignored)" );
00476               candidates[ candidate ].sr_err = LDAP_OTHER;
00477               if ( META_BACK_ONERR_STOP( mi ) ) {
00478                      return META_SEARCH_ERR;
00479               }
00480               candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
00481               return META_SEARCH_NOT_CANDIDATE;
00482        }
00483 
00484        Debug( LDAP_DEBUG_TRACE, "%s >>> meta_back_search_start[%d]\n", op->o_log_prefix, candidate, 0 );
00485 
00486        /*
00487         * modifies the base according to the scope, if required
00488         */
00489        if ( mt->mt_nsuffix.bv_len > op->o_req_ndn.bv_len ) {
00490               switch ( op->ors_scope ) {
00491               case LDAP_SCOPE_SUBTREE:
00492                      /*
00493                       * make the target suffix the new base
00494                       * FIXME: this is very forgiving, because
00495                       * "illegal" searchBases may be turned
00496                       * into the suffix of the target; however,
00497                       * the requested searchBase already passed
00498                       * thru the candidate analyzer...
00499                       */
00500                      if ( dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) ) {
00501                             realbase = mt->mt_nsuffix;
00502                             if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
00503                                    realscope = LDAP_SCOPE_SUBORDINATE;
00504                             }
00505 
00506                      } else {
00507                             /*
00508                              * this target is no longer candidate
00509                              */
00510                             retcode = META_SEARCH_NOT_CANDIDATE;
00511                             goto doreturn;
00512                      }
00513                      break;
00514 
00515               case LDAP_SCOPE_SUBORDINATE:
00516               case LDAP_SCOPE_ONELEVEL:
00517               {
00518                      struct berval rdn = mt->mt_nsuffix;
00519                      rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," );
00520                      if ( dnIsOneLevelRDN( &rdn )
00521                                    && dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) )
00522                      {
00523                             /*
00524                              * if there is exactly one level,
00525                              * make the target suffix the new
00526                              * base, and make scope "base"
00527                              */
00528                             realbase = mt->mt_nsuffix;
00529                             if ( op->ors_scope == LDAP_SCOPE_SUBORDINATE ) {
00530                                    if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
00531                                           realscope = LDAP_SCOPE_SUBORDINATE;
00532                                    } else {
00533                                           realscope = LDAP_SCOPE_SUBTREE;
00534                                    }
00535                             } else {
00536                                    realscope = LDAP_SCOPE_BASE;
00537                             }
00538                             break;
00539                      } /* else continue with the next case */
00540               }
00541 
00542               case LDAP_SCOPE_BASE:
00543                      /*
00544                       * this target is no longer candidate
00545                       */
00546                      retcode = META_SEARCH_NOT_CANDIDATE;
00547                      goto doreturn;
00548               }
00549        }
00550 
00551        /* initiate dobind */
00552        retcode = meta_search_dobind_init( op, rs, mcp, candidate, candidates );
00553 
00554        Debug( LDAP_DEBUG_TRACE, "%s <<< meta_search_dobind_init[%d]=%d\n", op->o_log_prefix, candidate, retcode );
00555 
00556        if ( retcode != META_SEARCH_CANDIDATE ) {
00557               goto doreturn;
00558        }
00559 
00560        /*
00561         * Rewrite the search base, if required
00562         */
00563        dc->target = mt;
00564        dc->ctx = "searchBase";
00565        switch ( ldap_back_dn_massage( dc, &realbase, &mbase ) ) {
00566        case LDAP_SUCCESS:
00567               break;
00568 
00569        case LDAP_UNWILLING_TO_PERFORM:
00570               rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
00571               rs->sr_text = "Operation not allowed";
00572               send_ldap_result( op, rs );
00573               retcode = META_SEARCH_ERR;
00574               goto doreturn;
00575 
00576        default:
00577 
00578               /*
00579                * this target is no longer candidate
00580                */
00581               retcode = META_SEARCH_NOT_CANDIDATE;
00582               goto doreturn;
00583        }
00584 
00585        /*
00586         * Maps filter
00587         */
00588        rc = ldap_back_filter_map_rewrite( dc, op->ors_filter,
00589                      &mfilter, BACKLDAP_MAP, op->o_tmpmemctx );
00590        switch ( rc ) {
00591        case LDAP_SUCCESS:
00592               break;
00593 
00594        case LDAP_COMPARE_FALSE:
00595        default:
00596               /*
00597                * this target is no longer candidate
00598                */
00599               retcode = META_SEARCH_NOT_CANDIDATE;
00600               goto done;
00601        }
00602 
00603        /*
00604         * Maps required attributes
00605         */
00606        rc = ldap_back_map_attrs( op, &mt->mt_rwmap.rwm_at,
00607                      op->ors_attrs, BACKLDAP_MAP, &mapped_attrs );
00608        if ( rc != LDAP_SUCCESS ) {
00609               /*
00610                * this target is no longer candidate
00611                */
00612               retcode = META_SEARCH_NOT_CANDIDATE;
00613               goto done;
00614        }
00615 
00616        if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
00617               tv.tv_sec = op->ors_tlimit > 0 ? op->ors_tlimit : 1;
00618               tv.tv_usec = 0;
00619               tvp = &tv;
00620        }
00621 
00622 #ifdef SLAPD_META_CLIENT_PR
00623        save_ctrls = op->o_ctrls;
00624        {
00625               LDAPControl *pr_c = NULL;
00626               int i = 0, nc = 0;
00627 
00628               if ( save_ctrls ) {
00629                      for ( ; save_ctrls[i] != NULL; i++ );
00630                      nc = i;
00631                      pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, save_ctrls, NULL );
00632               }
00633 
00634               if ( pr_c != NULL ) nc--;
00635               if ( mt->mt_ps > 0 || prcookie != NULL ) nc++;
00636 
00637               if ( mt->mt_ps > 0 || prcookie != NULL || pr_c != NULL ) {
00638                      int src = 0, dst = 0;
00639                      BerElementBuffer berbuf;
00640                      BerElement *ber = (BerElement *)&berbuf;
00641                      struct berval val = BER_BVNULL;
00642                      ber_len_t len;
00643 
00644                      len = sizeof( LDAPControl * )*( nc + 1 ) + sizeof( LDAPControl );
00645 
00646                      if ( mt->mt_ps > 0 || prcookie != NULL ) {
00647                             struct berval nullcookie = BER_BVNULL;
00648                             ber_tag_t tag;
00649 
00650                             if ( prsize == 0 && mt->mt_ps > 0 ) prsize = mt->mt_ps;
00651                             if ( prcookie == NULL ) prcookie = &nullcookie;
00652 
00653                             ber_init2( ber, NULL, LBER_USE_DER );
00654                             tag = ber_printf( ber, "{iO}", prsize, prcookie ); 
00655                             if ( tag == LBER_ERROR ) {
00656                                    /* error */
00657                                    (void) ber_free_buf( ber );
00658                                    goto done_pr;
00659                             }
00660 
00661                             tag = ber_flatten2( ber, &val, 0 );
00662                             if ( tag == LBER_ERROR ) {
00663                                    /* error */
00664                                    (void) ber_free_buf( ber );
00665                                    goto done_pr;
00666                             }
00667 
00668                             len += val.bv_len + 1;
00669                      }
00670 
00671                      op->o_ctrls = op->o_tmpalloc( len, op->o_tmpmemctx );
00672                      if ( save_ctrls ) {
00673                             for ( ; save_ctrls[ src ] != NULL; src++ ) {
00674                                    if ( save_ctrls[ src ] != pr_c ) {
00675                                           op->o_ctrls[ dst ] = save_ctrls[ src ];
00676                                           dst++;
00677                                    }
00678                             }
00679                      }
00680 
00681                      if ( mt->mt_ps > 0 || prcookie != NULL ) {
00682                             op->o_ctrls[ dst ] = (LDAPControl *)&op->o_ctrls[ nc + 1 ];
00683 
00684                             op->o_ctrls[ dst ]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
00685                             op->o_ctrls[ dst ]->ldctl_iscritical = 1;
00686 
00687                             op->o_ctrls[ dst ]->ldctl_value.bv_val = (char *)&op->o_ctrls[ dst ][ 1 ];
00688                             AC_MEMCPY( op->o_ctrls[ dst ]->ldctl_value.bv_val, val.bv_val, val.bv_len + 1 );
00689                             op->o_ctrls[ dst ]->ldctl_value.bv_len = val.bv_len;
00690                             dst++;
00691 
00692                             (void)ber_free_buf( ber );
00693                      }
00694 
00695                      op->o_ctrls[ dst ] = NULL;
00696               }
00697 done_pr:;
00698        }
00699 #endif /* SLAPD_META_CLIENT_PR */
00700 
00701 retry:;
00702        ctrls = op->o_ctrls;
00703        if ( meta_back_controls_add( op, rs, *mcp, candidate, &ctrls )
00704               != LDAP_SUCCESS )
00705        {
00706               candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
00707               retcode = META_SEARCH_NOT_CANDIDATE;
00708               goto done;
00709        }
00710 
00711        /*
00712         * Starts the search
00713         */
00714        assert( msc->msc_ld != NULL );
00715        rc = ldap_pvt_search( msc->msc_ld,
00716                      mbase.bv_val, realscope, mfilter.bv_val,
00717                      mapped_attrs, op->ors_attrsonly,
00718                      ctrls, NULL, tvp, op->ors_slimit, op->ors_deref,
00719                      &candidates[ candidate ].sr_msgid ); 
00720        switch ( rc ) {
00721        case LDAP_SUCCESS:
00722               retcode = META_SEARCH_CANDIDATE;
00723               break;
00724        
00725        case LDAP_SERVER_DOWN:
00726               if ( nretries && meta_back_retry( op, rs, mcp, candidate, LDAP_BACK_DONTSEND ) ) {
00727                      nretries = 0;
00728                      /* if the identity changed, there might be need to re-authz */
00729                      (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
00730                      goto retry;
00731               }
00732 
00733               if ( *mcp == NULL ) {
00734                      retcode = META_SEARCH_ERR;
00735                      candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
00736                      break;
00737               }
00738               /* fall thru */
00739 
00740        default:
00741               candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
00742               retcode = META_SEARCH_NOT_CANDIDATE;
00743        }
00744 
00745 done:;
00746        (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
00747 #ifdef SLAPD_META_CLIENT_PR
00748        if ( save_ctrls != op->o_ctrls ) {
00749               op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx );
00750               op->o_ctrls = save_ctrls;
00751        }
00752 #endif /* SLAPD_META_CLIENT_PR */
00753 
00754        if ( mapped_attrs ) {
00755               ber_memfree_x( mapped_attrs, op->o_tmpmemctx );
00756        }
00757        if ( mfilter.bv_val != op->ors_filterstr.bv_val ) {
00758               ber_memfree_x( mfilter.bv_val, op->o_tmpmemctx );
00759        }
00760        if ( mbase.bv_val != realbase.bv_val ) {
00761               free( mbase.bv_val );
00762        }
00763 
00764 doreturn:;
00765        Debug( LDAP_DEBUG_TRACE, "%s <<< meta_back_search_start[%d]=%d\n", op->o_log_prefix, candidate, retcode );
00766 
00767        return retcode;
00768 }
00769 
00770 int
00771 meta_back_search( Operation *op, SlapReply *rs )
00772 {
00773        metainfo_t    *mi = ( metainfo_t * )op->o_bd->be_private;
00774        metaconn_t    *mc;
00775        struct timeval       save_tv = { 0, 0 },
00776                      tv;
00777        time_t        stoptime = (time_t)(-1),
00778                      lastres_time = slap_get_time(),
00779                      timeout = 0;
00780        int           rc = 0, sres = LDAP_SUCCESS;
00781        char          *matched = NULL;
00782        int           last = 0, ncandidates = 0,
00783                      initial_candidates = 0, candidate_match = 0,
00784                      needbind = 0;
00785        ldap_back_send_t     sendok = LDAP_BACK_SENDERR;
00786        long          i;
00787        dncookie      dc;
00788        int           is_ok = 0;
00789        void          *savepriv;
00790        SlapReply     *candidates = NULL;
00791        int           do_taint = 0;
00792 
00793        rs_assert_ready( rs );
00794        rs->sr_flags &= ~REP_ENTRY_MASK; /* paranoia, we can set rs = non-entry */
00795 
00796        /*
00797         * controls are set in ldap_back_dobind()
00798         * 
00799         * FIXME: in case of values return filter, we might want
00800         * to map attrs and maybe rewrite value
00801         */
00802 getconn:;
00803        mc = meta_back_getconn( op, rs, NULL, sendok );
00804        if ( !mc ) {
00805               return rs->sr_err;
00806        }
00807 
00808        dc.conn = op->o_conn;
00809        dc.rs = rs;
00810 
00811        if ( candidates == NULL ) candidates = meta_back_candidates_get( op );
00812        /*
00813         * Inits searches
00814         */
00815        for ( i = 0; i < mi->mi_ntargets; i++ ) {
00816               /* reset sr_msgid; it is used in most loops
00817                * to check if that target is still to be considered */
00818               candidates[ i ].sr_msgid = META_MSGID_IGNORE;
00819 
00820               /* a target is marked as candidate by meta_back_getconn();
00821                * if for any reason (an error, it's over or so) it is
00822                * no longer active, sr_msgid is set to META_MSGID_IGNORE
00823                * but it remains candidate, which means it has been active
00824                * at some point during the operation.  This allows to 
00825                * use its response code and more to compute the final
00826                * response */
00827               if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
00828                      continue;
00829               }
00830 
00831               candidates[ i ].sr_matched = NULL;
00832               candidates[ i ].sr_text = NULL;
00833               candidates[ i ].sr_ref = NULL;
00834               candidates[ i ].sr_ctrls = NULL;
00835               candidates[ i ].sr_nentries = 0;
00836 
00837               /* get largest timeout among candidates */
00838               if ( mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ]
00839                      && mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ] > timeout )
00840               {
00841                      timeout = mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ];
00842               }
00843        }
00844 
00845        for ( i = 0; i < mi->mi_ntargets; i++ ) {
00846               if ( !META_IS_CANDIDATE( &candidates[ i ] )
00847                      || candidates[ i ].sr_err != LDAP_SUCCESS )
00848               {
00849                      continue;
00850               }
00851 
00852               switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 ) )
00853               {
00854               case META_SEARCH_NOT_CANDIDATE:
00855                      candidates[ i ].sr_msgid = META_MSGID_IGNORE;
00856                      break;
00857 
00858               case META_SEARCH_NEED_BIND:
00859                      ++needbind;
00860                      /* fallthru */
00861 
00862               case META_SEARCH_CONNECTING:
00863               case META_SEARCH_CANDIDATE:
00864               case META_SEARCH_BINDING:
00865                      candidates[ i ].sr_type = REP_INTERMEDIATE;
00866                      ++ncandidates;
00867                      break;
00868 
00869               case META_SEARCH_ERR:
00870                      savepriv = op->o_private;
00871                      op->o_private = (void *)i;
00872                      send_ldap_result( op, rs );
00873                      op->o_private = savepriv;
00874                      rc = -1;
00875                      goto finish;
00876 
00877               default:
00878                      assert( 0 );
00879                      break;
00880               }
00881        }
00882 
00883        if ( ncandidates > 0 && needbind == ncandidates ) {
00884               /*
00885                * give up the second time...
00886                *
00887                * NOTE: this should not occur the second time, since a fresh
00888                * connection has ben created; however, targets may also
00889                * need bind because the bind timed out or so.
00890                */
00891               if ( sendok & LDAP_BACK_BINDING ) {
00892                      Debug( LDAP_DEBUG_ANY,
00893                             "%s meta_back_search: unable to initialize conn\n",
00894                             op->o_log_prefix, 0, 0 );
00895                      rs->sr_err = LDAP_UNAVAILABLE;
00896                      rs->sr_text = "unable to initialize connection to remote targets";
00897                      send_ldap_result( op, rs );
00898                      rc = -1;
00899                      goto finish;
00900               }
00901 
00902               /* FIXME: better create a separate connection? */
00903               sendok |= LDAP_BACK_BINDING;
00904 
00905 #ifdef DEBUG_205
00906               Debug( LDAP_DEBUG_ANY, "*** %s drop mc=%p create new connection\n",
00907                      op->o_log_prefix, (void *)mc, 0 );
00908 #endif /* DEBUG_205 */
00909 
00910               meta_back_release_conn( mi, mc );
00911               mc = NULL;
00912 
00913               needbind = 0;
00914               ncandidates = 0;
00915 
00916               goto getconn;
00917        }
00918 
00919        initial_candidates = ncandidates;
00920 
00921        if ( LogTest( LDAP_DEBUG_TRACE ) ) {
00922               char   cnd[ SLAP_TEXT_BUFLEN ];
00923               int    c;
00924 
00925               for ( c = 0; c < mi->mi_ntargets; c++ ) {
00926                      if ( META_IS_CANDIDATE( &candidates[ c ] ) ) {
00927                             cnd[ c ] = '*';
00928                      } else {
00929                             cnd[ c ] = ' ';
00930                      }
00931               }
00932               cnd[ c ] = '\0';
00933 
00934               Debug( LDAP_DEBUG_TRACE, "%s meta_back_search: ncandidates=%d "
00935                      "cnd=\"%s\"\n", op->o_log_prefix, ncandidates, cnd );
00936        }
00937 
00938        if ( initial_candidates == 0 ) {
00939               /* NOTE: here we are not sending any matchedDN;
00940                * this is intended, because if the back-meta
00941                * is serving this search request, but no valid
00942                * candidate could be looked up, it means that
00943                * there is a hole in the mapping of the targets
00944                * and thus no knowledge of any remote superior
00945                * is available */
00946               Debug( LDAP_DEBUG_ANY, "%s meta_back_search: "
00947                      "base=\"%s\" scope=%d: "
00948                      "no candidate could be selected\n",
00949                      op->o_log_prefix, op->o_req_dn.bv_val,
00950                      op->ors_scope );
00951 
00952               /* FIXME: we're sending the first error we encounter;
00953                * maybe we should pick the worst... */
00954               rc = LDAP_NO_SUCH_OBJECT;
00955               for ( i = 0; i < mi->mi_ntargets; i++ ) {
00956                      if ( META_IS_CANDIDATE( &candidates[ i ] )
00957                             && candidates[ i ].sr_err != LDAP_SUCCESS )
00958                      {
00959                             rc = candidates[ i ].sr_err;
00960                             break;
00961                      }
00962               }
00963 
00964               send_ldap_error( op, rs, rc, NULL );
00965 
00966               goto finish;
00967        }
00968 
00969        /* We pull apart the ber result, stuff it into a slapd entry, and
00970         * let send_search_entry stuff it back into ber format. Slow & ugly,
00971         * but this is necessary for version matching, and for ACL processing.
00972         */
00973 
00974        if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
00975               stoptime = op->o_time + op->ors_tlimit;
00976        }
00977 
00978        /*
00979         * In case there are no candidates, no cycle takes place...
00980         *
00981         * FIXME: we might use a queue, to better balance the load 
00982         * among the candidates
00983         */
00984        for ( rc = 0; ncandidates > 0; ) {
00985               int    gotit = 0,
00986                      doabandon = 0,
00987                      alreadybound = ncandidates;
00988 
00989               /* check timeout */
00990               if ( timeout && lastres_time > 0
00991                      && ( slap_get_time() - lastres_time ) > timeout )
00992               {
00993                      doabandon = 1;
00994                      rs->sr_text = "Operation timed out";
00995                      rc = rs->sr_err = op->o_protocol >= LDAP_VERSION3 ?
00996                             LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
00997                      savepriv = op->o_private;
00998                      op->o_private = (void *)i;
00999                      send_ldap_result( op, rs );
01000                      op->o_private = savepriv;
01001                      goto finish;
01002               }
01003 
01004               /* check time limit */
01005               if ( op->ors_tlimit != SLAP_NO_LIMIT
01006                             && slap_get_time() > stoptime )
01007               {
01008                      doabandon = 1;
01009                      rc = rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
01010                      savepriv = op->o_private;
01011                      op->o_private = (void *)i;
01012                      send_ldap_result( op, rs );
01013                      op->o_private = savepriv;
01014                      goto finish;
01015               }
01016 
01017               for ( i = 0; i < mi->mi_ntargets; i++ ) {
01018                      meta_search_candidate_t     retcode = META_SEARCH_UNDEFINED;
01019                      metasingleconn_t     *msc = &mc->mc_conns[ i ];
01020                      LDAPMessage          *res = NULL, *msg;
01021 
01022                      /* if msgid is invalid, don't ldap_result() */
01023                      if ( candidates[ i ].sr_msgid == META_MSGID_IGNORE ) {
01024                             continue;
01025                      }
01026 
01027                      /* if target still needs bind, retry */
01028                      if ( candidates[ i ].sr_msgid == META_MSGID_NEED_BIND
01029                             || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
01030                      {
01031                             /* initiate dobind */
01032                             retcode = meta_search_dobind_init( op, rs, &mc, i, candidates );
01033 
01034                             Debug( LDAP_DEBUG_TRACE, "%s <<< meta_search_dobind_init[%ld]=%d\n",
01035                                    op->o_log_prefix, i, retcode );
01036 
01037                             switch ( retcode ) {
01038                             case META_SEARCH_NEED_BIND:
01039                                    alreadybound--;
01040                                    /* fallthru */
01041 
01042                             case META_SEARCH_CONNECTING:
01043                             case META_SEARCH_BINDING:
01044                                    break;
01045 
01046                             case META_SEARCH_ERR:
01047                                    candidates[ i ].sr_err = rs->sr_err;
01048                                    if ( META_BACK_ONERR_STOP( mi ) ) {
01049                                           savepriv = op->o_private;
01050                                           op->o_private = (void *)i;
01051                                           send_ldap_result( op, rs );
01052                                           op->o_private = savepriv;
01053                                           goto finish;
01054                                    }
01055                                    /* fallthru */
01056 
01057                             case META_SEARCH_NOT_CANDIDATE:
01058                                    /*
01059                                     * When no candidates are left,
01060                                     * the outer cycle finishes
01061                                     */
01062                                    candidates[ i ].sr_msgid = META_MSGID_IGNORE;
01063                                    assert( ncandidates > 0 );
01064                                    --ncandidates;
01065                                    break;
01066 
01067                             case META_SEARCH_CANDIDATE:
01068                                    candidates[ i ].sr_msgid = META_MSGID_IGNORE;
01069                                    switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 ) )
01070                                    {
01071                                    case META_SEARCH_CANDIDATE:
01072                                           assert( candidates[ i ].sr_msgid >= 0 );
01073                                           break;
01074 
01075                                    case META_SEARCH_ERR:
01076                                           candidates[ i ].sr_err = rs->sr_err;
01077                                           if ( META_BACK_ONERR_STOP( mi ) ) {
01078                                                  savepriv = op->o_private;
01079                                                  op->o_private = (void *)i;
01080                                                  send_ldap_result( op, rs );
01081                                                  op->o_private = savepriv;
01082                                                  goto finish;
01083                                           }
01084                                           /* fallthru */
01085 
01086                                    case META_SEARCH_NOT_CANDIDATE:
01087                                           /* means that meta_back_search_start()
01088                                            * failed but onerr == continue */
01089                                           candidates[ i ].sr_msgid = META_MSGID_IGNORE;
01090                                           assert( ncandidates > 0 );
01091                                           --ncandidates;
01092                                           break;
01093 
01094                                    default:
01095                                           /* impossible */
01096                                           assert( 0 );
01097                                           break;
01098                                    }
01099                                    break;
01100 
01101                             default:
01102                                    /* impossible */
01103                                    assert( 0 );
01104                                    break;
01105                             }
01106                             continue;
01107                      }
01108 
01109                      /* check for abandon */
01110                      if ( op->o_abandon || LDAP_BACK_CONN_ABANDON( mc ) ) {
01111                             break;
01112                      }
01113 
01114 #ifdef DEBUG_205
01115                      if ( msc->msc_ld == NULL ) {
01116                             char   buf[ SLAP_TEXT_BUFLEN ];
01117 
01118                             ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
01119                             snprintf( buf, sizeof( buf ),
01120                                    "%s meta_back_search[%ld] mc=%p msgid=%d%s%s%s\n",
01121                                    op->o_log_prefix, (long)i, (void *)mc,
01122                                    candidates[ i ].sr_msgid,
01123                                    META_IS_BINDING( &candidates[ i ] ) ? " binding" : "",
01124                                    LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ? " connbinding" : "",
01125                                    META_BACK_CONN_CREATING( &mc->mc_conns[ i ] ) ? " conncreating" : "" );
01126                             ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
01127                                    
01128                             Debug( LDAP_DEBUG_ANY, "!!! %s\n", buf, 0, 0 );
01129                      }
01130 #endif /* DEBUG_205 */
01131                      
01132                      /*
01133                       * FIXME: handle time limit as well?
01134                       * Note that target servers are likely 
01135                       * to handle it, so at some time we'll
01136                       * get a LDAP_TIMELIMIT_EXCEEDED from
01137                       * one of them ...
01138                       */
01139                      tv = save_tv;
01140                      rc = ldap_result( msc->msc_ld, candidates[ i ].sr_msgid,
01141                                    LDAP_MSG_RECEIVED, &tv, &res );
01142                      switch ( rc ) {
01143                      case 0:
01144                             /* FIXME: res should not need to be freed */
01145                             assert( res == NULL );
01146                             continue;
01147 
01148                      case -1:
01149 really_bad:;
01150                             /* something REALLY bad happened! */
01151                             if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
01152                                    candidates[ i ].sr_type = REP_RESULT;
01153 
01154                                    if ( meta_back_retry( op, rs, &mc, i, LDAP_BACK_DONTSEND ) ) {
01155                                           candidates[ i ].sr_msgid = META_MSGID_IGNORE;
01156                                           switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 ) )
01157                                           {
01158                                                  /* means that failed but onerr == continue */
01159                                           case META_SEARCH_NOT_CANDIDATE:
01160                                                  candidates[ i ].sr_msgid = META_MSGID_IGNORE;
01161 
01162                                                  assert( ncandidates > 0 );
01163                                                  --ncandidates;
01164 
01165                                                  candidates[ i ].sr_err = rs->sr_err;
01166                                                  if ( META_BACK_ONERR_STOP( mi ) ) {
01167                                                         savepriv = op->o_private;
01168                                                         op->o_private = (void *)i;
01169                                                         send_ldap_result( op, rs );
01170                                                         op->o_private = savepriv;
01171                                                         goto finish;
01172                                                  }
01173                                                  /* fall thru */
01174 
01175                                           case META_SEARCH_CANDIDATE:
01176                                                  /* get back into business... */
01177                                                  continue;
01178 
01179                                           case META_SEARCH_BINDING:
01180                                           case META_SEARCH_CONNECTING:
01181                                           case META_SEARCH_NEED_BIND:
01182                                           case META_SEARCH_UNDEFINED:
01183                                                  assert( 0 );
01184 
01185                                           default:
01186                                                  /* unrecoverable error */
01187                                                  candidates[ i ].sr_msgid = META_MSGID_IGNORE;
01188                                                  rc = rs->sr_err = LDAP_OTHER;
01189                                                  goto finish;
01190                                           }
01191                                    }
01192 
01193                                    candidates[ i ].sr_err = rs->sr_err;
01194                                    if ( META_BACK_ONERR_STOP( mi ) ) {
01195                                           savepriv = op->o_private;
01196                                           op->o_private = (void *)i;
01197                                           send_ldap_result( op, rs );
01198                                           op->o_private = savepriv;
01199                                           goto finish;
01200                                    }
01201                             }
01202 
01203                             /*
01204                              * When no candidates are left,
01205                              * the outer cycle finishes
01206                              */
01207                             candidates[ i ].sr_msgid = META_MSGID_IGNORE;
01208                             assert( ncandidates > 0 );
01209                             --ncandidates;
01210                             rs->sr_err = candidates[ i ].sr_err;
01211                             continue;
01212 
01213                      default:
01214                             lastres_time = slap_get_time();
01215 
01216                             /* only touch when activity actually took place... */
01217                             if ( mi->mi_idle_timeout != 0 && msc->msc_time < lastres_time ) {
01218                                    msc->msc_time = lastres_time;
01219                             }
01220                             break;
01221                      }
01222 
01223                      for ( msg = ldap_first_message( msc->msc_ld, res );
01224                             msg != NULL;
01225                             msg = ldap_next_message( msc->msc_ld, msg ) )
01226                      {
01227                             rc = ldap_msgtype( msg );
01228                             if ( rc == LDAP_RES_SEARCH_ENTRY ) {
01229                                    LDAPMessage   *e;
01230 
01231                                    if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
01232                                           /* don't retry any more... */
01233                                           candidates[ i ].sr_type = REP_RESULT;
01234                                    }
01235 
01236                                    /* count entries returned by target */
01237                                    candidates[ i ].sr_nentries++;
01238 
01239                                    is_ok++;
01240 
01241                                    e = ldap_first_entry( msc->msc_ld, msg );
01242                                    savepriv = op->o_private;
01243                                    op->o_private = (void *)i;
01244                                    rs->sr_err = meta_send_entry( op, rs, mc, i, e );
01245 
01246                                    switch ( rs->sr_err ) {
01247                                    case LDAP_SIZELIMIT_EXCEEDED:
01248                                           savepriv = op->o_private;
01249                                           op->o_private = (void *)i;
01250                                           send_ldap_result( op, rs );
01251                                           op->o_private = savepriv;
01252                                           rs->sr_err = LDAP_SUCCESS;
01253                                           ldap_msgfree( res );
01254                                           res = NULL;
01255                                           goto finish;
01256 
01257                                    case LDAP_UNAVAILABLE:
01258                                           rs->sr_err = LDAP_OTHER;
01259                                           ldap_msgfree( res );
01260                                           res = NULL;
01261                                           goto finish;
01262                                    }
01263                                    op->o_private = savepriv;
01264 
01265                                    /* don't wait any longer... */
01266                                    gotit = 1;
01267                                    save_tv.tv_sec = 0;
01268                                    save_tv.tv_usec = 0;
01269 
01270                             } else if ( rc == LDAP_RES_SEARCH_REFERENCE ) {
01271                                    char          **references = NULL;
01272                                    int           cnt;
01273 
01274                                    if ( META_BACK_TGT_NOREFS( mi->mi_targets[ i ] ) ) {
01275                                           continue;
01276                                    }
01277 
01278                                    if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
01279                                           /* don't retry any more... */
01280                                           candidates[ i ].sr_type = REP_RESULT;
01281                                    }
01282        
01283                                    is_ok++;
01284        
01285                                    rc = ldap_parse_reference( msc->msc_ld, msg,
01286                                                  &references, &rs->sr_ctrls, 0 );
01287        
01288                                    if ( rc != LDAP_SUCCESS ) {
01289                                           continue;
01290                                    }
01291        
01292                                    if ( references == NULL ) {
01293                                           continue;
01294                                    }
01295 
01296 #ifdef ENABLE_REWRITE
01297                                    dc.ctx = "referralDN";
01298 #else /* ! ENABLE_REWRITE */
01299                                    dc.tofrom = 0;
01300                                    dc.normalized = 0;
01301 #endif /* ! ENABLE_REWRITE */
01302 
01303                                    /* FIXME: merge all and return at the end */
01304        
01305                                    for ( cnt = 0; references[ cnt ]; cnt++ )
01306                                           ;
01307        
01308                                    rs->sr_ref = ber_memalloc_x( sizeof( struct berval ) * ( cnt + 1 ),
01309                                           op->o_tmpmemctx );
01310        
01311                                    for ( cnt = 0; references[ cnt ]; cnt++ ) {
01312                                           ber_str2bv_x( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ],
01313                                           op->o_tmpmemctx );
01314                                    }
01315                                    BER_BVZERO( &rs->sr_ref[ cnt ] );
01316        
01317                                    ( void )ldap_back_referral_result_rewrite( &dc, rs->sr_ref,
01318                                           op->o_tmpmemctx );
01319 
01320                                    if ( rs->sr_ref != NULL && !BER_BVISNULL( &rs->sr_ref[ 0 ] ) ) {
01321                                           /* ignore return value by now */
01322                                           savepriv = op->o_private;
01323                                           op->o_private = (void *)i;
01324                                           ( void )send_search_reference( op, rs );
01325                                           op->o_private = savepriv;
01326        
01327                                           ber_bvarray_free_x( rs->sr_ref, op->o_tmpmemctx );
01328                                           rs->sr_ref = NULL;
01329                                    }
01330 
01331                                    /* cleanup */
01332                                    if ( references ) {
01333                                           ber_memvfree( (void **)references );
01334                                    }
01335 
01336                                    if ( rs->sr_ctrls ) {
01337                                           ldap_controls_free( rs->sr_ctrls );
01338                                           rs->sr_ctrls = NULL;
01339                                    }
01340 
01341                             } else if ( rc == LDAP_RES_INTERMEDIATE ) {
01342                                    if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
01343                                           /* don't retry any more... */
01344                                           candidates[ i ].sr_type = REP_RESULT;
01345                                    }
01346        
01347                                    /* FIXME: response controls
01348                                     * are passed without checks */
01349                                    rs->sr_err = ldap_parse_intermediate( msc->msc_ld,
01350                                           msg,
01351                                           (char **)&rs->sr_rspoid,
01352                                           &rs->sr_rspdata,
01353                                           &rs->sr_ctrls,
01354                                           0 );
01355                                    if ( rs->sr_err != LDAP_SUCCESS ) {
01356                                           candidates[ i ].sr_type = REP_RESULT;
01357                                           ldap_msgfree( res );
01358                                           res = NULL;
01359                                           goto really_bad;
01360                                    }
01361 
01362                                    slap_send_ldap_intermediate( op, rs );
01363 
01364                                    if ( rs->sr_rspoid != NULL ) {
01365                                           ber_memfree( (char *)rs->sr_rspoid );
01366                                           rs->sr_rspoid = NULL;
01367                                    }
01368 
01369                                    if ( rs->sr_rspdata != NULL ) {
01370                                           ber_bvfree( rs->sr_rspdata );
01371                                           rs->sr_rspdata = NULL;
01372                                    }
01373 
01374                                    if ( rs->sr_ctrls != NULL ) {
01375                                           ldap_controls_free( rs->sr_ctrls );
01376                                           rs->sr_ctrls = NULL;
01377                                    }
01378 
01379                             } else if ( rc == LDAP_RES_SEARCH_RESULT ) {
01380                                    char          buf[ SLAP_TEXT_BUFLEN ];
01381                                    char          **references = NULL;
01382                                    LDAPControl   **ctrls = NULL;
01383 
01384                                    if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
01385                                           /* don't retry any more... */
01386                                           candidates[ i ].sr_type = REP_RESULT;
01387                                    }
01388        
01389                                    candidates[ i ].sr_msgid = META_MSGID_IGNORE;
01390 
01391                                    /* NOTE: ignores response controls
01392                                     * (and intermediate response controls
01393                                     * as well, except for those with search
01394                                     * references); this may not be correct,
01395                                     * but if they're not ignored then
01396                                     * back-meta would need to merge them
01397                                     * consistently (think of pagedResults...)
01398                                     */
01399                                    /* FIXME: response controls? */
01400                                    rs->sr_err = ldap_parse_result( msc->msc_ld,
01401                                           msg,
01402                                           &candidates[ i ].sr_err,
01403                                           (char **)&candidates[ i ].sr_matched,
01404                                           (char **)&candidates[ i ].sr_text,
01405                                           &references,
01406                                           &ctrls /* &candidates[ i ].sr_ctrls (unused) */ ,
01407                                           0 );
01408                                    if ( rs->sr_err != LDAP_SUCCESS ) {
01409                                           candidates[ i ].sr_err = rs->sr_err;
01410                                           sres = slap_map_api2result( &candidates[ i ] );
01411                                           candidates[ i ].sr_type = REP_RESULT;
01412                                           ldap_msgfree( res );
01413                                           res = NULL;
01414                                           goto really_bad;
01415                                    }
01416 
01417                                    rs->sr_err = candidates[ i ].sr_err;
01418 
01419                                    /* massage matchedDN if need be */
01420                                    if ( candidates[ i ].sr_matched != NULL ) {
01421                                           struct berval match, mmatch;
01422 
01423                                           ber_str2bv( candidates[ i ].sr_matched,
01424                                                  0, 0, &match );
01425                                           candidates[ i ].sr_matched = NULL;
01426 
01427                                           dc.ctx = "matchedDN";
01428                                           dc.target = mi->mi_targets[ i ];
01429                                           if ( !ldap_back_dn_massage( &dc, &match, &mmatch ) ) {
01430                                                  if ( mmatch.bv_val == match.bv_val ) {
01431                                                         candidates[ i ].sr_matched
01432                                                                = ch_strdup( mmatch.bv_val );
01433 
01434                                                  } else {
01435                                                         candidates[ i ].sr_matched = mmatch.bv_val;
01436                                                  }
01437 
01438                                                  candidate_match++;
01439                                           } 
01440                                           ldap_memfree( match.bv_val );
01441                                    }
01442 
01443                                    /* add references to array */
01444                                    /* RFC 4511: referrals can only appear
01445                                     * if result code is LDAP_REFERRAL */
01446                                    if ( references != NULL
01447                                           && references[ 0 ] != NULL
01448                                           && references[ 0 ][ 0 ] != '\0' )
01449                                    {
01450                                           if ( rs->sr_err != LDAP_REFERRAL ) {
01451                                                  Debug( LDAP_DEBUG_ANY,
01452                                                         "%s meta_back_search[%ld]: "
01453                                                         "got referrals with err=%d\n",
01454                                                         op->o_log_prefix,
01455                                                         i, rs->sr_err );
01456 
01457                                           } else {
01458                                                  BerVarray     sr_ref;
01459                                                  int           cnt;
01460        
01461                                                  for ( cnt = 0; references[ cnt ]; cnt++ )
01462                                                         ;
01463        
01464                                                  sr_ref = ber_memalloc_x( sizeof( struct berval ) * ( cnt + 1 ),
01465                                                         op->o_tmpmemctx );
01466        
01467                                                  for ( cnt = 0; references[ cnt ]; cnt++ ) {
01468                                                         ber_str2bv_x( references[ cnt ], 0, 1, &sr_ref[ cnt ],
01469                                                                op->o_tmpmemctx );
01470                                                  }
01471                                                  BER_BVZERO( &sr_ref[ cnt ] );
01472        
01473                                                  ( void )ldap_back_referral_result_rewrite( &dc, sr_ref,
01474                                                         op->o_tmpmemctx );
01475                                    
01476                                                  if ( rs->sr_v2ref == NULL ) {
01477                                                         rs->sr_v2ref = sr_ref;
01478 
01479                                                  } else {
01480                                                         for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) {
01481                                                                ber_bvarray_add_x( &rs->sr_v2ref, &sr_ref[ cnt ],
01482                                                                       op->o_tmpmemctx );
01483                                                         }
01484                                                         ber_memfree_x( sr_ref, op->o_tmpmemctx );
01485                                                  }
01486                                           }
01487 
01488                                    } else if ( rs->sr_err == LDAP_REFERRAL ) {
01489                                           Debug( LDAP_DEBUG_ANY,
01490                                                  "%s meta_back_search[%ld]: "
01491                                                  "got err=%d with null "
01492                                                  "or empty referrals\n",
01493                                                  op->o_log_prefix,
01494                                                  i, rs->sr_err );
01495 
01496                                           rs->sr_err = LDAP_NO_SUCH_OBJECT;
01497                                    }
01498 
01499                                    /* cleanup */
01500                                    ber_memvfree( (void **)references );
01501 
01502                                    sres = slap_map_api2result( rs );
01503        
01504                                    if ( LogTest( LDAP_DEBUG_TRACE | LDAP_DEBUG_ANY ) ) {
01505                                           snprintf( buf, sizeof( buf ),
01506                                                  "%s meta_back_search[%ld] "
01507                                                  "match=\"%s\" err=%ld",
01508                                                  op->o_log_prefix, i,
01509                                                  candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
01510                                                  (long) candidates[ i ].sr_err );
01511                                           if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
01512                                                  Debug( LDAP_DEBUG_TRACE, "%s.\n", buf, 0, 0 );
01513        
01514                                           } else {
01515                                                  Debug( LDAP_DEBUG_ANY, "%s (%s).\n",
01516                                                         buf, ldap_err2string( candidates[ i ].sr_err ), 0 );
01517                                           }
01518                                    }
01519        
01520                                    switch ( sres ) {
01521                                    case LDAP_NO_SUCH_OBJECT:
01522                                           /* is_ok is touched any time a valid
01523                                            * (even intermediate) result is
01524                                            * returned; as a consequence, if
01525                                            * a candidate returns noSuchObject
01526                                            * it is ignored and the candidate
01527                                            * is simply demoted. */
01528                                           if ( is_ok ) {
01529                                                  sres = LDAP_SUCCESS;
01530                                           }
01531                                           break;
01532        
01533                                    case LDAP_SUCCESS:
01534                                           if ( ctrls != NULL && ctrls[0] != NULL ) {
01535 #ifdef SLAPD_META_CLIENT_PR
01536                                                  LDAPControl *pr_c;
01537 
01538                                                  pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, ctrls, NULL );
01539                                                  if ( pr_c != NULL ) {
01540                                                         BerElementBuffer berbuf;
01541                                                         BerElement *ber = (BerElement *)&berbuf;
01542                                                         ber_tag_t tag;
01543                                                         ber_int_t prsize;
01544                                                         struct berval prcookie;
01545 
01546                                                         /* unsolicited, do not accept */
01547                                                         if ( mi->mi_targets[i]->mt_ps == 0 ) {
01548                                                                rs->sr_err = LDAP_OTHER;
01549                                                                goto err_pr;
01550                                                         }
01551 
01552                                                         ber_init2( ber, &pr_c->ldctl_value, LBER_USE_DER );
01553 
01554                                                         tag = ber_scanf( ber, "{im}", &prsize, &prcookie );
01555                                                         if ( tag == LBER_ERROR ) {
01556                                                                rs->sr_err = LDAP_OTHER;
01557                                                                goto err_pr;
01558                                                         }
01559 
01560                                                         /* more pages? new search request */
01561                                                         if ( !BER_BVISNULL( &prcookie ) && !BER_BVISEMPTY( &prcookie ) ) {
01562                                                                if ( mi->mi_targets[i]->mt_ps > 0 ) {
01563                                                                       /* ignore size if specified */
01564                                                                       prsize = 0;
01565 
01566                                                                } else if ( prsize == 0 ) {
01567                                                                       /* guess the page size from the entries returned so far */
01568                                                                       prsize = candidates[ i ].sr_nentries;
01569                                                                }
01570 
01571                                                                candidates[ i ].sr_nentries = 0;
01572                                                                candidates[ i ].sr_msgid = META_MSGID_IGNORE;
01573                                                                candidates[ i ].sr_type = REP_INTERMEDIATE;
01574                                                         
01575                                                                assert( candidates[ i ].sr_matched == NULL );
01576                                                                assert( candidates[ i ].sr_text == NULL );
01577                                                                assert( candidates[ i ].sr_ref == NULL );
01578 
01579                                                                switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, &prcookie, prsize ) )
01580                                                                {
01581                                                                case META_SEARCH_CANDIDATE:
01582                                                                       assert( candidates[ i ].sr_msgid >= 0 );
01583                                                                       ldap_controls_free( ctrls );
01584                                                                       goto free_message;
01585 
01586                                                                case META_SEARCH_ERR:
01587 err_pr:;
01588                                                                       candidates[ i ].sr_err = rs->sr_err;
01589                                                                       if ( META_BACK_ONERR_STOP( mi ) ) {
01590                                                                              savepriv = op->o_private;
01591                                                                              op->o_private = (void *)i;
01592                                                                              send_ldap_result( op, rs );
01593                                                                              op->o_private = savepriv;
01594                                                                              ldap_controls_free( ctrls );
01595                                                                              goto finish;
01596                                                                       }
01597                                                                       /* fallthru */
01598 
01599                                                                case META_SEARCH_NOT_CANDIDATE:
01600                                                                       /* means that meta_back_search_start()
01601                                                                        * failed but onerr == continue */
01602                                                                       candidates[ i ].sr_msgid = META_MSGID_IGNORE;
01603                                                                       assert( ncandidates > 0 );
01604                                                                       --ncandidates;
01605                                                                       break;
01606 
01607                                                                default:
01608                                                                       /* impossible */
01609                                                                       assert( 0 );
01610                                                                       break;
01611                                                                }
01612                                                                break;
01613                                                         }
01614                                                  }
01615 #endif /* SLAPD_META_CLIENT_PR */
01616 
01617                                                  ldap_controls_free( ctrls );
01618                                           }
01619                                           /* fallthru */
01620 
01621                                    case LDAP_REFERRAL:
01622                                           is_ok++;
01623                                           break;
01624        
01625                                    case LDAP_SIZELIMIT_EXCEEDED:
01626                                           /* if a target returned sizelimitExceeded
01627                                            * and the entry count is equal to the
01628                                            * proxy's limit, the target would have
01629                                            * returned more, and the error must be
01630                                            * propagated to the client; otherwise,
01631                                            * the target enforced a limit lower
01632                                            * than what requested by the proxy;
01633                                            * ignore it */
01634                                           candidates[ i ].sr_err = rs->sr_err;
01635                                           if ( rs->sr_nentries == op->ors_slimit
01636                                                  || META_BACK_ONERR_STOP( mi ) )
01637                                           {
01638                                                  const char *save_text = rs->sr_text;
01639                                                  savepriv = op->o_private;
01640                                                  op->o_private = (void *)i;
01641                                                  rs->sr_text = candidates[ i ].sr_text;
01642                                                  send_ldap_result( op, rs );
01643                                                  rs->sr_text = save_text;
01644                                                  op->o_private = savepriv;
01645                                                  ldap_msgfree( res );
01646                                                  res = NULL;
01647                                                  goto finish;
01648                                           }
01649                                           break;
01650        
01651                                    default:
01652                                           candidates[ i ].sr_err = rs->sr_err;
01653                                           if ( META_BACK_ONERR_STOP( mi ) ) {
01654                                                  const char *save_text = rs->sr_text;
01655                                                  savepriv = op->o_private;
01656                                                  op->o_private = (void *)i;
01657                                                  rs->sr_text = candidates[ i ].sr_text;
01658                                                  send_ldap_result( op, rs );
01659                                                  rs->sr_text = save_text;
01660                                                  op->o_private = savepriv;
01661                                                  ldap_msgfree( res );
01662                                                  res = NULL;
01663                                                  goto finish;
01664                                           }
01665                                           break;
01666                                    }
01667        
01668                                    last = i;
01669                                    rc = 0;
01670        
01671                                    /*
01672                                     * When no candidates are left,
01673                                     * the outer cycle finishes
01674                                     */
01675                                    assert( ncandidates > 0 );
01676                                    --ncandidates;
01677 
01678                             } else if ( rc == LDAP_RES_BIND ) {
01679                                    meta_search_candidate_t     retcode;
01680        
01681                                    retcode = meta_search_dobind_result( op, rs, &mc, i, candidates, msg );
01682                                    if ( retcode == META_SEARCH_CANDIDATE ) {
01683                                           candidates[ i ].sr_msgid = META_MSGID_IGNORE;
01684                                           retcode = meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 );
01685                                    }
01686        
01687                                    switch ( retcode ) {
01688                                    case META_SEARCH_CANDIDATE:
01689                                           break;
01690        
01691                                           /* means that failed but onerr == continue */
01692                                    case META_SEARCH_NOT_CANDIDATE:
01693                                    case META_SEARCH_ERR:
01694                                           candidates[ i ].sr_msgid = META_MSGID_IGNORE;
01695                                           assert( ncandidates > 0 );
01696                                           --ncandidates;
01697        
01698                                           candidates[ i ].sr_err = rs->sr_err;
01699                                           if ( META_BACK_ONERR_STOP( mi ) ) {
01700                                                  savepriv = op->o_private;
01701                                                  op->o_private = (void *)i;
01702                                                  send_ldap_result( op, rs );
01703                                                  op->o_private = savepriv;
01704                                                  ldap_msgfree( res );
01705                                                  res = NULL;
01706                                                  goto finish;
01707                                           }
01708                                           goto free_message;
01709        
01710                                    default:
01711                                           assert( 0 );
01712                                           break;
01713                                    }
01714        
01715                             } else {
01716                                    Debug( LDAP_DEBUG_ANY,
01717                                           "%s meta_back_search[%ld]: "
01718                                           "unrecognized response message tag=%d\n",
01719                                           op->o_log_prefix,
01720                                           i, rc );
01721                             
01722                                    ldap_msgfree( res );
01723                                    res = NULL;
01724                                    goto really_bad;
01725                             }
01726                      }
01727 
01728 free_message:;
01729                      ldap_msgfree( res );
01730                      res = NULL;
01731               }
01732 
01733               /* check for abandon */
01734               if ( op->o_abandon || LDAP_BACK_CONN_ABANDON( mc ) ) {
01735                      for ( i = 0; i < mi->mi_ntargets; i++ ) {
01736                             if ( candidates[ i ].sr_msgid >= 0
01737                                    || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
01738                             {
01739                                    if ( META_IS_BINDING( &candidates[ i ] )
01740                                           || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
01741                                    {
01742                                           ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
01743                                           if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] )
01744                                                  || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
01745                                           {
01746                                                  /* if still binding, destroy */
01747 
01748 #ifdef DEBUG_205
01749                                                  char buf[ SLAP_TEXT_BUFLEN ];
01750 
01751                                                  snprintf( buf, sizeof( buf), "%s meta_back_search(abandon) "
01752                                                         "ldap_unbind_ext[%ld] mc=%p ld=%p",
01753                                                         op->o_log_prefix, i, (void *)mc,
01754                                                         (void *)mc->mc_conns[i].msc_ld );
01755 
01756                                                  Debug( LDAP_DEBUG_ANY, "### %s\n", buf, 0, 0 );
01757 #endif /* DEBUG_205 */
01758 
01759                                                  meta_clear_one_candidate( op, mc, i );
01760                                           }
01761                                           ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
01762                                           META_BINDING_CLEAR( &candidates[ i ] );
01763                                           
01764                                    } else {
01765                                           (void)meta_back_cancel( mc, op, rs,
01766                                                  candidates[ i ].sr_msgid, i,
01767                                                  LDAP_BACK_DONTSEND );
01768                                    }
01769 
01770                                    candidates[ i ].sr_msgid = META_MSGID_IGNORE;
01771                                    assert( ncandidates > 0 );
01772                                    --ncandidates;
01773                             }
01774                      }
01775 
01776                      if ( op->o_abandon ) {
01777                             rc = SLAPD_ABANDON;
01778                      }
01779 
01780                      /* let send_ldap_result play cleanup handlers (ITS#4645) */
01781                      break;
01782               }
01783 
01784               /* if no entry was found during this loop,
01785                * set a minimal timeout */
01786               if ( ncandidates > 0 && gotit == 0 ) {
01787                      if ( save_tv.tv_sec == 0 && save_tv.tv_usec == 0 ) {
01788                             save_tv.tv_usec = LDAP_BACK_RESULT_UTIMEOUT/initial_candidates;
01789 
01790                             /* arbitrarily limit to something between 1 and 2 minutes */
01791                      } else if ( ( stoptime == -1 && save_tv.tv_sec < 60 )
01792                             || save_tv.tv_sec < ( stoptime - slap_get_time() ) / ( 2 * ncandidates ) )
01793                      {
01794                             /* double the timeout */
01795                             lutil_timermul( &save_tv, 2, &save_tv );
01796                      }
01797 
01798                      if ( alreadybound == 0 ) {
01799                             tv = save_tv;
01800                             (void)select( 0, NULL, NULL, NULL, &tv );
01801 
01802                      } else {
01803                             ldap_pvt_thread_yield();
01804                      }
01805               }
01806        }
01807 
01808        if ( rc == -1 ) {
01809               /*
01810                * FIXME: need a better strategy to handle errors
01811                */
01812               if ( mc ) {
01813                      rc = meta_back_op_result( mc, op, rs, META_TARGET_NONE,
01814                             -1, stoptime != -1 ? (stoptime - slap_get_time()) : 0,
01815                             LDAP_BACK_SENDERR );
01816               } else {
01817                      rc = rs->sr_err;
01818               }
01819               goto finish;
01820        }
01821 
01822        /*
01823         * Rewrite the matched portion of the search base, if required
01824         * 
01825         * FIXME: only the last one gets caught!
01826         */
01827        savepriv = op->o_private;
01828        op->o_private = (void *)(long)mi->mi_ntargets;
01829        if ( candidate_match > 0 ) {
01830               struct berval pmatched = BER_BVNULL;
01831 
01832               /* we use the first one */
01833               for ( i = 0; i < mi->mi_ntargets; i++ ) {
01834                      if ( META_IS_CANDIDATE( &candidates[ i ] )
01835                                    && candidates[ i ].sr_matched != NULL )
01836                      {
01837                             struct berval bv, pbv;
01838                             int           rc;
01839 
01840                             /* if we got success, and this target
01841                              * returned noSuchObject, and its suffix
01842                              * is a superior of the searchBase,
01843                              * ignore the matchedDN */
01844                             if ( sres == LDAP_SUCCESS
01845                                    && candidates[ i ].sr_err == LDAP_NO_SUCH_OBJECT
01846                                    && op->o_req_ndn.bv_len > mi->mi_targets[ i ]->mt_nsuffix.bv_len )
01847                             {
01848                                    free( (char *)candidates[ i ].sr_matched );
01849                                    candidates[ i ].sr_matched = NULL;
01850                                    continue;
01851                             }
01852 
01853                             ber_str2bv( candidates[ i ].sr_matched, 0, 0, &bv );
01854                             rc = dnPretty( NULL, &bv, &pbv, op->o_tmpmemctx );
01855 
01856                             if ( rc == LDAP_SUCCESS ) {
01857 
01858                                    /* NOTE: if they all are superiors
01859                                     * of the baseDN, the shorter is also 
01860                                     * superior of the longer... */
01861                                    if ( pbv.bv_len > pmatched.bv_len ) {
01862                                           if ( !BER_BVISNULL( &pmatched ) ) {
01863                                                  op->o_tmpfree( pmatched.bv_val, op->o_tmpmemctx );
01864                                           }
01865                                           pmatched = pbv;
01866                                           op->o_private = (void *)i;
01867 
01868                                    } else {
01869                                           op->o_tmpfree( pbv.bv_val, op->o_tmpmemctx );
01870                                    }
01871                             }
01872 
01873                             if ( candidates[ i ].sr_matched != NULL ) {
01874                                    free( (char *)candidates[ i ].sr_matched );
01875                                    candidates[ i ].sr_matched = NULL;
01876                             }
01877                      }
01878               }
01879 
01880               if ( !BER_BVISNULL( &pmatched ) ) {
01881                      matched = pmatched.bv_val;
01882               }
01883 
01884        } else if ( sres == LDAP_NO_SUCH_OBJECT ) {
01885               matched = op->o_bd->be_suffix[ 0 ].bv_val;
01886        }
01887 
01888        /*
01889         * In case we returned at least one entry, we return LDAP_SUCCESS
01890         * otherwise, the latter error code we got
01891         */
01892 
01893        if ( sres == LDAP_SUCCESS ) {
01894               if ( rs->sr_v2ref ) {
01895                      sres = LDAP_REFERRAL;
01896               }
01897 
01898               if ( META_BACK_ONERR_REPORT( mi ) ) {
01899                      /*
01900                       * Report errors, if any
01901                       *
01902                       * FIXME: we should handle error codes and return the more 
01903                       * important/reasonable
01904                       */
01905                      for ( i = 0; i < mi->mi_ntargets; i++ ) {
01906                             if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
01907                                    continue;
01908                             }
01909 
01910                             if ( candidates[ i ].sr_err != LDAP_SUCCESS
01911                                    && candidates[ i ].sr_err != LDAP_NO_SUCH_OBJECT )
01912                             {
01913                                    sres = candidates[ i ].sr_err;
01914                                    break;
01915                             }
01916                      }
01917               }
01918        }
01919 
01920        rs->sr_err = sres;
01921        rs->sr_matched = ( sres == LDAP_SUCCESS ? NULL : matched );
01922        rs->sr_ref = ( sres == LDAP_REFERRAL ? rs->sr_v2ref : NULL );
01923        send_ldap_result( op, rs );
01924        op->o_private = savepriv;
01925        rs->sr_matched = NULL;
01926        rs->sr_ref = NULL;
01927 
01928 finish:;
01929        if ( matched && matched != op->o_bd->be_suffix[ 0 ].bv_val ) {
01930               op->o_tmpfree( matched, op->o_tmpmemctx );
01931        }
01932 
01933        if ( rs->sr_v2ref ) {
01934               ber_bvarray_free_x( rs->sr_v2ref, op->o_tmpmemctx );
01935        }
01936 
01937        for ( i = 0; i < mi->mi_ntargets; i++ ) {
01938               if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
01939                      continue;
01940               }
01941 
01942               if ( mc ) {
01943                      if ( META_IS_BINDING( &candidates[ i ] )
01944                             || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
01945                      {
01946                             ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
01947                             if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] )
01948                                    || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
01949                             {
01950                                    assert( candidates[ i ].sr_msgid >= 0
01951                                           || candidates[ i ].sr_msgid == META_MSGID_CONNECTING );
01952                                    assert( mc->mc_conns[ i ].msc_ld != NULL );
01953 
01954 #ifdef DEBUG_205
01955                                    Debug( LDAP_DEBUG_ANY, "### %s meta_back_search(cleanup) "
01956                                           "ldap_unbind_ext[%ld] ld=%p\n",
01957                                           op->o_log_prefix, i, (void *)mc->mc_conns[i].msc_ld );
01958 #endif /* DEBUG_205 */
01959 
01960                                    /* if still binding, destroy */
01961                                    meta_clear_one_candidate( op, mc, i );
01962                             }
01963                             ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
01964                             META_BINDING_CLEAR( &candidates[ i ] );
01965 
01966                      } else if ( candidates[ i ].sr_msgid >= 0 ) {
01967                             (void)meta_back_cancel( mc, op, rs,
01968                                    candidates[ i ].sr_msgid, i,
01969                                    LDAP_BACK_DONTSEND );
01970                      }
01971               }
01972 
01973               if ( candidates[ i ].sr_matched ) {
01974                      free( (char *)candidates[ i ].sr_matched );
01975                      candidates[ i ].sr_matched = NULL;
01976               }
01977 
01978               if ( candidates[ i ].sr_text ) {
01979                      ldap_memfree( (char *)candidates[ i ].sr_text );
01980                      candidates[ i ].sr_text = NULL;
01981               }
01982 
01983               if ( candidates[ i ].sr_ref ) {
01984                      ber_bvarray_free( candidates[ i ].sr_ref );
01985                      candidates[ i ].sr_ref = NULL;
01986               }
01987 
01988               if ( candidates[ i ].sr_ctrls ) {
01989                      ldap_controls_free( candidates[ i ].sr_ctrls );
01990                      candidates[ i ].sr_ctrls = NULL;
01991               }
01992 
01993               if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) {
01994                      meta_back_quarantine( op, &candidates[ i ], i );
01995               }
01996 
01997               /* only in case of timelimit exceeded, if the timelimit exceeded because
01998                * one contacted target never responded, invalidate the connection
01999                * NOTE: should we quarantine the target as well?  right now, the connection
02000                * is invalidated; the next time it will be recreated and the target
02001                * will be quarantined if it cannot be contacted */
02002               if ( mi->mi_idle_timeout != 0
02003                      && rs->sr_err == LDAP_TIMELIMIT_EXCEEDED
02004                      && op->o_time > mc->mc_conns[ i ].msc_time )
02005               {
02006                      /* don't let anyone else use this expired connection */
02007                      do_taint++;
02008               }
02009        }
02010 
02011        if ( mc ) {
02012               ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
02013               if ( do_taint ) {
02014                      LDAP_BACK_CONN_TAINTED_SET( mc );
02015               }
02016               meta_back_release_conn_lock( mi, mc, 0 );
02017               ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
02018        }
02019 
02020        return rs->sr_err;
02021 }
02022 
02023 static int
02024 meta_send_entry(
02025        Operation     *op,
02026        SlapReply     *rs,
02027        metaconn_t    *mc,
02028        int           target,
02029        LDAPMessage   *e )
02030 {
02031        metainfo_t           *mi = ( metainfo_t * )op->o_bd->be_private;
02032        struct berval        a, mapped;
02033        int                  check_duplicate_attrs = 0;
02034        int                  check_sorted_attrs = 0;
02035        Entry                ent = { 0 };
02036        BerElement           ber = *ldap_get_message_ber( e );
02037        Attribute            *attr, **attrp;
02038        struct berval               bdn,
02039                             dn = BER_BVNULL;
02040        const char           *text;
02041        dncookie             dc;
02042        ber_len_t            len;
02043        int                  rc;
02044 
02045        if ( ber_scanf( &ber, "l{", &len ) == LBER_ERROR ) {
02046               return LDAP_DECODING_ERROR;
02047        }
02048 
02049        if ( ber_set_option( &ber, LBER_OPT_REMAINING_BYTES, &len ) != LBER_OPT_SUCCESS ) {
02050               return LDAP_OTHER;
02051        }
02052 
02053        if ( ber_scanf( &ber, "m{", &bdn ) == LBER_ERROR ) {
02054               return LDAP_DECODING_ERROR;
02055        }
02056 
02057        /*
02058         * Rewrite the dn of the result, if needed
02059         */
02060        dc.target = mi->mi_targets[ target ];
02061        dc.conn = op->o_conn;
02062        dc.rs = rs;
02063        dc.ctx = "searchResult";
02064 
02065        rs->sr_err = ldap_back_dn_massage( &dc, &bdn, &dn );
02066        if ( rs->sr_err != LDAP_SUCCESS) {
02067               return rs->sr_err;
02068        }
02069 
02070        /*
02071         * Note: this may fail if the target host(s) schema differs
02072         * from the one known to the meta, and a DN with unknown
02073         * attributes is returned.
02074         * 
02075         * FIXME: should we log anything, or delegate to dnNormalize?
02076         */
02077        rc = dnPrettyNormal( NULL, &dn, &ent.e_name, &ent.e_nname,
02078               op->o_tmpmemctx );
02079        if ( dn.bv_val != bdn.bv_val ) {
02080               free( dn.bv_val );
02081        }
02082        BER_BVZERO( &dn );
02083 
02084        if ( rc != LDAP_SUCCESS ) {
02085               Debug( LDAP_DEBUG_ANY,
02086                      "%s meta_send_entry(\"%s\"): "
02087                      "invalid DN syntax\n",
02088                      op->o_log_prefix, ent.e_name.bv_val, 0 );
02089               rc = LDAP_INVALID_DN_SYNTAX;
02090               goto done;
02091        }
02092 
02093        /*
02094         * cache dn
02095         */
02096        if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) {
02097               ( void )meta_dncache_update_entry( &mi->mi_cache,
02098                             &ent.e_nname, target );
02099        }
02100 
02101        attrp = &ent.e_attrs;
02102 
02103        dc.ctx = "searchAttrDN";
02104        while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
02105               int                         last = 0;
02106               slap_syntax_validate_func   *validate;
02107               slap_syntax_transform_func  *pretty;
02108 
02109               if ( ber_pvt_ber_remaining( &ber ) < 0 ) {
02110                      Debug( LDAP_DEBUG_ANY,
02111                             "%s meta_send_entry(\"%s\"): "
02112                             "unable to parse attr \"%s\".\n",
02113                             op->o_log_prefix, ent.e_name.bv_val, a.bv_val );
02114                             
02115                      rc = LDAP_OTHER;
02116                      goto done;
02117               }
02118 
02119               if ( ber_pvt_ber_remaining( &ber ) == 0 ) {
02120                      break;
02121               }
02122 
02123               ldap_back_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_at, 
02124                             &a, &mapped, BACKLDAP_REMAP );
02125               if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) {
02126                      ( void )ber_scanf( &ber, "x" /* [W] */ );
02127                      continue;
02128               }
02129               if ( mapped.bv_val != a.bv_val ) {
02130                      /* will need to check for duplicate attrs */
02131                      check_duplicate_attrs++;
02132               }
02133               attr = attr_alloc( NULL );
02134               if ( attr == NULL ) {
02135                      rc = LDAP_OTHER;
02136                      goto done;
02137               }
02138               if ( slap_bv2ad( &mapped, &attr->a_desc, &text )
02139                             != LDAP_SUCCESS) {
02140                      if ( slap_bv2undef_ad( &mapped, &attr->a_desc, &text,
02141                             SLAP_AD_PROXIED ) != LDAP_SUCCESS )
02142                      {
02143                             char   buf[ SLAP_TEXT_BUFLEN ];
02144 
02145                             snprintf( buf, sizeof( buf ),
02146                                    "%s meta_send_entry(\"%s\"): "
02147                                    "slap_bv2undef_ad(%s): %s\n",
02148                                    op->o_log_prefix, ent.e_name.bv_val,
02149                                    mapped.bv_val, text );
02150 
02151                             Debug( LDAP_DEBUG_ANY, "%s", buf, 0, 0 );
02152                             ( void )ber_scanf( &ber, "x" /* [W] */ );
02153                             attr_free( attr );
02154                             continue;
02155                      }
02156               }
02157 
02158               if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL )
02159                      check_sorted_attrs = 1;
02160 
02161               /* no subschemaSubentry */
02162               if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry
02163                      || attr->a_desc == slap_schema.si_ad_entryDN )
02164               {
02165 
02166                      /* 
02167                       * We eat target's subschemaSubentry because
02168                       * a search for this value is likely not
02169                       * to resolve to the appropriate backend;
02170                       * later, the local subschemaSubentry is
02171                       * added.
02172                       *
02173                       * We also eat entryDN because the frontend
02174                       * will reattach it without checking if already
02175                       * present...
02176                       */
02177                      ( void )ber_scanf( &ber, "x" /* [W] */ );
02178                      attr_free(attr);
02179                      continue;
02180               }
02181 
02182               if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR 
02183                             || attr->a_vals == NULL )
02184               {
02185                      attr->a_vals = (struct berval *)&slap_dummy_bv;
02186 
02187               } else {
02188                      for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); ++last )
02189                             ;
02190               }
02191               attr->a_numvals = last;
02192 
02193               validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate;
02194               pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty;
02195 
02196               if ( !validate && !pretty ) {
02197                      attr_free( attr );
02198                      goto next_attr;
02199               }
02200 
02201               if ( attr->a_desc == slap_schema.si_ad_objectClass
02202                             || attr->a_desc == slap_schema.si_ad_structuralObjectClass )
02203               {
02204                      struct berval        *bv;
02205 
02206                      for ( bv = attr->a_vals; !BER_BVISNULL( bv ); bv++ ) {
02207                             ObjectClass *oc;
02208 
02209                             ldap_back_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_oc,
02210                                           bv, &mapped, BACKLDAP_REMAP );
02211                             if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0') {
02212 remove_oc:;
02213                                    free( bv->bv_val );
02214                                    BER_BVZERO( bv );
02215                                    if ( --last < 0 ) {
02216                                           break;
02217                                    }
02218                                    *bv = attr->a_vals[ last ];
02219                                    BER_BVZERO( &attr->a_vals[ last ] );
02220                                    bv--;
02221 
02222                             } else if ( mapped.bv_val != bv->bv_val ) {
02223                                    int    i;
02224 
02225                                    for ( i = 0; !BER_BVISNULL( &attr->a_vals[ i ] ); i++ ) {
02226                                           if ( &attr->a_vals[ i ] == bv ) {
02227                                                  continue;
02228                                           }
02229 
02230                                           if ( ber_bvstrcasecmp( &mapped, &attr->a_vals[ i ] ) == 0 ) {
02231                                                  break;
02232                                           }
02233                                    }
02234 
02235                                    if ( !BER_BVISNULL( &attr->a_vals[ i ] ) ) {
02236                                           goto remove_oc;
02237                                    }
02238 
02239                                    ber_bvreplace( bv, &mapped );
02240 
02241                             } else if ( ( oc = oc_bvfind_undef( bv ) ) == NULL ) {
02242                                    goto remove_oc;
02243 
02244                             } else {
02245                                    ber_bvreplace( bv, &oc->soc_cname );
02246                             }
02247                      }
02248               /*
02249                * It is necessary to try to rewrite attributes with
02250                * dn syntax because they might be used in ACLs as
02251                * members of groups; since ACLs are applied to the
02252                * rewritten stuff, no dn-based subecj clause could
02253                * be used at the ldap backend side (see
02254                * http://www.OpenLDAP.org/faq/data/cache/452.html)
02255                * The problem can be overcome by moving the dn-based
02256                * ACLs to the target directory server, and letting
02257                * everything pass thru the ldap backend.
02258                */
02259               } else {
02260                      int    i;
02261 
02262                      if ( attr->a_desc->ad_type->sat_syntax ==
02263                             slap_schema.si_syn_distinguishedName )
02264                      {
02265                             ldap_dnattr_result_rewrite( &dc, attr->a_vals );
02266 
02267                      } else if ( attr->a_desc == slap_schema.si_ad_ref ) {
02268                             ldap_back_referral_result_rewrite( &dc, attr->a_vals, NULL );
02269 
02270                      }
02271 
02272                      for ( i = 0; i < last; i++ ) {
02273                             struct berval pval;
02274                             int           rc;
02275 
02276                             if ( pretty ) {
02277                                    rc = ordered_value_pretty( attr->a_desc,
02278                                           &attr->a_vals[i], &pval, NULL );
02279 
02280                             } else {
02281                                    rc = ordered_value_validate( attr->a_desc,
02282                                           &attr->a_vals[i], 0 );
02283                             }
02284 
02285                             if ( rc ) {
02286                                    ber_memfree( attr->a_vals[i].bv_val );
02287                                    if ( --last == i ) {
02288                                           BER_BVZERO( &attr->a_vals[ i ] );
02289                                           break;
02290                                    }
02291                                    attr->a_vals[i] = attr->a_vals[last];
02292                                    BER_BVZERO( &attr->a_vals[last] );
02293                                    i--;
02294                                    continue;
02295                             }
02296 
02297                             if ( pretty ) {
02298                                    ber_memfree( attr->a_vals[i].bv_val );
02299                                    attr->a_vals[i] = pval;
02300                             }
02301                      }
02302 
02303                      if ( last == 0 && attr->a_vals != &slap_dummy_bv ) {
02304                             attr_free( attr );
02305                             goto next_attr;
02306                      }
02307               }
02308 
02309               if ( last && attr->a_desc->ad_type->sat_equality &&
02310                      attr->a_desc->ad_type->sat_equality->smr_normalize )
02311               {
02312                      int i;
02313 
02314                      attr->a_nvals = ch_malloc( ( last + 1 ) * sizeof( struct berval ) );
02315                      for ( i = 0; i<last; i++ ) {
02316                             /* if normalizer fails, drop this value */
02317                             if ( ordered_value_normalize(
02318                                    SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
02319                                    attr->a_desc,
02320                                    attr->a_desc->ad_type->sat_equality,
02321                                    &attr->a_vals[i], &attr->a_nvals[i],
02322                                    NULL )) {
02323                                    ber_memfree( attr->a_vals[i].bv_val );
02324                                    if ( --last == i ) {
02325                                           BER_BVZERO( &attr->a_vals[ i ] );
02326                                           break;
02327                                    }
02328                                    attr->a_vals[i] = attr->a_vals[last];
02329                                    BER_BVZERO( &attr->a_vals[last] );
02330                                    i--;
02331                             }
02332                      }
02333                      BER_BVZERO( &attr->a_nvals[i] );
02334                      if ( last == 0 ) {
02335                             attr_free( attr );
02336                             goto next_attr;
02337                      }
02338 
02339               } else {
02340                      attr->a_nvals = attr->a_vals;
02341               }
02342 
02343               attr->a_numvals = last;
02344               *attrp = attr;
02345               attrp = &attr->a_next;
02346 next_attr:;
02347        }
02348 
02349        /* only check if some mapping occurred */
02350        if ( check_duplicate_attrs ) {
02351               Attribute     **ap;
02352 
02353               for ( ap = &ent.e_attrs; *ap != NULL; ap = &(*ap)->a_next ) {
02354                      Attribute     **tap;
02355 
02356                      for ( tap = &(*ap)->a_next; *tap != NULL; ) {
02357                             if ( (*tap)->a_desc == (*ap)->a_desc ) {
02358                                    Entry         e = { 0 };
02359                                    Modification  mod = { 0 };
02360                                    const char    *text = NULL;
02361                                    char          textbuf[ SLAP_TEXT_BUFLEN ];
02362                                    Attribute     *next = (*tap)->a_next;
02363 
02364                                    BER_BVSTR( &e.e_name, "" );
02365                                    BER_BVSTR( &e.e_nname, "" );
02366                                    e.e_attrs = *ap;
02367                                    mod.sm_op = LDAP_MOD_ADD;
02368                                    mod.sm_desc = (*ap)->a_desc;
02369                                    mod.sm_type = mod.sm_desc->ad_cname;
02370                                    mod.sm_numvals = (*ap)->a_numvals;
02371                                    mod.sm_values = (*tap)->a_vals;
02372                                    if ( (*tap)->a_nvals != (*tap)->a_vals ) {
02373                                           mod.sm_nvalues = (*tap)->a_nvals;
02374                                    }
02375 
02376                                    (void)modify_add_values( &e, &mod,
02377                                           /* permissive */ 1,
02378                                           &text, textbuf, sizeof( textbuf ) );
02379 
02380                                    /* should not insert new attrs! */
02381                                    assert( e.e_attrs == *ap );
02382 
02383                                    attr_free( *tap );
02384                                    *tap = next;
02385 
02386                             } else {
02387                                    tap = &(*tap)->a_next;
02388                             }
02389                      }
02390               }
02391        }
02392 
02393        /* Check for sorted attributes */
02394        if ( check_sorted_attrs ) {
02395               for ( attr = ent.e_attrs; attr; attr = attr->a_next ) {
02396                      if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) {
02397                             while ( attr->a_numvals > 1 ) {
02398                                    int i;
02399                                    int rc = slap_sort_vals( (Modifications *)attr, &text, &i, op->o_tmpmemctx );
02400                                    if ( rc != LDAP_TYPE_OR_VALUE_EXISTS )
02401                                           break;
02402 
02403                                    /* Strip duplicate values */
02404                                    if ( attr->a_nvals != attr->a_vals )
02405                                           ber_memfree( attr->a_nvals[i].bv_val );
02406                                    ber_memfree( attr->a_vals[i].bv_val );
02407                                    attr->a_numvals--;
02408                                    if ( (unsigned)i < attr->a_numvals ) {
02409                                           attr->a_vals[i] = attr->a_vals[attr->a_numvals];
02410                                           if ( attr->a_nvals != attr->a_vals )
02411                                                  attr->a_nvals[i] = attr->a_nvals[attr->a_numvals];
02412                                    }
02413                                    BER_BVZERO(&attr->a_vals[attr->a_numvals]);
02414                                    if ( attr->a_nvals != attr->a_vals )
02415                                           BER_BVZERO(&attr->a_nvals[attr->a_numvals]);
02416                             }
02417                             attr->a_flags |= SLAP_ATTR_SORTED_VALS;
02418                      }
02419               }
02420        }
02421 
02422        ldap_get_entry_controls( mc->mc_conns[target].msc_ld,
02423               e, &rs->sr_ctrls );
02424        rs->sr_entry = &ent;
02425        rs->sr_attrs = op->ors_attrs;
02426        rs->sr_operational_attrs = NULL;
02427        rs->sr_flags = mi->mi_targets[ target ]->mt_rep_flags;
02428        rs->sr_err = LDAP_SUCCESS;
02429        rc = send_search_entry( op, rs );
02430        switch ( rc ) {
02431        case LDAP_UNAVAILABLE:
02432               rc = LDAP_OTHER;
02433               break;
02434        }
02435 
02436 done:;
02437        rs->sr_entry = NULL;
02438        rs->sr_attrs = NULL;
02439        if ( rs->sr_ctrls != NULL ) {
02440               ldap_controls_free( rs->sr_ctrls );
02441               rs->sr_ctrls = NULL;
02442        }
02443        if ( !BER_BVISNULL( &ent.e_name ) ) {
02444               free( ent.e_name.bv_val );
02445               BER_BVZERO( &ent.e_name );
02446        }
02447        if ( !BER_BVISNULL( &ent.e_nname ) ) {
02448               free( ent.e_nname.bv_val );
02449               BER_BVZERO( &ent.e_nname );
02450        }
02451        entry_clean( &ent );
02452 
02453        return rc;
02454 }
02455