]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/search.c
- setup framework for monitoring of back-bdb/back-hdb stuff in their
[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-2006 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 "slap.h"
32 #include "../back-ldap/back-ldap.h"
33 #include "back-meta.h"
34 #undef ldap_debug       /* silence a warning in ldap-int.h */
35 #include "ldap_log.h"
36 #include "../../../libraries/libldap/ldap-int.h"
37
38 /* IGNORE means that target does not (no longer) participate
39  * in the search;
40  * NOTREADY means the search on that target has not been initialized yet
41  */
42 #define META_MSGID_IGNORE       (-1)
43 #define META_MSGID_NEED_BIND    (-2)
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_ERR = -1,
55         META_SEARCH_NOT_CANDIDATE,
56         META_SEARCH_CANDIDATE,
57         META_SEARCH_BINDING,
58         META_SEARCH_NEED_BIND
59 } meta_search_candidate_t;
60
61 /*
62  * meta_search_dobind_init()
63  *
64  * initiates bind for a candidate target of a search.
65  */
66 static meta_search_candidate_t
67 meta_search_dobind_init(
68         Operation               *op,
69         SlapReply               *rs,
70         metaconn_t              **mcp,
71         int                     candidate,
72         SlapReply               *candidates )
73 {
74         metaconn_t              *mc = *mcp;
75         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
76         metatarget_t            *mt = mi->mi_targets[ candidate ];
77         metasingleconn_t        *msc = &mc->mc_conns[ candidate ];
78
79         struct berval           binddn = msc->msc_bound_ndn,
80                                 cred = msc->msc_cred;
81         int                     method;
82
83         int                     rc;
84
85         meta_search_candidate_t retcode;
86
87         Debug( LDAP_DEBUG_TRACE, "%s >>> meta_search_dobind_init[%d]\n", op->o_log_prefix, candidate, 0 );
88
89         /*
90          * all the targets are already bound as pseudoroot
91          */
92         if ( mc->mc_authz_target == META_BOUND_ALL ) {
93                 return META_SEARCH_CANDIDATE;
94         }
95
96         retcode = META_SEARCH_BINDING;
97         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
98         if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
99                 /* already bound (or anonymous) */
100                 retcode = META_SEARCH_CANDIDATE;
101
102         } else if ( LDAP_BACK_CONN_BINDING( msc ) ) {
103                 /* another thread is binding the target for this conn; wait */
104                 candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND;
105                 retcode = META_SEARCH_NEED_BIND;
106
107         } else {
108                 /* we'll need to bind the target for this conn */
109                 LDAP_BACK_CONN_BINDING_SET( msc );
110         }
111         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
112         if ( retcode != META_SEARCH_BINDING ) {
113                 return retcode;
114         }
115
116         /* NOTE: this obsoletes pseudorootdn */
117         if ( op->o_conn != NULL &&
118                 !op->o_do_not_cache &&
119                 ( BER_BVISNULL( &msc->msc_bound_ndn ) ||
120                         BER_BVISEMPTY( &msc->msc_bound_ndn ) ||
121                         ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
122         {
123                 rc = meta_back_proxy_authz_cred( mc, candidate, op, rs, LDAP_BACK_DONTSEND, &binddn, &cred, &method );
124                 if ( rc != LDAP_SUCCESS ) {
125                         goto down;
126                 }
127
128                 /* NOTE: we copy things here, even if bind didn't succeed yet,
129                  * because the connection is not shared until bind is over */
130                 if ( !BER_BVISNULL( &binddn ) ) {
131                         ber_bvreplace( &msc->msc_bound_ndn, &binddn );
132                         if ( LDAP_BACK_SAVECRED( mi ) && !BER_BVISNULL( &cred ) ) {
133                                 ber_dupbv( &msc->msc_cred, &cred );
134                         }
135                 }
136
137                 if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
138                         /* apparently, idassert was configured with SASL bind,
139                          * so bind occurred inside meta_back_proxy_authz_cred() */
140                         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
141                         LDAP_BACK_CONN_BINDING_CLEAR( msc );
142                         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
143                         return META_SEARCH_CANDIDATE;
144                 }
145
146                 /* paranoid */
147                 switch ( method ) {
148                 case LDAP_AUTH_NONE:
149                 case LDAP_AUTH_SIMPLE:
150                         /* do a simple bind with binddn, cred */
151                         break;
152
153                 default:
154                         assert( 0 );
155                         break;
156                 }
157         }
158
159         assert( msc->msc_ld != NULL );
160
161         rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred,
162                         NULL, NULL, &candidates[ candidate ].sr_msgid );
163         switch ( rc ) {
164         case LDAP_SUCCESS:
165                 META_BINDING_SET( &candidates[ candidate ] );
166                 return META_SEARCH_BINDING;
167
168 down:;
169         case LDAP_SERVER_DOWN:
170                 /* This is the worst thing that could happen:
171                  * the search will wait until the retry is over. */
172                 if ( meta_back_retry( op, rs, mcp, candidate, LDAP_BACK_DONTSEND ) ) {
173                         return META_SEARCH_CANDIDATE;
174                 }
175
176                 if ( *mcp == NULL ) {
177                         retcode = META_SEARCH_ERR;
178                         rs->sr_err = LDAP_UNAVAILABLE;
179                         break;
180                 }
181                 /* fall thru */
182
183         default:
184                 rs->sr_err = rc;
185                 rc = slap_map_api2result( rs );
186
187                 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
188                 LDAP_BACK_CONN_BINDING_CLEAR( msc );
189                 if ( META_BACK_ONERR_STOP( mi ) ) {
190                         LDAP_BACK_CONN_TAINTED_SET( mc );
191                         meta_back_release_conn( op, mc );
192                         *mcp = NULL;
193
194                         retcode = META_SEARCH_ERR;
195
196                 } else {
197                         candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
198                         retcode = META_SEARCH_NOT_CANDIDATE;
199                 }
200                 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
201                 break;
202         }
203
204         return retcode;
205 }
206
207 static meta_search_candidate_t
208 meta_search_dobind_result(
209         Operation               *op,
210         SlapReply               *rs,
211         metaconn_t              **mcp,
212         int                     candidate,
213         SlapReply               *candidates,
214         LDAPMessage             *res )
215 {
216         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
217         metaconn_t              *mc = *mcp;
218         metasingleconn_t        *msc = &mc->mc_conns[ candidate ];
219
220         meta_search_candidate_t retcode = META_SEARCH_NOT_CANDIDATE;
221         int                     rc;
222
223         assert( msc->msc_ld != NULL );
224
225         /* FIXME: matched? referrals? response controls? */
226         rc = ldap_parse_result( msc->msc_ld, res,
227                 &candidates[ candidate ].sr_err,
228                 NULL, NULL, NULL, NULL, 1 );
229         if ( rc != LDAP_SUCCESS ) {
230                 candidates[ candidate ].sr_err = rc;
231         }
232         rc = slap_map_api2result( &candidates[ candidate ] );
233
234         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
235         LDAP_BACK_CONN_BINDING_CLEAR( msc );
236         if ( rc != LDAP_SUCCESS ) {
237                 if ( META_BACK_ONERR_STOP( mi ) ) {
238                         LDAP_BACK_CONN_TAINTED_SET( mc );
239                         meta_back_release_conn( op, mc );
240                         *mcp = NULL;
241                         retcode = META_SEARCH_ERR;
242                 }
243
244         } else {
245                 /* FIXME: check if bound as idassert authcDN! */
246                 if ( be_isroot( op ) ) {
247                         LDAP_BACK_CONN_ISBOUND_SET( msc );
248                 } else {
249                         LDAP_BACK_CONN_ISANON_SET( msc );
250                 }
251                 retcode = META_SEARCH_CANDIDATE;
252         }
253         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
254
255         META_BINDING_CLEAR( &candidates[ candidate ] );
256
257         return retcode;
258 }
259
260 static meta_search_candidate_t
261 meta_back_search_start(
262         Operation               *op,
263         SlapReply               *rs,
264         dncookie                *dc,
265         metaconn_t              **mcp,
266         int                     candidate,
267         SlapReply               *candidates )
268 {
269         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
270         metatarget_t            *mt = mi->mi_targets[ candidate ];
271         metasingleconn_t        *msc = &(*mcp)->mc_conns[ candidate ];
272         struct berval           realbase = op->o_req_dn;
273         int                     realscope = op->ors_scope;
274         struct berval           mbase = BER_BVNULL; 
275         struct berval           mfilter = BER_BVNULL;
276         char                    **mapped_attrs = NULL;
277         int                     rc;
278         meta_search_candidate_t retcode;
279         struct timeval          tv, *tvp = NULL;
280         int                     nretries = 1;
281         LDAPControl             **ctrls = NULL;
282
283         /* this should not happen; just in case... */
284         if ( msc->msc_ld == NULL ) {
285                 Debug( LDAP_DEBUG_ANY,
286                         "%s: meta_back_search_start candidate=%d ld=NULL%s.\n",
287                         op->o_log_prefix, candidate,
288                         META_BACK_ONERR_STOP( mi ) ? "" : " (ignored)" );
289                 if ( META_BACK_ONERR_STOP( mi ) ) {
290                         return META_SEARCH_ERR;
291                 }
292                 return META_SEARCH_NOT_CANDIDATE;
293         }
294
295         Debug( LDAP_DEBUG_TRACE, "%s >>> meta_back_search_start[%d]\n", op->o_log_prefix, candidate, 0 );
296
297         /*
298          * modifies the base according to the scope, if required
299          */
300         if ( mt->mt_nsuffix.bv_len > op->o_req_ndn.bv_len ) {
301                 switch ( op->ors_scope ) {
302                 case LDAP_SCOPE_SUBTREE:
303                         /*
304                          * make the target suffix the new base
305                          * FIXME: this is very forgiving, because
306                          * "illegal" searchBases may be turned
307                          * into the suffix of the target; however,
308                          * the requested searchBase already passed
309                          * thru the candidate analyzer...
310                          */
311                         if ( dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) ) {
312                                 realbase = mt->mt_nsuffix;
313                                 if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
314                                         realscope = LDAP_SCOPE_SUBORDINATE;
315                                 }
316
317                         } else {
318                                 /*
319                                  * this target is no longer candidate
320                                  */
321                                 retcode = META_SEARCH_NOT_CANDIDATE;
322                                 goto doreturn;
323                         }
324                         break;
325
326                 case LDAP_SCOPE_SUBORDINATE:
327                 case LDAP_SCOPE_ONELEVEL:
328                 {
329                         struct berval   rdn = mt->mt_nsuffix;
330                         rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," );
331                         if ( dnIsOneLevelRDN( &rdn )
332                                         && dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) )
333                         {
334                                 /*
335                                  * if there is exactly one level,
336                                  * make the target suffix the new
337                                  * base, and make scope "base"
338                                  */
339                                 realbase = mt->mt_nsuffix;
340                                 if ( op->ors_scope == LDAP_SCOPE_SUBORDINATE ) {
341                                         if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
342                                                 realscope = LDAP_SCOPE_SUBORDINATE;
343                                         } else {
344                                                 realscope = LDAP_SCOPE_SUBTREE;
345                                         }
346                                 } else {
347                                         realscope = LDAP_SCOPE_BASE;
348                                 }
349                                 break;
350                         } /* else continue with the next case */
351                 }
352
353                 case LDAP_SCOPE_BASE:
354                         /*
355                          * this target is no longer candidate
356                          */
357                         retcode = META_SEARCH_NOT_CANDIDATE;
358                         goto doreturn;
359                 }
360         }
361
362         /* initiate dobind */
363         retcode = meta_search_dobind_init( op, rs, mcp, candidate, candidates );
364
365         Debug( LDAP_DEBUG_TRACE, "%s <<< meta_search_dobind_init[%d]=%d\n", op->o_log_prefix, candidate, retcode );
366
367         if ( retcode != META_SEARCH_CANDIDATE ) {
368                 goto doreturn;
369         }
370
371         /*
372          * Rewrite the search base, if required
373          */
374         dc->target = mt;
375         dc->ctx = "searchBase";
376         switch ( ldap_back_dn_massage( dc, &realbase, &mbase ) ) {
377         default:
378                 break;
379
380         case REWRITE_REGEXEC_UNWILLING:
381                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
382                 rs->sr_text = "Operation not allowed";
383                 send_ldap_result( op, rs );
384                 retcode = META_SEARCH_ERR;
385                 goto doreturn;
386
387         case REWRITE_REGEXEC_ERR:
388
389                 /*
390                  * this target is no longer candidate
391                  */
392                 retcode = META_SEARCH_NOT_CANDIDATE;
393                 goto doreturn;
394         }
395
396         /*
397          * Maps filter
398          */
399         rc = ldap_back_filter_map_rewrite( dc, op->ors_filter,
400                         &mfilter, BACKLDAP_MAP );
401         switch ( rc ) {
402         case LDAP_SUCCESS:
403                 break;
404
405         case LDAP_COMPARE_FALSE:
406         default:
407                 /*
408                  * this target is no longer candidate
409                  */
410                 retcode = META_SEARCH_NOT_CANDIDATE;
411                 goto done;
412         }
413
414         /*
415          * Maps required attributes
416          */
417         rc = ldap_back_map_attrs( &mt->mt_rwmap.rwm_at,
418                         op->ors_attrs, BACKLDAP_MAP, &mapped_attrs );
419         if ( rc != LDAP_SUCCESS ) {
420                 /*
421                  * this target is no longer candidate
422                  */
423                 retcode = META_SEARCH_NOT_CANDIDATE;
424                 goto done;
425         }
426
427         /* should we check return values? */
428         if ( op->ors_deref != -1 ) {
429                 assert( msc->msc_ld != NULL );
430                 (void)ldap_set_option( msc->msc_ld, LDAP_OPT_DEREF,
431                                 ( void * )&op->ors_deref );
432         }
433
434         if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
435                 tv.tv_sec = op->ors_tlimit > 0 ? op->ors_tlimit : 1;
436                 tv.tv_usec = 0;
437                 tvp = &tv;
438         }
439
440         ctrls = op->o_ctrls;
441         if ( ldap_back_proxy_authz_ctrl( &msc->msc_bound_ndn,
442                 mt->mt_version, &mt->mt_idassert, op, rs, &ctrls )
443                 != LDAP_SUCCESS )
444         {
445                 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
446                 retcode = META_SEARCH_NOT_CANDIDATE;
447                 goto done;
448         }
449
450         /*
451          * Starts the search
452          */
453 retry:;
454         assert( msc->msc_ld != NULL );
455         rc = ldap_search_ext( msc->msc_ld,
456                         mbase.bv_val, realscope, mfilter.bv_val,
457                         mapped_attrs, op->ors_attrsonly,
458                         ctrls, NULL, tvp, op->ors_slimit,
459                         &candidates[ candidate ].sr_msgid ); 
460         switch ( rc ) {
461         case LDAP_SUCCESS:
462                 retcode = META_SEARCH_CANDIDATE;
463                 break;
464         
465         case LDAP_SERVER_DOWN:
466                 if ( nretries && meta_back_retry( op, rs, mcp, candidate, LDAP_BACK_DONTSEND ) ) {
467                         nretries = 0;
468                         goto retry;
469                 }
470
471                 if ( *mcp == NULL ) {
472                         retcode = META_SEARCH_ERR;
473                         break;
474                 }
475                 /* fall thru */
476
477         default:
478                 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
479                 retcode = META_SEARCH_NOT_CANDIDATE;
480         }
481
482 done:;
483         (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
484
485         if ( mapped_attrs ) {
486                 free( mapped_attrs );
487         }
488         if ( mfilter.bv_val != op->ors_filterstr.bv_val ) {
489                 free( mfilter.bv_val );
490         }
491         if ( mbase.bv_val != realbase.bv_val ) {
492                 free( mbase.bv_val );
493         }
494
495 doreturn:;
496         Debug( LDAP_DEBUG_TRACE, "%s <<< meta_back_search_start[%d]=%d\n", op->o_log_prefix, candidate, retcode );
497
498         return retcode;
499 }
500
501 int
502 meta_back_search( Operation *op, SlapReply *rs )
503 {
504         metainfo_t      *mi = ( metainfo_t * )op->o_bd->be_private;
505         metaconn_t      *mc;
506         struct timeval  tv = { 0, 0 };
507         time_t          stoptime = (time_t)-1;
508         LDAPMessage     *res = NULL, *e;
509         int             rc = 0, sres = LDAP_SUCCESS;
510         char            *matched = NULL;
511         int             last = 0, ncandidates = 0,
512                         initial_candidates = 0, candidate_match = 0;
513         long            i;
514         dncookie        dc;
515         int             is_ok = 0;
516         void            *savepriv;
517         SlapReply       *candidates = meta_back_candidates_get( op );
518
519         /*
520          * controls are set in ldap_back_dobind()
521          * 
522          * FIXME: in case of values return filter, we might want
523          * to map attrs and maybe rewrite value
524          */
525         mc = meta_back_getconn( op, rs, NULL, LDAP_BACK_SENDERR );
526         if ( !mc ) {
527                 return rs->sr_err;
528         }
529
530         dc.conn = op->o_conn;
531         dc.rs = rs;
532
533         /*
534          * Inits searches
535          */
536         for ( i = 0; i < mi->mi_ntargets; i++ ) {
537                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
538
539                 if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
540                         continue;
541                 }
542
543                 candidates[ i ].sr_matched = NULL;
544                 candidates[ i ].sr_text = NULL;
545                 candidates[ i ].sr_ref = NULL;
546                 candidates[ i ].sr_ctrls = NULL;
547         }
548
549         for ( i = 0; i < mi->mi_ntargets; i++ ) {
550                 if ( !META_IS_CANDIDATE( &candidates[ i ] )
551                         || candidates[ i ].sr_err != LDAP_SUCCESS )
552                 {
553                         continue;
554                 }
555
556                 switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
557                 {
558                 case META_SEARCH_NOT_CANDIDATE:
559                         break;
560
561                 case META_SEARCH_CANDIDATE:
562                 case META_SEARCH_BINDING:
563                 case META_SEARCH_NEED_BIND:
564                         candidates[ i ].sr_type = REP_INTERMEDIATE;
565                         ++ncandidates;
566                         break;
567
568                 case META_SEARCH_ERR:
569                         savepriv = op->o_private;
570                         op->o_private = (void *)i;
571                         send_ldap_result( op, rs );
572                         op->o_private = savepriv;
573                         rc = -1;
574                         goto finish;
575                 }
576         }
577
578         initial_candidates = ncandidates;
579
580         if ( LogTest( LDAP_DEBUG_TRACE ) ) {
581                 char    cnd[BUFSIZ];
582                 int     c;
583
584                 for ( c = 0; c < mi->mi_ntargets; c++ ) {
585                         if ( META_IS_CANDIDATE( &candidates[ c ] ) ) {
586                                 cnd[ c ] = '*';
587                         } else {
588                                 cnd[ c ] = ' ';
589                         }
590                 }
591                 cnd[ c ] = '\0';
592
593                 Debug( LDAP_DEBUG_TRACE, "%s meta_back_search: ncandidates=%d "
594                         "cnd=\"%s\"\n", op->o_log_prefix, ncandidates, cnd );
595         }
596
597         if ( initial_candidates == 0 ) {
598                 /* NOTE: here we are not sending any matchedDN;
599                  * this is intended, because if the back-meta
600                  * is serving this search request, but no valid
601                  * candidate could be looked up, it means that
602                  * there is a hole in the mapping of the targets
603                  * and thus no knowledge of any remote superior
604                  * is available */
605                 Debug( LDAP_DEBUG_ANY, "%s meta_back_search: "
606                         "base=\"%s\" scope=%d: "
607                         "no candidate could be selected\n",
608                         op->o_log_prefix, op->o_req_dn.bv_val,
609                         op->ors_scope );
610
611                 /* FIXME: we're sending the first error we encounter;
612                  * maybe we should pick the worst... */
613                 rc = LDAP_NO_SUCH_OBJECT;
614                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
615                         if ( META_IS_CANDIDATE( &candidates[ i ] )
616                                 && candidates[ i ].sr_err != LDAP_SUCCESS )
617                         {
618                                 rc = candidates[ i ].sr_err;
619                                 break;
620                         }
621                 }
622
623                 send_ldap_error( op, rs, rc, NULL );
624
625                 goto finish;
626         }
627
628         /* We pull apart the ber result, stuff it into a slapd entry, and
629          * let send_search_entry stuff it back into ber format. Slow & ugly,
630          * but this is necessary for version matching, and for ACL processing.
631          */
632
633         if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
634                 stoptime = op->o_time + op->ors_tlimit;
635         }
636
637         /*
638          * In case there are no candidates, no cycle takes place...
639          *
640          * FIXME: we might use a queue, to better balance the load 
641          * among the candidates
642          */
643         for ( rc = 0; ncandidates > 0; ) {
644                 int     gotit = 0, doabandon = 0;
645
646                 /* check time limit */
647                 if ( op->ors_tlimit != SLAP_NO_LIMIT
648                                 && slap_get_time() > stoptime )
649                 {
650                         doabandon = 1;
651                         rc = rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
652                         savepriv = op->o_private;
653                         op->o_private = (void *)i;
654                         send_ldap_result( op, rs );
655                         op->o_private = savepriv;
656                         goto finish;
657                 }
658
659                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
660                         metasingleconn_t        *msc = &mc->mc_conns[ i ];
661
662                         if ( candidates[ i ].sr_msgid == META_MSGID_IGNORE ) {
663                                 continue;
664                         }
665
666                         if ( candidates[ i ].sr_msgid == META_MSGID_NEED_BIND ) {
667                                 meta_search_candidate_t retcode;
668
669                                 /* initiate dobind */
670                                 retcode = meta_search_dobind_init( op, rs, &mc, i, candidates );
671
672                                 Debug( LDAP_DEBUG_TRACE, "%s <<< meta_search_dobind_init[%ld]=%d\n",
673                                         op->o_log_prefix, i, retcode );
674
675                                 switch ( retcode ) {
676                                 case META_SEARCH_BINDING:
677                                 case META_SEARCH_NEED_BIND:
678                                         break;
679
680                                 case META_SEARCH_NOT_CANDIDATE:
681                                         /*
682                                          * When no candidates are left,
683                                          * the outer cycle finishes
684                                          */
685                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
686                                         --ncandidates;
687                                         break;
688
689                                 case META_SEARCH_ERR:
690                                         if ( META_BACK_ONERR_STOP( mi ) ) {
691                                                 savepriv = op->o_private;
692                                                 op->o_private = (void *)i;
693                                                 send_ldap_result( op, rs );
694                                                 op->o_private = savepriv;
695                                                 goto finish;
696                                         }
697                                         break;
698
699                                 case META_SEARCH_CANDIDATE:
700                                         switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
701                                         {
702                                         case META_SEARCH_CANDIDATE:
703                                                 goto get_result;
704
705                                                 /* means that failed but onerr == continue */
706                                         case META_SEARCH_NOT_CANDIDATE:
707                                         case META_SEARCH_ERR:
708                                                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
709                                                 --ncandidates;
710
711                                                 if ( META_BACK_ONERR_STOP( mi ) ) {
712                                                         savepriv = op->o_private;
713                                                         op->o_private = (void *)i;
714                                                         send_ldap_result( op, rs );
715                                                         op->o_private = savepriv;
716                                                         goto finish;
717                                                 }
718                                                 break;
719
720                                         default:
721                                                 /* impossible */
722                                                 assert( 0 );
723                                                 break;
724                                         }
725                                         break;
726
727                                 default:
728                                         /* impossible */
729                                         assert( 0 );
730                                         break;
731                                 }
732                                 continue;
733                         }
734
735                         /* check for abandon */
736                         if ( op->o_abandon ) {
737                                 break;
738                         }
739                         
740                         /*
741                          * FIXME: handle time limit as well?
742                          * Note that target servers are likely 
743                          * to handle it, so at some time we'll
744                          * get a LDAP_TIMELIMIT_EXCEEDED from
745                          * one of them ...
746                          */
747 get_result:;
748                         rc = ldap_result( msc->msc_ld, candidates[ i ].sr_msgid,
749                                         LDAP_MSG_ONE, &tv, &res );
750
751                         switch ( rc ) {
752                         case 0:
753                                 /* FIXME: res should not need to be freed */
754                                 assert( res == NULL );
755
756                                 continue;
757
758                         case -1:
759 really_bad:;
760                                 /* something REALLY bad happened! */
761                                 if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
762                                         candidates[ i ].sr_type = REP_RESULT;
763
764                                         if ( meta_back_retry( op, rs, &mc, i, LDAP_BACK_DONTSEND ) ) {
765                                                 switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
766                                                 {
767                                                 case META_SEARCH_CANDIDATE:
768                                                         goto get_result;
769
770                                                         /* means that failed but onerr == continue */
771                                                 case META_SEARCH_NOT_CANDIDATE:
772                                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
773                                                         --ncandidates;
774
775                                                         if ( META_BACK_ONERR_STOP( mi ) ) {
776                                                                 savepriv = op->o_private;
777                                                                 op->o_private = (void *)i;
778                                                                 send_ldap_result( op, rs );
779                                                                 op->o_private = savepriv;
780                                                                 goto finish;
781                                                         }
782                                                         break;
783
784                                                 case META_SEARCH_BINDING:
785                                                 case META_SEARCH_NEED_BIND:
786                                                         assert( 0 );
787
788                                                 default:
789                                                         rc = rs->sr_err = LDAP_OTHER;
790                                                         goto finish;
791                                                 }
792                                         }
793
794                                         if ( META_BACK_ONERR_STOP( mi ) ) {
795                                                 savepriv = op->o_private;
796                                                 op->o_private = (void *)i;
797                                                 send_ldap_result( op, rs );
798                                                 op->o_private = savepriv;
799                                                 goto finish;
800                                         }
801                                 }
802
803                                 /*
804                                  * When no candidates are left,
805                                  * the outer cycle finishes
806                                  */
807                                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
808                                 --ncandidates;
809                                 rs->sr_err = candidates[ i ].sr_err;
810                                 continue;
811
812                         default:
813                                 /* only touch when activity actually took place... */
814                                 if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
815                                         msc->msc_time = op->o_time;
816                                 }
817                                 break;
818                         }
819
820                         if ( rc == LDAP_RES_SEARCH_ENTRY ) {
821                                 if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
822                                         /* don't retry any more... */
823                                         candidates[ i ].sr_type = REP_RESULT;
824                                 }
825
826                                 is_ok++;
827
828                                 e = ldap_first_entry( msc->msc_ld, res );
829                                 savepriv = op->o_private;
830                                 op->o_private = (void *)i;
831                                 rs->sr_err = meta_send_entry( op, rs, mc, i, e );
832                                 ldap_msgfree( res );
833                                 res = NULL;
834
835                                 switch ( rs->sr_err ) {
836                                 case LDAP_SIZELIMIT_EXCEEDED:
837                                         savepriv = op->o_private;
838                                         op->o_private = (void *)i;
839                                         send_ldap_result( op, rs );
840                                         op->o_private = savepriv;
841                                         rs->sr_err = LDAP_SUCCESS;
842                                         goto finish;
843
844                                 case LDAP_UNAVAILABLE:
845                                         rs->sr_err = LDAP_OTHER;
846                                         goto finish;
847                                 }
848                                 op->o_private = savepriv;
849
850                                 /* don't wait any longer... */
851                                 gotit = 1;
852                                 tv.tv_sec = 0;
853                                 tv.tv_usec = 0;
854
855 #if 0
856                                 /*
857                                  * If scope is BASE, we need to jump out
858                                  * as soon as one entry is found; if
859                                  * the target pool is properly crafted,
860                                  * this should correspond to the sole
861                                  * entry that has the base DN
862                                  */
863                                 /* FIXME: this defeats the purpose of
864                                  * doing a search with scope == base and
865                                  * sizelimit = 1 to determine if a
866                                  * candidate is actually unique */
867                                 if ( op->ors_scope == LDAP_SCOPE_BASE
868                                                 && rs->sr_nentries > 0 )
869                                 {
870                                         doabandon = 1;
871                                         ncandidates = 0;
872                                         sres = LDAP_SUCCESS;
873                                         break;
874                                 }
875 #endif
876
877                         } else if ( rc == LDAP_RES_SEARCH_REFERENCE ) {
878                                 char            **references = NULL;
879                                 int             cnt;
880
881                                 if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
882                                         /* don't retry any more... */
883                                         candidates[ i ].sr_type = REP_RESULT;
884                                 }
885
886                                 is_ok++;
887
888                                 rc = ldap_parse_reference( msc->msc_ld, res,
889                                                 &references, &rs->sr_ctrls, 1 );
890                                 res = NULL;
891
892                                 if ( rc != LDAP_SUCCESS ) {
893                                         continue;
894                                 }
895
896                                 if ( references == NULL ) {
897                                         continue;
898                                 }
899
900 #ifdef ENABLE_REWRITE
901                                 dc.ctx = "referralDN";
902 #else /* ! ENABLE_REWRITE */
903                                 dc.tofrom = 0;
904                                 dc.normalized = 0;
905 #endif /* ! ENABLE_REWRITE */
906
907                                 /* FIXME: merge all and return at the end */
908
909                                 for ( cnt = 0; references[ cnt ]; cnt++ )
910                                         ;
911
912                                 rs->sr_ref = ch_calloc( sizeof( struct berval ), cnt + 1 );
913
914                                 for ( cnt = 0; references[ cnt ]; cnt++ ) {
915                                         ber_str2bv( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ] );
916                                 }
917                                 BER_BVZERO( &rs->sr_ref[ cnt ] );
918
919                                 ( void )ldap_back_referral_result_rewrite( &dc, rs->sr_ref );
920
921                                 if ( rs->sr_ref != NULL && !BER_BVISNULL( &rs->sr_ref[ 0 ] ) ) {
922                                         /* ignore return value by now */
923                                         savepriv = op->o_private;
924                                         op->o_private = (void *)i;
925                                         ( void )send_search_reference( op, rs );
926                                         op->o_private = savepriv;
927
928                                         ber_bvarray_free( rs->sr_ref );
929                                         rs->sr_ref = NULL;
930                                 }
931
932                                 /* cleanup */
933                                 if ( references ) {
934                                         ber_memvfree( (void **)references );
935                                 }
936
937                                 if ( rs->sr_ctrls ) {
938                                         ldap_controls_free( rs->sr_ctrls );
939                                         rs->sr_ctrls = NULL;
940                                 }
941
942                         } else if ( rc == LDAP_RES_SEARCH_RESULT ) {
943                                 char            buf[ SLAP_TEXT_BUFLEN ];
944                                 char            **references = NULL;
945
946                                 if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
947                                         /* don't retry any more... */
948                                         candidates[ i ].sr_type = REP_RESULT;
949                                 }
950
951                                 /* NOTE: ignores response controls
952                                  * (and intermediate response controls
953                                  * as well, except for those with search
954                                  * references); this may not be correct,
955                                  * but if they're not ignored then
956                                  * back-meta would need to merge them
957                                  * consistently (think of pagedResults...)
958                                  */
959                                 /* FIXME: response controls? */
960                                 rs->sr_err = ldap_parse_result( msc->msc_ld,
961                                                         res,
962                                                         &candidates[ i ].sr_err,
963                                                         (char **)&candidates[ i ].sr_matched,
964                                                         NULL /* (char **)&candidates[ i ].sr_text */ ,
965                                                         &references,
966                                                         NULL /* &candidates[ i ].sr_ctrls (unused) */ ,
967                                                         1 );
968                                 res = NULL;
969                                 if ( rs->sr_err != LDAP_SUCCESS ) {
970                                         ldap_get_option( msc->msc_ld,
971                                                         LDAP_OPT_ERROR_NUMBER,
972                                                         &rs->sr_err );
973                                         sres = slap_map_api2result( rs );
974                                         candidates[ i ].sr_type = REP_RESULT;
975                                         goto really_bad;
976                                 }
977
978                                 /* massage matchedDN if need be */
979                                 if ( candidates[ i ].sr_matched != NULL ) {
980                                         struct berval   match, mmatch;
981
982                                         ber_str2bv( candidates[ i ].sr_matched,
983                                                 0, 0, &match );
984                                         candidates[ i ].sr_matched = NULL;
985
986                                         dc.ctx = "matchedDN";
987                                         dc.target = mi->mi_targets[ i ];
988                                         if ( !ldap_back_dn_massage( &dc, &match, &mmatch ) ) {
989                                                 if ( mmatch.bv_val == match.bv_val ) {
990                                                         candidates[ i ].sr_matched = ch_strdup( mmatch.bv_val );
991
992                                                 } else {
993                                                         candidates[ i ].sr_matched = mmatch.bv_val;
994                                                 }
995
996                                                 candidate_match++;
997                                         } 
998                                         ldap_memfree( match.bv_val );
999                                 }
1000
1001                                 /* add references to array */
1002                                 if ( references ) {
1003                                         BerVarray       sr_ref;
1004                                         int             cnt;
1005
1006                                         for ( cnt = 0; references[ cnt ]; cnt++ )
1007                                                 ;
1008
1009                                         sr_ref = ch_calloc( sizeof( struct berval ), cnt + 1 );
1010
1011                                         for ( cnt = 0; references[ cnt ]; cnt++ ) {
1012                                                 ber_str2bv( references[ cnt ], 0, 1, &sr_ref[ cnt ] );
1013                                         }
1014                                         BER_BVZERO( &sr_ref[ cnt ] );
1015
1016                                         ( void )ldap_back_referral_result_rewrite( &dc, sr_ref );
1017                                 
1018                                         /* cleanup */
1019                                         ber_memvfree( (void **)references );
1020
1021                                         if ( rs->sr_v2ref == NULL ) {
1022                                                 rs->sr_v2ref = sr_ref;
1023
1024                                         } else {
1025                                                 for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) {
1026                                                         ber_bvarray_add( &rs->sr_v2ref, &sr_ref[ cnt ] );
1027                                                 }
1028                                                 ber_memfree( sr_ref );
1029                                         }
1030                                 }
1031
1032                                 rs->sr_err = candidates[ i ].sr_err;
1033                                 sres = slap_map_api2result( rs );
1034
1035                                 if ( LogTest( LDAP_DEBUG_TRACE | LDAP_DEBUG_ANY ) ) {
1036                                         snprintf( buf, sizeof( buf ),
1037                                                 "%s meta_back_search[%ld] "
1038                                                 "match=\"%s\" err=%ld",
1039                                                 op->o_log_prefix, i,
1040                                                 candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
1041                                                 (long) candidates[ i ].sr_err );
1042                                         if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
1043                                                 Debug( LDAP_DEBUG_TRACE, "%s.\n", buf, 0, 0 );
1044
1045                                         } else {
1046                                                 Debug( LDAP_DEBUG_ANY, "%s (%s).\n",
1047                                                         buf, ldap_err2string( candidates[ i ].sr_err ), 0 );
1048                                         }
1049                                 }
1050
1051                                 switch ( sres ) {
1052                                 case LDAP_NO_SUCH_OBJECT:
1053                                         /* is_ok is touched any time a valid
1054                                          * (even intermediate) result is
1055                                          * returned; as a consequence, if
1056                                          * a candidate returns noSuchObject
1057                                          * it is ignored and the candidate
1058                                          * is simply demoted. */
1059                                         if ( is_ok ) {
1060                                                 sres = LDAP_SUCCESS;
1061                                         }
1062                                         break;
1063
1064                                 case LDAP_SUCCESS:
1065                                 case LDAP_REFERRAL:
1066                                         is_ok++;
1067                                         break;
1068
1069                                 case LDAP_SIZELIMIT_EXCEEDED:
1070                                         /* if a target returned sizelimitExceeded
1071                                          * and the entry count is equal to the
1072                                          * proxy's limit, the target would have
1073                                          * returned more, and the error must be
1074                                          * propagated to the client; otherwise,
1075                                          * the target enforced a limit lower
1076                                          * than what requested by the proxy;
1077                                          * ignore it */
1078                                         if ( rs->sr_nentries == op->ors_slimit
1079                                                 || META_BACK_ONERR_STOP( mi ) )
1080                                         {
1081                                                 savepriv = op->o_private;
1082                                                 op->o_private = (void *)i;
1083                                                 send_ldap_result( op, rs );
1084                                                 op->o_private = savepriv;
1085                                                 goto finish;
1086                                         }
1087                                         break;
1088
1089                                 default:
1090                                         if ( META_BACK_ONERR_STOP( mi ) ) {
1091                                                 savepriv = op->o_private;
1092                                                 op->o_private = (void *)i;
1093                                                 send_ldap_result( op, rs );
1094                                                 op->o_private = savepriv;
1095                                                 goto finish;
1096                                         }
1097                                         break;
1098                                 }
1099
1100                                 last = i;
1101                                 rc = 0;
1102
1103                                 /*
1104                                  * When no candidates are left,
1105                                  * the outer cycle finishes
1106                                  */
1107                                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1108                                 --ncandidates;
1109
1110                         } else if ( rc == LDAP_RES_BIND ) {
1111                                 meta_search_candidate_t retcode;
1112
1113                                 retcode = meta_search_dobind_result( op, rs, &mc, i, candidates, res );
1114                                 if ( retcode == META_SEARCH_CANDIDATE ) {
1115                                         retcode = meta_back_search_start( op, rs, &dc, &mc, i, candidates );
1116                                 }
1117
1118                                 switch ( retcode ) {
1119                                 case META_SEARCH_CANDIDATE:
1120                                         goto get_result;
1121
1122                                         /* means that failed but onerr == continue */
1123                                 case META_SEARCH_NOT_CANDIDATE:
1124                                 case META_SEARCH_ERR:
1125                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1126                                         --ncandidates;
1127
1128                                         if ( META_BACK_ONERR_STOP( mi ) ) {
1129                                                 savepriv = op->o_private;
1130                                                 op->o_private = (void *)i;
1131                                                 send_ldap_result( op, rs );
1132                                                 op->o_private = savepriv;
1133                                                 goto finish;
1134                                         }
1135                                         break;
1136
1137                                 default:
1138                                         assert( 0 );
1139                                         break;
1140                                 }
1141
1142                         } else {
1143                                 assert( 0 );
1144                                 goto really_bad;
1145                         }
1146                 }
1147
1148                 /* check for abandon */
1149                 if ( op->o_abandon || doabandon ) {
1150                         for ( i = 0; i < mi->mi_ntargets; i++ ) {
1151                                 if ( candidates[ i ].sr_msgid >= 0 ) {
1152                                         if ( META_IS_BINDING( &candidates[ i ] ) ) {
1153                                                 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
1154                                                 if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ) {
1155                                                         /* if still binding, destroy */
1156                                                         ldap_unbind_ext( mc->mc_conns[ i ].msc_ld, NULL, NULL );
1157                                                         mc->mc_conns[ i ].msc_ld = NULL;
1158                                                         LDAP_BACK_CONN_BINDING_CLEAR( &mc->mc_conns[ i ] );
1159                                                 }
1160                                                 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1161                                                 META_BINDING_CLEAR( &candidates[ i ] );
1162                                                 
1163                                         } else {
1164                                                 (void)meta_back_cancel( mc, op, rs,
1165                                                         candidates[ i ].sr_msgid, i,
1166                                                         LDAP_BACK_DONTSEND );
1167                                         }
1168
1169                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1170                                 }
1171                         }
1172
1173                         if ( op->o_abandon ) {
1174                                 rc = SLAPD_ABANDON;
1175                                 /* let send_ldap_result play cleanup handlers (ITS#4645) */
1176                                 break;
1177                         }
1178                 }
1179
1180                 /* if no entry was found during this loop,
1181                  * set a minimal timeout */
1182                 if ( gotit == 0 ) {
1183                         /* make the entire wait last
1184                          * LDAP_BACK_RESULT_UTIMEOUT at worst */
1185                         tv.tv_sec = 0;
1186                         tv.tv_usec = LDAP_BACK_RESULT_UTIMEOUT/initial_candidates;
1187                         ldap_pvt_thread_yield();
1188                 }
1189         }
1190
1191         if ( rc == -1 ) {
1192                 /*
1193                  * FIXME: need a better strategy to handle errors
1194                  */
1195                 if ( mc ) {
1196                         rc = meta_back_op_result( mc, op, rs, META_TARGET_NONE,
1197                                 -1, stoptime != -1 ? (stoptime - slap_get_time()) : 0,
1198                                 LDAP_BACK_SENDERR );
1199                 } else {
1200                         rc = rs->sr_err;
1201                 }
1202                 goto finish;
1203         }
1204
1205         /*
1206          * Rewrite the matched portion of the search base, if required
1207          * 
1208          * FIXME: only the last one gets caught!
1209          */
1210         savepriv = op->o_private;
1211         op->o_private = (void *)(long)mi->mi_ntargets;
1212         if ( candidate_match > 0 ) {
1213                 struct berval   pmatched = BER_BVNULL;
1214
1215                 /* we use the first one */
1216                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
1217                         if ( META_IS_CANDIDATE( &candidates[ i ] )
1218                                         && candidates[ i ].sr_matched != NULL )
1219                         {
1220                                 struct berval   bv, pbv;
1221                                 int             rc;
1222
1223                                 /* if we got success, and this target
1224                                  * returned noSuchObject, and its suffix
1225                                  * is a superior of the searchBase,
1226                                  * ignore the matchedDN */
1227                                 if ( sres == LDAP_SUCCESS
1228                                         && candidates[ i ].sr_err == LDAP_NO_SUCH_OBJECT
1229                                         && op->o_req_ndn.bv_len > mi->mi_targets[ i ]->mt_nsuffix.bv_len )
1230                                 {
1231                                         free( (char *)candidates[ i ].sr_matched );
1232                                         candidates[ i ].sr_matched = NULL;
1233                                         continue;
1234                                 }
1235
1236                                 ber_str2bv( candidates[ i ].sr_matched, 0, 0, &bv );
1237                                 rc = dnPretty( NULL, &bv, &pbv, op->o_tmpmemctx );
1238
1239                                 if ( rc == LDAP_SUCCESS ) {
1240
1241                                         /* NOTE: if they all are superiors
1242                                          * of the baseDN, the shorter is also 
1243                                          * superior of the longer... */
1244                                         if ( pbv.bv_len > pmatched.bv_len ) {
1245                                                 if ( !BER_BVISNULL( &pmatched ) ) {
1246                                                         op->o_tmpfree( pmatched.bv_val, op->o_tmpmemctx );
1247                                                 }
1248                                                 pmatched = pbv;
1249                                                 op->o_private = (void *)i;
1250
1251                                         } else {
1252                                                 op->o_tmpfree( pbv.bv_val, op->o_tmpmemctx );
1253                                         }
1254                                 }
1255
1256                                 if ( candidates[ i ].sr_matched != NULL ) {
1257                                         free( (char *)candidates[ i ].sr_matched );
1258                                         candidates[ i ].sr_matched = NULL;
1259                                 }
1260                         }
1261                 }
1262
1263                 if ( !BER_BVISNULL( &pmatched ) ) {
1264                         matched = pmatched.bv_val;
1265                 }
1266
1267         } else if ( sres == LDAP_NO_SUCH_OBJECT ) {
1268                 matched = op->o_bd->be_suffix[ 0 ].bv_val;
1269         }
1270
1271 #if 0
1272         {
1273                 char    buf[BUFSIZ];
1274                 char    cnd[BUFSIZ];
1275                 int     i;
1276
1277                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
1278                         if ( META_IS_CANDIDATE( &candidates[ i ] ) ) {
1279                                 cnd[ i ] = '*';
1280                         } else {
1281                                 cnd[ i ] = ' ';
1282                         }
1283                 }
1284                 cnd[ i ] = '\0';
1285
1286                 snprintf( buf, sizeof( buf ), "%s meta_back_search: is_scope=%d is_ok=%d cnd=\"%s\"\n",
1287                         op->o_log_prefix, initial_candidates, is_ok, cnd );
1288
1289                 Debug( LDAP_DEBUG_ANY, "%s", buf, 0, 0 );
1290         }
1291 #endif
1292
1293         /*
1294          * In case we returned at least one entry, we return LDAP_SUCCESS
1295          * otherwise, the latter error code we got
1296          *
1297          * FIXME: we should handle error codes and return the more 
1298          * important/reasonable
1299          */
1300
1301         if ( sres == LDAP_SUCCESS && rs->sr_v2ref ) {
1302                 sres = LDAP_REFERRAL;
1303         }
1304         rs->sr_err = sres;
1305         rs->sr_matched = matched;
1306         rs->sr_ref = ( sres == LDAP_REFERRAL ? rs->sr_v2ref : NULL );
1307         send_ldap_result( op, rs );
1308         op->o_private = savepriv;
1309         rs->sr_matched = NULL;
1310         rs->sr_ref = NULL;
1311
1312 finish:;
1313         if ( matched && matched != op->o_bd->be_suffix[ 0 ].bv_val ) {
1314                 op->o_tmpfree( matched, op->o_tmpmemctx );
1315         }
1316
1317         if ( rs->sr_v2ref ) {
1318                 ber_bvarray_free( rs->sr_v2ref );
1319         }
1320
1321         for ( i = 0; i < mi->mi_ntargets; i++ ) {
1322                 if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
1323                         continue;
1324                 }
1325
1326                 if ( mc && META_IS_BINDING( &candidates[ i ] ) ) {
1327                         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
1328                         if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ) {
1329                                 LDAP_BACK_CONN_BINDING_CLEAR( &mc->mc_conns[ i ] );
1330
1331                                 assert( candidates[ i ].sr_msgid >= 0 );
1332                                 assert( mc->mc_conns[ i ].msc_ld != NULL );
1333
1334                                 /* if still binding, destroy */
1335                                 ldap_unbind_ext( mc->mc_conns[ i ].msc_ld, NULL, NULL );
1336                                 mc->mc_conns[ i ].msc_ld = NULL;
1337                         }
1338                         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1339                         META_BINDING_CLEAR( &candidates[ i ] );
1340                 }
1341
1342                 if ( candidates[ i ].sr_matched ) {
1343                         free( (char *)candidates[ i ].sr_matched );
1344                         candidates[ i ].sr_matched = NULL;
1345                 }
1346
1347                 if ( candidates[ i ].sr_text ) {
1348                         ldap_memfree( (char *)candidates[ i ].sr_text );
1349                         candidates[ i ].sr_text = NULL;
1350                 }
1351
1352                 if ( candidates[ i ].sr_ref ) {
1353                         ber_bvarray_free( candidates[ i ].sr_ref );
1354                         candidates[ i ].sr_ref = NULL;
1355                 }
1356
1357                 if ( candidates[ i ].sr_ctrls ) {
1358                         ldap_controls_free( candidates[ i ].sr_ctrls );
1359                         candidates[ i ].sr_ctrls = NULL;
1360                 }
1361
1362                 if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) {
1363                         meta_back_quarantine( op, &candidates[ i ], i );
1364                 }
1365
1366                 /* only in case of timelimit exceeded, if the timelimit exceeded because
1367                  * one contacted target never responded, invalidate the connection
1368                  * NOTE: should we quarantine the target as well?  right now, the connection
1369                  * is invalidated; the next time it will be recreated and the target
1370                  * will be quarantined if it cannot be contacted */
1371                 if ( mi->mi_idle_timeout != 0
1372                         && rs->sr_err == LDAP_TIMELIMIT_EXCEEDED
1373                         && op->o_time > mc->mc_conns[ i ].msc_time )
1374                 {
1375                         /* don't let anyone else use this expired connection */
1376                         LDAP_BACK_CONN_TAINTED_SET( mc );
1377                 }
1378         }
1379
1380         if ( mc ) {
1381                 meta_back_release_conn( op, mc );
1382         }
1383
1384         return rs->sr_err;
1385 }
1386
1387 static int
1388 meta_send_entry(
1389         Operation       *op,
1390         SlapReply       *rs,
1391         metaconn_t      *mc,
1392         int             target,
1393         LDAPMessage     *e )
1394 {
1395         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
1396         struct berval           a, mapped;
1397         Entry                   ent = { 0 };
1398         BerElement              ber = *e->lm_ber;
1399         Attribute               *attr, **attrp;
1400         struct berval           bdn,
1401                                 dn = BER_BVNULL;
1402         const char              *text;
1403         dncookie                dc;
1404         int                     rc;
1405
1406         if ( ber_scanf( &ber, "{m{", &bdn ) == LBER_ERROR ) {
1407                 return LDAP_DECODING_ERROR;
1408         }
1409
1410         /*
1411          * Rewrite the dn of the result, if needed
1412          */
1413         dc.target = mi->mi_targets[ target ];
1414         dc.conn = op->o_conn;
1415         dc.rs = rs;
1416         dc.ctx = "searchResult";
1417
1418         rs->sr_err = ldap_back_dn_massage( &dc, &bdn, &dn );
1419         if ( rs->sr_err != LDAP_SUCCESS) {
1420                 return rs->sr_err;
1421         }
1422
1423         /*
1424          * Note: this may fail if the target host(s) schema differs
1425          * from the one known to the meta, and a DN with unknown
1426          * attributes is returned.
1427          * 
1428          * FIXME: should we log anything, or delegate to dnNormalize?
1429          */
1430         rc = dnPrettyNormal( NULL, &dn, &ent.e_name, &ent.e_nname,
1431                 op->o_tmpmemctx );
1432         if ( dn.bv_val != bdn.bv_val ) {
1433                 free( dn.bv_val );
1434         }
1435         BER_BVZERO( &dn );
1436
1437         if ( rc != LDAP_SUCCESS ) {
1438                 return LDAP_INVALID_DN_SYNTAX;
1439         }
1440
1441         /*
1442          * cache dn
1443          */
1444         if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) {
1445                 ( void )meta_dncache_update_entry( &mi->mi_cache,
1446                                 &ent.e_nname, target );
1447         }
1448
1449         attrp = &ent.e_attrs;
1450
1451         dc.ctx = "searchAttrDN";
1452         while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
1453                 int                             last = 0;
1454                 slap_syntax_validate_func       *validate;
1455                 slap_syntax_transform_func      *pretty;
1456
1457                 ldap_back_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_at, 
1458                                 &a, &mapped, BACKLDAP_REMAP );
1459                 if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) {
1460                         ( void )ber_scanf( &ber, "x" /* [W] */ );
1461                         continue;
1462                 }
1463                 attr = attr_alloc( NULL );
1464                 if ( attr == NULL ) {
1465                         continue;
1466                 }
1467                 if ( slap_bv2ad( &mapped, &attr->a_desc, &text )
1468                                 != LDAP_SUCCESS) {
1469                         if ( slap_bv2undef_ad( &mapped, &attr->a_desc, &text,
1470                                 SLAP_AD_PROXIED ) != LDAP_SUCCESS )
1471                         {
1472                                 char    buf[ SLAP_TEXT_BUFLEN ];
1473
1474                                 snprintf( buf, sizeof( buf ),
1475                                         "%s meta_send_entry(\"%s\"): "
1476                                         "slap_bv2undef_ad(%s): %s\n",
1477                                         op->o_log_prefix, ent.e_name.bv_val,
1478                                         mapped.bv_val, text );
1479
1480                                 Debug( LDAP_DEBUG_ANY, "%s", buf, 0, 0 );
1481                                 attr_free( attr );
1482                                 continue;
1483                         }
1484                 }
1485
1486                 /* no subschemaSubentry */
1487                 if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry
1488                         || attr->a_desc == slap_schema.si_ad_entryDN )
1489                 {
1490
1491                         /* 
1492                          * We eat target's subschemaSubentry because
1493                          * a search for this value is likely not
1494                          * to resolve to the appropriate backend;
1495                          * later, the local subschemaSubentry is
1496                          * added.
1497                          *
1498                          * We also eat entryDN because the frontend
1499                          * will reattach it without checking if already
1500                          * present...
1501                          */
1502                         ( void )ber_scanf( &ber, "x" /* [W] */ );
1503
1504                         attr_free(attr);
1505                         continue;
1506                 }
1507
1508                 if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR 
1509                                 || attr->a_vals == NULL )
1510                 {
1511                         attr->a_vals = (struct berval *)&slap_dummy_bv;
1512
1513                 } else {
1514                         for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); ++last )
1515                                 ;
1516                 }
1517
1518                 validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate;
1519                 pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty;
1520
1521                 if ( !validate && !pretty ) {
1522                         attr_free( attr );
1523                         goto next_attr;
1524                 }
1525
1526                 if ( attr->a_desc == slap_schema.si_ad_objectClass
1527                                 || attr->a_desc == slap_schema.si_ad_structuralObjectClass )
1528                 {
1529                         struct berval   *bv;
1530
1531                         for ( bv = attr->a_vals; !BER_BVISNULL( bv ); bv++ ) {
1532                                 ldap_back_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_oc,
1533                                                 bv, &mapped, BACKLDAP_REMAP );
1534                                 if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0') {
1535                                         free( bv->bv_val );
1536                                         BER_BVZERO( bv );
1537                                         if ( --last < 0 ) {
1538                                                 break;
1539                                         }
1540                                         *bv = attr->a_vals[ last ];
1541                                         BER_BVZERO( &attr->a_vals[ last ] );
1542                                         bv--;
1543
1544                                 } else if ( mapped.bv_val != bv->bv_val ) {
1545                                         free( bv->bv_val );
1546                                         ber_dupbv( bv, &mapped );
1547                                 }
1548                         }
1549                 /*
1550                  * It is necessary to try to rewrite attributes with
1551                  * dn syntax because they might be used in ACLs as
1552                  * members of groups; since ACLs are applied to the
1553                  * rewritten stuff, no dn-based subecj clause could
1554                  * be used at the ldap backend side (see
1555                  * http://www.OpenLDAP.org/faq/data/cache/452.html)
1556                  * The problem can be overcome by moving the dn-based
1557                  * ACLs to the target directory server, and letting
1558                  * everything pass thru the ldap backend.
1559                  */
1560                 } else {
1561                         int     i;
1562
1563                         if ( attr->a_desc->ad_type->sat_syntax ==
1564                                 slap_schema.si_syn_distinguishedName )
1565                         {
1566                                 ldap_dnattr_result_rewrite( &dc, attr->a_vals );
1567
1568                         } else if ( attr->a_desc == slap_schema.si_ad_ref ) {
1569                                 ldap_back_referral_result_rewrite( &dc, attr->a_vals );
1570
1571                         }
1572
1573                         for ( i = 0; i < last; i++ ) {
1574                                 struct berval   pval;
1575                                 int             rc;
1576
1577                                 if ( pretty ) {
1578                                         rc = pretty( attr->a_desc->ad_type->sat_syntax,
1579                                                 &attr->a_vals[i], &pval, NULL );
1580
1581                                 } else {
1582                                         rc = validate( attr->a_desc->ad_type->sat_syntax,
1583                                                 &attr->a_vals[i] );
1584                                 }
1585
1586                                 if ( rc ) {
1587                                         LBER_FREE( attr->a_vals[i].bv_val );
1588                                         if ( --last == i ) {
1589                                                 BER_BVZERO( &attr->a_vals[ i ] );
1590                                                 break;
1591                                         }
1592                                         attr->a_vals[i] = attr->a_vals[last];
1593                                         BER_BVZERO( &attr->a_vals[last] );
1594                                         i--;
1595                                         continue;
1596                                 }
1597
1598                                 if ( pretty ) {
1599                                         LBER_FREE( attr->a_vals[i].bv_val );
1600                                         attr->a_vals[i] = pval;
1601                                 }
1602                         }
1603
1604                         if ( last == 0 && attr->a_vals != &slap_dummy_bv ) {
1605                                 attr_free( attr );
1606                                 goto next_attr;
1607                         }
1608                 }
1609
1610                 if ( last && attr->a_desc->ad_type->sat_equality &&
1611                         attr->a_desc->ad_type->sat_equality->smr_normalize )
1612                 {
1613                         int i;
1614
1615                         attr->a_nvals = ch_malloc( ( last + 1 ) * sizeof( struct berval ) );
1616                         for ( i = 0; i<last; i++ ) {
1617                                 attr->a_desc->ad_type->sat_equality->smr_normalize(
1618                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
1619                                         attr->a_desc->ad_type->sat_syntax,
1620                                         attr->a_desc->ad_type->sat_equality,
1621                                         &attr->a_vals[i], &attr->a_nvals[i],
1622                                         NULL );
1623                         }
1624                         BER_BVZERO( &attr->a_nvals[i] );
1625
1626                 } else {
1627                         attr->a_nvals = attr->a_vals;
1628                 }
1629
1630                 *attrp = attr;
1631                 attrp = &attr->a_next;
1632 next_attr:;
1633         }
1634         rs->sr_entry = &ent;
1635         rs->sr_attrs = op->ors_attrs;
1636         rs->sr_flags = 0;
1637         rs->sr_err = LDAP_SUCCESS;
1638         rc = send_search_entry( op, rs );
1639         switch ( rc ) {
1640         case LDAP_UNAVAILABLE:
1641                 rc = LDAP_OTHER;
1642                 break;
1643         }
1644         rs->sr_entry = NULL;
1645         rs->sr_attrs = NULL;
1646         
1647         if ( !BER_BVISNULL( &ent.e_name ) ) {
1648                 free( ent.e_name.bv_val );
1649                 BER_BVZERO( &ent.e_name );
1650         }
1651         if ( !BER_BVISNULL( &ent.e_nname ) ) {
1652                 free( ent.e_nname.bv_val );
1653                 BER_BVZERO( &ent.e_nname );
1654         }
1655         entry_clean( &ent );
1656
1657         return rc;
1658 }
1659