]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/search.c
fix response code mapping
[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-2007 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 "lutil.h"
32 #include "slap.h"
33 #include "../back-ldap/back-ldap.h"
34 #include "back-meta.h"
35 #undef ldap_debug       /* silence a warning in ldap-int.h */
36 #include "ldap_log.h"
37 #include "../../../libraries/libldap/ldap-int.h"
38
39 /* IGNORE means that target does not (no longer) participate
40  * in the search;
41  * NOTREADY means the search on that target has not been initialized yet
42  */
43 #define META_MSGID_IGNORE       (-1)
44 #define META_MSGID_NEED_BIND    (-2)
45
46 static int
47 meta_send_entry(
48         Operation       *op,
49         SlapReply       *rs,
50         metaconn_t      *mc,
51         int             i,
52         LDAPMessage     *e );
53
54 typedef enum meta_search_candidate_t {
55         META_SEARCH_ERR = -1,
56         META_SEARCH_NOT_CANDIDATE,
57         META_SEARCH_CANDIDATE,
58         META_SEARCH_BINDING,
59         META_SEARCH_NEED_BIND
60 } meta_search_candidate_t;
61
62 /*
63  * meta_search_dobind_init()
64  *
65  * initiates bind for a candidate target of a search.
66  */
67 static meta_search_candidate_t
68 meta_search_dobind_init(
69         Operation               *op,
70         SlapReply               *rs,
71         metaconn_t              **mcp,
72         int                     candidate,
73         SlapReply               *candidates )
74 {
75         metaconn_t              *mc = *mcp;
76         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
77         metatarget_t            *mt = mi->mi_targets[ candidate ];
78         metasingleconn_t        *msc = &mc->mc_conns[ candidate ];
79
80         struct berval           binddn = msc->msc_bound_ndn,
81                                 cred = msc->msc_cred;
82         int                     method;
83
84         int                     rc;
85
86         meta_search_candidate_t retcode;
87
88         Debug( LDAP_DEBUG_TRACE, "%s >>> meta_search_dobind_init[%d]\n",
89                 op->o_log_prefix, candidate, 0 );
90
91         /*
92          * all the targets are already bound as pseudoroot
93          */
94         if ( mc->mc_authz_target == META_BOUND_ALL ) {
95                 return META_SEARCH_CANDIDATE;
96         }
97
98         retcode = META_SEARCH_BINDING;
99         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
100         if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
101                 /* already bound (or anonymous) */
102
103 #ifdef DEBUG_205
104                 char    buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
105                 int     bound = 0;
106
107                 if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
108                         bound = 1;
109                 }
110
111                 snprintf( buf, sizeof( buf ), " mc=%p ld=%p%s DN=\"%s\"",
112                         (void *)mc, (void *)msc->msc_ld,
113                         bound ? " bound" : " anonymous",
114                         bound == 0 ? "" : msc->msc_bound_ndn.bv_val );
115                 Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
116                         op->o_log_prefix, candidate, buf );
117 #endif /* DEBUG_205 */
118
119                 retcode = META_SEARCH_CANDIDATE;
120
121         } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) ) {
122                 /* another thread is binding the target for this conn; wait */
123
124 #ifdef DEBUG_205
125                 char    buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
126
127                 snprintf( buf, sizeof( buf ), " mc=%p ld=%p needbind",
128                         (void *)mc, (void *)msc->msc_ld );
129                 Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
130                         op->o_log_prefix, candidate, buf );
131 #endif /* DEBUG_205 */
132
133                 candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND;
134                 retcode = META_SEARCH_NEED_BIND;
135
136         } else {
137                 /* we'll need to bind the target for this conn */
138
139 #ifdef DEBUG_205
140                 char buf[ SLAP_TEXT_BUFLEN ];
141
142                 snprintf( buf, sizeof( buf ), " mc=%p ld=%p binding",
143                         (void *)mc, (void *)msc->msc_ld );
144                 Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
145                         op->o_log_prefix, candidate, buf );
146 #endif /* DEBUG_205 */
147
148                 if ( msc->msc_ld == NULL ) {
149                         /* for some reason (e.g. because formerly in "binding"
150                          * state, with eventual connection expiration or invalidation)
151                          * it was not initialized as expected */
152
153                         Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p ld=NULL\n",
154                                 op->o_log_prefix, candidate, (void *)mc );
155
156                         rc = meta_back_init_one_conn( op, rs, *mcp, candidate,
157                                 LDAP_BACK_CONN_ISPRIV( *mcp ), LDAP_BACK_DONTSEND, 0 );
158                         switch ( rc ) {
159                         case LDAP_SUCCESS:
160                                 assert( msc->msc_ld != NULL );
161                                 break;
162
163                         case LDAP_SERVER_DOWN:
164                         case LDAP_UNAVAILABLE:
165                                 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
166                                 goto down;
167         
168                         default:
169                                 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
170                                 goto other;
171                         }
172                 }
173
174                 LDAP_BACK_CONN_BINDING_SET( msc );
175         }
176
177         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
178
179         if ( retcode != META_SEARCH_BINDING ) {
180                 return retcode;
181         }
182
183         /* NOTE: this obsoletes pseudorootdn */
184         if ( op->o_conn != NULL &&
185                 !op->o_do_not_cache &&
186                 ( BER_BVISNULL( &msc->msc_bound_ndn ) ||
187                         BER_BVISEMPTY( &msc->msc_bound_ndn ) ||
188                         ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
189         {
190                 rc = meta_back_proxy_authz_cred( mc, candidate, op, rs, LDAP_BACK_DONTSEND, &binddn, &cred, &method );
191                 if ( rc != LDAP_SUCCESS ) {
192                         goto down;
193                 }
194
195                 /* NOTE: we copy things here, even if bind didn't succeed yet,
196                  * because the connection is not shared until bind is over */
197                 if ( !BER_BVISNULL( &binddn ) ) {
198                         ber_bvreplace( &msc->msc_bound_ndn, &binddn );
199                         if ( LDAP_BACK_SAVECRED( mi ) && !BER_BVISNULL( &cred ) ) {
200                                 if ( !BER_BVISNULL( &msc->msc_cred ) ) {
201                                         memset( msc->msc_cred.bv_val, 0,
202                                                 msc->msc_cred.bv_len );
203                                 }
204                                 ber_bvreplace( &msc->msc_cred, &cred );
205                         }
206                 }
207
208                 if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
209                         /* apparently, idassert was configured with SASL bind,
210                          * so bind occurred inside meta_back_proxy_authz_cred() */
211                         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
212                         LDAP_BACK_CONN_BINDING_CLEAR( msc );
213                         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
214                         return META_SEARCH_CANDIDATE;
215                 }
216
217                 /* paranoid */
218                 switch ( method ) {
219                 case LDAP_AUTH_NONE:
220                 case LDAP_AUTH_SIMPLE:
221                         /* do a simple bind with binddn, cred */
222                         break;
223
224                 default:
225                         assert( 0 );
226                         break;
227                 }
228         }
229
230         assert( msc->msc_ld != NULL );
231
232         /* connect must be async */
233 retry:;
234         ldap_set_option( msc->msc_ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_ON );
235
236         rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred,
237                         NULL, NULL, &candidates[ candidate ].sr_msgid );
238
239 #ifdef DEBUG_205
240         {
241                 char buf[ SLAP_TEXT_BUFLEN ];
242
243                 snprintf( buf, sizeof( buf ), "meta_search_dobind_init[%d] mc=%p ld=%p rc=%d",
244                         candidate, (void *)mc, (void *)mc->mc_conns[ candidate ].msc_ld, rc );
245                 Debug( LDAP_DEBUG_ANY, "### %s %s\n",
246                         op->o_log_prefix, buf, 0 );
247         }
248 #endif /* DEBUG_205 */
249
250         switch ( rc ) {
251         case LDAP_SUCCESS:
252                 assert( candidates[ candidate ].sr_msgid >= 0 );
253                 META_BINDING_SET( &candidates[ candidate ] );
254                 return META_SEARCH_BINDING;
255
256         case LDAP_X_CONNECTING:
257                 /* must retry, same conn */
258                 candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND;
259                 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
260                 LDAP_BACK_CONN_BINDING_CLEAR( msc );
261                 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
262                 return META_SEARCH_NEED_BIND;
263
264         case LDAP_SERVER_DOWN:
265 down:;
266                 /* This is the worst thing that could happen:
267                  * the search will wait until the retry is over. */
268                 if ( !META_IS_RETRYING( &candidates[ candidate ] ) ) {
269                         META_RETRYING_SET( &candidates[ candidate ] );
270
271                         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
272
273                         assert( mc->mc_refcnt > 0 );
274                         if ( LogTest( LDAP_DEBUG_ANY ) ) {
275                                 char    buf[ SLAP_TEXT_BUFLEN ];
276
277                                 /* this lock is required; however,
278                                  * it's invoked only when logging is on */
279                                 ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
280                                 snprintf( buf, sizeof( buf ),
281                                         "retrying URI=\"%s\" DN=\"%s\"",
282                                         mt->mt_uri,
283                                         BER_BVISNULL( &msc->msc_bound_ndn ) ?
284                                                 "" : msc->msc_bound_ndn.bv_val );
285                                 ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
286
287                                 Debug( LDAP_DEBUG_ANY,
288                                         "%s meta_search_dobind_init[%d]: %s.\n",
289                                         op->o_log_prefix, candidate, buf );
290                         }
291
292                         meta_clear_one_candidate( op, mc, candidate );
293                         LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
294
295                         ( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn );
296
297                         /* mc here must be the regular mc, reset and ready for init */
298                         rc = meta_back_init_one_conn( op, rs, mc, candidate,
299                                 LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 );
300
301                         LDAP_BACK_CONN_BINDING_SET( msc );
302                         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
303
304                         goto retry;
305                 }
306
307                 if ( *mcp == NULL ) {
308                         retcode = META_SEARCH_ERR;
309                         rs->sr_err = LDAP_UNAVAILABLE;
310                         break;
311                 }
312                 /* fall thru */
313
314         default:
315 other:;
316                 rs->sr_err = rc;
317                 rc = slap_map_api2result( rs );
318
319                 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
320                 meta_clear_one_candidate( op, mc, candidate );
321                 candidates[ candidate ].sr_err = rc;
322                 if ( META_BACK_ONERR_STOP( mi ) ) {
323                         LDAP_BACK_CONN_TAINTED_SET( mc );
324                         meta_back_release_conn_lock( op, mc, 0 );
325                         *mcp = NULL;
326                         rs->sr_err = rc;
327
328                         retcode = META_SEARCH_ERR;
329
330                 } else {
331                         retcode = META_SEARCH_NOT_CANDIDATE;
332                 }
333                 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
334                 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
335                 break;
336         }
337
338         return retcode;
339 }
340
341 static meta_search_candidate_t
342 meta_search_dobind_result(
343         Operation               *op,
344         SlapReply               *rs,
345         metaconn_t              **mcp,
346         int                     candidate,
347         SlapReply               *candidates,
348         LDAPMessage             *res )
349 {
350         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
351         metaconn_t              *mc = *mcp;
352         metasingleconn_t        *msc = &mc->mc_conns[ candidate ];
353
354         meta_search_candidate_t retcode = META_SEARCH_NOT_CANDIDATE;
355         int                     rc;
356
357         assert( msc->msc_ld != NULL );
358
359         /* FIXME: matched? referrals? response controls? */
360         rc = ldap_parse_result( msc->msc_ld, res,
361                 &candidates[ candidate ].sr_err,
362                 NULL, NULL, NULL, NULL, 0 );
363         if ( rc != LDAP_SUCCESS ) {
364                 candidates[ candidate ].sr_err = rc;
365
366         } else {
367                 rc = slap_map_api2result( &candidates[ candidate ] );
368         }
369
370         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
371         LDAP_BACK_CONN_BINDING_CLEAR( msc );
372         if ( rc != LDAP_SUCCESS ) {
373                 meta_clear_one_candidate( op, mc, candidate );
374                 candidates[ candidate ].sr_err = rc;
375                 if ( META_BACK_ONERR_STOP( mi ) ) {
376                         LDAP_BACK_CONN_TAINTED_SET( mc );
377                         meta_back_release_conn_lock( op, mc, 0 );
378                         *mcp = NULL;
379                         retcode = META_SEARCH_ERR;
380                         rs->sr_err = rc;
381                 }
382
383         } else {
384                 /* FIXME: check if bound as idassert authcDN! */
385                 if ( BER_BVISNULL( &msc->msc_bound_ndn )
386                         || BER_BVISEMPTY( &msc->msc_bound_ndn ) )
387                 {
388                         LDAP_BACK_CONN_ISANON_SET( msc );
389
390                 } else {
391                         LDAP_BACK_CONN_ISBOUND_SET( msc );
392                 }
393                 retcode = META_SEARCH_CANDIDATE;
394
395                 /* connect must be async */
396                 ldap_set_option( msc->msc_ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_OFF );
397         }
398
399         candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
400         META_BINDING_CLEAR( &candidates[ candidate ] );
401
402         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
403
404         return retcode;
405 }
406
407 static meta_search_candidate_t
408 meta_back_search_start(
409         Operation               *op,
410         SlapReply               *rs,
411         dncookie                *dc,
412         metaconn_t              **mcp,
413         int                     candidate,
414         SlapReply               *candidates )
415 {
416         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
417         metatarget_t            *mt = mi->mi_targets[ candidate ];
418         metasingleconn_t        *msc = &(*mcp)->mc_conns[ candidate ];
419         struct berval           realbase = op->o_req_dn;
420         int                     realscope = op->ors_scope;
421         struct berval           mbase = BER_BVNULL; 
422         struct berval           mfilter = BER_BVNULL;
423         char                    **mapped_attrs = NULL;
424         int                     rc;
425         meta_search_candidate_t retcode;
426         struct timeval          tv, *tvp = NULL;
427         int                     nretries = 1;
428         LDAPControl             **ctrls = NULL;
429
430         /* this should not happen; just in case... */
431         if ( msc->msc_ld == NULL ) {
432                 Debug( LDAP_DEBUG_ANY,
433                         "%s: meta_back_search_start candidate=%d ld=NULL%s.\n",
434                         op->o_log_prefix, candidate,
435                         META_BACK_ONERR_STOP( mi ) ? "" : " (ignored)" );
436                 candidates[ candidate ].sr_err = LDAP_OTHER;
437                 if ( META_BACK_ONERR_STOP( mi ) ) {
438                         return META_SEARCH_ERR;
439                 }
440                 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
441                 return META_SEARCH_NOT_CANDIDATE;
442         }
443
444         Debug( LDAP_DEBUG_TRACE, "%s >>> meta_back_search_start[%d]\n", op->o_log_prefix, candidate, 0 );
445
446         /*
447          * modifies the base according to the scope, if required
448          */
449         if ( mt->mt_nsuffix.bv_len > op->o_req_ndn.bv_len ) {
450                 switch ( op->ors_scope ) {
451                 case LDAP_SCOPE_SUBTREE:
452                         /*
453                          * make the target suffix the new base
454                          * FIXME: this is very forgiving, because
455                          * "illegal" searchBases may be turned
456                          * into the suffix of the target; however,
457                          * the requested searchBase already passed
458                          * thru the candidate analyzer...
459                          */
460                         if ( dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) ) {
461                                 realbase = mt->mt_nsuffix;
462                                 if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
463                                         realscope = LDAP_SCOPE_SUBORDINATE;
464                                 }
465
466                         } else {
467                                 /*
468                                  * this target is no longer candidate
469                                  */
470                                 retcode = META_SEARCH_NOT_CANDIDATE;
471                                 goto doreturn;
472                         }
473                         break;
474
475                 case LDAP_SCOPE_SUBORDINATE:
476                 case LDAP_SCOPE_ONELEVEL:
477                 {
478                         struct berval   rdn = mt->mt_nsuffix;
479                         rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," );
480                         if ( dnIsOneLevelRDN( &rdn )
481                                         && dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) )
482                         {
483                                 /*
484                                  * if there is exactly one level,
485                                  * make the target suffix the new
486                                  * base, and make scope "base"
487                                  */
488                                 realbase = mt->mt_nsuffix;
489                                 if ( op->ors_scope == LDAP_SCOPE_SUBORDINATE ) {
490                                         if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
491                                                 realscope = LDAP_SCOPE_SUBORDINATE;
492                                         } else {
493                                                 realscope = LDAP_SCOPE_SUBTREE;
494                                         }
495                                 } else {
496                                         realscope = LDAP_SCOPE_BASE;
497                                 }
498                                 break;
499                         } /* else continue with the next case */
500                 }
501
502                 case LDAP_SCOPE_BASE:
503                         /*
504                          * this target is no longer candidate
505                          */
506                         retcode = META_SEARCH_NOT_CANDIDATE;
507                         goto doreturn;
508                 }
509         }
510
511         /* initiate dobind */
512         retcode = meta_search_dobind_init( op, rs, mcp, candidate, candidates );
513
514         Debug( LDAP_DEBUG_TRACE, "%s <<< meta_search_dobind_init[%d]=%d\n", op->o_log_prefix, candidate, retcode );
515
516         if ( retcode != META_SEARCH_CANDIDATE ) {
517                 goto doreturn;
518         }
519
520         /*
521          * Rewrite the search base, if required
522          */
523         dc->target = mt;
524         dc->ctx = "searchBase";
525         switch ( ldap_back_dn_massage( dc, &realbase, &mbase ) ) {
526         case LDAP_SUCCESS:
527                 break;
528
529         case LDAP_UNWILLING_TO_PERFORM:
530                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
531                 rs->sr_text = "Operation not allowed";
532                 send_ldap_result( op, rs );
533                 retcode = META_SEARCH_ERR;
534                 goto doreturn;
535
536         default:
537
538                 /*
539                  * this target is no longer candidate
540                  */
541                 retcode = META_SEARCH_NOT_CANDIDATE;
542                 goto doreturn;
543         }
544
545         /*
546          * Maps filter
547          */
548         rc = ldap_back_filter_map_rewrite( dc, op->ors_filter,
549                         &mfilter, BACKLDAP_MAP );
550         switch ( rc ) {
551         case LDAP_SUCCESS:
552                 break;
553
554         case LDAP_COMPARE_FALSE:
555         default:
556                 /*
557                  * this target is no longer candidate
558                  */
559                 retcode = META_SEARCH_NOT_CANDIDATE;
560                 goto done;
561         }
562
563         /*
564          * Maps required attributes
565          */
566         rc = ldap_back_map_attrs( &mt->mt_rwmap.rwm_at,
567                         op->ors_attrs, BACKLDAP_MAP, &mapped_attrs );
568         if ( rc != LDAP_SUCCESS ) {
569                 /*
570                  * this target is no longer candidate
571                  */
572                 retcode = META_SEARCH_NOT_CANDIDATE;
573                 goto done;
574         }
575
576         /* should we check return values? */
577         if ( op->ors_deref != -1 ) {
578                 assert( msc->msc_ld != NULL );
579                 (void)ldap_set_option( msc->msc_ld, LDAP_OPT_DEREF,
580                                 ( void * )&op->ors_deref );
581         }
582
583         if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
584                 tv.tv_sec = op->ors_tlimit > 0 ? op->ors_tlimit : 1;
585                 tv.tv_usec = 0;
586                 tvp = &tv;
587         }
588
589 retry:;
590         ctrls = op->o_ctrls;
591         if ( ldap_back_proxy_authz_ctrl( &msc->msc_bound_ndn,
592                 mt->mt_version, &mt->mt_idassert, op, rs, &ctrls )
593                 != LDAP_SUCCESS )
594         {
595                 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
596                 retcode = META_SEARCH_NOT_CANDIDATE;
597                 goto done;
598         }
599
600         /*
601          * Starts the search
602          */
603         assert( msc->msc_ld != NULL );
604         rc = ldap_search_ext( msc->msc_ld,
605                         mbase.bv_val, realscope, mfilter.bv_val,
606                         mapped_attrs, op->ors_attrsonly,
607                         ctrls, NULL, tvp, op->ors_slimit,
608                         &candidates[ candidate ].sr_msgid ); 
609         switch ( rc ) {
610         case LDAP_SUCCESS:
611                 retcode = META_SEARCH_CANDIDATE;
612                 break;
613         
614         case LDAP_SERVER_DOWN:
615                 if ( nretries && meta_back_retry( op, rs, mcp, candidate, LDAP_BACK_DONTSEND ) ) {
616                         nretries = 0;
617                         /* if the identity changed, there might be need to re-authz */
618                         (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
619                         goto retry;
620                 }
621
622                 if ( *mcp == NULL ) {
623                         retcode = META_SEARCH_ERR;
624                         break;
625                 }
626                 /* fall thru */
627
628         default:
629                 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
630                 retcode = META_SEARCH_NOT_CANDIDATE;
631         }
632
633 done:;
634         (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
635
636         if ( mapped_attrs ) {
637                 free( mapped_attrs );
638         }
639         if ( mfilter.bv_val != op->ors_filterstr.bv_val ) {
640                 free( mfilter.bv_val );
641         }
642         if ( mbase.bv_val != realbase.bv_val ) {
643                 free( mbase.bv_val );
644         }
645
646 doreturn:;
647         Debug( LDAP_DEBUG_TRACE, "%s <<< meta_back_search_start[%d]=%d\n", op->o_log_prefix, candidate, retcode );
648
649         return retcode;
650 }
651
652 int
653 meta_back_search( Operation *op, SlapReply *rs )
654 {
655         metainfo_t      *mi = ( metainfo_t * )op->o_bd->be_private;
656         metaconn_t      *mc;
657         struct timeval  save_tv = { 0, 0 },
658                         tv;
659         time_t          stoptime = (time_t)-1;
660         int             rc = 0, sres = LDAP_SUCCESS;
661         char            *matched = NULL;
662         int             last = 0, ncandidates = 0,
663                         initial_candidates = 0, candidate_match = 0,
664                         needbind = 0;
665         ldap_back_send_t        sendok = LDAP_BACK_SENDERR;
666         long            i;
667         dncookie        dc;
668         int             is_ok = 0;
669         void            *savepriv;
670         SlapReply       *candidates = meta_back_candidates_get( op );
671
672         /*
673          * controls are set in ldap_back_dobind()
674          * 
675          * FIXME: in case of values return filter, we might want
676          * to map attrs and maybe rewrite value
677          */
678 getconn:;
679         mc = meta_back_getconn( op, rs, NULL, sendok );
680         if ( !mc ) {
681                 return rs->sr_err;
682         }
683
684         dc.conn = op->o_conn;
685         dc.rs = rs;
686
687         /*
688          * Inits searches
689          */
690         for ( i = 0; i < mi->mi_ntargets; i++ ) {
691                 /* reset sr_msgid; it is used in most loops
692                  * to check if that target is still to be considered */
693                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
694
695                 /* a target is marked as candidate by meta_back_getconn();
696                  * if for any reason (an error, it's over or so) it is
697                  * no longer active, sr_msgid is set to META_MSGID_IGNORE
698                  * but it remains candidate, which means it has been active
699                  * at some point during the operation.  This allows to 
700                  * use its response code and more to compute the final
701                  * response */
702                 if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
703                         continue;
704                 }
705
706                 candidates[ i ].sr_matched = NULL;
707                 candidates[ i ].sr_text = NULL;
708                 candidates[ i ].sr_ref = NULL;
709                 candidates[ i ].sr_ctrls = NULL;
710         }
711
712         for ( i = 0; i < mi->mi_ntargets; i++ ) {
713                 if ( !META_IS_CANDIDATE( &candidates[ i ] )
714                         || candidates[ i ].sr_err != LDAP_SUCCESS )
715                 {
716                         continue;
717                 }
718
719                 switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
720                 {
721                 case META_SEARCH_NOT_CANDIDATE:
722                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
723                         break;
724
725                 case META_SEARCH_NEED_BIND:
726                         ++needbind;
727                         /* fallthru */
728
729                 case META_SEARCH_CANDIDATE:
730                 case META_SEARCH_BINDING:
731                         candidates[ i ].sr_type = REP_INTERMEDIATE;
732                         ++ncandidates;
733                         break;
734
735                 case META_SEARCH_ERR:
736                         savepriv = op->o_private;
737                         op->o_private = (void *)i;
738                         send_ldap_result( op, rs );
739                         op->o_private = savepriv;
740                         rc = -1;
741                         goto finish;
742                 }
743         }
744
745         if ( ncandidates > 0 && needbind == ncandidates ) {
746                 /*
747                  * give up the second time...
748                  *
749                  * NOTE: this should not occur the second time, since a fresh
750                  * connection has ben created; however, targets may also
751                  * need bind because the bind timed out or so.
752                  */
753                 if ( sendok & LDAP_BACK_BINDING ) {
754                         Debug( LDAP_DEBUG_ANY,
755                                 "%s meta_back_search: unable to initialize conn\n",
756                                 op->o_log_prefix, 0, 0 );
757                         rs->sr_err = LDAP_UNAVAILABLE;
758                         rs->sr_text = "unable to initialize connection to remote targets";
759                         send_ldap_result( op, rs );
760                         rc = -1;
761                         goto finish;
762                 }
763
764                 /* FIXME: better create a separate connection? */
765                 sendok |= LDAP_BACK_BINDING;
766
767 #ifdef DEBUG_205
768                 Debug( LDAP_DEBUG_ANY, "*** %s drop mc=%p create new connection\n",
769                         op->o_log_prefix, (void *)mc, 0 );
770 #endif /* DEBUG_205 */
771
772                 meta_back_release_conn( op, mc );
773                 mc = NULL;
774
775                 needbind = 0;
776                 ncandidates = 0;
777
778                 goto getconn;
779         }
780
781         initial_candidates = ncandidates;
782
783         if ( LogTest( LDAP_DEBUG_TRACE ) ) {
784                 char    cnd[ SLAP_TEXT_BUFLEN ];
785                 int     c;
786
787                 for ( c = 0; c < mi->mi_ntargets; c++ ) {
788                         if ( META_IS_CANDIDATE( &candidates[ c ] ) ) {
789                                 cnd[ c ] = '*';
790                         } else {
791                                 cnd[ c ] = ' ';
792                         }
793                 }
794                 cnd[ c ] = '\0';
795
796                 Debug( LDAP_DEBUG_TRACE, "%s meta_back_search: ncandidates=%d "
797                         "cnd=\"%s\"\n", op->o_log_prefix, ncandidates, cnd );
798         }
799
800         if ( initial_candidates == 0 ) {
801                 /* NOTE: here we are not sending any matchedDN;
802                  * this is intended, because if the back-meta
803                  * is serving this search request, but no valid
804                  * candidate could be looked up, it means that
805                  * there is a hole in the mapping of the targets
806                  * and thus no knowledge of any remote superior
807                  * is available */
808                 Debug( LDAP_DEBUG_ANY, "%s meta_back_search: "
809                         "base=\"%s\" scope=%d: "
810                         "no candidate could be selected\n",
811                         op->o_log_prefix, op->o_req_dn.bv_val,
812                         op->ors_scope );
813
814                 /* FIXME: we're sending the first error we encounter;
815                  * maybe we should pick the worst... */
816                 rc = LDAP_NO_SUCH_OBJECT;
817                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
818                         if ( META_IS_CANDIDATE( &candidates[ i ] )
819                                 && candidates[ i ].sr_err != LDAP_SUCCESS )
820                         {
821                                 rc = candidates[ i ].sr_err;
822                                 break;
823                         }
824                 }
825
826                 send_ldap_error( op, rs, rc, NULL );
827
828                 goto finish;
829         }
830
831         /* We pull apart the ber result, stuff it into a slapd entry, and
832          * let send_search_entry stuff it back into ber format. Slow & ugly,
833          * but this is necessary for version matching, and for ACL processing.
834          */
835
836         if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
837                 stoptime = op->o_time + op->ors_tlimit;
838         }
839
840         /*
841          * In case there are no candidates, no cycle takes place...
842          *
843          * FIXME: we might use a queue, to better balance the load 
844          * among the candidates
845          */
846         for ( rc = 0; ncandidates > 0; ) {
847                 int     gotit = 0,
848                         doabandon = 0,
849                         alreadybound = ncandidates;
850
851                 /* check time limit */
852                 if ( op->ors_tlimit != SLAP_NO_LIMIT
853                                 && slap_get_time() > stoptime )
854                 {
855                         doabandon = 1;
856                         rc = rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
857                         savepriv = op->o_private;
858                         op->o_private = (void *)i;
859                         send_ldap_result( op, rs );
860                         op->o_private = savepriv;
861                         goto finish;
862                 }
863
864                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
865                         metasingleconn_t        *msc = &mc->mc_conns[ i ];
866                         LDAPMessage             *res = NULL, *msg;
867
868                         /* if msgid is invalid, don't ldap_result() */
869                         if ( candidates[ i ].sr_msgid == META_MSGID_IGNORE ) {
870                                 continue;
871                         }
872
873                         /* if target still needs bind, retry */
874                         if ( candidates[ i ].sr_msgid == META_MSGID_NEED_BIND ) {
875                                 meta_search_candidate_t retcode;
876
877                                 /* initiate dobind */
878                                 retcode = meta_search_dobind_init( op, rs, &mc, i, candidates );
879
880                                 Debug( LDAP_DEBUG_TRACE, "%s <<< meta_search_dobind_init[%ld]=%d\n",
881                                         op->o_log_prefix, i, retcode );
882
883                                 switch ( retcode ) {
884                                 case META_SEARCH_NEED_BIND:
885                                         alreadybound--;
886                                         /* fallthru */
887
888                                 case META_SEARCH_BINDING:
889                                         break;
890
891                                 case META_SEARCH_ERR:
892                                         candidates[ i ].sr_err = rs->sr_err;
893                                         if ( META_BACK_ONERR_STOP( mi ) ) {
894                                                 savepriv = op->o_private;
895                                                 op->o_private = (void *)i;
896                                                 send_ldap_result( op, rs );
897                                                 op->o_private = savepriv;
898                                                 goto finish;
899                                         }
900                                         /* fallthru */
901
902                                 case META_SEARCH_NOT_CANDIDATE:
903                                         /*
904                                          * When no candidates are left,
905                                          * the outer cycle finishes
906                                          */
907                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
908                                         assert( ncandidates > 0 );
909                                         --ncandidates;
910                                         break;
911
912                                 case META_SEARCH_CANDIDATE:
913                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
914                                         switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
915                                         {
916                                         case META_SEARCH_CANDIDATE:
917                                                 assert( candidates[ i ].sr_msgid >= 0 );
918                                                 break;
919
920                                         case META_SEARCH_ERR:
921                                                 candidates[ i ].sr_err = rs->sr_err;
922                                                 if ( META_BACK_ONERR_STOP( mi ) ) {
923                                                         savepriv = op->o_private;
924                                                         op->o_private = (void *)i;
925                                                         send_ldap_result( op, rs );
926                                                         op->o_private = savepriv;
927                                                         goto finish;
928                                                 }
929                                                 /* fallthru */
930
931                                         case META_SEARCH_NOT_CANDIDATE:
932                                                 /* means that meta_back_search_start()
933                                                  * failed but onerr == continue */
934                                                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
935                                                 assert( ncandidates > 0 );
936                                                 --ncandidates;
937                                                 break;
938
939                                         default:
940                                                 /* impossible */
941                                                 assert( 0 );
942                                                 break;
943                                         }
944                                         break;
945
946                                 default:
947                                         /* impossible */
948                                         assert( 0 );
949                                         break;
950                                 }
951                                 continue;
952                         }
953
954                         /* check for abandon */
955                         if ( op->o_abandon ) {
956                                 break;
957                         }
958
959 #ifdef DEBUG_205
960                         if ( msc->msc_ld == NULL ) {
961                                 char    buf[ SLAP_TEXT_BUFLEN ];
962
963                                 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
964                                 snprintf( buf, sizeof( buf ),
965                                         "%s meta_back_search[%ld] mc=%p msgid=%d%s%s%s\n",
966                                         op->o_log_prefix, (long)i, (void *)mc,
967                                         candidates[ i ].sr_msgid,
968                                         META_IS_BINDING( &candidates[ i ] ) ? " binding" : "",
969                                         LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ? " connbinding" : "",
970                                         META_BACK_CONN_CREATING( &mc->mc_conns[ i ] ) ? " conncreating" : "" );
971                                 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
972                                         
973                                 Debug( LDAP_DEBUG_ANY, "!!! %s\n", buf, 0, 0 );
974                         }
975 #endif /* DEBUG_205 */
976                         
977                         /*
978                          * FIXME: handle time limit as well?
979                          * Note that target servers are likely 
980                          * to handle it, so at some time we'll
981                          * get a LDAP_TIMELIMIT_EXCEEDED from
982                          * one of them ...
983                          */
984                         tv = save_tv;
985                         rc = ldap_result( msc->msc_ld, candidates[ i ].sr_msgid,
986                                         LDAP_MSG_RECEIVED, &tv, &res );
987                         switch ( rc ) {
988                         case 0:
989                                 /* FIXME: res should not need to be freed */
990                                 assert( res == NULL );
991                                 continue;
992
993                         case -1:
994 really_bad:;
995                                 /* something REALLY bad happened! */
996                                 if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
997                                         candidates[ i ].sr_type = REP_RESULT;
998
999                                         if ( meta_back_retry( op, rs, &mc, i, LDAP_BACK_DONTSEND ) ) {
1000                                                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1001                                                 switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
1002                                                 {
1003                                                 case META_SEARCH_CANDIDATE:
1004                                                         /* get back into business... */
1005                                                         continue;
1006
1007                                                         /* means that failed but onerr == continue */
1008                                                 case META_SEARCH_NOT_CANDIDATE:
1009                                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1010                                                         --ncandidates;
1011
1012                                                         candidates[ i ].sr_err = rs->sr_err;
1013                                                         if ( META_BACK_ONERR_STOP( mi ) ) {
1014                                                                 savepriv = op->o_private;
1015                                                                 op->o_private = (void *)i;
1016                                                                 send_ldap_result( op, rs );
1017                                                                 op->o_private = savepriv;
1018                                                                 goto finish;
1019                                                         }
1020                                                         break;
1021
1022                                                 case META_SEARCH_BINDING:
1023                                                 case META_SEARCH_NEED_BIND:
1024                                                         assert( 0 );
1025
1026                                                 default:
1027                                                         /* unrecoverable error */
1028                                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1029                                                         rc = rs->sr_err = LDAP_OTHER;
1030                                                         goto finish;
1031                                                 }
1032                                         }
1033
1034                                         candidates[ i ].sr_err = rs->sr_err;
1035                                         if ( META_BACK_ONERR_STOP( mi ) ) {
1036                                                 savepriv = op->o_private;
1037                                                 op->o_private = (void *)i;
1038                                                 send_ldap_result( op, rs );
1039                                                 op->o_private = savepriv;
1040                                                 goto finish;
1041                                         }
1042                                 }
1043
1044                                 /*
1045                                  * When no candidates are left,
1046                                  * the outer cycle finishes
1047                                  */
1048                                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1049                                 assert( ncandidates > 0 );
1050                                 --ncandidates;
1051                                 rs->sr_err = candidates[ i ].sr_err;
1052                                 continue;
1053
1054                         default:
1055                                 /* only touch when activity actually took place... */
1056                                 if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
1057                                         msc->msc_time = op->o_time;
1058                                 }
1059                                 break;
1060                         }
1061
1062                         for ( msg = ldap_first_message( msc->msc_ld, res );
1063                                 msg != NULL;
1064                                 msg = ldap_next_message( msc->msc_ld, msg ) )
1065                         {
1066                                 rc = ldap_msgtype( msg );
1067                                 if ( rc == LDAP_RES_SEARCH_ENTRY ) {
1068                                         LDAPMessage     *e;
1069
1070                                         if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
1071                                                 /* don't retry any more... */
1072                                                 candidates[ i ].sr_type = REP_RESULT;
1073                                         }
1074
1075                                         is_ok++;
1076
1077                                         e = ldap_first_entry( msc->msc_ld, msg );
1078                                         savepriv = op->o_private;
1079                                         op->o_private = (void *)i;
1080                                         rs->sr_err = meta_send_entry( op, rs, mc, i, e );
1081
1082                                         switch ( rs->sr_err ) {
1083                                         case LDAP_SIZELIMIT_EXCEEDED:
1084                                                 savepriv = op->o_private;
1085                                                 op->o_private = (void *)i;
1086                                                 send_ldap_result( op, rs );
1087                                                 op->o_private = savepriv;
1088                                                 rs->sr_err = LDAP_SUCCESS;
1089                                                 ldap_msgfree( res );
1090                                                 res = NULL;
1091                                                 goto finish;
1092
1093                                         case LDAP_UNAVAILABLE:
1094                                                 rs->sr_err = LDAP_OTHER;
1095                                                 ldap_msgfree( res );
1096                                                 res = NULL;
1097                                                 goto finish;
1098                                         }
1099                                         op->o_private = savepriv;
1100
1101                                         /* don't wait any longer... */
1102                                         gotit = 1;
1103                                         save_tv.tv_sec = 0;
1104                                         save_tv.tv_usec = 0;
1105
1106                                 } else if ( rc == LDAP_RES_SEARCH_REFERENCE ) {
1107                                         char            **references = NULL;
1108                                         int             cnt;
1109
1110                                         if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
1111                                                 /* don't retry any more... */
1112                                                 candidates[ i ].sr_type = REP_RESULT;
1113                                         }
1114         
1115                                         is_ok++;
1116         
1117                                         rc = ldap_parse_reference( msc->msc_ld, msg,
1118                                                         &references, &rs->sr_ctrls, 0 );
1119         
1120                                         if ( rc != LDAP_SUCCESS ) {
1121                                                 continue;
1122                                         }
1123         
1124                                         if ( references == NULL ) {
1125                                                 continue;
1126                                         }
1127
1128 #ifdef ENABLE_REWRITE
1129                                         dc.ctx = "referralDN";
1130 #else /* ! ENABLE_REWRITE */
1131                                         dc.tofrom = 0;
1132                                         dc.normalized = 0;
1133 #endif /* ! ENABLE_REWRITE */
1134
1135                                         /* FIXME: merge all and return at the end */
1136         
1137                                         for ( cnt = 0; references[ cnt ]; cnt++ )
1138                                                 ;
1139         
1140                                         rs->sr_ref = ch_calloc( sizeof( struct berval ), cnt + 1 );
1141         
1142                                         for ( cnt = 0; references[ cnt ]; cnt++ ) {
1143                                                 ber_str2bv( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ] );
1144                                         }
1145                                         BER_BVZERO( &rs->sr_ref[ cnt ] );
1146         
1147                                         ( void )ldap_back_referral_result_rewrite( &dc, rs->sr_ref );
1148
1149                                         if ( rs->sr_ref != NULL && !BER_BVISNULL( &rs->sr_ref[ 0 ] ) ) {
1150                                                 /* ignore return value by now */
1151                                                 savepriv = op->o_private;
1152                                                 op->o_private = (void *)i;
1153                                                 ( void )send_search_reference( op, rs );
1154                                                 op->o_private = savepriv;
1155         
1156                                                 ber_bvarray_free( rs->sr_ref );
1157                                                 rs->sr_ref = NULL;
1158                                         }
1159
1160                                         /* cleanup */
1161                                         if ( references ) {
1162                                                 ber_memvfree( (void **)references );
1163                                         }
1164
1165                                         if ( rs->sr_ctrls ) {
1166                                                 ldap_controls_free( rs->sr_ctrls );
1167                                                 rs->sr_ctrls = NULL;
1168                                         }
1169
1170                                 } else if ( rc == LDAP_RES_SEARCH_RESULT ) {
1171                                         char            buf[ SLAP_TEXT_BUFLEN ];
1172                                         char            **references = NULL;
1173
1174                                         if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
1175                                                 /* don't retry any more... */
1176                                                 candidates[ i ].sr_type = REP_RESULT;
1177                                         }
1178         
1179                                         /* NOTE: ignores response controls
1180                                          * (and intermediate response controls
1181                                          * as well, except for those with search
1182                                          * references); this may not be correct,
1183                                          * but if they're not ignored then
1184                                          * back-meta would need to merge them
1185                                          * consistently (think of pagedResults...)
1186                                          */
1187                                         /* FIXME: response controls? */
1188                                         rs->sr_err = ldap_parse_result( msc->msc_ld,
1189                                                 msg,
1190                                                 &candidates[ i ].sr_err,
1191                                                 (char **)&candidates[ i ].sr_matched,
1192                                                 NULL /* (char **)&candidates[ i ].sr_text */ ,
1193                                                 &references,
1194                                                 NULL /* &candidates[ i ].sr_ctrls (unused) */ ,
1195                                                 0 );
1196                                         if ( rs->sr_err != LDAP_SUCCESS ) {
1197                                                 ldap_get_option( msc->msc_ld,
1198                                                         LDAP_OPT_ERROR_NUMBER,
1199                                                         &rs->sr_err );
1200                                                 sres = slap_map_api2result( rs );
1201                                                 candidates[ i ].sr_type = REP_RESULT;
1202                                                 ldap_msgfree( res );
1203                                                 res = NULL;
1204                                                 goto really_bad;
1205                                         }
1206
1207                                         /* massage matchedDN if need be */
1208                                         if ( candidates[ i ].sr_matched != NULL ) {
1209                                                 struct berval   match, mmatch;
1210
1211                                                 ber_str2bv( candidates[ i ].sr_matched,
1212                                                         0, 0, &match );
1213                                                 candidates[ i ].sr_matched = NULL;
1214
1215                                                 dc.ctx = "matchedDN";
1216                                                 dc.target = mi->mi_targets[ i ];
1217                                                 if ( !ldap_back_dn_massage( &dc, &match, &mmatch ) ) {
1218                                                         if ( mmatch.bv_val == match.bv_val ) {
1219                                                                 candidates[ i ].sr_matched
1220                                                                         = ch_strdup( mmatch.bv_val );
1221
1222                                                         } else {
1223                                                                 candidates[ i ].sr_matched = mmatch.bv_val;
1224                                                         }
1225
1226                                                         candidate_match++;
1227                                                 } 
1228                                                 ldap_memfree( match.bv_val );
1229                                         }
1230
1231                                         /* add references to array */
1232                                         if ( references ) {
1233                                                 BerVarray       sr_ref;
1234                                                 int             cnt;
1235         
1236                                                 for ( cnt = 0; references[ cnt ]; cnt++ )
1237                                                         ;
1238         
1239                                                 sr_ref = ch_calloc( sizeof( struct berval ), cnt + 1 );
1240         
1241                                                 for ( cnt = 0; references[ cnt ]; cnt++ ) {
1242                                                         ber_str2bv( references[ cnt ], 0, 1, &sr_ref[ cnt ] );
1243                                                 }
1244                                                 BER_BVZERO( &sr_ref[ cnt ] );
1245         
1246                                                 ( void )ldap_back_referral_result_rewrite( &dc, sr_ref );
1247                                         
1248                                                 /* cleanup */
1249                                                 ber_memvfree( (void **)references );
1250         
1251                                                 if ( rs->sr_v2ref == NULL ) {
1252                                                         rs->sr_v2ref = sr_ref;
1253
1254                                                 } else {
1255                                                         for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) {
1256                                                                 ber_bvarray_add( &rs->sr_v2ref, &sr_ref[ cnt ] );
1257                                                         }
1258                                                         ber_memfree( sr_ref );
1259                                                 }
1260                                         }
1261         
1262                                         rs->sr_err = candidates[ i ].sr_err;
1263                                         sres = slap_map_api2result( rs );
1264         
1265                                         if ( LogTest( LDAP_DEBUG_TRACE | LDAP_DEBUG_ANY ) ) {
1266                                                 snprintf( buf, sizeof( buf ),
1267                                                         "%s meta_back_search[%ld] "
1268                                                         "match=\"%s\" err=%ld",
1269                                                         op->o_log_prefix, i,
1270                                                         candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
1271                                                         (long) candidates[ i ].sr_err );
1272                                                 if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
1273                                                         Debug( LDAP_DEBUG_TRACE, "%s.\n", buf, 0, 0 );
1274         
1275                                                 } else {
1276                                                         Debug( LDAP_DEBUG_ANY, "%s (%s).\n",
1277                                                                 buf, ldap_err2string( candidates[ i ].sr_err ), 0 );
1278                                                 }
1279                                         }
1280         
1281                                         switch ( sres ) {
1282                                         case LDAP_NO_SUCH_OBJECT:
1283                                                 /* is_ok is touched any time a valid
1284                                                  * (even intermediate) result is
1285                                                  * returned; as a consequence, if
1286                                                  * a candidate returns noSuchObject
1287                                                  * it is ignored and the candidate
1288                                                  * is simply demoted. */
1289                                                 if ( is_ok ) {
1290                                                         sres = LDAP_SUCCESS;
1291                                                 }
1292                                                 break;
1293         
1294                                         case LDAP_SUCCESS:
1295                                         case LDAP_REFERRAL:
1296                                                 is_ok++;
1297                                                 break;
1298         
1299                                         case LDAP_SIZELIMIT_EXCEEDED:
1300                                                 /* if a target returned sizelimitExceeded
1301                                                  * and the entry count is equal to the
1302                                                  * proxy's limit, the target would have
1303                                                  * returned more, and the error must be
1304                                                  * propagated to the client; otherwise,
1305                                                  * the target enforced a limit lower
1306                                                  * than what requested by the proxy;
1307                                                  * ignore it */
1308                                                 candidates[ i ].sr_err = rs->sr_err;
1309                                                 if ( rs->sr_nentries == op->ors_slimit
1310                                                         || META_BACK_ONERR_STOP( mi ) )
1311                                                 {
1312                                                         savepriv = op->o_private;
1313                                                         op->o_private = (void *)i;
1314                                                         send_ldap_result( op, rs );
1315                                                         op->o_private = savepriv;
1316                                                         ldap_msgfree( res );
1317                                                         res = NULL;
1318                                                         goto finish;
1319                                                 }
1320                                                 break;
1321         
1322                                         default:
1323                                                 candidates[ i ].sr_err = rs->sr_err;
1324                                                 if ( META_BACK_ONERR_STOP( mi ) ) {
1325                                                         savepriv = op->o_private;
1326                                                         op->o_private = (void *)i;
1327                                                         send_ldap_result( op, rs );
1328                                                         op->o_private = savepriv;
1329                                                         ldap_msgfree( res );
1330                                                         res = NULL;
1331                                                         goto finish;
1332                                                 }
1333                                                 break;
1334                                         }
1335         
1336                                         last = i;
1337                                         rc = 0;
1338         
1339                                         /*
1340                                          * When no candidates are left,
1341                                          * the outer cycle finishes
1342                                          */
1343                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1344                                         --ncandidates;
1345         
1346                                 } else if ( rc == LDAP_RES_BIND ) {
1347                                         meta_search_candidate_t retcode;
1348         
1349                                         retcode = meta_search_dobind_result( op, rs, &mc, i, candidates, msg );
1350                                         if ( retcode == META_SEARCH_CANDIDATE ) {
1351                                                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1352                                                 retcode = meta_back_search_start( op, rs, &dc, &mc, i, candidates );
1353                                         }
1354         
1355                                         switch ( retcode ) {
1356                                         case META_SEARCH_CANDIDATE:
1357                                                 break;
1358         
1359                                                 /* means that failed but onerr == continue */
1360                                         case META_SEARCH_NOT_CANDIDATE:
1361                                         case META_SEARCH_ERR:
1362                                                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1363                                                 --ncandidates;
1364         
1365                                                 candidates[ i ].sr_err = rs->sr_err;
1366                                                 if ( META_BACK_ONERR_STOP( mi ) ) {
1367                                                         savepriv = op->o_private;
1368                                                         op->o_private = (void *)i;
1369                                                         send_ldap_result( op, rs );
1370                                                         op->o_private = savepriv;
1371                                                         ldap_msgfree( res );
1372                                                         res = NULL;
1373                                                         goto finish;
1374                                                 }
1375                                                 break;
1376         
1377                                         default:
1378                                                 assert( 0 );
1379                                                 break;
1380                                         }
1381         
1382                                 } else {
1383                                         assert( 0 );
1384                                         ldap_msgfree( res );
1385                                         res = NULL;
1386                                         goto really_bad;
1387                                 }
1388                         }
1389
1390                         ldap_msgfree( res );
1391                         res = NULL;
1392                 }
1393
1394                 /* check for abandon */
1395                 if ( op->o_abandon || doabandon ) {
1396                         for ( i = 0; i < mi->mi_ntargets; i++ ) {
1397                                 if ( candidates[ i ].sr_msgid >= 0 ) {
1398                                         if ( META_IS_BINDING( &candidates[ i ] ) ) {
1399                                                 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
1400                                                 if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ) {
1401                                                         /* if still binding, destroy */
1402
1403 #ifdef DEBUG_205
1404                                                         char buf[ SLAP_TEXT_BUFLEN ];
1405
1406                                                         snprintf( buf, sizeof( buf), "%s meta_back_search(abandon) "
1407                                                                 "ldap_unbind_ext[%ld] mc=%p ld=%p",
1408                                                                 op->o_log_prefix, i, (void *)mc,
1409                                                                 (void *)mc->mc_conns[i].msc_ld );
1410
1411                                                         Debug( LDAP_DEBUG_ANY, "### %s\n", buf, 0, 0 );
1412 #endif /* DEBUG_205 */
1413
1414                                                         meta_clear_one_candidate( op, mc, i );
1415                                                 }
1416                                                 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1417                                                 META_BINDING_CLEAR( &candidates[ i ] );
1418                                                 
1419                                         } else {
1420                                                 (void)meta_back_cancel( mc, op, rs,
1421                                                         candidates[ i ].sr_msgid, i,
1422                                                         LDAP_BACK_DONTSEND );
1423                                         }
1424
1425                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1426                                         assert( ncandidates > 0 );
1427                                         --ncandidates;
1428                                 }
1429                         }
1430
1431                         if ( op->o_abandon ) {
1432                                 rc = SLAPD_ABANDON;
1433                                 /* let send_ldap_result play cleanup handlers (ITS#4645) */
1434                                 break;
1435                         }
1436                 }
1437
1438                 /* if no entry was found during this loop,
1439                  * set a minimal timeout */
1440                 if ( ncandidates > 0 && gotit == 0 ) {
1441                         if ( save_tv.tv_sec == 0 && save_tv.tv_usec == 0 ) {
1442                                 save_tv.tv_usec = LDAP_BACK_RESULT_UTIMEOUT/initial_candidates;
1443
1444                                 /* arbitrarily limit to something between 1 and 2 minutes */
1445                         } else if ( ( stoptime == -1 && save_tv.tv_sec < 60 )
1446                                 || save_tv.tv_sec < ( stoptime - slap_get_time() ) / ( 2 * ncandidates ) )
1447                         {
1448                                 /* double the timeout */
1449                                 lutil_timermul( &save_tv, 2, &save_tv );
1450                         }
1451
1452 #if 0
1453                         if ( LogTest( LDAP_DEBUG_TRACE ) ) {
1454                                 char    buf[ SLAP_TEXT_BUFLEN ];
1455
1456                                 snprintf( buf, sizeof( buf ), "%s %ld.%06ld %d/%d mc=%p",
1457                                         op->o_log_prefix, save_tv.tv_sec, save_tv.tv_usec,
1458                                         ncandidates, initial_candidates, mc );
1459                                 Debug( LDAP_DEBUG_TRACE, "### %s\n", buf, 0, 0 );
1460                                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
1461                                         if ( candidates[ i ].sr_msgid == META_MSGID_IGNORE ) {
1462                                                 continue;
1463                                         }
1464                         
1465                                         snprintf( buf, sizeof( buf ), "[%ld] ld=%p%s%s\n",
1466                                                 i,
1467                                                 mc->mc_conns[ i ].msc_ld,
1468                                                 ( candidates[ i ].sr_msgid == META_MSGID_NEED_BIND ) ?  " needbind" : "",
1469                                                 META_IS_BINDING( &candidates[ i ] ) ? " binding" : "" );
1470                                         Debug( LDAP_DEBUG_TRACE, "###    %s\n", buf, 0, 0 );
1471                                 }
1472                         }
1473 #endif
1474
1475                         if ( alreadybound == 0 ) {
1476 #if 0
1477                                 Debug( LDAP_DEBUG_TRACE, "### %s select(%ld.%06ld)\n",
1478                                         op->o_log_prefix, save_tv.tv_sec, save_tv.tv_usec );
1479 #endif
1480                                 tv = save_tv;
1481                                 (void)select( 0, NULL, NULL, NULL, &tv );
1482
1483                         } else {
1484                                 ldap_pvt_thread_yield();
1485                         }
1486                 }
1487         }
1488
1489         if ( rc == -1 ) {
1490                 /*
1491                  * FIXME: need a better strategy to handle errors
1492                  */
1493                 if ( mc ) {
1494                         rc = meta_back_op_result( mc, op, rs, META_TARGET_NONE,
1495                                 -1, stoptime != -1 ? (stoptime - slap_get_time()) : 0,
1496                                 LDAP_BACK_SENDERR );
1497                 } else {
1498                         rc = rs->sr_err;
1499                 }
1500                 goto finish;
1501         }
1502
1503         /*
1504          * Rewrite the matched portion of the search base, if required
1505          * 
1506          * FIXME: only the last one gets caught!
1507          */
1508         savepriv = op->o_private;
1509         op->o_private = (void *)(long)mi->mi_ntargets;
1510         if ( candidate_match > 0 ) {
1511                 struct berval   pmatched = BER_BVNULL;
1512
1513                 /* we use the first one */
1514                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
1515                         if ( META_IS_CANDIDATE( &candidates[ i ] )
1516                                         && candidates[ i ].sr_matched != NULL )
1517                         {
1518                                 struct berval   bv, pbv;
1519                                 int             rc;
1520
1521                                 /* if we got success, and this target
1522                                  * returned noSuchObject, and its suffix
1523                                  * is a superior of the searchBase,
1524                                  * ignore the matchedDN */
1525                                 if ( sres == LDAP_SUCCESS
1526                                         && candidates[ i ].sr_err == LDAP_NO_SUCH_OBJECT
1527                                         && op->o_req_ndn.bv_len > mi->mi_targets[ i ]->mt_nsuffix.bv_len )
1528                                 {
1529                                         free( (char *)candidates[ i ].sr_matched );
1530                                         candidates[ i ].sr_matched = NULL;
1531                                         continue;
1532                                 }
1533
1534                                 ber_str2bv( candidates[ i ].sr_matched, 0, 0, &bv );
1535                                 rc = dnPretty( NULL, &bv, &pbv, op->o_tmpmemctx );
1536
1537                                 if ( rc == LDAP_SUCCESS ) {
1538
1539                                         /* NOTE: if they all are superiors
1540                                          * of the baseDN, the shorter is also 
1541                                          * superior of the longer... */
1542                                         if ( pbv.bv_len > pmatched.bv_len ) {
1543                                                 if ( !BER_BVISNULL( &pmatched ) ) {
1544                                                         op->o_tmpfree( pmatched.bv_val, op->o_tmpmemctx );
1545                                                 }
1546                                                 pmatched = pbv;
1547                                                 op->o_private = (void *)i;
1548
1549                                         } else {
1550                                                 op->o_tmpfree( pbv.bv_val, op->o_tmpmemctx );
1551                                         }
1552                                 }
1553
1554                                 if ( candidates[ i ].sr_matched != NULL ) {
1555                                         free( (char *)candidates[ i ].sr_matched );
1556                                         candidates[ i ].sr_matched = NULL;
1557                                 }
1558                         }
1559                 }
1560
1561                 if ( !BER_BVISNULL( &pmatched ) ) {
1562                         matched = pmatched.bv_val;
1563                 }
1564
1565         } else if ( sres == LDAP_NO_SUCH_OBJECT ) {
1566                 matched = op->o_bd->be_suffix[ 0 ].bv_val;
1567         }
1568
1569 #if 0
1570         {
1571                 char    buf[ SLAP_TEXT_BUFLEN ];
1572                 char    cnd[ SLAP_TEXT_BUFLEN ];
1573                 int     i;
1574
1575                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
1576                         if ( META_IS_CANDIDATE( &candidates[ i ] ) ) {
1577                                 cnd[ i ] = '*';
1578                         } else {
1579                                 cnd[ i ] = ' ';
1580                         }
1581                 }
1582                 cnd[ i ] = '\0';
1583
1584                 snprintf( buf, sizeof( buf ), "%s meta_back_search: is_scope=%d is_ok=%d cnd=\"%s\"\n",
1585                         op->o_log_prefix, initial_candidates, is_ok, cnd );
1586
1587                 Debug( LDAP_DEBUG_ANY, "%s", buf, 0, 0 );
1588         }
1589 #endif
1590
1591         /*
1592          * In case we returned at least one entry, we return LDAP_SUCCESS
1593          * otherwise, the latter error code we got
1594          */
1595
1596         if ( sres == LDAP_SUCCESS ) {
1597                 if ( rs->sr_v2ref ) {
1598                         sres = LDAP_REFERRAL;
1599                 }
1600
1601                 if ( META_BACK_ONERR_REPORT( mi ) ) {
1602                         /*
1603                          * Report errors, if any
1604                          *
1605                          * FIXME: we should handle error codes and return the more 
1606                          * important/reasonable
1607                          */
1608                         for ( i = 0; i < mi->mi_ntargets; i++ ) {
1609                                 if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
1610                                         continue;
1611                                 }
1612
1613                                 if ( candidates[ i ].sr_err != LDAP_SUCCESS
1614                                         && candidates[ i ].sr_err != LDAP_NO_SUCH_OBJECT )
1615                                 {
1616                                         sres = candidates[ i ].sr_err;
1617                                         break;
1618                                 }
1619                         }
1620                 }
1621         }
1622
1623         rs->sr_err = sres;
1624         rs->sr_matched = matched;
1625         rs->sr_ref = ( sres == LDAP_REFERRAL ? rs->sr_v2ref : NULL );
1626         send_ldap_result( op, rs );
1627         op->o_private = savepriv;
1628         rs->sr_matched = NULL;
1629         rs->sr_ref = NULL;
1630
1631 finish:;
1632         if ( matched && matched != op->o_bd->be_suffix[ 0 ].bv_val ) {
1633                 op->o_tmpfree( matched, op->o_tmpmemctx );
1634         }
1635
1636         if ( rs->sr_v2ref ) {
1637                 ber_bvarray_free( rs->sr_v2ref );
1638         }
1639
1640         for ( i = 0; i < mi->mi_ntargets; i++ ) {
1641                 if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
1642                         continue;
1643                 }
1644
1645                 if ( mc && META_IS_BINDING( &candidates[ i ] ) ) {
1646                         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
1647                         if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ) {
1648                                 assert( candidates[ i ].sr_msgid >= 0 );
1649                                 assert( mc->mc_conns[ i ].msc_ld != NULL );
1650
1651 #ifdef DEBUG_205
1652                                 Debug( LDAP_DEBUG_ANY, "### %s meta_back_search(cleanup) "
1653                                         "ldap_unbind_ext[%ld] ld=%p\n",
1654                                         op->o_log_prefix, i, (void *)mc->mc_conns[i].msc_ld );
1655 #endif /* DEBUG_205 */
1656
1657                                 /* if still binding, destroy */
1658                                 meta_clear_one_candidate( op, mc, i );
1659                         }
1660                         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1661                         META_BINDING_CLEAR( &candidates[ i ] );
1662                 }
1663
1664                 if ( candidates[ i ].sr_matched ) {
1665                         free( (char *)candidates[ i ].sr_matched );
1666                         candidates[ i ].sr_matched = NULL;
1667                 }
1668
1669                 if ( candidates[ i ].sr_text ) {
1670                         ldap_memfree( (char *)candidates[ i ].sr_text );
1671                         candidates[ i ].sr_text = NULL;
1672                 }
1673
1674                 if ( candidates[ i ].sr_ref ) {
1675                         ber_bvarray_free( candidates[ i ].sr_ref );
1676                         candidates[ i ].sr_ref = NULL;
1677                 }
1678
1679                 if ( candidates[ i ].sr_ctrls ) {
1680                         ldap_controls_free( candidates[ i ].sr_ctrls );
1681                         candidates[ i ].sr_ctrls = NULL;
1682                 }
1683
1684                 if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) {
1685                         meta_back_quarantine( op, &candidates[ i ], i );
1686                 }
1687
1688                 /* only in case of timelimit exceeded, if the timelimit exceeded because
1689                  * one contacted target never responded, invalidate the connection
1690                  * NOTE: should we quarantine the target as well?  right now, the connection
1691                  * is invalidated; the next time it will be recreated and the target
1692                  * will be quarantined if it cannot be contacted */
1693                 if ( mi->mi_idle_timeout != 0
1694                         && rs->sr_err == LDAP_TIMELIMIT_EXCEEDED
1695                         && op->o_time > mc->mc_conns[ i ].msc_time )
1696                 {
1697                         /* don't let anyone else use this expired connection */
1698                         LDAP_BACK_CONN_TAINTED_SET( mc );
1699                 }
1700         }
1701
1702         if ( mc ) {
1703                 meta_back_release_conn( op, mc );
1704         }
1705
1706         return rs->sr_err;
1707 }
1708
1709 static int
1710 meta_send_entry(
1711         Operation       *op,
1712         SlapReply       *rs,
1713         metaconn_t      *mc,
1714         int             target,
1715         LDAPMessage     *e )
1716 {
1717         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
1718         struct berval           a, mapped;
1719         Entry                   ent = { 0 };
1720         BerElement              ber = *e->lm_ber;
1721         Attribute               *attr, **attrp;
1722         struct berval           bdn,
1723                                 dn = BER_BVNULL;
1724         const char              *text;
1725         dncookie                dc;
1726         int                     rc;
1727
1728         if ( ber_scanf( &ber, "{m{", &bdn ) == LBER_ERROR ) {
1729                 return LDAP_DECODING_ERROR;
1730         }
1731
1732         /*
1733          * Rewrite the dn of the result, if needed
1734          */
1735         dc.target = mi->mi_targets[ target ];
1736         dc.conn = op->o_conn;
1737         dc.rs = rs;
1738         dc.ctx = "searchResult";
1739
1740         rs->sr_err = ldap_back_dn_massage( &dc, &bdn, &dn );
1741         if ( rs->sr_err != LDAP_SUCCESS) {
1742                 return rs->sr_err;
1743         }
1744
1745         /*
1746          * Note: this may fail if the target host(s) schema differs
1747          * from the one known to the meta, and a DN with unknown
1748          * attributes is returned.
1749          * 
1750          * FIXME: should we log anything, or delegate to dnNormalize?
1751          */
1752         rc = dnPrettyNormal( NULL, &dn, &ent.e_name, &ent.e_nname,
1753                 op->o_tmpmemctx );
1754         if ( dn.bv_val != bdn.bv_val ) {
1755                 free( dn.bv_val );
1756         }
1757         BER_BVZERO( &dn );
1758
1759         if ( rc != LDAP_SUCCESS ) {
1760                 return LDAP_INVALID_DN_SYNTAX;
1761         }
1762
1763         /*
1764          * cache dn
1765          */
1766         if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) {
1767                 ( void )meta_dncache_update_entry( &mi->mi_cache,
1768                                 &ent.e_nname, target );
1769         }
1770
1771         attrp = &ent.e_attrs;
1772
1773         dc.ctx = "searchAttrDN";
1774         while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
1775                 int                             last = 0;
1776                 slap_syntax_validate_func       *validate;
1777                 slap_syntax_transform_func      *pretty;
1778
1779                 ldap_back_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_at, 
1780                                 &a, &mapped, BACKLDAP_REMAP );
1781                 if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) {
1782                         ( void )ber_scanf( &ber, "x" /* [W] */ );
1783                         continue;
1784                 }
1785                 attr = attr_alloc( NULL );
1786                 if ( attr == NULL ) {
1787                         continue;
1788                 }
1789                 if ( slap_bv2ad( &mapped, &attr->a_desc, &text )
1790                                 != LDAP_SUCCESS) {
1791                         if ( slap_bv2undef_ad( &mapped, &attr->a_desc, &text,
1792                                 SLAP_AD_PROXIED ) != LDAP_SUCCESS )
1793                         {
1794                                 char    buf[ SLAP_TEXT_BUFLEN ];
1795
1796                                 snprintf( buf, sizeof( buf ),
1797                                         "%s meta_send_entry(\"%s\"): "
1798                                         "slap_bv2undef_ad(%s): %s\n",
1799                                         op->o_log_prefix, ent.e_name.bv_val,
1800                                         mapped.bv_val, text );
1801
1802                                 Debug( LDAP_DEBUG_ANY, "%s", buf, 0, 0 );
1803                                 attr_free( attr );
1804                                 continue;
1805                         }
1806                 }
1807
1808                 /* no subschemaSubentry */
1809                 if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry
1810                         || attr->a_desc == slap_schema.si_ad_entryDN )
1811                 {
1812
1813                         /* 
1814                          * We eat target's subschemaSubentry because
1815                          * a search for this value is likely not
1816                          * to resolve to the appropriate backend;
1817                          * later, the local subschemaSubentry is
1818                          * added.
1819                          *
1820                          * We also eat entryDN because the frontend
1821                          * will reattach it without checking if already
1822                          * present...
1823                          */
1824                         ( void )ber_scanf( &ber, "x" /* [W] */ );
1825
1826                         attr_free(attr);
1827                         continue;
1828                 }
1829
1830                 if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR 
1831                                 || attr->a_vals == NULL )
1832                 {
1833                         attr->a_vals = (struct berval *)&slap_dummy_bv;
1834
1835                 } else {
1836                         for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); ++last )
1837                                 ;
1838                 }
1839
1840                 validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate;
1841                 pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty;
1842
1843                 if ( !validate && !pretty ) {
1844                         attr_free( attr );
1845                         goto next_attr;
1846                 }
1847
1848                 if ( attr->a_desc == slap_schema.si_ad_objectClass
1849                                 || attr->a_desc == slap_schema.si_ad_structuralObjectClass )
1850                 {
1851                         struct berval   *bv;
1852
1853                         for ( bv = attr->a_vals; !BER_BVISNULL( bv ); bv++ ) {
1854                                 ldap_back_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_oc,
1855                                                 bv, &mapped, BACKLDAP_REMAP );
1856                                 if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0') {
1857                                         free( bv->bv_val );
1858                                         BER_BVZERO( bv );
1859                                         if ( --last < 0 ) {
1860                                                 break;
1861                                         }
1862                                         *bv = attr->a_vals[ last ];
1863                                         BER_BVZERO( &attr->a_vals[ last ] );
1864                                         bv--;
1865
1866                                 } else if ( mapped.bv_val != bv->bv_val ) {
1867                                         free( bv->bv_val );
1868                                         ber_dupbv( bv, &mapped );
1869                                 }
1870                         }
1871                 /*
1872                  * It is necessary to try to rewrite attributes with
1873                  * dn syntax because they might be used in ACLs as
1874                  * members of groups; since ACLs are applied to the
1875                  * rewritten stuff, no dn-based subecj clause could
1876                  * be used at the ldap backend side (see
1877                  * http://www.OpenLDAP.org/faq/data/cache/452.html)
1878                  * The problem can be overcome by moving the dn-based
1879                  * ACLs to the target directory server, and letting
1880                  * everything pass thru the ldap backend.
1881                  */
1882                 } else {
1883                         int     i;
1884
1885                         if ( attr->a_desc->ad_type->sat_syntax ==
1886                                 slap_schema.si_syn_distinguishedName )
1887                         {
1888                                 ldap_dnattr_result_rewrite( &dc, attr->a_vals );
1889
1890                         } else if ( attr->a_desc == slap_schema.si_ad_ref ) {
1891                                 ldap_back_referral_result_rewrite( &dc, attr->a_vals );
1892
1893                         }
1894
1895                         for ( i = 0; i < last; i++ ) {
1896                                 struct berval   pval;
1897                                 int             rc;
1898
1899                                 if ( pretty ) {
1900                                         rc = pretty( attr->a_desc->ad_type->sat_syntax,
1901                                                 &attr->a_vals[i], &pval, NULL );
1902
1903                                 } else {
1904                                         rc = validate( attr->a_desc->ad_type->sat_syntax,
1905                                                 &attr->a_vals[i] );
1906                                 }
1907
1908                                 if ( rc ) {
1909                                         LBER_FREE( attr->a_vals[i].bv_val );
1910                                         if ( --last == i ) {
1911                                                 BER_BVZERO( &attr->a_vals[ i ] );
1912                                                 break;
1913                                         }
1914                                         attr->a_vals[i] = attr->a_vals[last];
1915                                         BER_BVZERO( &attr->a_vals[last] );
1916                                         i--;
1917                                         continue;
1918                                 }
1919
1920                                 if ( pretty ) {
1921                                         LBER_FREE( attr->a_vals[i].bv_val );
1922                                         attr->a_vals[i] = pval;
1923                                 }
1924                         }
1925
1926                         if ( last == 0 && attr->a_vals != &slap_dummy_bv ) {
1927                                 attr_free( attr );
1928                                 goto next_attr;
1929                         }
1930                 }
1931
1932                 if ( last && attr->a_desc->ad_type->sat_equality &&
1933                         attr->a_desc->ad_type->sat_equality->smr_normalize )
1934                 {
1935                         int i;
1936
1937                         attr->a_nvals = ch_malloc( ( last + 1 ) * sizeof( struct berval ) );
1938                         for ( i = 0; i<last; i++ ) {
1939                                 attr->a_desc->ad_type->sat_equality->smr_normalize(
1940                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
1941                                         attr->a_desc->ad_type->sat_syntax,
1942                                         attr->a_desc->ad_type->sat_equality,
1943                                         &attr->a_vals[i], &attr->a_nvals[i],
1944                                         NULL );
1945                         }
1946                         BER_BVZERO( &attr->a_nvals[i] );
1947
1948                 } else {
1949                         attr->a_nvals = attr->a_vals;
1950                 }
1951
1952                 *attrp = attr;
1953                 attrp = &attr->a_next;
1954 next_attr:;
1955         }
1956         rs->sr_entry = &ent;
1957         rs->sr_attrs = op->ors_attrs;
1958         rs->sr_flags = 0;
1959         rs->sr_err = LDAP_SUCCESS;
1960         rc = send_search_entry( op, rs );
1961         switch ( rc ) {
1962         case LDAP_UNAVAILABLE:
1963                 rc = LDAP_OTHER;
1964                 break;
1965         }
1966         rs->sr_entry = NULL;
1967         rs->sr_attrs = NULL;
1968         
1969         if ( !BER_BVISNULL( &ent.e_name ) ) {
1970                 free( ent.e_name.bv_val );
1971                 BER_BVZERO( &ent.e_name );
1972         }
1973         if ( !BER_BVISNULL( &ent.e_nname ) ) {
1974                 free( ent.e_nname.bv_val );
1975                 BER_BVZERO( &ent.e_nname );
1976         }
1977         entry_clean( &ent );
1978
1979         return rc;
1980 }
1981