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