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