]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/search.c
ITS#5421 drop ldap-int.h
[openldap] / servers / slapd / back-meta / search.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2011 The OpenLDAP Foundation.
5  * Portions Copyright 2001-2003 Pierangelo Masarati.
6  * Portions Copyright 1999-2003 Howard Chu.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by the Howard Chu for inclusion
19  * in OpenLDAP Software and subsequently enhanced by Pierangelo
20  * Masarati.
21  */
22
23 #include "portable.h"
24
25 #include <stdio.h>
26
27 #include <ac/socket.h>
28 #include <ac/string.h>
29 #include <ac/time.h>
30
31 #include "lutil.h"
32 #include "slap.h"
33 #include "../back-ldap/back-ldap.h"
34 #include "back-meta.h"
35 #include "../../../libraries/liblber/lber-int.h"
36
37 /* IGNORE means that target does not (no longer) participate
38  * in the search;
39  * NOTREADY means the search on that target has not been initialized yet
40  */
41 #define META_MSGID_IGNORE       (-1)
42 #define META_MSGID_NEED_BIND    (-2)
43 #define META_MSGID_CONNECTING   (-3)
44
45 static int
46 meta_send_entry(
47         Operation       *op,
48         SlapReply       *rs,
49         metaconn_t      *mc,
50         int             i,
51         LDAPMessage     *e );
52
53 typedef enum meta_search_candidate_t {
54         META_SEARCH_UNDEFINED = -2,
55         META_SEARCH_ERR = -1,
56         META_SEARCH_NOT_CANDIDATE,
57         META_SEARCH_CANDIDATE,
58         META_SEARCH_BINDING,
59         META_SEARCH_NEED_BIND,
60         META_SEARCH_CONNECTING
61 } meta_search_candidate_t;
62
63 /*
64  * meta_search_dobind_init()
65  *
66  * initiates bind for a candidate target of a search.
67  */
68 static meta_search_candidate_t
69 meta_search_dobind_init(
70         Operation               *op,
71         SlapReply               *rs,
72         metaconn_t              **mcp,
73         int                     candidate,
74         SlapReply               *candidates )
75 {
76         metaconn_t              *mc = *mcp;
77         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
78         metatarget_t            *mt = mi->mi_targets[ candidate ];
79         metasingleconn_t        *msc = &mc->mc_conns[ candidate ];
80
81         struct berval           binddn = msc->msc_bound_ndn,
82                                 cred = msc->msc_cred;
83         int                     method;
84
85         int                     rc;
86
87         meta_search_candidate_t retcode;
88
89         Debug( LDAP_DEBUG_TRACE, "%s >>> meta_search_dobind_init[%d]\n",
90                 op->o_log_prefix, candidate, 0 );
91
92         /*
93          * all the targets are already bound as pseudoroot
94          */
95         if ( mc->mc_authz_target == META_BOUND_ALL ) {
96                 return META_SEARCH_CANDIDATE;
97         }
98
99         retcode = META_SEARCH_BINDING;
100         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
101         if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
102                 /* already bound (or anonymous) */
103
104 #ifdef DEBUG_205
105                 char    buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
106                 int     bound = 0;
107
108                 if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
109                         bound = 1;
110                 }
111
112                 snprintf( buf, sizeof( buf ), " mc=%p ld=%p%s DN=\"%s\"",
113                         (void *)mc, (void *)msc->msc_ld,
114                         bound ? " bound" : " anonymous",
115                         bound == 0 ? "" : msc->msc_bound_ndn.bv_val );
116                 Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
117                         op->o_log_prefix, candidate, buf );
118 #endif /* DEBUG_205 */
119
120                 retcode = META_SEARCH_CANDIDATE;
121
122         } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) ) {
123                 /* another thread is binding the target for this conn; wait */
124
125 #ifdef DEBUG_205
126                 char    buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
127
128                 snprintf( buf, sizeof( buf ), " mc=%p ld=%p needbind",
129                         (void *)mc, (void *)msc->msc_ld );
130                 Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
131                         op->o_log_prefix, candidate, buf );
132 #endif /* DEBUG_205 */
133
134                 candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND;
135                 retcode = META_SEARCH_NEED_BIND;
136
137         } else {
138                 /* we'll need to bind the target for this conn */
139
140 #ifdef DEBUG_205
141                 char buf[ SLAP_TEXT_BUFLEN ];
142
143                 snprintf( buf, sizeof( buf ), " mc=%p ld=%p binding",
144                         (void *)mc, (void *)msc->msc_ld );
145                 Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
146                         op->o_log_prefix, candidate, buf );
147 #endif /* DEBUG_205 */
148
149                 if ( msc->msc_ld == NULL ) {
150                         /* for some reason (e.g. because formerly in "binding"
151                          * state, with eventual connection expiration or invalidation)
152                          * it was not initialized as expected */
153
154                         Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p ld=NULL\n",
155                                 op->o_log_prefix, candidate, (void *)mc );
156
157                         rc = meta_back_init_one_conn( op, rs, *mcp, candidate,
158                                 LDAP_BACK_CONN_ISPRIV( *mcp ), LDAP_BACK_DONTSEND, 0 );
159                         switch ( rc ) {
160                         case LDAP_SUCCESS:
161                                 assert( msc->msc_ld != NULL );
162                                 break;
163
164                         case LDAP_SERVER_DOWN:
165                         case LDAP_UNAVAILABLE:
166                                 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
167                                 goto down;
168         
169                         default:
170                                 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
171                                 goto other;
172                         }
173                 }
174
175                 LDAP_BACK_CONN_BINDING_SET( msc );
176         }
177
178         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
179
180         if ( retcode != META_SEARCH_BINDING ) {
181                 return retcode;
182         }
183
184         /* NOTE: this obsoletes pseudorootdn */
185         if ( op->o_conn != NULL &&
186                 !op->o_do_not_cache &&
187                 ( BER_BVISNULL( &msc->msc_bound_ndn ) ||
188                         BER_BVISEMPTY( &msc->msc_bound_ndn ) ||
189                         ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
190         {
191                 rc = meta_back_proxy_authz_cred( mc, candidate, op, rs, LDAP_BACK_DONTSEND, &binddn, &cred, &method );
192                 switch ( rc ) {
193                 case LDAP_SUCCESS:
194                         break;
195                 case LDAP_UNAVAILABLE:
196                         goto down;
197                 default:
198                         goto other;
199                 }
200
201                 /* NOTE: we copy things here, even if bind didn't succeed yet,
202                  * because the connection is not shared until bind is over */
203                 if ( !BER_BVISNULL( &binddn ) ) {
204                         ber_bvreplace( &msc->msc_bound_ndn, &binddn );
205                         if ( META_BACK_TGT_SAVECRED( mt ) && !BER_BVISNULL( &cred ) ) {
206                                 if ( !BER_BVISNULL( &msc->msc_cred ) ) {
207                                         memset( msc->msc_cred.bv_val, 0,
208                                                 msc->msc_cred.bv_len );
209                                 }
210                                 ber_bvreplace( &msc->msc_cred, &cred );
211                         }
212                 }
213
214                 if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
215                         /* apparently, idassert was configured with SASL bind,
216                          * so bind occurred inside meta_back_proxy_authz_cred() */
217                         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
218                         LDAP_BACK_CONN_BINDING_CLEAR( msc );
219                         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
220                         return META_SEARCH_CANDIDATE;
221                 }
222
223                 /* paranoid */
224                 switch ( method ) {
225                 case LDAP_AUTH_NONE:
226                 case LDAP_AUTH_SIMPLE:
227                         /* do a simple bind with binddn, cred */
228                         break;
229
230                 default:
231                         assert( 0 );
232                         break;
233                 }
234         }
235
236         assert( msc->msc_ld != NULL );
237
238         if ( !BER_BVISEMPTY( &binddn ) && BER_BVISEMPTY( &cred ) ) {
239                 /* bind anonymously? */
240                 Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p: "
241                         "non-empty dn with empty cred; binding anonymously\n",
242                         op->o_log_prefix, candidate, (void *)mc );
243                 cred = slap_empty_bv;
244                 
245         } else if ( BER_BVISEMPTY( &binddn ) && !BER_BVISEMPTY( &cred ) ) {
246                 /* error */
247                 Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p: "
248                         "empty dn with non-empty cred: error\n",
249                         op->o_log_prefix, candidate, (void *)mc );
250                 goto other;
251         }
252
253         /* connect must be async only the first time... */
254         ldap_set_option( msc->msc_ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_ON );
255
256 retry:;
257         rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred,
258                         NULL, NULL, &candidates[ candidate ].sr_msgid );
259
260 #ifdef DEBUG_205
261         {
262                 char buf[ SLAP_TEXT_BUFLEN ];
263
264                 snprintf( buf, sizeof( buf ), "meta_search_dobind_init[%d] mc=%p ld=%p rc=%d",
265                         candidate, (void *)mc, (void *)mc->mc_conns[ candidate ].msc_ld, rc );
266                 Debug( LDAP_DEBUG_ANY, "### %s %s\n",
267                         op->o_log_prefix, buf, 0 );
268         }
269 #endif /* DEBUG_205 */
270
271         switch ( rc ) {
272         case LDAP_SUCCESS:
273                 assert( candidates[ candidate ].sr_msgid >= 0 );
274                 META_BINDING_SET( &candidates[ candidate ] );
275                 return META_SEARCH_BINDING;
276
277         case LDAP_X_CONNECTING:
278                 /* must retry, same conn */
279                 candidates[ candidate ].sr_msgid = META_MSGID_CONNECTING;
280                 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
281                 LDAP_BACK_CONN_BINDING_CLEAR( msc );
282                 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
283                 return META_SEARCH_CONNECTING;
284
285         case LDAP_SERVER_DOWN:
286 down:;
287                 /* This is the worst thing that could happen:
288                  * the search will wait until the retry is over. */
289                 if ( !META_IS_RETRYING( &candidates[ candidate ] ) ) {
290                         META_RETRYING_SET( &candidates[ candidate ] );
291
292                         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
293
294                         assert( mc->mc_refcnt > 0 );
295                         if ( LogTest( LDAP_DEBUG_ANY ) ) {
296                                 char    buf[ SLAP_TEXT_BUFLEN ];
297
298                                 /* this lock is required; however,
299                                  * it's invoked only when logging is on */
300                                 ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
301                                 snprintf( buf, sizeof( buf ),
302                                         "retrying URI=\"%s\" DN=\"%s\"",
303                                         mt->mt_uri,
304                                         BER_BVISNULL( &msc->msc_bound_ndn ) ?
305                                                 "" : msc->msc_bound_ndn.bv_val );
306                                 ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
307
308                                 Debug( LDAP_DEBUG_ANY,
309                                         "%s meta_search_dobind_init[%d]: %s.\n",
310                                         op->o_log_prefix, candidate, buf );
311                         }
312
313                         meta_clear_one_candidate( op, mc, candidate );
314                         LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
315
316                         ( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn );
317
318                         /* mc here must be the regular mc, reset and ready for init */
319                         rc = meta_back_init_one_conn( op, rs, mc, candidate,
320                                 LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 );
321
322                         if ( rc == LDAP_SUCCESS ) {
323                                 LDAP_BACK_CONN_BINDING_SET( msc );
324                         }
325
326                         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
327
328                         if ( rc == LDAP_SUCCESS ) {
329                                 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
330                                 goto retry;
331                         }
332                 }
333
334                 if ( *mcp == NULL ) {
335                         retcode = META_SEARCH_ERR;
336                         rs->sr_err = LDAP_UNAVAILABLE;
337                         candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
338                         break;
339                 }
340                 /* fall thru */
341
342         default:
343 other:;
344                 rs->sr_err = rc;
345                 rc = slap_map_api2result( rs );
346
347                 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
348                 meta_clear_one_candidate( op, mc, candidate );
349                 candidates[ candidate ].sr_err = rc;
350                 if ( META_BACK_ONERR_STOP( mi ) ) {
351                         LDAP_BACK_CONN_TAINTED_SET( mc );
352                         meta_back_release_conn_lock( mi, mc, 0 );
353                         *mcp = NULL;
354                         rs->sr_err = rc;
355
356                         retcode = META_SEARCH_ERR;
357
358                 } else {
359                         retcode = META_SEARCH_NOT_CANDIDATE;
360                 }
361                 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
362                 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
363                 break;
364         }
365
366         return retcode;
367 }
368
369 static meta_search_candidate_t
370 meta_search_dobind_result(
371         Operation               *op,
372         SlapReply               *rs,
373         metaconn_t              **mcp,
374         int                     candidate,
375         SlapReply               *candidates,
376         LDAPMessage             *res )
377 {
378         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
379         metatarget_t            *mt = mi->mi_targets[ candidate ];
380         metaconn_t              *mc = *mcp;
381         metasingleconn_t        *msc = &mc->mc_conns[ candidate ];
382
383         meta_search_candidate_t retcode = META_SEARCH_NOT_CANDIDATE;
384         int                     rc;
385
386         assert( msc->msc_ld != NULL );
387
388         /* FIXME: matched? referrals? response controls? */
389         rc = ldap_parse_result( msc->msc_ld, res,
390                 &candidates[ candidate ].sr_err,
391                 NULL, NULL, NULL, NULL, 0 );
392         if ( rc != LDAP_SUCCESS ) {
393                 candidates[ candidate ].sr_err = rc;
394         }
395         rc = slap_map_api2result( &candidates[ candidate ] );
396
397         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
398         LDAP_BACK_CONN_BINDING_CLEAR( msc );
399         if ( rc != LDAP_SUCCESS ) {
400                 meta_clear_one_candidate( op, mc, candidate );
401                 candidates[ candidate ].sr_err = rc;
402                 if ( META_BACK_ONERR_STOP( mi ) ) {
403                         LDAP_BACK_CONN_TAINTED_SET( mc );
404                         meta_back_release_conn_lock( mi, mc, 0 );
405                         *mcp = NULL;
406                         retcode = META_SEARCH_ERR;
407                         rs->sr_err = rc;
408                 }
409
410         } else {
411                 /* FIXME: check if bound as idassert authcDN! */
412                 if ( BER_BVISNULL( &msc->msc_bound_ndn )
413                         || BER_BVISEMPTY( &msc->msc_bound_ndn ) )
414                 {
415                         LDAP_BACK_CONN_ISANON_SET( msc );
416
417                 } else {
418                         if ( META_BACK_TGT_SAVECRED( mt ) &&
419                                 !BER_BVISNULL( &msc->msc_cred ) &&
420                                 !BER_BVISEMPTY( &msc->msc_cred ) )
421                         {
422                                 ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
423                         }
424                         LDAP_BACK_CONN_ISBOUND_SET( msc );
425                 }
426                 retcode = META_SEARCH_CANDIDATE;
427
428                 /* connect must be async */
429                 ldap_set_option( msc->msc_ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_OFF );
430         }
431
432         candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
433         META_BINDING_CLEAR( &candidates[ candidate ] );
434
435         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
436
437         return retcode;
438 }
439
440 static meta_search_candidate_t
441 meta_back_search_start(
442         Operation               *op,
443         SlapReply               *rs,
444         dncookie                *dc,
445         metaconn_t              **mcp,
446         int                     candidate,
447         SlapReply               *candidates,
448         struct berval           *prcookie,
449         ber_int_t               prsize )
450 {
451         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
452         metatarget_t            *mt = mi->mi_targets[ candidate ];
453         metasingleconn_t        *msc = &(*mcp)->mc_conns[ candidate ];
454         struct berval           realbase = op->o_req_dn;
455         int                     realscope = op->ors_scope;
456         struct berval           mbase = BER_BVNULL; 
457         struct berval           mfilter = BER_BVNULL;
458         char                    **mapped_attrs = NULL;
459         int                     rc;
460         meta_search_candidate_t retcode;
461         struct timeval          tv, *tvp = NULL;
462         int                     nretries = 1;
463         LDAPControl             **ctrls = NULL;
464 #ifdef SLAPD_META_CLIENT_PR
465         LDAPControl             **save_ctrls = NULL;
466 #endif /* SLAPD_META_CLIENT_PR */
467
468         /* this should not happen; just in case... */
469         if ( msc->msc_ld == NULL ) {
470                 Debug( LDAP_DEBUG_ANY,
471                         "%s: meta_back_search_start candidate=%d ld=NULL%s.\n",
472                         op->o_log_prefix, candidate,
473                         META_BACK_ONERR_STOP( mi ) ? "" : " (ignored)" );
474                 candidates[ candidate ].sr_err = LDAP_OTHER;
475                 if ( META_BACK_ONERR_STOP( mi ) ) {
476                         return META_SEARCH_ERR;
477                 }
478                 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
479                 return META_SEARCH_NOT_CANDIDATE;
480         }
481
482         Debug( LDAP_DEBUG_TRACE, "%s >>> meta_back_search_start[%d]\n", op->o_log_prefix, candidate, 0 );
483
484         /*
485          * modifies the base according to the scope, if required
486          */
487         if ( mt->mt_nsuffix.bv_len > op->o_req_ndn.bv_len ) {
488                 switch ( op->ors_scope ) {
489                 case LDAP_SCOPE_SUBTREE:
490                         /*
491                          * make the target suffix the new base
492                          * FIXME: this is very forgiving, because
493                          * "illegal" searchBases may be turned
494                          * into the suffix of the target; however,
495                          * the requested searchBase already passed
496                          * thru the candidate analyzer...
497                          */
498                         if ( dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) ) {
499                                 realbase = mt->mt_nsuffix;
500                                 if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
501                                         realscope = LDAP_SCOPE_SUBORDINATE;
502                                 }
503
504                         } else {
505                                 /*
506                                  * this target is no longer candidate
507                                  */
508                                 retcode = META_SEARCH_NOT_CANDIDATE;
509                                 goto doreturn;
510                         }
511                         break;
512
513                 case LDAP_SCOPE_SUBORDINATE:
514                 case LDAP_SCOPE_ONELEVEL:
515                 {
516                         struct berval   rdn = mt->mt_nsuffix;
517                         rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," );
518                         if ( dnIsOneLevelRDN( &rdn )
519                                         && dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) )
520                         {
521                                 /*
522                                  * if there is exactly one level,
523                                  * make the target suffix the new
524                                  * base, and make scope "base"
525                                  */
526                                 realbase = mt->mt_nsuffix;
527                                 if ( op->ors_scope == LDAP_SCOPE_SUBORDINATE ) {
528                                         if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
529                                                 realscope = LDAP_SCOPE_SUBORDINATE;
530                                         } else {
531                                                 realscope = LDAP_SCOPE_SUBTREE;
532                                         }
533                                 } else {
534                                         realscope = LDAP_SCOPE_BASE;
535                                 }
536                                 break;
537                         } /* else continue with the next case */
538                 }
539
540                 case LDAP_SCOPE_BASE:
541                         /*
542                          * this target is no longer candidate
543                          */
544                         retcode = META_SEARCH_NOT_CANDIDATE;
545                         goto doreturn;
546                 }
547         }
548
549         /* initiate dobind */
550         retcode = meta_search_dobind_init( op, rs, mcp, candidate, candidates );
551
552         Debug( LDAP_DEBUG_TRACE, "%s <<< meta_search_dobind_init[%d]=%d\n", op->o_log_prefix, candidate, retcode );
553
554         if ( retcode != META_SEARCH_CANDIDATE ) {
555                 goto doreturn;
556         }
557
558         /*
559          * Rewrite the search base, if required
560          */
561         dc->target = mt;
562         dc->ctx = "searchBase";
563         switch ( ldap_back_dn_massage( dc, &realbase, &mbase ) ) {
564         case LDAP_SUCCESS:
565                 break;
566
567         case LDAP_UNWILLING_TO_PERFORM:
568                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
569                 rs->sr_text = "Operation not allowed";
570                 send_ldap_result( op, rs );
571                 retcode = META_SEARCH_ERR;
572                 goto doreturn;
573
574         default:
575
576                 /*
577                  * this target is no longer candidate
578                  */
579                 retcode = META_SEARCH_NOT_CANDIDATE;
580                 goto doreturn;
581         }
582
583         /*
584          * Maps filter
585          */
586         rc = ldap_back_filter_map_rewrite( dc, op->ors_filter,
587                         &mfilter, BACKLDAP_MAP, op->o_tmpmemctx );
588         switch ( rc ) {
589         case LDAP_SUCCESS:
590                 break;
591
592         case LDAP_COMPARE_FALSE:
593         default:
594                 /*
595                  * this target is no longer candidate
596                  */
597                 retcode = META_SEARCH_NOT_CANDIDATE;
598                 goto done;
599         }
600
601         /*
602          * Maps required attributes
603          */
604         rc = ldap_back_map_attrs( op, &mt->mt_rwmap.rwm_at,
605                         op->ors_attrs, BACKLDAP_MAP, &mapped_attrs );
606         if ( rc != LDAP_SUCCESS ) {
607                 /*
608                  * this target is no longer candidate
609                  */
610                 retcode = META_SEARCH_NOT_CANDIDATE;
611                 goto done;
612         }
613
614         if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
615                 tv.tv_sec = op->ors_tlimit > 0 ? op->ors_tlimit : 1;
616                 tv.tv_usec = 0;
617                 tvp = &tv;
618         }
619
620 #ifdef SLAPD_META_CLIENT_PR
621         save_ctrls = op->o_ctrls;
622         {
623                 LDAPControl *pr_c = NULL;
624                 int i = 0, nc = 0;
625
626                 if ( save_ctrls ) {
627                         for ( ; save_ctrls[i] != NULL; i++ );
628                         nc = i;
629                         pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, save_ctrls, NULL );
630                 }
631
632                 if ( pr_c != NULL ) nc--;
633                 if ( mt->mt_ps > 0 || prcookie != NULL ) nc++;
634
635                 if ( mt->mt_ps > 0 || prcookie != NULL || pr_c != NULL ) {
636                         int src = 0, dst = 0;
637                         BerElementBuffer berbuf;
638                         BerElement *ber = (BerElement *)&berbuf;
639                         struct berval val = BER_BVNULL;
640                         ber_len_t len;
641
642                         len = sizeof( LDAPControl * )*( nc + 1 ) + sizeof( LDAPControl );
643
644                         if ( mt->mt_ps > 0 || prcookie != NULL ) {
645                                 struct berval nullcookie = BER_BVNULL;
646                                 ber_tag_t tag;
647
648                                 if ( prsize == 0 && mt->mt_ps > 0 ) prsize = mt->mt_ps;
649                                 if ( prcookie == NULL ) prcookie = &nullcookie;
650
651                                 ber_init2( ber, NULL, LBER_USE_DER );
652                                 tag = ber_printf( ber, "{iO}", prsize, prcookie ); 
653                                 if ( tag == LBER_ERROR ) {
654                                         /* error */
655                                         (void) ber_free_buf( ber );
656                                         goto done_pr;
657                                 }
658
659                                 tag = ber_flatten2( ber, &val, 0 );
660                                 if ( tag == LBER_ERROR ) {
661                                         /* error */
662                                         (void) ber_free_buf( ber );
663                                         goto done_pr;
664                                 }
665
666                                 len += val.bv_len + 1;
667                         }
668
669                         op->o_ctrls = op->o_tmpalloc( len, op->o_tmpmemctx );
670                         if ( save_ctrls ) {
671                                 for ( ; save_ctrls[ src ] != NULL; src++ ) {
672                                         if ( save_ctrls[ src ] != pr_c ) {
673                                                 op->o_ctrls[ dst ] = save_ctrls[ src ];
674                                                 dst++;
675                                         }
676                                 }
677                         }
678
679                         if ( mt->mt_ps > 0 || prcookie != NULL ) {
680                                 op->o_ctrls[ dst ] = (LDAPControl *)&op->o_ctrls[ nc + 1 ];
681
682                                 op->o_ctrls[ dst ]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
683                                 op->o_ctrls[ dst ]->ldctl_iscritical = 1;
684
685                                 op->o_ctrls[ dst ]->ldctl_value.bv_val = (char *)&op->o_ctrls[ dst ][ 1 ];
686                                 AC_MEMCPY( op->o_ctrls[ dst ]->ldctl_value.bv_val, val.bv_val, val.bv_len + 1 );
687                                 op->o_ctrls[ dst ]->ldctl_value.bv_len = val.bv_len;
688                                 dst++;
689
690                                 (void)ber_free_buf( ber );
691                         }
692
693                         op->o_ctrls[ dst ] = NULL;
694                 }
695 done_pr:;
696         }
697 #endif /* SLAPD_META_CLIENT_PR */
698
699 retry:;
700         ctrls = op->o_ctrls;
701         if ( meta_back_controls_add( op, rs, *mcp, candidate, &ctrls )
702                 != LDAP_SUCCESS )
703         {
704                 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
705                 retcode = META_SEARCH_NOT_CANDIDATE;
706                 goto done;
707         }
708
709         /*
710          * Starts the search
711          */
712         assert( msc->msc_ld != NULL );
713         rc = ldap_pvt_search( msc->msc_ld,
714                         mbase.bv_val, realscope, mfilter.bv_val,
715                         mapped_attrs, op->ors_attrsonly,
716                         ctrls, NULL, tvp, op->ors_slimit, op->ors_deref,
717                         &candidates[ candidate ].sr_msgid ); 
718         switch ( rc ) {
719         case LDAP_SUCCESS:
720                 retcode = META_SEARCH_CANDIDATE;
721                 break;
722         
723         case LDAP_SERVER_DOWN:
724                 if ( nretries && meta_back_retry( op, rs, mcp, candidate, LDAP_BACK_DONTSEND ) ) {
725                         nretries = 0;
726                         /* if the identity changed, there might be need to re-authz */
727                         (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
728                         goto retry;
729                 }
730
731                 if ( *mcp == NULL ) {
732                         retcode = META_SEARCH_ERR;
733                         candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
734                         break;
735                 }
736                 /* fall thru */
737
738         default:
739                 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
740                 retcode = META_SEARCH_NOT_CANDIDATE;
741         }
742
743 done:;
744         (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
745 #ifdef SLAPD_META_CLIENT_PR
746         if ( save_ctrls != op->o_ctrls ) {
747                 op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx );
748                 op->o_ctrls = save_ctrls;
749         }
750 #endif /* SLAPD_META_CLIENT_PR */
751
752         if ( mapped_attrs ) {
753                 ber_memfree_x( mapped_attrs, op->o_tmpmemctx );
754         }
755         if ( mfilter.bv_val != op->ors_filterstr.bv_val ) {
756                 ber_memfree_x( mfilter.bv_val, op->o_tmpmemctx );
757         }
758         if ( mbase.bv_val != realbase.bv_val ) {
759                 free( mbase.bv_val );
760         }
761
762 doreturn:;
763         Debug( LDAP_DEBUG_TRACE, "%s <<< meta_back_search_start[%d]=%d\n", op->o_log_prefix, candidate, retcode );
764
765         return retcode;
766 }
767
768 int
769 meta_back_search( Operation *op, SlapReply *rs )
770 {
771         metainfo_t      *mi = ( metainfo_t * )op->o_bd->be_private;
772         metaconn_t      *mc;
773         struct timeval  save_tv = { 0, 0 },
774                         tv;
775         time_t          stoptime = (time_t)(-1),
776                         lastres_time = slap_get_time(),
777                         timeout = 0;
778         int             rc = 0, sres = LDAP_SUCCESS;
779         char            *matched = NULL;
780         int             last = 0, ncandidates = 0,
781                         initial_candidates = 0, candidate_match = 0,
782                         needbind = 0;
783         ldap_back_send_t        sendok = LDAP_BACK_SENDERR;
784         long            i;
785         dncookie        dc;
786         int             is_ok = 0;
787         void            *savepriv;
788         SlapReply       *candidates = NULL;
789         int             do_taint = 0;
790
791         rs_assert_ready( rs );
792         rs->sr_flags &= ~REP_ENTRY_MASK; /* paranoia, we can set rs = non-entry */
793
794         /*
795          * controls are set in ldap_back_dobind()
796          * 
797          * FIXME: in case of values return filter, we might want
798          * to map attrs and maybe rewrite value
799          */
800 getconn:;
801         mc = meta_back_getconn( op, rs, NULL, sendok );
802         if ( !mc ) {
803                 return rs->sr_err;
804         }
805
806         dc.conn = op->o_conn;
807         dc.rs = rs;
808
809         if ( candidates == NULL ) candidates = meta_back_candidates_get( op );
810         /*
811          * Inits searches
812          */
813         for ( i = 0; i < mi->mi_ntargets; i++ ) {
814                 /* reset sr_msgid; it is used in most loops
815                  * to check if that target is still to be considered */
816                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
817
818                 /* a target is marked as candidate by meta_back_getconn();
819                  * if for any reason (an error, it's over or so) it is
820                  * no longer active, sr_msgid is set to META_MSGID_IGNORE
821                  * but it remains candidate, which means it has been active
822                  * at some point during the operation.  This allows to 
823                  * use its response code and more to compute the final
824                  * response */
825                 if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
826                         continue;
827                 }
828
829                 candidates[ i ].sr_matched = NULL;
830                 candidates[ i ].sr_text = NULL;
831                 candidates[ i ].sr_ref = NULL;
832                 candidates[ i ].sr_ctrls = NULL;
833                 candidates[ i ].sr_nentries = 0;
834
835                 /* get largest timeout among candidates */
836                 if ( mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ]
837                         && mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ] > timeout )
838                 {
839                         timeout = mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ];
840                 }
841         }
842
843         for ( i = 0; i < mi->mi_ntargets; i++ ) {
844                 if ( !META_IS_CANDIDATE( &candidates[ i ] )
845                         || candidates[ i ].sr_err != LDAP_SUCCESS )
846                 {
847                         continue;
848                 }
849
850                 switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 ) )
851                 {
852                 case META_SEARCH_NOT_CANDIDATE:
853                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
854                         break;
855
856                 case META_SEARCH_NEED_BIND:
857                         ++needbind;
858                         /* fallthru */
859
860                 case META_SEARCH_CONNECTING:
861                 case META_SEARCH_CANDIDATE:
862                 case META_SEARCH_BINDING:
863                         candidates[ i ].sr_type = REP_INTERMEDIATE;
864                         ++ncandidates;
865                         break;
866
867                 case META_SEARCH_ERR:
868                         savepriv = op->o_private;
869                         op->o_private = (void *)i;
870                         send_ldap_result( op, rs );
871                         op->o_private = savepriv;
872                         rc = -1;
873                         goto finish;
874
875                 default:
876                         assert( 0 );
877                         break;
878                 }
879         }
880
881         if ( ncandidates > 0 && needbind == ncandidates ) {
882                 /*
883                  * give up the second time...
884                  *
885                  * NOTE: this should not occur the second time, since a fresh
886                  * connection has ben created; however, targets may also
887                  * need bind because the bind timed out or so.
888                  */
889                 if ( sendok & LDAP_BACK_BINDING ) {
890                         Debug( LDAP_DEBUG_ANY,
891                                 "%s meta_back_search: unable to initialize conn\n",
892                                 op->o_log_prefix, 0, 0 );
893                         rs->sr_err = LDAP_UNAVAILABLE;
894                         rs->sr_text = "unable to initialize connection to remote targets";
895                         send_ldap_result( op, rs );
896                         rc = -1;
897                         goto finish;
898                 }
899
900                 /* FIXME: better create a separate connection? */
901                 sendok |= LDAP_BACK_BINDING;
902
903 #ifdef DEBUG_205
904                 Debug( LDAP_DEBUG_ANY, "*** %s drop mc=%p create new connection\n",
905                         op->o_log_prefix, (void *)mc, 0 );
906 #endif /* DEBUG_205 */
907
908                 meta_back_release_conn( mi, mc );
909                 mc = NULL;
910
911                 needbind = 0;
912                 ncandidates = 0;
913
914                 goto getconn;
915         }
916
917         initial_candidates = ncandidates;
918
919         if ( LogTest( LDAP_DEBUG_TRACE ) ) {
920                 char    cnd[ SLAP_TEXT_BUFLEN ];
921                 int     c;
922
923                 for ( c = 0; c < mi->mi_ntargets; c++ ) {
924                         if ( META_IS_CANDIDATE( &candidates[ c ] ) ) {
925                                 cnd[ c ] = '*';
926                         } else {
927                                 cnd[ c ] = ' ';
928                         }
929                 }
930                 cnd[ c ] = '\0';
931
932                 Debug( LDAP_DEBUG_TRACE, "%s meta_back_search: ncandidates=%d "
933                         "cnd=\"%s\"\n", op->o_log_prefix, ncandidates, cnd );
934         }
935
936         if ( initial_candidates == 0 ) {
937                 /* NOTE: here we are not sending any matchedDN;
938                  * this is intended, because if the back-meta
939                  * is serving this search request, but no valid
940                  * candidate could be looked up, it means that
941                  * there is a hole in the mapping of the targets
942                  * and thus no knowledge of any remote superior
943                  * is available */
944                 Debug( LDAP_DEBUG_ANY, "%s meta_back_search: "
945                         "base=\"%s\" scope=%d: "
946                         "no candidate could be selected\n",
947                         op->o_log_prefix, op->o_req_dn.bv_val,
948                         op->ors_scope );
949
950                 /* FIXME: we're sending the first error we encounter;
951                  * maybe we should pick the worst... */
952                 rc = LDAP_NO_SUCH_OBJECT;
953                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
954                         if ( META_IS_CANDIDATE( &candidates[ i ] )
955                                 && candidates[ i ].sr_err != LDAP_SUCCESS )
956                         {
957                                 rc = candidates[ i ].sr_err;
958                                 break;
959                         }
960                 }
961
962                 send_ldap_error( op, rs, rc, NULL );
963
964                 goto finish;
965         }
966
967         /* We pull apart the ber result, stuff it into a slapd entry, and
968          * let send_search_entry stuff it back into ber format. Slow & ugly,
969          * but this is necessary for version matching, and for ACL processing.
970          */
971
972         if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
973                 stoptime = op->o_time + op->ors_tlimit;
974         }
975
976         /*
977          * In case there are no candidates, no cycle takes place...
978          *
979          * FIXME: we might use a queue, to better balance the load 
980          * among the candidates
981          */
982         for ( rc = 0; ncandidates > 0; ) {
983                 int     gotit = 0,
984                         doabandon = 0,
985                         alreadybound = ncandidates;
986
987                 /* check timeout */
988                 if ( timeout && lastres_time > 0
989                         && ( slap_get_time() - lastres_time ) > timeout )
990                 {
991                         doabandon = 1;
992                         rs->sr_text = "Operation timed out";
993                         rc = rs->sr_err = op->o_protocol >= LDAP_VERSION3 ?
994                                 LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
995                         savepriv = op->o_private;
996                         op->o_private = (void *)i;
997                         send_ldap_result( op, rs );
998                         op->o_private = savepriv;
999                         goto finish;
1000                 }
1001
1002                 /* check time limit */
1003                 if ( op->ors_tlimit != SLAP_NO_LIMIT
1004                                 && slap_get_time() > stoptime )
1005                 {
1006                         doabandon = 1;
1007                         rc = rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
1008                         savepriv = op->o_private;
1009                         op->o_private = (void *)i;
1010                         send_ldap_result( op, rs );
1011                         op->o_private = savepriv;
1012                         goto finish;
1013                 }
1014
1015                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
1016                         meta_search_candidate_t retcode = META_SEARCH_UNDEFINED;
1017                         metasingleconn_t        *msc = &mc->mc_conns[ i ];
1018                         LDAPMessage             *res = NULL, *msg;
1019
1020                         /* if msgid is invalid, don't ldap_result() */
1021                         if ( candidates[ i ].sr_msgid == META_MSGID_IGNORE ) {
1022                                 continue;
1023                         }
1024
1025                         /* if target still needs bind, retry */
1026                         if ( candidates[ i ].sr_msgid == META_MSGID_NEED_BIND
1027                                 || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
1028                         {
1029                                 /* initiate dobind */
1030                                 retcode = meta_search_dobind_init( op, rs, &mc, i, candidates );
1031
1032                                 Debug( LDAP_DEBUG_TRACE, "%s <<< meta_search_dobind_init[%ld]=%d\n",
1033                                         op->o_log_prefix, i, retcode );
1034
1035                                 switch ( retcode ) {
1036                                 case META_SEARCH_NEED_BIND:
1037                                         alreadybound--;
1038                                         /* fallthru */
1039
1040                                 case META_SEARCH_CONNECTING:
1041                                 case META_SEARCH_BINDING:
1042                                         break;
1043
1044                                 case META_SEARCH_ERR:
1045                                         candidates[ i ].sr_err = rs->sr_err;
1046                                         if ( META_BACK_ONERR_STOP( mi ) ) {
1047                                                 savepriv = op->o_private;
1048                                                 op->o_private = (void *)i;
1049                                                 send_ldap_result( op, rs );
1050                                                 op->o_private = savepriv;
1051                                                 goto finish;
1052                                         }
1053                                         /* fallthru */
1054
1055                                 case META_SEARCH_NOT_CANDIDATE:
1056                                         /*
1057                                          * When no candidates are left,
1058                                          * the outer cycle finishes
1059                                          */
1060                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1061                                         assert( ncandidates > 0 );
1062                                         --ncandidates;
1063                                         break;
1064
1065                                 case META_SEARCH_CANDIDATE:
1066                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1067                                         switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 ) )
1068                                         {
1069                                         case META_SEARCH_CANDIDATE:
1070                                                 assert( candidates[ i ].sr_msgid >= 0 );
1071                                                 break;
1072
1073                                         case META_SEARCH_ERR:
1074                                                 candidates[ i ].sr_err = rs->sr_err;
1075                                                 if ( META_BACK_ONERR_STOP( mi ) ) {
1076                                                         savepriv = op->o_private;
1077                                                         op->o_private = (void *)i;
1078                                                         send_ldap_result( op, rs );
1079                                                         op->o_private = savepriv;
1080                                                         goto finish;
1081                                                 }
1082                                                 /* fallthru */
1083
1084                                         case META_SEARCH_NOT_CANDIDATE:
1085                                                 /* means that meta_back_search_start()
1086                                                  * failed but onerr == continue */
1087                                                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1088                                                 assert( ncandidates > 0 );
1089                                                 --ncandidates;
1090                                                 break;
1091
1092                                         default:
1093                                                 /* impossible */
1094                                                 assert( 0 );
1095                                                 break;
1096                                         }
1097                                         break;
1098
1099                                 default:
1100                                         /* impossible */
1101                                         assert( 0 );
1102                                         break;
1103                                 }
1104                                 continue;
1105                         }
1106
1107                         /* check for abandon */
1108                         if ( op->o_abandon || LDAP_BACK_CONN_ABANDON( mc ) ) {
1109                                 break;
1110                         }
1111
1112 #ifdef DEBUG_205
1113                         if ( msc->msc_ld == NULL ) {
1114                                 char    buf[ SLAP_TEXT_BUFLEN ];
1115
1116                                 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
1117                                 snprintf( buf, sizeof( buf ),
1118                                         "%s meta_back_search[%ld] mc=%p msgid=%d%s%s%s\n",
1119                                         op->o_log_prefix, (long)i, (void *)mc,
1120                                         candidates[ i ].sr_msgid,
1121                                         META_IS_BINDING( &candidates[ i ] ) ? " binding" : "",
1122                                         LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ? " connbinding" : "",
1123                                         META_BACK_CONN_CREATING( &mc->mc_conns[ i ] ) ? " conncreating" : "" );
1124                                 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1125                                         
1126                                 Debug( LDAP_DEBUG_ANY, "!!! %s\n", buf, 0, 0 );
1127                         }
1128 #endif /* DEBUG_205 */
1129                         
1130                         /*
1131                          * FIXME: handle time limit as well?
1132                          * Note that target servers are likely 
1133                          * to handle it, so at some time we'll
1134                          * get a LDAP_TIMELIMIT_EXCEEDED from
1135                          * one of them ...
1136                          */
1137                         tv = save_tv;
1138                         rc = ldap_result( msc->msc_ld, candidates[ i ].sr_msgid,
1139                                         LDAP_MSG_RECEIVED, &tv, &res );
1140                         switch ( rc ) {
1141                         case 0:
1142                                 /* FIXME: res should not need to be freed */
1143                                 assert( res == NULL );
1144                                 continue;
1145
1146                         case -1:
1147 really_bad:;
1148                                 /* something REALLY bad happened! */
1149                                 if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
1150                                         candidates[ i ].sr_type = REP_RESULT;
1151
1152                                         if ( meta_back_retry( op, rs, &mc, i, LDAP_BACK_DONTSEND ) ) {
1153                                                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1154                                                 switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 ) )
1155                                                 {
1156                                                         /* means that failed but onerr == continue */
1157                                                 case META_SEARCH_NOT_CANDIDATE:
1158                                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1159
1160                                                         assert( ncandidates > 0 );
1161                                                         --ncandidates;
1162
1163                                                         candidates[ i ].sr_err = rs->sr_err;
1164                                                         if ( META_BACK_ONERR_STOP( mi ) ) {
1165                                                                 savepriv = op->o_private;
1166                                                                 op->o_private = (void *)i;
1167                                                                 send_ldap_result( op, rs );
1168                                                                 op->o_private = savepriv;
1169                                                                 goto finish;
1170                                                         }
1171                                                         /* fall thru */
1172
1173                                                 case META_SEARCH_CANDIDATE:
1174                                                         /* get back into business... */
1175                                                         continue;
1176
1177                                                 case META_SEARCH_BINDING:
1178                                                 case META_SEARCH_CONNECTING:
1179                                                 case META_SEARCH_NEED_BIND:
1180                                                 case META_SEARCH_UNDEFINED:
1181                                                         assert( 0 );
1182
1183                                                 default:
1184                                                         /* unrecoverable error */
1185                                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1186                                                         rc = rs->sr_err = LDAP_OTHER;
1187                                                         goto finish;
1188                                                 }
1189                                         }
1190
1191                                         candidates[ i ].sr_err = rs->sr_err;
1192                                         if ( META_BACK_ONERR_STOP( mi ) ) {
1193                                                 savepriv = op->o_private;
1194                                                 op->o_private = (void *)i;
1195                                                 send_ldap_result( op, rs );
1196                                                 op->o_private = savepriv;
1197                                                 goto finish;
1198                                         }
1199                                 }
1200
1201                                 /*
1202                                  * When no candidates are left,
1203                                  * the outer cycle finishes
1204                                  */
1205                                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1206                                 assert( ncandidates > 0 );
1207                                 --ncandidates;
1208                                 rs->sr_err = candidates[ i ].sr_err;
1209                                 continue;
1210
1211                         default:
1212                                 lastres_time = slap_get_time();
1213
1214                                 /* only touch when activity actually took place... */
1215                                 if ( mi->mi_idle_timeout != 0 && msc->msc_time < lastres_time ) {
1216                                         msc->msc_time = lastres_time;
1217                                 }
1218                                 break;
1219                         }
1220
1221                         for ( msg = ldap_first_message( msc->msc_ld, res );
1222                                 msg != NULL;
1223                                 msg = ldap_next_message( msc->msc_ld, msg ) )
1224                         {
1225                                 rc = ldap_msgtype( msg );
1226                                 if ( rc == LDAP_RES_SEARCH_ENTRY ) {
1227                                         LDAPMessage     *e;
1228
1229                                         if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
1230                                                 /* don't retry any more... */
1231                                                 candidates[ i ].sr_type = REP_RESULT;
1232                                         }
1233
1234                                         /* count entries returned by target */
1235                                         candidates[ i ].sr_nentries++;
1236
1237                                         is_ok++;
1238
1239                                         e = ldap_first_entry( msc->msc_ld, msg );
1240                                         savepriv = op->o_private;
1241                                         op->o_private = (void *)i;
1242                                         rs->sr_err = meta_send_entry( op, rs, mc, i, e );
1243
1244                                         switch ( rs->sr_err ) {
1245                                         case LDAP_SIZELIMIT_EXCEEDED:
1246                                                 savepriv = op->o_private;
1247                                                 op->o_private = (void *)i;
1248                                                 send_ldap_result( op, rs );
1249                                                 op->o_private = savepriv;
1250                                                 rs->sr_err = LDAP_SUCCESS;
1251                                                 ldap_msgfree( res );
1252                                                 res = NULL;
1253                                                 goto finish;
1254
1255                                         case LDAP_UNAVAILABLE:
1256                                                 rs->sr_err = LDAP_OTHER;
1257                                                 ldap_msgfree( res );
1258                                                 res = NULL;
1259                                                 goto finish;
1260                                         }
1261                                         op->o_private = savepriv;
1262
1263                                         /* don't wait any longer... */
1264                                         gotit = 1;
1265                                         save_tv.tv_sec = 0;
1266                                         save_tv.tv_usec = 0;
1267
1268                                 } else if ( rc == LDAP_RES_SEARCH_REFERENCE ) {
1269                                         char            **references = NULL;
1270                                         int             cnt;
1271
1272                                         if ( META_BACK_TGT_NOREFS( mi->mi_targets[ i ] ) ) {
1273                                                 continue;
1274                                         }
1275
1276                                         if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
1277                                                 /* don't retry any more... */
1278                                                 candidates[ i ].sr_type = REP_RESULT;
1279                                         }
1280         
1281                                         is_ok++;
1282         
1283                                         rc = ldap_parse_reference( msc->msc_ld, msg,
1284                                                         &references, &rs->sr_ctrls, 0 );
1285         
1286                                         if ( rc != LDAP_SUCCESS ) {
1287                                                 continue;
1288                                         }
1289         
1290                                         if ( references == NULL ) {
1291                                                 continue;
1292                                         }
1293
1294 #ifdef ENABLE_REWRITE
1295                                         dc.ctx = "referralDN";
1296 #else /* ! ENABLE_REWRITE */
1297                                         dc.tofrom = 0;
1298                                         dc.normalized = 0;
1299 #endif /* ! ENABLE_REWRITE */
1300
1301                                         /* FIXME: merge all and return at the end */
1302         
1303                                         for ( cnt = 0; references[ cnt ]; cnt++ )
1304                                                 ;
1305         
1306                                         rs->sr_ref = ber_memalloc_x( sizeof( struct berval ) * ( cnt + 1 ),
1307                                                 op->o_tmpmemctx );
1308         
1309                                         for ( cnt = 0; references[ cnt ]; cnt++ ) {
1310                                                 ber_str2bv_x( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ],
1311                                                 op->o_tmpmemctx );
1312                                         }
1313                                         BER_BVZERO( &rs->sr_ref[ cnt ] );
1314         
1315                                         ( void )ldap_back_referral_result_rewrite( &dc, rs->sr_ref,
1316                                                 op->o_tmpmemctx );
1317
1318                                         if ( rs->sr_ref != NULL && !BER_BVISNULL( &rs->sr_ref[ 0 ] ) ) {
1319                                                 /* ignore return value by now */
1320                                                 savepriv = op->o_private;
1321                                                 op->o_private = (void *)i;
1322                                                 ( void )send_search_reference( op, rs );
1323                                                 op->o_private = savepriv;
1324         
1325                                                 ber_bvarray_free_x( rs->sr_ref, op->o_tmpmemctx );
1326                                                 rs->sr_ref = NULL;
1327                                         }
1328
1329                                         /* cleanup */
1330                                         if ( references ) {
1331                                                 ber_memvfree( (void **)references );
1332                                         }
1333
1334                                         if ( rs->sr_ctrls ) {
1335                                                 ldap_controls_free( rs->sr_ctrls );
1336                                                 rs->sr_ctrls = NULL;
1337                                         }
1338
1339                                 } else if ( rc == LDAP_RES_INTERMEDIATE ) {
1340                                         if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
1341                                                 /* don't retry any more... */
1342                                                 candidates[ i ].sr_type = REP_RESULT;
1343                                         }
1344         
1345                                         /* FIXME: response controls
1346                                          * are passed without checks */
1347                                         rs->sr_err = ldap_parse_intermediate( msc->msc_ld,
1348                                                 msg,
1349                                                 (char **)&rs->sr_rspoid,
1350                                                 &rs->sr_rspdata,
1351                                                 &rs->sr_ctrls,
1352                                                 0 );
1353                                         if ( rs->sr_err != LDAP_SUCCESS ) {
1354                                                 candidates[ i ].sr_type = REP_RESULT;
1355                                                 ldap_msgfree( res );
1356                                                 res = NULL;
1357                                                 goto really_bad;
1358                                         }
1359
1360                                         slap_send_ldap_intermediate( op, rs );
1361
1362                                         if ( rs->sr_rspoid != NULL ) {
1363                                                 ber_memfree( (char *)rs->sr_rspoid );
1364                                                 rs->sr_rspoid = NULL;
1365                                         }
1366
1367                                         if ( rs->sr_rspdata != NULL ) {
1368                                                 ber_bvfree( rs->sr_rspdata );
1369                                                 rs->sr_rspdata = NULL;
1370                                         }
1371
1372                                         if ( rs->sr_ctrls != NULL ) {
1373                                                 ldap_controls_free( rs->sr_ctrls );
1374                                                 rs->sr_ctrls = NULL;
1375                                         }
1376
1377                                 } else if ( rc == LDAP_RES_SEARCH_RESULT ) {
1378                                         char            buf[ SLAP_TEXT_BUFLEN ];
1379                                         char            **references = NULL;
1380                                         LDAPControl     **ctrls = NULL;
1381
1382                                         if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
1383                                                 /* don't retry any more... */
1384                                                 candidates[ i ].sr_type = REP_RESULT;
1385                                         }
1386         
1387                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1388
1389                                         /* NOTE: ignores response controls
1390                                          * (and intermediate response controls
1391                                          * as well, except for those with search
1392                                          * references); this may not be correct,
1393                                          * but if they're not ignored then
1394                                          * back-meta would need to merge them
1395                                          * consistently (think of pagedResults...)
1396                                          */
1397                                         /* FIXME: response controls? */
1398                                         rs->sr_err = ldap_parse_result( msc->msc_ld,
1399                                                 msg,
1400                                                 &candidates[ i ].sr_err,
1401                                                 (char **)&candidates[ i ].sr_matched,
1402                                                 (char **)&candidates[ i ].sr_text,
1403                                                 &references,
1404                                                 &ctrls /* &candidates[ i ].sr_ctrls (unused) */ ,
1405                                                 0 );
1406                                         if ( rs->sr_err != LDAP_SUCCESS ) {
1407                                                 candidates[ i ].sr_err = rs->sr_err;
1408                                                 sres = slap_map_api2result( &candidates[ i ] );
1409                                                 candidates[ i ].sr_type = REP_RESULT;
1410                                                 ldap_msgfree( res );
1411                                                 res = NULL;
1412                                                 goto really_bad;
1413                                         }
1414
1415                                         rs->sr_err = candidates[ i ].sr_err;
1416
1417                                         /* massage matchedDN if need be */
1418                                         if ( candidates[ i ].sr_matched != NULL ) {
1419                                                 struct berval   match, mmatch;
1420
1421                                                 ber_str2bv( candidates[ i ].sr_matched,
1422                                                         0, 0, &match );
1423                                                 candidates[ i ].sr_matched = NULL;
1424
1425                                                 dc.ctx = "matchedDN";
1426                                                 dc.target = mi->mi_targets[ i ];
1427                                                 if ( !ldap_back_dn_massage( &dc, &match, &mmatch ) ) {
1428                                                         if ( mmatch.bv_val == match.bv_val ) {
1429                                                                 candidates[ i ].sr_matched
1430                                                                         = ch_strdup( mmatch.bv_val );
1431
1432                                                         } else {
1433                                                                 candidates[ i ].sr_matched = mmatch.bv_val;
1434                                                         }
1435
1436                                                         candidate_match++;
1437                                                 } 
1438                                                 ldap_memfree( match.bv_val );
1439                                         }
1440
1441                                         /* add references to array */
1442                                         /* RFC 4511: referrals can only appear
1443                                          * if result code is LDAP_REFERRAL */
1444                                         if ( references != NULL
1445                                                 && references[ 0 ] != NULL
1446                                                 && references[ 0 ][ 0 ] != '\0' )
1447                                         {
1448                                                 if ( rs->sr_err != LDAP_REFERRAL ) {
1449                                                         Debug( LDAP_DEBUG_ANY,
1450                                                                 "%s meta_back_search[%ld]: "
1451                                                                 "got referrals with err=%d\n",
1452                                                                 op->o_log_prefix,
1453                                                                 i, rs->sr_err );
1454
1455                                                 } else {
1456                                                         BerVarray       sr_ref;
1457                                                         int             cnt;
1458         
1459                                                         for ( cnt = 0; references[ cnt ]; cnt++ )
1460                                                                 ;
1461         
1462                                                         sr_ref = ber_memalloc_x( sizeof( struct berval ) * ( cnt + 1 ),
1463                                                                 op->o_tmpmemctx );
1464         
1465                                                         for ( cnt = 0; references[ cnt ]; cnt++ ) {
1466                                                                 ber_str2bv_x( references[ cnt ], 0, 1, &sr_ref[ cnt ],
1467                                                                         op->o_tmpmemctx );
1468                                                         }
1469                                                         BER_BVZERO( &sr_ref[ cnt ] );
1470         
1471                                                         ( void )ldap_back_referral_result_rewrite( &dc, sr_ref,
1472                                                                 op->o_tmpmemctx );
1473                                         
1474                                                         if ( rs->sr_v2ref == NULL ) {
1475                                                                 rs->sr_v2ref = sr_ref;
1476
1477                                                         } else {
1478                                                                 for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) {
1479                                                                         ber_bvarray_add_x( &rs->sr_v2ref, &sr_ref[ cnt ],
1480                                                                                 op->o_tmpmemctx );
1481                                                                 }
1482                                                                 ber_memfree_x( sr_ref, op->o_tmpmemctx );
1483                                                         }
1484                                                 }
1485
1486                                         } else if ( rs->sr_err == LDAP_REFERRAL ) {
1487                                                 Debug( LDAP_DEBUG_ANY,
1488                                                         "%s meta_back_search[%ld]: "
1489                                                         "got err=%d with null "
1490                                                         "or empty referrals\n",
1491                                                         op->o_log_prefix,
1492                                                         i, rs->sr_err );
1493
1494                                                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
1495                                         }
1496
1497                                         /* cleanup */
1498                                         ber_memvfree( (void **)references );
1499
1500                                         sres = slap_map_api2result( rs );
1501         
1502                                         if ( LogTest( LDAP_DEBUG_TRACE | LDAP_DEBUG_ANY ) ) {
1503                                                 snprintf( buf, sizeof( buf ),
1504                                                         "%s meta_back_search[%ld] "
1505                                                         "match=\"%s\" err=%ld",
1506                                                         op->o_log_prefix, i,
1507                                                         candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
1508                                                         (long) candidates[ i ].sr_err );
1509                                                 if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
1510                                                         Debug( LDAP_DEBUG_TRACE, "%s.\n", buf, 0, 0 );
1511         
1512                                                 } else {
1513                                                         Debug( LDAP_DEBUG_ANY, "%s (%s).\n",
1514                                                                 buf, ldap_err2string( candidates[ i ].sr_err ), 0 );
1515                                                 }
1516                                         }
1517         
1518                                         switch ( sres ) {
1519                                         case LDAP_NO_SUCH_OBJECT:
1520                                                 /* is_ok is touched any time a valid
1521                                                  * (even intermediate) result is
1522                                                  * returned; as a consequence, if
1523                                                  * a candidate returns noSuchObject
1524                                                  * it is ignored and the candidate
1525                                                  * is simply demoted. */
1526                                                 if ( is_ok ) {
1527                                                         sres = LDAP_SUCCESS;
1528                                                 }
1529                                                 break;
1530         
1531                                         case LDAP_SUCCESS:
1532                                                 if ( ctrls != NULL && ctrls[0] != NULL ) {
1533 #ifdef SLAPD_META_CLIENT_PR
1534                                                         LDAPControl *pr_c;
1535
1536                                                         pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, ctrls, NULL );
1537                                                         if ( pr_c != NULL ) {
1538                                                                 BerElementBuffer berbuf;
1539                                                                 BerElement *ber = (BerElement *)&berbuf;
1540                                                                 ber_tag_t tag;
1541                                                                 ber_int_t prsize;
1542                                                                 struct berval prcookie;
1543
1544                                                                 /* unsolicited, do not accept */
1545                                                                 if ( mi->mi_targets[i]->mt_ps == 0 ) {
1546                                                                         rs->sr_err = LDAP_OTHER;
1547                                                                         goto err_pr;
1548                                                                 }
1549
1550                                                                 ber_init2( ber, &pr_c->ldctl_value, LBER_USE_DER );
1551
1552                                                                 tag = ber_scanf( ber, "{im}", &prsize, &prcookie );
1553                                                                 if ( tag == LBER_ERROR ) {
1554                                                                         rs->sr_err = LDAP_OTHER;
1555                                                                         goto err_pr;
1556                                                                 }
1557
1558                                                                 /* more pages? new search request */
1559                                                                 if ( !BER_BVISNULL( &prcookie ) && !BER_BVISEMPTY( &prcookie ) ) {
1560                                                                         if ( mi->mi_targets[i]->mt_ps > 0 ) {
1561                                                                                 /* ignore size if specified */
1562                                                                                 prsize = 0;
1563
1564                                                                         } else if ( prsize == 0 ) {
1565                                                                                 /* guess the page size from the entries returned so far */
1566                                                                                 prsize = candidates[ i ].sr_nentries;
1567                                                                         }
1568
1569                                                                         candidates[ i ].sr_nentries = 0;
1570                                                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1571                                                                         candidates[ i ].sr_type = REP_INTERMEDIATE;
1572                                                                 
1573                                                                         assert( candidates[ i ].sr_matched == NULL );
1574                                                                         assert( candidates[ i ].sr_text == NULL );
1575                                                                         assert( candidates[ i ].sr_ref == NULL );
1576
1577                                                                         switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, &prcookie, prsize ) )
1578                                                                         {
1579                                                                         case META_SEARCH_CANDIDATE:
1580                                                                                 assert( candidates[ i ].sr_msgid >= 0 );
1581                                                                                 ldap_controls_free( ctrls );
1582                                                                                 goto free_message;
1583
1584                                                                         case META_SEARCH_ERR:
1585 err_pr:;
1586                                                                                 candidates[ i ].sr_err = rs->sr_err;
1587                                                                                 if ( META_BACK_ONERR_STOP( mi ) ) {
1588                                                                                         savepriv = op->o_private;
1589                                                                                         op->o_private = (void *)i;
1590                                                                                         send_ldap_result( op, rs );
1591                                                                                         op->o_private = savepriv;
1592                                                                                         ldap_controls_free( ctrls );
1593                                                                                         goto finish;
1594                                                                                 }
1595                                                                                 /* fallthru */
1596
1597                                                                         case META_SEARCH_NOT_CANDIDATE:
1598                                                                                 /* means that meta_back_search_start()
1599                                                                                  * failed but onerr == continue */
1600                                                                                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1601                                                                                 assert( ncandidates > 0 );
1602                                                                                 --ncandidates;
1603                                                                                 break;
1604
1605                                                                         default:
1606                                                                                 /* impossible */
1607                                                                                 assert( 0 );
1608                                                                                 break;
1609                                                                         }
1610                                                                         break;
1611                                                                 }
1612                                                         }
1613 #endif /* SLAPD_META_CLIENT_PR */
1614
1615                                                         ldap_controls_free( ctrls );
1616                                                 }
1617                                                 /* fallthru */
1618
1619                                         case LDAP_REFERRAL:
1620                                                 is_ok++;
1621                                                 break;
1622         
1623                                         case LDAP_SIZELIMIT_EXCEEDED:
1624                                                 /* if a target returned sizelimitExceeded
1625                                                  * and the entry count is equal to the
1626                                                  * proxy's limit, the target would have
1627                                                  * returned more, and the error must be
1628                                                  * propagated to the client; otherwise,
1629                                                  * the target enforced a limit lower
1630                                                  * than what requested by the proxy;
1631                                                  * ignore it */
1632                                                 candidates[ i ].sr_err = rs->sr_err;
1633                                                 if ( rs->sr_nentries == op->ors_slimit
1634                                                         || META_BACK_ONERR_STOP( mi ) )
1635                                                 {
1636                                                         const char *save_text = rs->sr_text;
1637                                                         savepriv = op->o_private;
1638                                                         op->o_private = (void *)i;
1639                                                         rs->sr_text = candidates[ i ].sr_text;
1640                                                         send_ldap_result( op, rs );
1641                                                         rs->sr_text = save_text;
1642                                                         op->o_private = savepriv;
1643                                                         ldap_msgfree( res );
1644                                                         res = NULL;
1645                                                         goto finish;
1646                                                 }
1647                                                 break;
1648         
1649                                         default:
1650                                                 candidates[ i ].sr_err = rs->sr_err;
1651                                                 if ( META_BACK_ONERR_STOP( mi ) ) {
1652                                                         const char *save_text = rs->sr_text;
1653                                                         savepriv = op->o_private;
1654                                                         op->o_private = (void *)i;
1655                                                         rs->sr_text = candidates[ i ].sr_text;
1656                                                         send_ldap_result( op, rs );
1657                                                         rs->sr_text = save_text;
1658                                                         op->o_private = savepriv;
1659                                                         ldap_msgfree( res );
1660                                                         res = NULL;
1661                                                         goto finish;
1662                                                 }
1663                                                 break;
1664                                         }
1665         
1666                                         last = i;
1667                                         rc = 0;
1668         
1669                                         /*
1670                                          * When no candidates are left,
1671                                          * the outer cycle finishes
1672                                          */
1673                                         assert( ncandidates > 0 );
1674                                         --ncandidates;
1675
1676                                 } else if ( rc == LDAP_RES_BIND ) {
1677                                         meta_search_candidate_t retcode;
1678         
1679                                         retcode = meta_search_dobind_result( op, rs, &mc, i, candidates, msg );
1680                                         if ( retcode == META_SEARCH_CANDIDATE ) {
1681                                                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1682                                                 retcode = meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 );
1683                                         }
1684         
1685                                         switch ( retcode ) {
1686                                         case META_SEARCH_CANDIDATE:
1687                                                 break;
1688         
1689                                                 /* means that failed but onerr == continue */
1690                                         case META_SEARCH_NOT_CANDIDATE:
1691                                         case META_SEARCH_ERR:
1692                                                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1693                                                 assert( ncandidates > 0 );
1694                                                 --ncandidates;
1695         
1696                                                 candidates[ i ].sr_err = rs->sr_err;
1697                                                 if ( META_BACK_ONERR_STOP( mi ) ) {
1698                                                         savepriv = op->o_private;
1699                                                         op->o_private = (void *)i;
1700                                                         send_ldap_result( op, rs );
1701                                                         op->o_private = savepriv;
1702                                                         ldap_msgfree( res );
1703                                                         res = NULL;
1704                                                         goto finish;
1705                                                 }
1706                                                 goto free_message;
1707         
1708                                         default:
1709                                                 assert( 0 );
1710                                                 break;
1711                                         }
1712         
1713                                 } else {
1714                                         Debug( LDAP_DEBUG_ANY,
1715                                                 "%s meta_back_search[%ld]: "
1716                                                 "unrecognized response message tag=%d\n",
1717                                                 op->o_log_prefix,
1718                                                 i, rc );
1719                                 
1720                                         ldap_msgfree( res );
1721                                         res = NULL;
1722                                         goto really_bad;
1723                                 }
1724                         }
1725
1726 free_message:;
1727                         ldap_msgfree( res );
1728                         res = NULL;
1729                 }
1730
1731                 /* check for abandon */
1732                 if ( op->o_abandon || LDAP_BACK_CONN_ABANDON( mc ) ) {
1733                         for ( i = 0; i < mi->mi_ntargets; i++ ) {
1734                                 if ( candidates[ i ].sr_msgid >= 0
1735                                         || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
1736                                 {
1737                                         if ( META_IS_BINDING( &candidates[ i ] )
1738                                                 || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
1739                                         {
1740                                                 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
1741                                                 if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] )
1742                                                         || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
1743                                                 {
1744                                                         /* if still binding, destroy */
1745
1746 #ifdef DEBUG_205
1747                                                         char buf[ SLAP_TEXT_BUFLEN ];
1748
1749                                                         snprintf( buf, sizeof( buf), "%s meta_back_search(abandon) "
1750                                                                 "ldap_unbind_ext[%ld] mc=%p ld=%p",
1751                                                                 op->o_log_prefix, i, (void *)mc,
1752                                                                 (void *)mc->mc_conns[i].msc_ld );
1753
1754                                                         Debug( LDAP_DEBUG_ANY, "### %s\n", buf, 0, 0 );
1755 #endif /* DEBUG_205 */
1756
1757                                                         meta_clear_one_candidate( op, mc, i );
1758                                                 }
1759                                                 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1760                                                 META_BINDING_CLEAR( &candidates[ i ] );
1761                                                 
1762                                         } else {
1763                                                 (void)meta_back_cancel( mc, op, rs,
1764                                                         candidates[ i ].sr_msgid, i,
1765                                                         LDAP_BACK_DONTSEND );
1766                                         }
1767
1768                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1769                                         assert( ncandidates > 0 );
1770                                         --ncandidates;
1771                                 }
1772                         }
1773
1774                         if ( op->o_abandon ) {
1775                                 rc = SLAPD_ABANDON;
1776                         }
1777
1778                         /* let send_ldap_result play cleanup handlers (ITS#4645) */
1779                         break;
1780                 }
1781
1782                 /* if no entry was found during this loop,
1783                  * set a minimal timeout */
1784                 if ( ncandidates > 0 && gotit == 0 ) {
1785                         if ( save_tv.tv_sec == 0 && save_tv.tv_usec == 0 ) {
1786                                 save_tv.tv_usec = LDAP_BACK_RESULT_UTIMEOUT/initial_candidates;
1787
1788                                 /* arbitrarily limit to something between 1 and 2 minutes */
1789                         } else if ( ( stoptime == -1 && save_tv.tv_sec < 60 )
1790                                 || save_tv.tv_sec < ( stoptime - slap_get_time() ) / ( 2 * ncandidates ) )
1791                         {
1792                                 /* double the timeout */
1793                                 lutil_timermul( &save_tv, 2, &save_tv );
1794                         }
1795
1796                         if ( alreadybound == 0 ) {
1797                                 tv = save_tv;
1798                                 (void)select( 0, NULL, NULL, NULL, &tv );
1799
1800                         } else {
1801                                 ldap_pvt_thread_yield();
1802                         }
1803                 }
1804         }
1805
1806         if ( rc == -1 ) {
1807                 /*
1808                  * FIXME: need a better strategy to handle errors
1809                  */
1810                 if ( mc ) {
1811                         rc = meta_back_op_result( mc, op, rs, META_TARGET_NONE,
1812                                 -1, stoptime != -1 ? (stoptime - slap_get_time()) : 0,
1813                                 LDAP_BACK_SENDERR );
1814                 } else {
1815                         rc = rs->sr_err;
1816                 }
1817                 goto finish;
1818         }
1819
1820         /*
1821          * Rewrite the matched portion of the search base, if required
1822          * 
1823          * FIXME: only the last one gets caught!
1824          */
1825         savepriv = op->o_private;
1826         op->o_private = (void *)(long)mi->mi_ntargets;
1827         if ( candidate_match > 0 ) {
1828                 struct berval   pmatched = BER_BVNULL;
1829
1830                 /* we use the first one */
1831                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
1832                         if ( META_IS_CANDIDATE( &candidates[ i ] )
1833                                         && candidates[ i ].sr_matched != NULL )
1834                         {
1835                                 struct berval   bv, pbv;
1836                                 int             rc;
1837
1838                                 /* if we got success, and this target
1839                                  * returned noSuchObject, and its suffix
1840                                  * is a superior of the searchBase,
1841                                  * ignore the matchedDN */
1842                                 if ( sres == LDAP_SUCCESS
1843                                         && candidates[ i ].sr_err == LDAP_NO_SUCH_OBJECT
1844                                         && op->o_req_ndn.bv_len > mi->mi_targets[ i ]->mt_nsuffix.bv_len )
1845                                 {
1846                                         free( (char *)candidates[ i ].sr_matched );
1847                                         candidates[ i ].sr_matched = NULL;
1848                                         continue;
1849                                 }
1850
1851                                 ber_str2bv( candidates[ i ].sr_matched, 0, 0, &bv );
1852                                 rc = dnPretty( NULL, &bv, &pbv, op->o_tmpmemctx );
1853
1854                                 if ( rc == LDAP_SUCCESS ) {
1855
1856                                         /* NOTE: if they all are superiors
1857                                          * of the baseDN, the shorter is also 
1858                                          * superior of the longer... */
1859                                         if ( pbv.bv_len > pmatched.bv_len ) {
1860                                                 if ( !BER_BVISNULL( &pmatched ) ) {
1861                                                         op->o_tmpfree( pmatched.bv_val, op->o_tmpmemctx );
1862                                                 }
1863                                                 pmatched = pbv;
1864                                                 op->o_private = (void *)i;
1865
1866                                         } else {
1867                                                 op->o_tmpfree( pbv.bv_val, op->o_tmpmemctx );
1868                                         }
1869                                 }
1870
1871                                 if ( candidates[ i ].sr_matched != NULL ) {
1872                                         free( (char *)candidates[ i ].sr_matched );
1873                                         candidates[ i ].sr_matched = NULL;
1874                                 }
1875                         }
1876                 }
1877
1878                 if ( !BER_BVISNULL( &pmatched ) ) {
1879                         matched = pmatched.bv_val;
1880                 }
1881
1882         } else if ( sres == LDAP_NO_SUCH_OBJECT ) {
1883                 matched = op->o_bd->be_suffix[ 0 ].bv_val;
1884         }
1885
1886         /*
1887          * In case we returned at least one entry, we return LDAP_SUCCESS
1888          * otherwise, the latter error code we got
1889          */
1890
1891         if ( sres == LDAP_SUCCESS ) {
1892                 if ( rs->sr_v2ref ) {
1893                         sres = LDAP_REFERRAL;
1894                 }
1895
1896                 if ( META_BACK_ONERR_REPORT( mi ) ) {
1897                         /*
1898                          * Report errors, if any
1899                          *
1900                          * FIXME: we should handle error codes and return the more 
1901                          * important/reasonable
1902                          */
1903                         for ( i = 0; i < mi->mi_ntargets; i++ ) {
1904                                 if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
1905                                         continue;
1906                                 }
1907
1908                                 if ( candidates[ i ].sr_err != LDAP_SUCCESS
1909                                         && candidates[ i ].sr_err != LDAP_NO_SUCH_OBJECT )
1910                                 {
1911                                         sres = candidates[ i ].sr_err;
1912                                         break;
1913                                 }
1914                         }
1915                 }
1916         }
1917
1918         rs->sr_err = sres;
1919         rs->sr_matched = ( sres == LDAP_SUCCESS ? NULL : matched );
1920         rs->sr_ref = ( sres == LDAP_REFERRAL ? rs->sr_v2ref : NULL );
1921         send_ldap_result( op, rs );
1922         op->o_private = savepriv;
1923         rs->sr_matched = NULL;
1924         rs->sr_ref = NULL;
1925
1926 finish:;
1927         if ( matched && matched != op->o_bd->be_suffix[ 0 ].bv_val ) {
1928                 op->o_tmpfree( matched, op->o_tmpmemctx );
1929         }
1930
1931         if ( rs->sr_v2ref ) {
1932                 ber_bvarray_free_x( rs->sr_v2ref, op->o_tmpmemctx );
1933         }
1934
1935         for ( i = 0; i < mi->mi_ntargets; i++ ) {
1936                 if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
1937                         continue;
1938                 }
1939
1940                 if ( mc ) {
1941                         if ( META_IS_BINDING( &candidates[ i ] )
1942                                 || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
1943                         {
1944                                 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
1945                                 if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] )
1946                                         || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
1947                                 {
1948                                         assert( candidates[ i ].sr_msgid >= 0
1949                                                 || candidates[ i ].sr_msgid == META_MSGID_CONNECTING );
1950                                         assert( mc->mc_conns[ i ].msc_ld != NULL );
1951
1952 #ifdef DEBUG_205
1953                                         Debug( LDAP_DEBUG_ANY, "### %s meta_back_search(cleanup) "
1954                                                 "ldap_unbind_ext[%ld] ld=%p\n",
1955                                                 op->o_log_prefix, i, (void *)mc->mc_conns[i].msc_ld );
1956 #endif /* DEBUG_205 */
1957
1958                                         /* if still binding, destroy */
1959                                         meta_clear_one_candidate( op, mc, i );
1960                                 }
1961                                 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1962                                 META_BINDING_CLEAR( &candidates[ i ] );
1963
1964                         } else if ( candidates[ i ].sr_msgid >= 0 ) {
1965                                 (void)meta_back_cancel( mc, op, rs,
1966                                         candidates[ i ].sr_msgid, i,
1967                                         LDAP_BACK_DONTSEND );
1968                         }
1969                 }
1970
1971                 if ( candidates[ i ].sr_matched ) {
1972                         free( (char *)candidates[ i ].sr_matched );
1973                         candidates[ i ].sr_matched = NULL;
1974                 }
1975
1976                 if ( candidates[ i ].sr_text ) {
1977                         ldap_memfree( (char *)candidates[ i ].sr_text );
1978                         candidates[ i ].sr_text = NULL;
1979                 }
1980
1981                 if ( candidates[ i ].sr_ref ) {
1982                         ber_bvarray_free( candidates[ i ].sr_ref );
1983                         candidates[ i ].sr_ref = NULL;
1984                 }
1985
1986                 if ( candidates[ i ].sr_ctrls ) {
1987                         ldap_controls_free( candidates[ i ].sr_ctrls );
1988                         candidates[ i ].sr_ctrls = NULL;
1989                 }
1990
1991                 if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) {
1992                         meta_back_quarantine( op, &candidates[ i ], i );
1993                 }
1994
1995                 /* only in case of timelimit exceeded, if the timelimit exceeded because
1996                  * one contacted target never responded, invalidate the connection
1997                  * NOTE: should we quarantine the target as well?  right now, the connection
1998                  * is invalidated; the next time it will be recreated and the target
1999                  * will be quarantined if it cannot be contacted */
2000                 if ( mi->mi_idle_timeout != 0
2001                         && rs->sr_err == LDAP_TIMELIMIT_EXCEEDED
2002                         && op->o_time > mc->mc_conns[ i ].msc_time )
2003                 {
2004                         /* don't let anyone else use this expired connection */
2005                         do_taint++;
2006                 }
2007         }
2008
2009         if ( mc ) {
2010                 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
2011                 if ( do_taint ) {
2012                         LDAP_BACK_CONN_TAINTED_SET( mc );
2013                 }
2014                 meta_back_release_conn_lock( mi, mc, 0 );
2015                 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
2016         }
2017
2018         return rs->sr_err;
2019 }
2020
2021 static int
2022 meta_send_entry(
2023         Operation       *op,
2024         SlapReply       *rs,
2025         metaconn_t      *mc,
2026         int             target,
2027         LDAPMessage     *e )
2028 {
2029         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
2030         struct berval           a, mapped;
2031         int                     check_duplicate_attrs = 0;
2032         int                     check_sorted_attrs = 0;
2033         Entry                   ent = { 0 };
2034         BerElement              ber = *ldap_get_message_ber( e );
2035         Attribute               *attr, **attrp;
2036         struct berval           bdn,
2037                                 dn = BER_BVNULL;
2038         const char              *text;
2039         dncookie                dc;
2040         ber_len_t               len;
2041         int                     rc;
2042
2043         if ( ber_scanf( &ber, "l{", &len ) == LBER_ERROR ) {
2044                 return LDAP_DECODING_ERROR;
2045         }
2046
2047         if ( ber_set_option( &ber, LBER_OPT_REMAINING_BYTES, &len ) != LBER_OPT_SUCCESS ) {
2048                 return LDAP_OTHER;
2049         }
2050
2051         if ( ber_scanf( &ber, "m{", &bdn ) == LBER_ERROR ) {
2052                 return LDAP_DECODING_ERROR;
2053         }
2054
2055         /*
2056          * Rewrite the dn of the result, if needed
2057          */
2058         dc.target = mi->mi_targets[ target ];
2059         dc.conn = op->o_conn;
2060         dc.rs = rs;
2061         dc.ctx = "searchResult";
2062
2063         rs->sr_err = ldap_back_dn_massage( &dc, &bdn, &dn );
2064         if ( rs->sr_err != LDAP_SUCCESS) {
2065                 return rs->sr_err;
2066         }
2067
2068         /*
2069          * Note: this may fail if the target host(s) schema differs
2070          * from the one known to the meta, and a DN with unknown
2071          * attributes is returned.
2072          * 
2073          * FIXME: should we log anything, or delegate to dnNormalize?
2074          */
2075         rc = dnPrettyNormal( NULL, &dn, &ent.e_name, &ent.e_nname,
2076                 op->o_tmpmemctx );
2077         if ( dn.bv_val != bdn.bv_val ) {
2078                 free( dn.bv_val );
2079         }
2080         BER_BVZERO( &dn );
2081
2082         if ( rc != LDAP_SUCCESS ) {
2083                 Debug( LDAP_DEBUG_ANY,
2084                         "%s meta_send_entry(\"%s\"): "
2085                         "invalid DN syntax\n",
2086                         op->o_log_prefix, ent.e_name.bv_val, 0 );
2087                 rc = LDAP_INVALID_DN_SYNTAX;
2088                 goto done;
2089         }
2090
2091         /*
2092          * cache dn
2093          */
2094         if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) {
2095                 ( void )meta_dncache_update_entry( &mi->mi_cache,
2096                                 &ent.e_nname, target );
2097         }
2098
2099         attrp = &ent.e_attrs;
2100
2101         dc.ctx = "searchAttrDN";
2102         while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
2103                 int                             last = 0;
2104                 slap_syntax_validate_func       *validate;
2105                 slap_syntax_transform_func      *pretty;
2106
2107                 if ( ber_pvt_ber_remaining( &ber ) < 0 ) {
2108                         Debug( LDAP_DEBUG_ANY,
2109                                 "%s meta_send_entry(\"%s\"): "
2110                                 "unable to parse attr \"%s\".\n",
2111                                 op->o_log_prefix, ent.e_name.bv_val, a.bv_val );
2112                                 
2113                         rc = LDAP_OTHER;
2114                         goto done;
2115                 }
2116
2117                 if ( ber_pvt_ber_remaining( &ber ) == 0 ) {
2118                         break;
2119                 }
2120
2121                 ldap_back_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_at, 
2122                                 &a, &mapped, BACKLDAP_REMAP );
2123                 if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) {
2124                         ( void )ber_scanf( &ber, "x" /* [W] */ );
2125                         continue;
2126                 }
2127                 if ( mapped.bv_val != a.bv_val ) {
2128                         /* will need to check for duplicate attrs */
2129                         check_duplicate_attrs++;
2130                 }
2131                 attr = attr_alloc( NULL );
2132                 if ( attr == NULL ) {
2133                         rc = LDAP_OTHER;
2134                         goto done;
2135                 }
2136                 if ( slap_bv2ad( &mapped, &attr->a_desc, &text )
2137                                 != LDAP_SUCCESS) {
2138                         if ( slap_bv2undef_ad( &mapped, &attr->a_desc, &text,
2139                                 SLAP_AD_PROXIED ) != LDAP_SUCCESS )
2140                         {
2141                                 char    buf[ SLAP_TEXT_BUFLEN ];
2142
2143                                 snprintf( buf, sizeof( buf ),
2144                                         "%s meta_send_entry(\"%s\"): "
2145                                         "slap_bv2undef_ad(%s): %s\n",
2146                                         op->o_log_prefix, ent.e_name.bv_val,
2147                                         mapped.bv_val, text );
2148
2149                                 Debug( LDAP_DEBUG_ANY, "%s", buf, 0, 0 );
2150                                 ( void )ber_scanf( &ber, "x" /* [W] */ );
2151                                 attr_free( attr );
2152                                 continue;
2153                         }
2154                 }
2155
2156                 if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL )
2157                         check_sorted_attrs = 1;
2158
2159                 /* no subschemaSubentry */
2160                 if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry
2161                         || attr->a_desc == slap_schema.si_ad_entryDN )
2162                 {
2163
2164                         /* 
2165                          * We eat target's subschemaSubentry because
2166                          * a search for this value is likely not
2167                          * to resolve to the appropriate backend;
2168                          * later, the local subschemaSubentry is
2169                          * added.
2170                          *
2171                          * We also eat entryDN because the frontend
2172                          * will reattach it without checking if already
2173                          * present...
2174                          */
2175                         ( void )ber_scanf( &ber, "x" /* [W] */ );
2176                         attr_free(attr);
2177                         continue;
2178                 }
2179
2180                 if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR 
2181                                 || attr->a_vals == NULL )
2182                 {
2183                         attr->a_vals = (struct berval *)&slap_dummy_bv;
2184
2185                 } else {
2186                         for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); ++last )
2187                                 ;
2188                 }
2189                 attr->a_numvals = last;
2190
2191                 validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate;
2192                 pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty;
2193
2194                 if ( !validate && !pretty ) {
2195                         attr_free( attr );
2196                         goto next_attr;
2197                 }
2198
2199                 if ( attr->a_desc == slap_schema.si_ad_objectClass
2200                                 || attr->a_desc == slap_schema.si_ad_structuralObjectClass )
2201                 {
2202                         struct berval   *bv;
2203
2204                         for ( bv = attr->a_vals; !BER_BVISNULL( bv ); bv++ ) {
2205                                 ObjectClass *oc;
2206
2207                                 ldap_back_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_oc,
2208                                                 bv, &mapped, BACKLDAP_REMAP );
2209                                 if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0') {
2210 remove_oc:;
2211                                         free( bv->bv_val );
2212                                         BER_BVZERO( bv );
2213                                         if ( --last < 0 ) {
2214                                                 break;
2215                                         }
2216                                         *bv = attr->a_vals[ last ];
2217                                         BER_BVZERO( &attr->a_vals[ last ] );
2218                                         bv--;
2219
2220                                 } else if ( mapped.bv_val != bv->bv_val ) {
2221                                         int     i;
2222
2223                                         for ( i = 0; !BER_BVISNULL( &attr->a_vals[ i ] ); i++ ) {
2224                                                 if ( &attr->a_vals[ i ] == bv ) {
2225                                                         continue;
2226                                                 }
2227
2228                                                 if ( ber_bvstrcasecmp( &mapped, &attr->a_vals[ i ] ) == 0 ) {
2229                                                         break;
2230                                                 }
2231                                         }
2232
2233                                         if ( !BER_BVISNULL( &attr->a_vals[ i ] ) ) {
2234                                                 goto remove_oc;
2235                                         }
2236
2237                                         ber_bvreplace( bv, &mapped );
2238
2239                                 } else if ( ( oc = oc_bvfind_undef( bv ) ) == NULL ) {
2240                                         goto remove_oc;
2241
2242                                 } else {
2243                                         ber_bvreplace( bv, &oc->soc_cname );
2244                                 }
2245                         }
2246                 /*
2247                  * It is necessary to try to rewrite attributes with
2248                  * dn syntax because they might be used in ACLs as
2249                  * members of groups; since ACLs are applied to the
2250                  * rewritten stuff, no dn-based subecj clause could
2251                  * be used at the ldap backend side (see
2252                  * http://www.OpenLDAP.org/faq/data/cache/452.html)
2253                  * The problem can be overcome by moving the dn-based
2254                  * ACLs to the target directory server, and letting
2255                  * everything pass thru the ldap backend.
2256                  */
2257                 } else {
2258                         int     i;
2259
2260                         if ( attr->a_desc->ad_type->sat_syntax ==
2261                                 slap_schema.si_syn_distinguishedName )
2262                         {
2263                                 ldap_dnattr_result_rewrite( &dc, attr->a_vals );
2264
2265                         } else if ( attr->a_desc == slap_schema.si_ad_ref ) {
2266                                 ldap_back_referral_result_rewrite( &dc, attr->a_vals, NULL );
2267
2268                         }
2269
2270                         for ( i = 0; i < last; i++ ) {
2271                                 struct berval   pval;
2272                                 int             rc;
2273
2274                                 if ( pretty ) {
2275                                         rc = ordered_value_pretty( attr->a_desc,
2276                                                 &attr->a_vals[i], &pval, NULL );
2277
2278                                 } else {
2279                                         rc = ordered_value_validate( attr->a_desc,
2280                                                 &attr->a_vals[i], 0 );
2281                                 }
2282
2283                                 if ( rc ) {
2284                                         ber_memfree( attr->a_vals[i].bv_val );
2285                                         if ( --last == i ) {
2286                                                 BER_BVZERO( &attr->a_vals[ i ] );
2287                                                 break;
2288                                         }
2289                                         attr->a_vals[i] = attr->a_vals[last];
2290                                         BER_BVZERO( &attr->a_vals[last] );
2291                                         i--;
2292                                         continue;
2293                                 }
2294
2295                                 if ( pretty ) {
2296                                         ber_memfree( attr->a_vals[i].bv_val );
2297                                         attr->a_vals[i] = pval;
2298                                 }
2299                         }
2300
2301                         if ( last == 0 && attr->a_vals != &slap_dummy_bv ) {
2302                                 attr_free( attr );
2303                                 goto next_attr;
2304                         }
2305                 }
2306
2307                 if ( last && attr->a_desc->ad_type->sat_equality &&
2308                         attr->a_desc->ad_type->sat_equality->smr_normalize )
2309                 {
2310                         int i;
2311
2312                         attr->a_nvals = ch_malloc( ( last + 1 ) * sizeof( struct berval ) );
2313                         for ( i = 0; i<last; i++ ) {
2314                                 /* if normalizer fails, drop this value */
2315                                 if ( ordered_value_normalize(
2316                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
2317                                         attr->a_desc,
2318                                         attr->a_desc->ad_type->sat_equality,
2319                                         &attr->a_vals[i], &attr->a_nvals[i],
2320                                         NULL )) {
2321                                         ber_memfree( attr->a_vals[i].bv_val );
2322                                         if ( --last == i ) {
2323                                                 BER_BVZERO( &attr->a_vals[ i ] );
2324                                                 break;
2325                                         }
2326                                         attr->a_vals[i] = attr->a_vals[last];
2327                                         BER_BVZERO( &attr->a_vals[last] );
2328                                         i--;
2329                                 }
2330                         }
2331                         BER_BVZERO( &attr->a_nvals[i] );
2332                         if ( last == 0 ) {
2333                                 attr_free( attr );
2334                                 goto next_attr;
2335                         }
2336
2337                 } else {
2338                         attr->a_nvals = attr->a_vals;
2339                 }
2340
2341                 attr->a_numvals = last;
2342                 *attrp = attr;
2343                 attrp = &attr->a_next;
2344 next_attr:;
2345         }
2346
2347         /* only check if some mapping occurred */
2348         if ( check_duplicate_attrs ) {
2349                 Attribute       **ap;
2350
2351                 for ( ap = &ent.e_attrs; *ap != NULL; ap = &(*ap)->a_next ) {
2352                         Attribute       **tap;
2353
2354                         for ( tap = &(*ap)->a_next; *tap != NULL; ) {
2355                                 if ( (*tap)->a_desc == (*ap)->a_desc ) {
2356                                         Entry           e = { 0 };
2357                                         Modification    mod = { 0 };
2358                                         const char      *text = NULL;
2359                                         char            textbuf[ SLAP_TEXT_BUFLEN ];
2360                                         Attribute       *next = (*tap)->a_next;
2361
2362                                         BER_BVSTR( &e.e_name, "" );
2363                                         BER_BVSTR( &e.e_nname, "" );
2364                                         e.e_attrs = *ap;
2365                                         mod.sm_op = LDAP_MOD_ADD;
2366                                         mod.sm_desc = (*ap)->a_desc;
2367                                         mod.sm_type = mod.sm_desc->ad_cname;
2368                                         mod.sm_numvals = (*ap)->a_numvals;
2369                                         mod.sm_values = (*tap)->a_vals;
2370                                         if ( (*tap)->a_nvals != (*tap)->a_vals ) {
2371                                                 mod.sm_nvalues = (*tap)->a_nvals;
2372                                         }
2373
2374                                         (void)modify_add_values( &e, &mod,
2375                                                 /* permissive */ 1,
2376                                                 &text, textbuf, sizeof( textbuf ) );
2377
2378                                         /* should not insert new attrs! */
2379                                         assert( e.e_attrs == *ap );
2380
2381                                         attr_free( *tap );
2382                                         *tap = next;
2383
2384                                 } else {
2385                                         tap = &(*tap)->a_next;
2386                                 }
2387                         }
2388                 }
2389         }
2390
2391         /* Check for sorted attributes */
2392         if ( check_sorted_attrs ) {
2393                 for ( attr = ent.e_attrs; attr; attr = attr->a_next ) {
2394                         if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) {
2395                                 while ( attr->a_numvals > 1 ) {
2396                                         int i;
2397                                         int rc = slap_sort_vals( (Modifications *)attr, &text, &i, op->o_tmpmemctx );
2398                                         if ( rc != LDAP_TYPE_OR_VALUE_EXISTS )
2399                                                 break;
2400
2401                                         /* Strip duplicate values */
2402                                         if ( attr->a_nvals != attr->a_vals )
2403                                                 ber_memfree( attr->a_nvals[i].bv_val );
2404                                         ber_memfree( attr->a_vals[i].bv_val );
2405                                         attr->a_numvals--;
2406                                         if ( (unsigned)i < attr->a_numvals ) {
2407                                                 attr->a_vals[i] = attr->a_vals[attr->a_numvals];
2408                                                 if ( attr->a_nvals != attr->a_vals )
2409                                                         attr->a_nvals[i] = attr->a_nvals[attr->a_numvals];
2410                                         }
2411                                         BER_BVZERO(&attr->a_vals[attr->a_numvals]);
2412                                         if ( attr->a_nvals != attr->a_vals )
2413                                                 BER_BVZERO(&attr->a_nvals[attr->a_numvals]);
2414                                 }
2415                                 attr->a_flags |= SLAP_ATTR_SORTED_VALS;
2416                         }
2417                 }
2418         }
2419
2420         ldap_get_entry_controls( mc->mc_conns[target].msc_ld,
2421                 e, &rs->sr_ctrls );
2422         rs->sr_entry = &ent;
2423         rs->sr_attrs = op->ors_attrs;
2424         rs->sr_operational_attrs = NULL;
2425         rs->sr_flags = mi->mi_targets[ target ]->mt_rep_flags;
2426         rs->sr_err = LDAP_SUCCESS;
2427         rc = send_search_entry( op, rs );
2428         switch ( rc ) {
2429         case LDAP_UNAVAILABLE:
2430                 rc = LDAP_OTHER;
2431                 break;
2432         }
2433
2434 done:;
2435         rs->sr_entry = NULL;
2436         rs->sr_attrs = NULL;
2437         if ( rs->sr_ctrls != NULL ) {
2438                 ldap_controls_free( rs->sr_ctrls );
2439                 rs->sr_ctrls = NULL;
2440         }
2441         if ( !BER_BVISNULL( &ent.e_name ) ) {
2442                 free( ent.e_name.bv_val );
2443                 BER_BVZERO( &ent.e_name );
2444         }
2445         if ( !BER_BVISNULL( &ent.e_nname ) ) {
2446                 free( ent.e_nname.bv_val );
2447                 BER_BVZERO( &ent.e_nname );
2448         }
2449         entry_clean( &ent );
2450
2451         return rc;
2452 }
2453