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