]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/search.c
more about previous commit
[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                                         break;
672
673                                 default:
674                                         /* impossible */
675                                         assert( 0 );
676                                         break;
677                                 }
678                                 continue;
679                         }
680
681                         /* check for abandon */
682                         if ( op->o_abandon ) {
683                                 break;
684                         }
685                         
686                         /*
687                          * FIXME: handle time limit as well?
688                          * Note that target servers are likely 
689                          * to handle it, so at some time we'll
690                          * get a LDAP_TIMELIMIT_EXCEEDED from
691                          * one of them ...
692                          */
693 get_result:;
694                         rc = ldap_result( msc->msc_ld, candidates[ i ].sr_msgid,
695                                         LDAP_MSG_ONE, &tv, &res );
696
697                         if ( rc == 0 ) {
698                                 /* FIXME: res should not need to be freed */
699                                 assert( res == NULL );
700
701                                 continue;
702
703                         } else if ( rc == -1 ) {
704 really_bad:;
705                                 /* something REALLY bad happened! */
706                                 if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
707                                         candidates[ i ].sr_type = REP_RESULT;
708
709                                         if ( meta_back_retry( op, rs, &mc, i, LDAP_BACK_DONTSEND ) ) {
710                                                 switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
711                                                 {
712                                                 case META_SEARCH_CANDIDATE:
713                                                         goto get_result;
714
715                                                         /* means that failed but onerr == continue */
716                                                 case META_SEARCH_NOT_CANDIDATE:
717                                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
718                                                         --ncandidates;
719
720                                                         if ( META_BACK_ONERR_STOP( mi ) ) {
721                                                                 savepriv = op->o_private;
722                                                                 op->o_private = (void *)i;
723                                                                 send_ldap_result( op, rs );
724                                                                 op->o_private = savepriv;
725                                                                 goto finish;
726                                                         }
727                                                         break;
728
729                                                 case META_SEARCH_BINDING:
730                                                 case META_SEARCH_NEED_BIND:
731                                                         assert( 0 );
732
733                                                 default:
734                                                         rc = rs->sr_err = LDAP_OTHER;
735                                                         goto finish;
736                                                 }
737                                         }
738
739                                         if ( META_BACK_ONERR_STOP( mi ) ) {
740                                                 savepriv = op->o_private;
741                                                 op->o_private = (void *)i;
742                                                 send_ldap_result( op, rs );
743                                                 op->o_private = savepriv;
744                                                 goto finish;
745                                         }
746                                 }
747
748                                 /*
749                                  * When no candidates are left,
750                                  * the outer cycle finishes
751                                  */
752                                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
753                                 --ncandidates;
754                                 rs->sr_err = candidates[ i ].sr_err;
755
756                         } else if ( rc == LDAP_RES_SEARCH_ENTRY ) {
757                                 if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
758                                         /* don't retry any more... */
759                                         candidates[ i ].sr_type = REP_RESULT;
760                                 }
761
762                                 is_ok++;
763
764                                 e = ldap_first_entry( msc->msc_ld, res );
765                                 savepriv = op->o_private;
766                                 op->o_private = (void *)i;
767                                 rs->sr_err = meta_send_entry( op, rs, mc, i, e );
768                                 ldap_msgfree( res );
769                                 res = NULL;
770
771                                 switch ( rs->sr_err ) {
772                                 case LDAP_SIZELIMIT_EXCEEDED:
773                                         savepriv = op->o_private;
774                                         op->o_private = (void *)i;
775                                         send_ldap_result( op, rs );
776                                         op->o_private = savepriv;
777                                         rs->sr_err = LDAP_SUCCESS;
778                                         goto finish;
779
780                                 case LDAP_UNAVAILABLE:
781                                         rs->sr_err = LDAP_OTHER;
782                                         goto finish;
783                                 }
784                                 op->o_private = savepriv;
785
786                                 /* don't wait any longer... */
787                                 gotit = 1;
788                                 tv.tv_sec = 0;
789                                 tv.tv_usec = 0;
790
791 #if 0
792                                 /*
793                                  * If scope is BASE, we need to jump out
794                                  * as soon as one entry is found; if
795                                  * the target pool is properly crafted,
796                                  * this should correspond to the sole
797                                  * entry that has the base DN
798                                  */
799                                 /* FIXME: this defeats the purpose of
800                                  * doing a search with scope == base and
801                                  * sizelimit = 1 to determine if a
802                                  * candidate is actually unique */
803                                 if ( op->ors_scope == LDAP_SCOPE_BASE
804                                                 && rs->sr_nentries > 0 )
805                                 {
806                                         doabandon = 1;
807                                         ncandidates = 0;
808                                         sres = LDAP_SUCCESS;
809                                         break;
810                                 }
811 #endif
812
813                         } else if ( rc == LDAP_RES_SEARCH_REFERENCE ) {
814                                 char            **references = NULL;
815                                 int             cnt;
816
817                                 if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
818                                         /* don't retry any more... */
819                                         candidates[ i ].sr_type = REP_RESULT;
820                                 }
821
822                                 is_ok++;
823
824                                 rc = ldap_parse_reference( msc->msc_ld, res,
825                                                 &references, &rs->sr_ctrls, 1 );
826                                 res = NULL;
827
828                                 if ( rc != LDAP_SUCCESS ) {
829                                         continue;
830                                 }
831
832                                 if ( references == NULL ) {
833                                         continue;
834                                 }
835
836 #ifdef ENABLE_REWRITE
837                                 dc.ctx = "referralDN";
838 #else /* ! ENABLE_REWRITE */
839                                 dc.tofrom = 0;
840                                 dc.normalized = 0;
841 #endif /* ! ENABLE_REWRITE */
842
843                                 /* FIXME: merge all and return at the end */
844
845                                 for ( cnt = 0; references[ cnt ]; cnt++ )
846                                         ;
847
848                                 rs->sr_ref = ch_calloc( sizeof( struct berval ), cnt + 1 );
849
850                                 for ( cnt = 0; references[ cnt ]; cnt++ ) {
851                                         ber_str2bv( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ] );
852                                 }
853                                 BER_BVZERO( &rs->sr_ref[ cnt ] );
854
855                                 ( void )ldap_back_referral_result_rewrite( &dc, rs->sr_ref );
856
857                                 if ( rs->sr_ref != NULL && !BER_BVISNULL( &rs->sr_ref[ 0 ] ) ) {
858                                         /* ignore return value by now */
859                                         savepriv = op->o_private;
860                                         op->o_private = (void *)i;
861                                         ( void )send_search_reference( op, rs );
862                                         op->o_private = savepriv;
863
864                                         ber_bvarray_free( rs->sr_ref );
865                                         rs->sr_ref = NULL;
866                                 }
867
868                                 /* cleanup */
869                                 if ( references ) {
870                                         ber_memvfree( (void **)references );
871                                 }
872
873                                 if ( rs->sr_ctrls ) {
874                                         ldap_controls_free( rs->sr_ctrls );
875                                         rs->sr_ctrls = NULL;
876                                 }
877
878                         } else if ( rc == LDAP_RES_SEARCH_RESULT ) {
879                                 char            buf[ SLAP_TEXT_BUFLEN ];
880                                 char            **references = NULL;
881
882                                 if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
883                                         /* don't retry any more... */
884                                         candidates[ i ].sr_type = REP_RESULT;
885                                 }
886
887                                 /* NOTE: ignores response controls
888                                  * (and intermediate response controls
889                                  * as well, except for those with search
890                                  * references); this may not be correct,
891                                  * but if they're not ignored then
892                                  * back-meta would need to merge them
893                                  * consistently (think of pagedResults...)
894                                  */
895                                 rs->sr_err = ldap_parse_result( msc->msc_ld,
896                                                         res,
897                                                         &candidates[ i ].sr_err,
898                                                         (char **)&candidates[ i ].sr_matched,
899                                                         NULL /* (char **)&candidates[ i ].sr_text */ ,
900                                                         &references,
901                                                         NULL /* &candidates[ i ].sr_ctrls (unused) */ ,
902                                                         1 );
903                                 res = NULL;
904                                 if ( rs->sr_err != LDAP_SUCCESS ) {
905                                         ldap_get_option( msc->msc_ld,
906                                                         LDAP_OPT_ERROR_NUMBER,
907                                                         &rs->sr_err );
908                                         sres = slap_map_api2result( rs );
909                                         candidates[ i ].sr_type = REP_RESULT;
910                                         goto really_bad;
911                                 }
912
913                                 /* massage matchedDN if need be */
914                                 if ( candidates[ i ].sr_matched != NULL ) {
915                                         struct berval   match, mmatch;
916
917                                         ber_str2bv( candidates[ i ].sr_matched,
918                                                 0, 0, &match );
919                                         candidates[ i ].sr_matched = NULL;
920
921                                         dc.ctx = "matchedDN";
922                                         dc.target = mi->mi_targets[ i ];
923                                         if ( !ldap_back_dn_massage( &dc, &match, &mmatch ) ) {
924                                                 if ( mmatch.bv_val == match.bv_val ) {
925                                                         candidates[ i ].sr_matched = ch_strdup( mmatch.bv_val );
926
927                                                 } else {
928                                                         candidates[ i ].sr_matched = mmatch.bv_val;
929                                                 }
930
931                                                 candidate_match++;
932                                         } 
933                                         ldap_memfree( match.bv_val );
934                                 }
935
936                                 /* add references to array */
937                                 if ( references ) {
938                                         BerVarray       sr_ref;
939                                         int             cnt;
940
941                                         for ( cnt = 0; references[ cnt ]; cnt++ )
942                                                 ;
943
944                                         sr_ref = ch_calloc( sizeof( struct berval ), cnt + 1 );
945
946                                         for ( cnt = 0; references[ cnt ]; cnt++ ) {
947                                                 ber_str2bv( references[ cnt ], 0, 1, &sr_ref[ cnt ] );
948                                         }
949                                         BER_BVZERO( &sr_ref[ cnt ] );
950
951                                         ( void )ldap_back_referral_result_rewrite( &dc, sr_ref );
952                                 
953                                         /* cleanup */
954                                         ber_memvfree( (void **)references );
955
956                                         if ( rs->sr_v2ref == NULL ) {
957                                                 rs->sr_v2ref = sr_ref;
958
959                                         } else {
960                                                 for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) {
961                                                         ber_bvarray_add( &rs->sr_v2ref, &sr_ref[ cnt ] );
962                                                 }
963                                                 ber_memfree( sr_ref );
964                                         }
965                                 }
966
967                                 rs->sr_err = candidates[ i ].sr_err;
968                                 sres = slap_map_api2result( rs );
969
970                                 if ( LogTest( LDAP_DEBUG_TRACE | LDAP_DEBUG_ANY ) ) {
971                                         snprintf( buf, sizeof( buf ),
972                                                 "%s meta_back_search[%ld] "
973                                                 "match=\"%s\" err=%ld",
974                                                 op->o_log_prefix, i,
975                                                 candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
976                                                 (long) candidates[ i ].sr_err );
977                                         if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
978                                                 Debug( LDAP_DEBUG_TRACE, "%s.\n", buf, 0, 0 );
979
980                                         } else {
981                                                 Debug( LDAP_DEBUG_ANY, "%s (%s).\n",
982                                                         buf, ldap_err2string( candidates[ i ].sr_err ), 0 );
983                                         }
984                                 }
985
986                                 switch ( sres ) {
987                                 case LDAP_NO_SUCH_OBJECT:
988                                         /* is_ok is touched any time a valid
989                                          * (even intermediate) result is
990                                          * returned; as a consequence, if
991                                          * a candidate returns noSuchObject
992                                          * it is ignored and the candidate
993                                          * is simply demoted. */
994                                         if ( is_ok ) {
995                                                 sres = LDAP_SUCCESS;
996                                         }
997                                         break;
998
999                                 case LDAP_SUCCESS:
1000                                 case LDAP_REFERRAL:
1001                                         is_ok++;
1002                                         break;
1003
1004                                 case LDAP_SIZELIMIT_EXCEEDED:
1005                                         /* if a target returned sizelimitExceeded
1006                                          * and the entry count is equal to the
1007                                          * proxy's limit, the target would have
1008                                          * returned more, and the error must be
1009                                          * propagated to the client; otherwise,
1010                                          * the target enforced a limit lower
1011                                          * than what requested by the proxy;
1012                                          * ignore it */
1013                                         if ( rs->sr_nentries == op->ors_slimit
1014                                                 || META_BACK_ONERR_STOP( mi ) )
1015                                         {
1016                                                 savepriv = op->o_private;
1017                                                 op->o_private = (void *)i;
1018                                                 send_ldap_result( op, rs );
1019                                                 op->o_private = savepriv;
1020                                                 goto finish;
1021                                         }
1022                                         break;
1023
1024                                 default:
1025                                         if ( META_BACK_ONERR_STOP( mi ) ) {
1026                                                 savepriv = op->o_private;
1027                                                 op->o_private = (void *)i;
1028                                                 send_ldap_result( op, rs );
1029                                                 op->o_private = savepriv;
1030                                                 goto finish;
1031                                         }
1032                                         break;
1033                                 }
1034
1035                                 last = i;
1036                                 rc = 0;
1037
1038                                 /*
1039                                  * When no candidates are left,
1040                                  * the outer cycle finishes
1041                                  */
1042                                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1043                                 --ncandidates;
1044
1045                         } else if ( rc == LDAP_RES_BIND ) {
1046                                 meta_search_candidate_t retcode;
1047
1048                                 retcode = meta_search_dobind_result( op, rs, &mc, i, candidates, res );
1049                                 if ( retcode == META_SEARCH_CANDIDATE ) {
1050                                         retcode = meta_back_search_start( op, rs, &dc, &mc, i, candidates );
1051                                 }
1052
1053                                 switch ( retcode ) {
1054                                 case META_SEARCH_CANDIDATE:
1055                                         goto get_result;
1056
1057                                         /* means that failed but onerr == continue */
1058                                 case META_SEARCH_NOT_CANDIDATE:
1059                                 case META_SEARCH_ERR:
1060                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1061                                         --ncandidates;
1062
1063                                         if ( META_BACK_ONERR_STOP( mi ) ) {
1064                                                 savepriv = op->o_private;
1065                                                 op->o_private = (void *)i;
1066                                                 send_ldap_result( op, rs );
1067                                                 op->o_private = savepriv;
1068                                                 goto finish;
1069                                         }
1070                                         break;
1071
1072                                 default:
1073                                         assert( 0 );
1074                                         break;
1075                                 }
1076
1077                         } else {
1078                                 assert( 0 );
1079                                 goto really_bad;
1080                         }
1081                 }
1082
1083                 /* check for abandon */
1084                 if ( op->o_abandon || doabandon ) {
1085                         for ( i = 0; i < mi->mi_ntargets; i++ ) {
1086                                 if ( candidates[ i ].sr_msgid != META_MSGID_IGNORE )
1087                                 {
1088                                         (void)meta_back_cancel( mc, op, rs,
1089                                                 candidates[ i ].sr_msgid, i,
1090                                                 LDAP_BACK_DONTSEND );
1091                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1092                                 }
1093                         }
1094
1095                         if ( op->o_abandon ) {
1096                                 rc = SLAPD_ABANDON;
1097                                 goto finish;
1098                         }
1099                 }
1100
1101                 /* if no entry was found during this loop,
1102                  * set a minimal timeout */
1103                 if ( gotit == 0 ) {
1104                         /* make the entire wait last
1105                          * LDAP_BACK_RESULT_UTIMEOUT at worst */
1106                         tv.tv_sec = 0;
1107                         tv.tv_usec = LDAP_BACK_RESULT_UTIMEOUT/initial_candidates;
1108                         ldap_pvt_thread_yield();
1109                 }
1110         }
1111
1112         if ( rc == -1 ) {
1113                 /*
1114                  * FIXME: need a better strategy to handle errors
1115                  */
1116                 if ( mc ) {
1117                         rc = meta_back_op_result( mc, op, rs, META_TARGET_NONE );
1118                 } else {
1119                         rc = rs->sr_err;
1120                 }
1121                 goto finish;
1122         }
1123
1124         /*
1125          * Rewrite the matched portion of the search base, if required
1126          * 
1127          * FIXME: only the last one gets caught!
1128          */
1129         savepriv = op->o_private;
1130         op->o_private = (void *)(long)mi->mi_ntargets;
1131         if ( candidate_match > 0 ) {
1132                 struct berval   pmatched = BER_BVNULL;
1133
1134                 /* we use the first one */
1135                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
1136                         if ( META_IS_CANDIDATE( &candidates[ i ] )
1137                                         && candidates[ i ].sr_matched != NULL )
1138                         {
1139                                 struct berval   bv, pbv;
1140                                 int             rc;
1141
1142                                 /* if we got success, and this target
1143                                  * returned noSuchObject, and its suffix
1144                                  * is a superior of the searchBase,
1145                                  * ignore the matchedDN */
1146                                 if ( sres == LDAP_SUCCESS
1147                                         && candidates[ i ].sr_err == LDAP_NO_SUCH_OBJECT
1148                                         && op->o_req_ndn.bv_len > mi->mi_targets[ i ]->mt_nsuffix.bv_len )
1149                                 {
1150                                         free( (char *)candidates[ i ].sr_matched );
1151                                         candidates[ i ].sr_matched = NULL;
1152                                         continue;
1153                                 }
1154
1155                                 ber_str2bv( candidates[ i ].sr_matched, 0, 0, &bv );
1156                                 rc = dnPretty( NULL, &bv, &pbv, op->o_tmpmemctx );
1157
1158                                 if ( rc == LDAP_SUCCESS ) {
1159
1160                                         /* NOTE: if they all are superiors
1161                                          * of the baseDN, the shorter is also 
1162                                          * superior of the longer... */
1163                                         if ( pbv.bv_len > pmatched.bv_len ) {
1164                                                 if ( !BER_BVISNULL( &pmatched ) ) {
1165                                                         op->o_tmpfree( pmatched.bv_val, op->o_tmpmemctx );
1166                                                 }
1167                                                 pmatched = pbv;
1168                                                 op->o_private = (void *)i;
1169
1170                                         } else {
1171                                                 op->o_tmpfree( pbv.bv_val, op->o_tmpmemctx );
1172                                         }
1173                                 }
1174
1175                                 if ( candidates[ i ].sr_matched != NULL ) {
1176                                         free( (char *)candidates[ i ].sr_matched );
1177                                         candidates[ i ].sr_matched = NULL;
1178                                 }
1179                         }
1180                 }
1181
1182                 if ( !BER_BVISNULL( &pmatched ) ) {
1183                         matched = pmatched.bv_val;
1184                 }
1185
1186         } else if ( sres == LDAP_NO_SUCH_OBJECT ) {
1187                 matched = op->o_bd->be_suffix[ 0 ].bv_val;
1188         }
1189
1190 #if 0
1191         {
1192                 char    buf[BUFSIZ];
1193                 char    cnd[BUFSIZ];
1194                 int     i;
1195
1196                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
1197                         if ( META_IS_CANDIDATE( &candidates[ i ] ) ) {
1198                                 cnd[ i ] = '*';
1199                         } else {
1200                                 cnd[ i ] = ' ';
1201                         }
1202                 }
1203                 cnd[ i ] = '\0';
1204
1205                 snprintf( buf, sizeof( buf ), "%s meta_back_search: is_scope=%d is_ok=%d cnd=\"%s\"\n",
1206                         op->o_log_prefix, initial_candidates, is_ok, cnd );
1207
1208                 Debug( LDAP_DEBUG_ANY, "%s", buf, 0, 0 );
1209         }
1210 #endif
1211
1212         /*
1213          * In case we returned at least one entry, we return LDAP_SUCCESS
1214          * otherwise, the latter error code we got
1215          *
1216          * FIXME: we should handle error codes and return the more 
1217          * important/reasonable
1218          */
1219
1220         if ( sres == LDAP_SUCCESS && rs->sr_v2ref ) {
1221                 sres = LDAP_REFERRAL;
1222         }
1223         rs->sr_err = sres;
1224         rs->sr_matched = matched;
1225         rs->sr_ref = ( sres == LDAP_REFERRAL ? rs->sr_v2ref : NULL );
1226         send_ldap_result( op, rs );
1227         op->o_private = savepriv;
1228         rs->sr_matched = NULL;
1229         rs->sr_ref = NULL;
1230
1231 finish:;
1232         if ( matched && matched != op->o_bd->be_suffix[ 0 ].bv_val ) {
1233                 op->o_tmpfree( matched, op->o_tmpmemctx );
1234         }
1235
1236         if ( rs->sr_v2ref ) {
1237                 ber_bvarray_free( rs->sr_v2ref );
1238         }
1239
1240         for ( i = 0; i < mi->mi_ntargets; i++ ) {
1241                 if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
1242                         continue;
1243                 }
1244
1245                 if ( mc && META_IS_BINDING( &candidates[ i ] ) ) {
1246                         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
1247                         if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ) {
1248                                 LDAP_BACK_CONN_BINDING_CLEAR( &mc->mc_conns[ i ] );
1249                         }
1250                         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1251                         META_BINDING_CLEAR( &candidates[ i ] );
1252                 }
1253
1254                 if ( candidates[ i ].sr_matched ) {
1255                         free( (char *)candidates[ i ].sr_matched );
1256                         candidates[ i ].sr_matched = NULL;
1257                 }
1258
1259                 if ( candidates[ i ].sr_text ) {
1260                         ldap_memfree( (char *)candidates[ i ].sr_text );
1261                         candidates[ i ].sr_text = NULL;
1262                 }
1263
1264                 if ( candidates[ i ].sr_ref ) {
1265                         ber_bvarray_free( candidates[ i ].sr_ref );
1266                         candidates[ i ].sr_ref = NULL;
1267                 }
1268
1269                 if ( candidates[ i ].sr_ctrls ) {
1270                         ldap_controls_free( candidates[ i ].sr_ctrls );
1271                         candidates[ i ].sr_ctrls = NULL;
1272                 }
1273
1274                 if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) {
1275                         meta_back_quarantine( op, &candidates[ i ], i );
1276                 }
1277         }
1278
1279         if ( mc ) {
1280                 meta_back_release_conn( op, mc );
1281         }
1282
1283         return rs->sr_err;
1284 }
1285
1286 static int
1287 meta_send_entry(
1288         Operation       *op,
1289         SlapReply       *rs,
1290         metaconn_t      *mc,
1291         int             target,
1292         LDAPMessage     *e )
1293 {
1294         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
1295         struct berval           a, mapped;
1296         Entry                   ent = { 0 };
1297         BerElement              ber = *e->lm_ber;
1298         Attribute               *attr, **attrp;
1299         struct berval           bdn,
1300                                 dn = BER_BVNULL;
1301         const char              *text;
1302         dncookie                dc;
1303         int                     rc;
1304
1305         if ( ber_scanf( &ber, "{m{", &bdn ) == LBER_ERROR ) {
1306                 return LDAP_DECODING_ERROR;
1307         }
1308
1309         /*
1310          * Rewrite the dn of the result, if needed
1311          */
1312         dc.target = mi->mi_targets[ target ];
1313         dc.conn = op->o_conn;
1314         dc.rs = rs;
1315         dc.ctx = "searchResult";
1316
1317         rs->sr_err = ldap_back_dn_massage( &dc, &bdn, &dn );
1318         if ( rs->sr_err != LDAP_SUCCESS) {
1319                 return rs->sr_err;
1320         }
1321
1322         /*
1323          * Note: this may fail if the target host(s) schema differs
1324          * from the one known to the meta, and a DN with unknown
1325          * attributes is returned.
1326          * 
1327          * FIXME: should we log anything, or delegate to dnNormalize?
1328          */
1329         rc = dnPrettyNormal( NULL, &dn, &ent.e_name, &ent.e_nname,
1330                 op->o_tmpmemctx );
1331         if ( dn.bv_val != bdn.bv_val ) {
1332                 free( dn.bv_val );
1333         }
1334         BER_BVZERO( &dn );
1335
1336         if ( rc != LDAP_SUCCESS ) {
1337                 return LDAP_INVALID_DN_SYNTAX;
1338         }
1339
1340         /*
1341          * cache dn
1342          */
1343         if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) {
1344                 ( void )meta_dncache_update_entry( &mi->mi_cache,
1345                                 &ent.e_nname, target );
1346         }
1347
1348         attrp = &ent.e_attrs;
1349
1350         dc.ctx = "searchAttrDN";
1351         while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
1352                 int                             last = 0;
1353                 slap_syntax_validate_func       *validate;
1354                 slap_syntax_transform_func      *pretty;
1355
1356                 ldap_back_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_at, 
1357                                 &a, &mapped, BACKLDAP_REMAP );
1358                 if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) {
1359                         ( void )ber_scanf( &ber, "x" /* [W] */ );
1360                         continue;
1361                 }
1362                 attr = ( Attribute * )ch_calloc( 1, sizeof( Attribute ) );
1363                 if ( attr == NULL ) {
1364                         continue;
1365                 }
1366                 if ( slap_bv2ad( &mapped, &attr->a_desc, &text )
1367                                 != LDAP_SUCCESS) {
1368                         if ( slap_bv2undef_ad( &mapped, &attr->a_desc, &text,
1369                                 SLAP_AD_PROXIED ) != LDAP_SUCCESS )
1370                         {
1371                                 char    buf[ SLAP_TEXT_BUFLEN ];
1372
1373                                 snprintf( buf, sizeof( buf ),
1374                                         "%s meta_send_entry(\"%s\"): "
1375                                         "slap_bv2undef_ad(%s): %s\n",
1376                                         op->o_log_prefix, ent.e_name.bv_val,
1377                                         mapped.bv_val, text );
1378
1379                                 Debug( LDAP_DEBUG_ANY, "%s", buf, 0, 0 );
1380                                 ch_free( attr );
1381                                 continue;
1382                         }
1383                 }
1384
1385                 /* no subschemaSubentry */
1386                 if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry
1387                         || attr->a_desc == slap_schema.si_ad_entryDN )
1388                 {
1389
1390                         /* 
1391                          * We eat target's subschemaSubentry because
1392                          * a search for this value is likely not
1393                          * to resolve to the appropriate backend;
1394                          * later, the local subschemaSubentry is
1395                          * added.
1396                          *
1397                          * We also eat entryDN because the frontend
1398                          * will reattach it without checking if already
1399                          * present...
1400                          */
1401                         ( void )ber_scanf( &ber, "x" /* [W] */ );
1402
1403                         ch_free(attr);
1404                         continue;
1405                 }
1406
1407                 if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR 
1408                                 || attr->a_vals == NULL )
1409                 {
1410                         attr->a_vals = (struct berval *)&slap_dummy_bv;
1411
1412                 } else {
1413                         for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); ++last )
1414                                 ;
1415                 }
1416
1417                 validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate;
1418                 pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty;
1419
1420                 if ( !validate && !pretty ) {
1421                         attr_free( attr );
1422                         goto next_attr;
1423                 }
1424
1425                 if ( attr->a_desc == slap_schema.si_ad_objectClass
1426                                 || attr->a_desc == slap_schema.si_ad_structuralObjectClass )
1427                 {
1428                         struct berval   *bv;
1429
1430                         for ( bv = attr->a_vals; !BER_BVISNULL( bv ); bv++ ) {
1431                                 ldap_back_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_oc,
1432                                                 bv, &mapped, BACKLDAP_REMAP );
1433                                 if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0') {
1434                                         free( bv->bv_val );
1435                                         BER_BVZERO( bv );
1436                                         if ( --last < 0 ) {
1437                                                 break;
1438                                         }
1439                                         *bv = attr->a_vals[ last ];
1440                                         BER_BVZERO( &attr->a_vals[ last ] );
1441                                         bv--;
1442
1443                                 } else if ( mapped.bv_val != bv->bv_val ) {
1444                                         free( bv->bv_val );
1445                                         ber_dupbv( bv, &mapped );
1446                                 }
1447                         }
1448                 /*
1449                  * It is necessary to try to rewrite attributes with
1450                  * dn syntax because they might be used in ACLs as
1451                  * members of groups; since ACLs are applied to the
1452                  * rewritten stuff, no dn-based subecj clause could
1453                  * be used at the ldap backend side (see
1454                  * http://www.OpenLDAP.org/faq/data/cache/452.html)
1455                  * The problem can be overcome by moving the dn-based
1456                  * ACLs to the target directory server, and letting
1457                  * everything pass thru the ldap backend.
1458                  */
1459                 } else {
1460                         int     i;
1461
1462                         if ( attr->a_desc->ad_type->sat_syntax ==
1463                                 slap_schema.si_syn_distinguishedName )
1464                         {
1465                                 ldap_dnattr_result_rewrite( &dc, attr->a_vals );
1466
1467                         } else if ( attr->a_desc == slap_schema.si_ad_ref ) {
1468                                 ldap_back_referral_result_rewrite( &dc, attr->a_vals );
1469
1470                         }
1471
1472                         for ( i = 0; i < last; i++ ) {
1473                                 struct berval   pval;
1474                                 int             rc;
1475
1476                                 if ( pretty ) {
1477                                         rc = pretty( attr->a_desc->ad_type->sat_syntax,
1478                                                 &attr->a_vals[i], &pval, NULL );
1479
1480                                 } else {
1481                                         rc = validate( attr->a_desc->ad_type->sat_syntax,
1482                                                 &attr->a_vals[i] );
1483                                 }
1484
1485                                 if ( rc ) {
1486                                         LBER_FREE( attr->a_vals[i].bv_val );
1487                                         if ( --last == i ) {
1488                                                 BER_BVZERO( &attr->a_vals[ i ] );
1489                                                 break;
1490                                         }
1491                                         attr->a_vals[i] = attr->a_vals[last];
1492                                         BER_BVZERO( &attr->a_vals[last] );
1493                                         i--;
1494                                         continue;
1495                                 }
1496
1497                                 if ( pretty ) {
1498                                         LBER_FREE( attr->a_vals[i].bv_val );
1499                                         attr->a_vals[i] = pval;
1500                                 }
1501                         }
1502
1503                         if ( last == 0 && attr->a_vals != &slap_dummy_bv ) {
1504                                 attr_free( attr );
1505                                 goto next_attr;
1506                         }
1507                 }
1508
1509                 if ( last && attr->a_desc->ad_type->sat_equality &&
1510                         attr->a_desc->ad_type->sat_equality->smr_normalize )
1511                 {
1512                         int i;
1513
1514                         attr->a_nvals = ch_malloc( ( last + 1 ) * sizeof( struct berval ) );
1515                         for ( i = 0; i<last; i++ ) {
1516                                 attr->a_desc->ad_type->sat_equality->smr_normalize(
1517                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
1518                                         attr->a_desc->ad_type->sat_syntax,
1519                                         attr->a_desc->ad_type->sat_equality,
1520                                         &attr->a_vals[i], &attr->a_nvals[i],
1521                                         NULL );
1522                         }
1523                         BER_BVZERO( &attr->a_nvals[i] );
1524
1525                 } else {
1526                         attr->a_nvals = attr->a_vals;
1527                 }
1528
1529                 *attrp = attr;
1530                 attrp = &attr->a_next;
1531 next_attr:;
1532         }
1533         rs->sr_entry = &ent;
1534         rs->sr_attrs = op->ors_attrs;
1535         rs->sr_flags = 0;
1536         rs->sr_err = LDAP_SUCCESS;
1537         rc = send_search_entry( op, rs );
1538         switch ( rc ) {
1539         case LDAP_UNAVAILABLE:
1540                 rc = LDAP_OTHER;
1541                 break;
1542         }
1543         rs->sr_entry = NULL;
1544         rs->sr_attrs = NULL;
1545         
1546         if ( !BER_BVISNULL( &ent.e_name ) ) {
1547                 free( ent.e_name.bv_val );
1548                 BER_BVZERO( &ent.e_name );
1549         }
1550         if ( !BER_BVISNULL( &ent.e_nname ) ) {
1551                 free( ent.e_nname.bv_val );
1552                 BER_BVZERO( &ent.e_nname );
1553         }
1554         entry_clean( &ent );
1555
1556         return rc;
1557 }
1558