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