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