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