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