1 /*        $NetBSD: search.c,v 1.3 2021/08/14 16:15:00 christos Exp $  */
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1999-2021 The OpenLDAP Foundation.
7  * Portions Copyright 2001-2003 Pierangelo Masarati.
8  * Portions Copyright 1999-2003 Howard Chu.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted only as authorized by the OpenLDAP
13  * Public License.
14  *
15  * A copy of this license is available in the file LICENSE in the
16  * top-level directory of the distribution or, alternatively, at
17  * <http://www.OpenLDAP.org/license.html>.
18  */
19 /* ACKNOWLEDGEMENTS:
20  * This work was initially developed by the Howard Chu for inclusion
21  * in OpenLDAP Software and subsequently enhanced by Pierangelo
22  * Masarati.
23  */
24 
25 #include <sys/cdefs.h>
26 __RCSID("$NetBSD: search.c,v 1.3 2021/08/14 16:15:00 christos Exp $");
27 
28 #include "portable.h"
29 
30 #include <stdio.h>
31 
32 #include <ac/socket.h>
33 #include <ac/string.h>
34 #include <ac/time.h>
35 
36 #include "lutil.h"
37 #include "slap.h"
38 #include "../back-ldap/back-ldap.h"
39 #include "back-meta.h"
40 #include "../../../libraries/liblber/lber-int.h"
41 
42 /* IGNORE means that target does not (no longer) participate
43  * in the search;
44  * NOTREADY means the search on that target has not been initialized yet
45  */
46 #define   META_MSGID_IGNORE   (-1)
47 #define   META_MSGID_NEED_BIND          (-2)
48 #define   META_MSGID_CONNECTING         (-3)
49 
50 static int
51 meta_send_entry(
52           Operation           *op,
53           SlapReply *rs,
54           metaconn_t          *mc,
55           int                 i,
56           LDAPMessage         *e );
57 
58 typedef enum meta_search_candidate_t {
59           META_SEARCH_UNDEFINED = -2,
60           META_SEARCH_ERR = -1,
61           META_SEARCH_NOT_CANDIDATE,
62           META_SEARCH_CANDIDATE,
63           META_SEARCH_BINDING,
64           META_SEARCH_NEED_BIND,
65           META_SEARCH_CONNECTING
66 } meta_search_candidate_t;
67 
68 /*
69  * meta_search_dobind_init()
70  *
71  * initiates bind for a candidate target of a search.
72  */
73 static meta_search_candidate_t
meta_search_dobind_init(Operation * op,SlapReply * rs,metaconn_t ** mcp,int candidate,SlapReply * candidates)74 meta_search_dobind_init(
75           Operation           *op,
76           SlapReply           *rs,
77           metaconn_t                    **mcp,
78           int                           candidate,
79           SlapReply           *candidates )
80 {
81           metaconn_t                    *mc = *mcp;
82           metainfo_t                    *mi = ( metainfo_t * )op->o_bd->be_private;
83           metatarget_t                  *mt = mi->mi_targets[ candidate ];
84           metasingleconn_t    *msc = &mc->mc_conns[ candidate ];
85 
86           struct berval                 binddn = msc->msc_bound_ndn,
87                                         cred = msc->msc_cred;
88           int                           method;
89 
90           int                           rc;
91 
92           meta_search_candidate_t       retcode;
93 
94           Debug( LDAP_DEBUG_TRACE, "%s >>> meta_search_dobind_init[%d]\n",
95                     op->o_log_prefix, candidate );
96 
97           /*
98            * all the targets are already bound as pseudoroot
99            */
100           if ( mc->mc_authz_target == META_BOUND_ALL ) {
101                     return META_SEARCH_CANDIDATE;
102           }
103 
104           retcode = META_SEARCH_BINDING;
105           ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
106           if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
107                     /* already bound (or anonymous) */
108 
109 #ifdef DEBUG_205
110                     int       bound = 0;
111 
112                     if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
113                               bound = 1;
114                     }
115 
116                     Debug(LDAP_DEBUG_ANY,
117                           "### %s meta_search_dobind_init[%d] mc=%p ld=%p%s DN=\"%s\"\n",
118                           op->o_log_prefix, candidate, (void *)mc,
119                           (void *)msc->msc_ld, bound ? " bound" : " anonymous",
120                           bound == 0 ? "" : msc->msc_bound_ndn.bv_val );
121 #endif /* DEBUG_205 */
122 
123                     retcode = META_SEARCH_CANDIDATE;
124 
125           } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) ) {
126                     /* another thread is binding the target for this conn; wait */
127 
128 #ifdef DEBUG_205
129                     Debug(LDAP_DEBUG_ANY,
130                           "### %s meta_search_dobind_init[%d] mc=%p ld=%p needbind\n",
131                           op->o_log_prefix, candidate, (void *)mc,
132                           (void *)msc->msc_ld );
133 #endif /* DEBUG_205 */
134 
135                     candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND;
136                     retcode = META_SEARCH_NEED_BIND;
137 
138           } else {
139                     /* we'll need to bind the target for this conn */
140 
141 #ifdef DEBUG_205
142                     Debug(LDAP_DEBUG_ANY,
143                           "### %s meta_search_dobind_init[%d] mc=%p ld=%p binding\n",
144                           op->o_log_prefix, candidate, (void *)mc,
145                           (void *)msc->msc_ld );
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                     switch ( rc ) {
192                     case LDAP_SUCCESS:
193                               break;
194                     case LDAP_UNAVAILABLE:
195                               goto down;
196                     default:
197                               goto other;
198                     }
199 
200                     /* NOTE: we copy things here, even if bind didn't succeed yet,
201                      * because the connection is not shared until bind is over */
202                     if ( !BER_BVISNULL( &binddn ) ) {
203                               ber_bvreplace( &msc->msc_bound_ndn, &binddn );
204                               if ( META_BACK_TGT_SAVECRED( mt ) && !BER_BVISNULL( &cred ) ) {
205                                         if ( !BER_BVISNULL( &msc->msc_cred ) ) {
206                                                   memset( msc->msc_cred.bv_val, 0,
207                                                             msc->msc_cred.bv_len );
208                                         }
209                                         ber_bvreplace( &msc->msc_cred, &cred );
210                               }
211                     }
212 
213                     if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
214                               /* apparently, idassert was configured with SASL bind,
215                                * so bind occurred inside meta_back_proxy_authz_cred() */
216                               ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
217                               LDAP_BACK_CONN_BINDING_CLEAR( msc );
218                               ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
219                               return META_SEARCH_CANDIDATE;
220                     }
221 
222                     /* paranoid */
223                     switch ( method ) {
224                     case LDAP_AUTH_NONE:
225                     case LDAP_AUTH_SIMPLE:
226                               /* do a simple bind with binddn, cred */
227                               break;
228 
229                     default:
230                               assert( 0 );
231                               break;
232                     }
233           }
234 
235           assert( msc->msc_ld != NULL );
236 
237           /* connect must be async only the first time... */
238           ldap_set_option( msc->msc_ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_ON );
239 
240 retry:;
241           if ( !BER_BVISEMPTY( &binddn ) && BER_BVISEMPTY( &cred ) ) {
242                     /* bind anonymously? */
243                     Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p: "
244                               "non-empty dn with empty cred; binding anonymously\n",
245                               op->o_log_prefix, candidate, (void *)mc );
246                     cred = slap_empty_bv;
247 
248           } else if ( BER_BVISEMPTY( &binddn ) && !BER_BVISEMPTY( &cred ) ) {
249                     /* error */
250                     Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p: "
251                               "empty dn with non-empty cred: error\n",
252                               op->o_log_prefix, candidate, (void *)mc );
253                     rc = LDAP_OTHER;
254                     goto other;
255           }
256 
257           rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred,
258                               NULL, NULL, &candidates[ candidate ].sr_msgid );
259 
260 #ifdef DEBUG_205
261           Debug(LDAP_DEBUG_ANY,
262                 "### %s meta_search_dobind_init[%d] mc=%p ld=%p rc=%d\n",
263                 op->o_log_prefix, candidate, (void *)mc,
264                 (void *)mc->mc_conns[candidate].msc_ld, rc );
265 #endif /* DEBUG_205 */
266 
267           switch ( rc ) {
268           case LDAP_SUCCESS:
269                     assert( candidates[ candidate ].sr_msgid >= 0 );
270                     META_BINDING_SET( &candidates[ candidate ] );
271                     return META_SEARCH_BINDING;
272 
273           case LDAP_X_CONNECTING:
274                     /* must retry, same conn */
275                     candidates[ candidate ].sr_msgid = META_MSGID_CONNECTING;
276                     ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
277                     LDAP_BACK_CONN_BINDING_CLEAR( msc );
278                     ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
279                     return META_SEARCH_CONNECTING;
280 
281           case LDAP_SERVER_DOWN:
282 down:;
283                     /* This is the worst thing that could happen:
284                      * the search will wait until the retry is over. */
285                     if ( !META_IS_RETRYING( &candidates[ candidate ] ) ) {
286                               META_RETRYING_SET( &candidates[ candidate ] );
287 
288                               ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
289 
290                               assert( mc->mc_refcnt > 0 );
291                               if ( LogTest( LDAP_DEBUG_ANY ) ) {
292                                         /* this lock is required; however,
293                                          * it's invoked only when logging is on */
294                                         ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
295                                         Debug(LDAP_DEBUG_ANY,
296                                               "%s meta_search_dobind_init[%d]: retrying URI=\"%s\" DN=\"%s\".\n",
297                                               op->o_log_prefix, candidate, mt->mt_uri,
298                                               BER_BVISNULL(&msc->msc_bound_ndn) ? "" : msc->msc_bound_ndn.bv_val );
299                                         ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
300                               }
301 
302                               meta_clear_one_candidate( op, mc, candidate );
303                               LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
304 
305                               ( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn );
306 
307                               /* mc here must be the regular mc, reset and ready for init */
308                               rc = meta_back_init_one_conn( op, rs, mc, candidate,
309                                         LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 );
310 
311                               if ( rc == LDAP_SUCCESS ) {
312                                         LDAP_BACK_CONN_BINDING_SET( msc );
313                               }
314 
315                               ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
316 
317                               if ( rc == LDAP_SUCCESS ) {
318                                         candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
319                                         binddn = msc->msc_bound_ndn;
320                                         cred = msc->msc_cred;
321                                         goto retry;
322                               }
323                     }
324 
325                     if ( *mcp == NULL ) {
326                               retcode = META_SEARCH_ERR;
327                               rc = LDAP_UNAVAILABLE;
328                               candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
329                               break;
330                     }
331                     /* fall thru */
332 
333           default:
334 other:;
335                     /* convert rc to the correct LDAP error and send it back to the client:
336                        assign the error to rs, so we can use it as argument to slap_map_api2result
337                        and then assign the output back to rs->sr_err */
338                     rs->sr_err = rc;
339                     rs->sr_err = slap_map_api2result( rs );
340 
341                     ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
342                     meta_clear_one_candidate( op, mc, candidate );
343                     candidates[ candidate ].sr_err = rs->sr_err;
344                     if ( META_BACK_ONERR_STOP( mi ) ) {
345                               LDAP_BACK_CONN_TAINTED_SET( mc );
346                               meta_back_release_conn_lock( mi, mc, 0 );
347                               *mcp = NULL;
348 
349                               retcode = META_SEARCH_ERR;
350 
351                     } else {
352                               retcode = META_SEARCH_NOT_CANDIDATE;
353                     }
354                     candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
355                     ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
356                     break;
357           }
358 
359           return retcode;
360 }
361 
362 static meta_search_candidate_t
meta_search_dobind_result(Operation * op,SlapReply * rs,metaconn_t ** mcp,int candidate,SlapReply * candidates,LDAPMessage * res)363 meta_search_dobind_result(
364           Operation           *op,
365           SlapReply           *rs,
366           metaconn_t                    **mcp,
367           int                           candidate,
368           SlapReply           *candidates,
369           LDAPMessage                   *res )
370 {
371           metainfo_t                    *mi = ( metainfo_t * )op->o_bd->be_private;
372           metatarget_t                  *mt = mi->mi_targets[ candidate ];
373           metaconn_t                    *mc = *mcp;
374           metasingleconn_t    *msc = &mc->mc_conns[ candidate ];
375 
376           meta_search_candidate_t       retcode = META_SEARCH_NOT_CANDIDATE;
377           int                           rc;
378 
379           assert( msc->msc_ld != NULL );
380 
381           /* FIXME: matched? referrals? response controls? */
382           rc = ldap_parse_result( msc->msc_ld, res,
383                     &candidates[ candidate ].sr_err,
384                     NULL, NULL, NULL, NULL, 0 );
385           if ( rc != LDAP_SUCCESS ) {
386                     candidates[ candidate ].sr_err = rc;
387           }
388           rc = slap_map_api2result( &candidates[ candidate ] );
389 
390           ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
391           LDAP_BACK_CONN_BINDING_CLEAR( msc );
392           if ( rc != LDAP_SUCCESS ) {
393                     meta_clear_one_candidate( op, mc, candidate );
394                     candidates[ candidate ].sr_err = rc;
395                     if ( META_BACK_ONERR_STOP( mi ) ) {
396                     LDAP_BACK_CONN_TAINTED_SET( mc );
397                               meta_back_release_conn_lock( mi, mc, 0 );
398                               *mcp = NULL;
399                               retcode = META_SEARCH_ERR;
400                               rs->sr_err = rc;
401                     }
402 
403           } else {
404                     /* FIXME: check if bound as idassert authcDN! */
405                     if ( BER_BVISNULL( &msc->msc_bound_ndn )
406                               || BER_BVISEMPTY( &msc->msc_bound_ndn ) )
407                     {
408                               LDAP_BACK_CONN_ISANON_SET( msc );
409 
410                     } else {
411                               if ( META_BACK_TGT_SAVECRED( mt ) &&
412                                         !BER_BVISNULL( &msc->msc_cred ) &&
413                                         !BER_BVISEMPTY( &msc->msc_cred ) )
414                               {
415                                         ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
416                               }
417                               LDAP_BACK_CONN_ISBOUND_SET( msc );
418                     }
419                     retcode = META_SEARCH_CANDIDATE;
420 
421                     /* connect must be async */
422                     ldap_set_option( msc->msc_ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_OFF );
423           }
424 
425           candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
426           META_BINDING_CLEAR( &candidates[ candidate ] );
427 
428           ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
429 
430           return retcode;
431 }
432 
433 static meta_search_candidate_t
meta_back_search_start(Operation * op,SlapReply * rs,dncookie * dc,metaconn_t ** mcp,int candidate,SlapReply * candidates,struct berval * prcookie,ber_int_t prsize)434 meta_back_search_start(
435           Operation           *op,
436           SlapReply           *rs,
437           dncookie            *dc,
438           metaconn_t                    **mcp,
439           int                           candidate,
440           SlapReply           *candidates,
441           struct berval                 *prcookie,
442           ber_int_t           prsize )
443 {
444           metainfo_t                    *mi = ( metainfo_t * )op->o_bd->be_private;
445           metatarget_t                  *mt = mi->mi_targets[ candidate ];
446           metasingleconn_t    *msc = &(*mcp)->mc_conns[ candidate ];
447           struct berval                 realbase = op->o_req_dn;
448           int                           realscope = op->ors_scope;
449           struct berval                 mbase = BER_BVNULL;
450           struct berval                 mfilter = BER_BVNULL;
451           char                          **mapped_attrs = NULL;
452           int                           rc;
453           meta_search_candidate_t       retcode;
454           struct timeval                tv, *tvp = NULL;
455           int                           nretries = 1;
456           LDAPControl                   **ctrls = NULL;
457 #ifdef SLAPD_META_CLIENT_PR
458           LDAPControl                   **save_ctrls = NULL;
459 #endif /* SLAPD_META_CLIENT_PR */
460 
461           /* this should not happen; just in case... */
462           if ( msc->msc_ld == NULL ) {
463                     Debug( LDAP_DEBUG_ANY,
464                               "%s: meta_back_search_start candidate=%d ld=NULL%s.\n",
465                               op->o_log_prefix, candidate,
466                               META_BACK_ONERR_STOP( mi ) ? "" : " (ignored)" );
467                     candidates[ candidate ].sr_err = LDAP_OTHER;
468                     if ( META_BACK_ONERR_STOP( mi ) ) {
469                               return META_SEARCH_ERR;
470                     }
471                     candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
472                     return META_SEARCH_NOT_CANDIDATE;
473           }
474 
475           Debug( LDAP_DEBUG_TRACE, "%s >>> meta_back_search_start[%d]\n", op->o_log_prefix, candidate );
476 
477           /*
478            * modifies the base according to the scope, if required
479            */
480           if ( mt->mt_nsuffix.bv_len > op->o_req_ndn.bv_len ) {
481                     switch ( op->ors_scope ) {
482                     case LDAP_SCOPE_SUBTREE:
483                               /*
484                                * make the target suffix the new base
485                                * FIXME: this is very forgiving, because
486                                * "illegal" searchBases may be turned
487                                * into the suffix of the target; however,
488                                * the requested searchBase already passed
489                                * thru the candidate analyzer...
490                                */
491                               if ( dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) ) {
492                                         realbase = mt->mt_nsuffix;
493                                         if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
494                                                   realscope = LDAP_SCOPE_SUBORDINATE;
495                                         }
496 
497                               } else {
498                                         /*
499                                          * this target is no longer candidate
500                                          */
501                                         retcode = META_SEARCH_NOT_CANDIDATE;
502                                         goto doreturn;
503                               }
504                               break;
505 
506                     case LDAP_SCOPE_SUBORDINATE:
507                     case LDAP_SCOPE_ONELEVEL:
508                     {
509                               struct berval       rdn = mt->mt_nsuffix;
510                               rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," );
511                               if ( dnIsOneLevelRDN( &rdn )
512                                                   && dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) )
513                               {
514                                         /*
515                                          * if there is exactly one level,
516                                          * make the target suffix the new
517                                          * base, and make scope "base"
518                                          */
519                                         realbase = mt->mt_nsuffix;
520                                         if ( op->ors_scope == LDAP_SCOPE_SUBORDINATE ) {
521                                                   if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
522                                                             realscope = LDAP_SCOPE_SUBORDINATE;
523                                                   } else {
524                                                             realscope = LDAP_SCOPE_SUBTREE;
525                                                   }
526                                         } else {
527                                                   realscope = LDAP_SCOPE_BASE;
528                                         }
529                                         break;
530                               } /* else continue with the next case */
531                     }
532 
533                     case LDAP_SCOPE_BASE:
534                               /*
535                                * this target is no longer candidate
536                                */
537                               retcode = META_SEARCH_NOT_CANDIDATE;
538                               goto doreturn;
539                     }
540           }
541 
542           /* check filter expression */
543           if ( mt->mt_filter ) {
544                     metafilter_t *mf;
545                     for ( mf = mt->mt_filter; mf; mf = mf->mf_next ) {
546                               if ( regexec( &mf->mf_regex, op->ors_filterstr.bv_val, 0, NULL, 0 ) == 0 )
547                                         break;
548                     }
549                     /* nothing matched, this target is no longer a candidate */
550                     if ( !mf ) {
551                               retcode = META_SEARCH_NOT_CANDIDATE;
552                               goto doreturn;
553                     }
554           }
555 
556           /* initiate dobind */
557           retcode = meta_search_dobind_init( op, rs, mcp, candidate, candidates );
558 
559           Debug( LDAP_DEBUG_TRACE, "%s <<< meta_search_dobind_init[%d]=%d\n", op->o_log_prefix, candidate, retcode );
560 
561           if ( retcode != META_SEARCH_CANDIDATE ) {
562                     goto doreturn;
563           }
564 
565           /*
566            * Rewrite the search base, if required
567            */
568           dc->target = mt;
569           dc->ctx = "searchBase";
570           switch ( ldap_back_dn_massage( dc, &realbase, &mbase ) ) {
571           case LDAP_SUCCESS:
572                     break;
573 
574           case LDAP_UNWILLING_TO_PERFORM:
575                     rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
576                     rs->sr_text = "Operation not allowed";
577                     send_ldap_result( op, rs );
578                     retcode = META_SEARCH_ERR;
579                     goto doreturn;
580 
581           default:
582 
583                     /*
584                      * this target is no longer candidate
585                      */
586                     retcode = META_SEARCH_NOT_CANDIDATE;
587                     goto doreturn;
588           }
589 
590           /*
591            * Maps filter
592            */
593           rc = ldap_back_filter_map_rewrite( dc, op->ors_filter,
594                               &mfilter, BACKLDAP_MAP, op->o_tmpmemctx );
595           switch ( rc ) {
596           case LDAP_SUCCESS:
597                     break;
598 
599           case LDAP_COMPARE_FALSE:
600           default:
601                     /*
602                      * this target is no longer candidate
603                      */
604                     retcode = META_SEARCH_NOT_CANDIDATE;
605                     goto done;
606           }
607 
608           /*
609            * Maps required attributes
610            */
611           rc = ldap_back_map_attrs( op, &mt->mt_rwmap.rwm_at,
612                               op->ors_attrs, BACKLDAP_MAP, &mapped_attrs );
613           if ( rc != LDAP_SUCCESS ) {
614                     /*
615                      * this target is no longer candidate
616                      */
617                     retcode = META_SEARCH_NOT_CANDIDATE;
618                     goto done;
619           }
620 
621           if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
622                     tv.tv_sec = op->ors_tlimit > 0 ? op->ors_tlimit : 1;
623                     tv.tv_usec = 0;
624                     tvp = &tv;
625           }
626 
627 #ifdef SLAPD_META_CLIENT_PR
628           save_ctrls = op->o_ctrls;
629           {
630                     LDAPControl *pr_c = NULL;
631                     int i = 0, nc = 0;
632 
633                     if ( save_ctrls ) {
634                               for ( ; save_ctrls[i] != NULL; i++ );
635                               nc = i;
636                               pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, save_ctrls, NULL );
637                     }
638 
639                     if ( pr_c != NULL ) nc--;
640                     if ( mt->mt_ps > 0 || prcookie != NULL ) nc++;
641 
642                     if ( mt->mt_ps > 0 || prcookie != NULL || pr_c != NULL ) {
643                               int src = 0, dst = 0;
644                               BerElementBuffer berbuf;
645                               BerElement *ber = (BerElement *)&berbuf;
646                               struct berval val = BER_BVNULL;
647                               ber_len_t len;
648 
649                               len = sizeof( LDAPControl * )*( nc + 1 ) + sizeof( LDAPControl );
650 
651                               if ( mt->mt_ps > 0 || prcookie != NULL ) {
652                                         struct berval nullcookie = BER_BVNULL;
653                                         ber_tag_t tag;
654 
655                                         if ( prsize == 0 && mt->mt_ps > 0 ) prsize = mt->mt_ps;
656                                         if ( prcookie == NULL ) prcookie = &nullcookie;
657 
658                                         ber_init2( ber, NULL, LBER_USE_DER );
659                                         tag = ber_printf( ber, "{iO}", prsize, prcookie );
660                                         if ( tag == LBER_ERROR ) {
661                                                   /* error */
662                                                   (void) ber_free_buf( ber );
663                                                   goto done_pr;
664                                         }
665 
666                                         tag = ber_flatten2( ber, &val, 0 );
667                                         if ( tag == LBER_ERROR ) {
668                                                   /* error */
669                                                   (void) ber_free_buf( ber );
670                                                   goto done_pr;
671                                         }
672 
673                                         len += val.bv_len + 1;
674                               }
675 
676                               op->o_ctrls = op->o_tmpalloc( len, op->o_tmpmemctx );
677                               if ( save_ctrls ) {
678                                         for ( ; save_ctrls[ src ] != NULL; src++ ) {
679                                                   if ( save_ctrls[ src ] != pr_c ) {
680                                                             op->o_ctrls[ dst ] = save_ctrls[ src ];
681                                                             dst++;
682                                                   }
683                                         }
684                               }
685 
686                               if ( mt->mt_ps > 0 || prcookie != NULL ) {
687                                         op->o_ctrls[ dst ] = (LDAPControl *)&op->o_ctrls[ nc + 1 ];
688 
689                                         op->o_ctrls[ dst ]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
690                                         op->o_ctrls[ dst ]->ldctl_iscritical = 1;
691 
692                                         op->o_ctrls[ dst ]->ldctl_value.bv_val = (char *)&op->o_ctrls[ dst ][ 1 ];
693                                         AC_MEMCPY( op->o_ctrls[ dst ]->ldctl_value.bv_val, val.bv_val, val.bv_len + 1 );
694                                         op->o_ctrls[ dst ]->ldctl_value.bv_len = val.bv_len;
695                                         dst++;
696 
697                                         (void)ber_free_buf( ber );
698                               }
699 
700                               op->o_ctrls[ dst ] = NULL;
701                     }
702 done_pr:;
703           }
704 #endif /* SLAPD_META_CLIENT_PR */
705 
706 retry:;
707           ctrls = op->o_ctrls;
708           if ( meta_back_controls_add( op, rs, *mcp, candidate, &ctrls )
709                     != LDAP_SUCCESS )
710           {
711                     candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
712                     retcode = META_SEARCH_NOT_CANDIDATE;
713                     goto done;
714           }
715 
716           /*
717            * Starts the search
718            */
719           assert( msc->msc_ld != NULL );
720           rc = ldap_pvt_search( msc->msc_ld,
721                               mbase.bv_val, realscope, mfilter.bv_val,
722                               mapped_attrs, op->ors_attrsonly,
723                               ctrls, NULL, tvp, op->ors_slimit, op->ors_deref,
724                               &candidates[ candidate ].sr_msgid );
725           switch ( rc ) {
726           case LDAP_SUCCESS:
727                     retcode = META_SEARCH_CANDIDATE;
728                     break;
729 
730           case LDAP_SERVER_DOWN:
731                     if ( nretries && meta_back_retry( op, rs, mcp, candidate, LDAP_BACK_DONTSEND ) ) {
732                               nretries = 0;
733                               /* if the identity changed, there might be need to re-authz */
734                               (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
735                               goto retry;
736                     }
737 
738                     if ( *mcp == NULL ) {
739                               retcode = META_SEARCH_ERR;
740                               candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
741                               break;
742                     }
743                     /* fall thru */
744 
745           default:
746                     candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
747                     retcode = META_SEARCH_NOT_CANDIDATE;
748           }
749 
750 done:;
751           (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
752 #ifdef SLAPD_META_CLIENT_PR
753           if ( save_ctrls != op->o_ctrls ) {
754                     op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx );
755                     op->o_ctrls = save_ctrls;
756           }
757 #endif /* SLAPD_META_CLIENT_PR */
758 
759           if ( mapped_attrs ) {
760                     ber_memfree_x( mapped_attrs, op->o_tmpmemctx );
761           }
762           if ( mfilter.bv_val != op->ors_filterstr.bv_val ) {
763                     ber_memfree_x( mfilter.bv_val, op->o_tmpmemctx );
764           }
765           if ( mbase.bv_val != realbase.bv_val ) {
766                     free( mbase.bv_val );
767           }
768 
769 doreturn:;
770           Debug( LDAP_DEBUG_TRACE, "%s <<< meta_back_search_start[%d]=%d\n", op->o_log_prefix, candidate, retcode );
771 
772           return retcode;
773 }
774 
775 int
meta_back_search(Operation * op,SlapReply * rs)776 meta_back_search( Operation *op, SlapReply *rs )
777 {
778           metainfo_t          *mi = ( metainfo_t * )op->o_bd->be_private;
779           metaconn_t          *mc;
780           struct timeval      save_tv = { 0, 0 },
781                               tv;
782           time_t              stoptime = (time_t)(-1),
783                               lastres_time = slap_get_time(),
784                               timeout = 0;
785           int                 rc = 0, sres = LDAP_SUCCESS;
786           char                *matched = NULL;
787           int                 last = 0, ncandidates = 0,
788                               initial_candidates = 0, candidate_match = 0,
789                               needbind = 0;
790           ldap_back_send_t    sendok = LDAP_BACK_SENDERR;
791           long                i;
792           dncookie  dc;
793           int                 is_ok = 0;
794           void                *savepriv;
795           SlapReply *candidates = NULL;
796           int                 do_taint = 0;
797 
798           rs_assert_ready( rs );
799           rs->sr_flags &= ~REP_ENTRY_MASK; /* paranoia, we can set rs = non-entry */
800 
801           /*
802            * controls are set in ldap_back_dobind()
803            *
804            * FIXME: in case of values return filter, we might want
805            * to map attrs and maybe rewrite value
806            */
807 getconn:;
808           mc = meta_back_getconn( op, rs, NULL, sendok );
809           if ( !mc ) {
810                     return rs->sr_err;
811           }
812 
813           dc.conn = op->o_conn;
814           dc.rs = rs;
815 
816           if ( candidates == NULL ) candidates = meta_back_candidates_get( op );
817           /*
818            * Inits searches
819            */
820           for ( i = 0; i < mi->mi_ntargets; i++ ) {
821                     /* reset sr_msgid; it is used in most loops
822                      * to check if that target is still to be considered */
823                     candidates[ i ].sr_msgid = META_MSGID_IGNORE;
824 
825                     /* a target is marked as candidate by meta_back_getconn();
826                      * if for any reason (an error, it's over or so) it is
827                      * no longer active, sr_msgid is set to META_MSGID_IGNORE
828                      * but it remains candidate, which means it has been active
829                      * at some point during the operation.  This allows to
830                      * use its response code and more to compute the final
831                      * response */
832                     if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
833                               continue;
834                     }
835 
836                     candidates[ i ].sr_matched = NULL;
837                     candidates[ i ].sr_text = NULL;
838                     candidates[ i ].sr_ref = NULL;
839                     candidates[ i ].sr_ctrls = NULL;
840                     candidates[ i ].sr_nentries = 0;
841 
842                     /* get largest timeout among candidates */
843                     if ( mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ]
844                               && mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ] > timeout )
845                     {
846                               timeout = mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ];
847                     }
848           }
849 
850           for ( i = 0; i < mi->mi_ntargets; i++ ) {
851                     if ( !META_IS_CANDIDATE( &candidates[ i ] )
852                               || candidates[ i ].sr_err != LDAP_SUCCESS )
853                     {
854                               continue;
855                     }
856 
857                     switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 ) )
858                     {
859                     case META_SEARCH_NOT_CANDIDATE:
860                               candidates[ i ].sr_msgid = META_MSGID_IGNORE;
861                               break;
862 
863                     case META_SEARCH_NEED_BIND:
864                               ++needbind;
865                               /* fallthru */
866 
867                     case META_SEARCH_CONNECTING:
868                     case META_SEARCH_CANDIDATE:
869                     case META_SEARCH_BINDING:
870                               candidates[ i ].sr_type = REP_INTERMEDIATE;
871                               ++ncandidates;
872                               break;
873 
874                     case META_SEARCH_ERR:
875                               savepriv = op->o_private;
876                               op->o_private = (void *)i;
877                               send_ldap_result( op, rs );
878                               op->o_private = savepriv;
879                               rc = -1;
880                               goto finish;
881 
882                     default:
883                               assert( 0 );
884                               break;
885                     }
886           }
887 
888           if ( ncandidates > 0 && needbind == ncandidates ) {
889                     /*
890                      * give up the second time...
891                      *
892                      * NOTE: this should not occur the second time, since a fresh
893                      * connection has ben created; however, targets may also
894                      * need bind because the bind timed out or so.
895                      */
896                     if ( sendok & LDAP_BACK_BINDING ) {
897                               Debug( LDAP_DEBUG_ANY,
898                                         "%s meta_back_search: unable to initialize conn\n",
899                                         op->o_log_prefix );
900                               rs->sr_err = LDAP_UNAVAILABLE;
901                               rs->sr_text = "unable to initialize connection to remote targets";
902                               send_ldap_result( op, rs );
903                               rc = -1;
904                               goto finish;
905                     }
906 
907                     /* FIXME: better create a separate connection? */
908                     sendok |= LDAP_BACK_BINDING;
909 
910 #ifdef DEBUG_205
911                     Debug( LDAP_DEBUG_ANY, "*** %s drop mc=%p create new connection\n",
912                               op->o_log_prefix, (void *)mc );
913 #endif /* DEBUG_205 */
914 
915                     meta_back_release_conn( mi, mc );
916                     mc = NULL;
917 
918                     needbind = 0;
919                     ncandidates = 0;
920 
921                     goto getconn;
922           }
923 
924           initial_candidates = ncandidates;
925 
926           if ( LogTest( LDAP_DEBUG_TRACE ) ) {
927                     char      cnd[ SLAP_TEXT_BUFLEN ];
928                     int       c;
929 
930                     for ( c = 0; c < mi->mi_ntargets; c++ ) {
931                               if ( META_IS_CANDIDATE( &candidates[ c ] ) ) {
932                                         cnd[ c ] = '*';
933                               } else {
934                                         cnd[ c ] = ' ';
935                               }
936                     }
937                     cnd[ c ] = '\0';
938 
939                     Debug( LDAP_DEBUG_TRACE, "%s meta_back_search: ncandidates=%d "
940                               "cnd=\"%s\"\n", op->o_log_prefix, ncandidates, cnd );
941           }
942 
943           if ( initial_candidates == 0 ) {
944                     /* NOTE: here we are not sending any matchedDN;
945                      * this is intended, because if the back-meta
946                      * is serving this search request, but no valid
947                      * candidate could be looked up, it means that
948                      * there is a hole in the mapping of the targets
949                      * and thus no knowledge of any remote superior
950                      * is available */
951                     Debug( LDAP_DEBUG_ANY, "%s meta_back_search: "
952                               "base=\"%s\" scope=%d: "
953                               "no candidate could be selected\n",
954                               op->o_log_prefix, op->o_req_dn.bv_val,
955                               op->ors_scope );
956 
957                     /* FIXME: we're sending the first error we encounter;
958                      * maybe we should pick the worst... */
959                     rc = LDAP_NO_SUCH_OBJECT;
960                     for ( i = 0; i < mi->mi_ntargets; i++ ) {
961                               if ( META_IS_CANDIDATE( &candidates[ i ] )
962                                         && candidates[ i ].sr_err != LDAP_SUCCESS )
963                               {
964                                         rc = candidates[ i ].sr_err;
965                                         break;
966                               }
967                     }
968 
969                     send_ldap_error( op, rs, rc, NULL );
970 
971                     goto finish;
972           }
973 
974           /* We pull apart the ber result, stuff it into a slapd entry, and
975            * let send_search_entry stuff it back into ber format. Slow & ugly,
976            * but this is necessary for version matching, and for ACL processing.
977            */
978 
979           if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
980                     stoptime = op->o_time + op->ors_tlimit;
981           }
982 
983           /*
984            * In case there are no candidates, no cycle takes place...
985            *
986            * FIXME: we might use a queue, to better balance the load
987            * among the candidates
988            */
989           for ( rc = 0; ncandidates > 0; ) {
990                     int       gotit = 0,
991                               doabandon = 0,
992                               alreadybound = ncandidates;
993 
994                     /* check timeout */
995                     if ( timeout && lastres_time > 0
996                               && ( slap_get_time() - lastres_time ) > timeout )
997                     {
998                               doabandon = 1;
999                               rs->sr_text = "Operation timed out";
1000                               rc = rs->sr_err = op->o_protocol >= LDAP_VERSION3 ?
1001                                         LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
1002                               savepriv = op->o_private;
1003                               op->o_private = (void *)i;
1004                               send_ldap_result( op, rs );
1005                               op->o_private = savepriv;
1006                               goto finish;
1007                     }
1008 
1009                     /* check time limit */
1010                     if ( op->ors_tlimit != SLAP_NO_LIMIT
1011                                         && slap_get_time() > stoptime )
1012                     {
1013                               doabandon = 1;
1014                               rc = rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
1015                               savepriv = op->o_private;
1016                               op->o_private = (void *)i;
1017                               send_ldap_result( op, rs );
1018                               op->o_private = savepriv;
1019                               goto finish;
1020                     }
1021 
1022                     for ( i = 0; i < mi->mi_ntargets; i++ ) {
1023                               meta_search_candidate_t       retcode = META_SEARCH_UNDEFINED;
1024                               metasingleconn_t    *msc = &mc->mc_conns[ i ];
1025                               LDAPMessage                   *res = NULL, *msg;
1026 
1027                               /* if msgid is invalid, don't ldap_result() */
1028                               if ( candidates[ i ].sr_msgid == META_MSGID_IGNORE ) {
1029                                         continue;
1030                               }
1031 
1032                               /* if target still needs bind, retry */
1033                               if ( candidates[ i ].sr_msgid == META_MSGID_NEED_BIND
1034                                         || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
1035                               {
1036                                         /* initiate dobind */
1037                                         retcode = meta_search_dobind_init( op, rs, &mc, i, candidates );
1038 
1039                                         Debug( LDAP_DEBUG_TRACE, "%s <<< meta_search_dobind_init[%ld]=%d\n",
1040                                                   op->o_log_prefix, i, retcode );
1041 
1042                                         switch ( retcode ) {
1043                                         case META_SEARCH_NEED_BIND:
1044                                                   alreadybound--;
1045                                                   /* fallthru */
1046 
1047                                         case META_SEARCH_CONNECTING:
1048                                         case META_SEARCH_BINDING:
1049                                                   break;
1050 
1051                                         case META_SEARCH_ERR:
1052                                                   candidates[ i ].sr_err = rs->sr_err;
1053                                                   if ( META_BACK_ONERR_STOP( mi ) ) {
1054                                                             savepriv = op->o_private;
1055                                                             op->o_private = (void *)i;
1056                                                             send_ldap_result( op, rs );
1057                                                             op->o_private = savepriv;
1058                                                             goto finish;
1059                                                   }
1060                                                   /* fallthru */
1061 
1062                                         case META_SEARCH_NOT_CANDIDATE:
1063                                                   /*
1064                                                    * When no candidates are left,
1065                                                    * the outer cycle finishes
1066                                                    */
1067                                                   candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1068                                                   assert( ncandidates > 0 );
1069                                                   --ncandidates;
1070                                                   break;
1071 
1072                                         case META_SEARCH_CANDIDATE:
1073                                                   candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1074                                                   switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 ) )
1075                                                   {
1076                                                   case META_SEARCH_CANDIDATE:
1077                                                             assert( candidates[ i ].sr_msgid >= 0 );
1078                                                             break;
1079 
1080                                                   case META_SEARCH_ERR:
1081                                                             candidates[ i ].sr_err = rs->sr_err;
1082                                                             if ( META_BACK_ONERR_STOP( mi ) ) {
1083                                                                       savepriv = op->o_private;
1084                                                                       op->o_private = (void *)i;
1085                                                                       send_ldap_result( op, rs );
1086                                                                       op->o_private = savepriv;
1087                                                                       goto finish;
1088                                                             }
1089                                                             /* fallthru */
1090 
1091                                                   case META_SEARCH_NOT_CANDIDATE:
1092                                                             /* means that meta_back_search_start()
1093                                                              * failed but onerr == continue */
1094                                                             candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1095                                                             assert( ncandidates > 0 );
1096                                                             --ncandidates;
1097                                                             break;
1098 
1099                                                   default:
1100                                                             /* impossible */
1101                                                             assert( 0 );
1102                                                             break;
1103                                                   }
1104                                                   break;
1105 
1106                                         default:
1107                                                   /* impossible */
1108                                                   assert( 0 );
1109                                                   break;
1110                                         }
1111                                         continue;
1112                               }
1113 
1114                               /* check for abandon */
1115                               if ( op->o_abandon || LDAP_BACK_CONN_ABANDON( mc ) ) {
1116                                         break;
1117                               }
1118 
1119 #ifdef DEBUG_205
1120                               if ( msc->msc_ld == NULL ) {
1121                                         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
1122                                         Debug(LDAP_DEBUG_ANY,
1123                                               "!!! %s meta_back_search[%ld] mc=%p msgid=%d%s%s%s\n\n",
1124                                               op->o_log_prefix, (long)i, (void *)mc,
1125                                               candidates[i].sr_msgid,
1126                                               META_IS_BINDING(&candidates[i]) ? " binding" : "",
1127                                               LDAP_BACK_CONN_BINDING(&mc->mc_conns[i]) ? " connbinding" : "",
1128                                               META_BACK_CONN_CREATING(&mc->mc_conns[i]) ? " conncreating" : "" );
1129                                         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1130                               }
1131 #endif /* DEBUG_205 */
1132 
1133                               /*
1134                                * FIXME: handle time limit as well?
1135                                * Note that target servers are likely
1136                                * to handle it, so at some time we'll
1137                                * get a LDAP_TIMELIMIT_EXCEEDED from
1138                                * one of them ...
1139                                */
1140                               tv = save_tv;
1141                               rc = ldap_result( msc->msc_ld, candidates[ i ].sr_msgid,
1142                                                   LDAP_MSG_RECEIVED, &tv, &res );
1143                               switch ( rc ) {
1144                               case 0:
1145                                         /* FIXME: res should not need to be freed */
1146                                         assert( res == NULL );
1147                                         continue;
1148 
1149                               case -1:
1150 really_bad:;
1151                                         /* something REALLY bad happened! */
1152                                         if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
1153                                                   candidates[ i ].sr_type = REP_RESULT;
1154 
1155                                                   if ( meta_back_retry( op, rs, &mc, i, LDAP_BACK_DONTSEND ) ) {
1156                                                             candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1157                                                             switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 ) )
1158                                                             {
1159                                                                       /* means that failed but onerr == continue */
1160                                                             case META_SEARCH_NOT_CANDIDATE:
1161                                                                       candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1162 
1163                                                                       assert( ncandidates > 0 );
1164                                                                       --ncandidates;
1165 
1166                                                                       candidates[ i ].sr_err = rs->sr_err;
1167                                                                       if ( META_BACK_ONERR_STOP( mi ) ) {
1168                                                                                 savepriv = op->o_private;
1169                                                                                 op->o_private = (void *)i;
1170                                                                                 send_ldap_result( op, rs );
1171                                                                                 op->o_private = savepriv;
1172                                                                                 goto finish;
1173                                                                       }
1174                                                                       /* fall thru */
1175 
1176                                                             case META_SEARCH_CANDIDATE:
1177                                                                       /* get back into business... */
1178                                                                       continue;
1179 
1180                                                             case META_SEARCH_BINDING:
1181                                                             case META_SEARCH_CONNECTING:
1182                                                             case META_SEARCH_NEED_BIND:
1183                                                             case META_SEARCH_UNDEFINED:
1184                                                                       assert( 0 );
1185 
1186                                                             default:
1187                                                                       /* unrecoverable error */
1188                                                                       candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1189                                                                       rc = rs->sr_err = LDAP_OTHER;
1190                                                                       goto finish;
1191                                                             }
1192                                                   }
1193 
1194                                                   candidates[ i ].sr_err = rs->sr_err;
1195                                                   if ( META_BACK_ONERR_STOP( mi ) ) {
1196                                                             savepriv = op->o_private;
1197                                                             op->o_private = (void *)i;
1198                                                             send_ldap_result( op, rs );
1199                                                             op->o_private = savepriv;
1200                                                             goto finish;
1201                                                   }
1202                                         }
1203 
1204                                         /*
1205                                          * When no candidates are left,
1206                                          * the outer cycle finishes
1207                                          */
1208                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1209                                         assert( ncandidates > 0 );
1210                                         --ncandidates;
1211                                         rs->sr_err = candidates[ i ].sr_err;
1212                                         continue;
1213 
1214                               default:
1215                                         lastres_time = slap_get_time();
1216 
1217                                         /* only touch when activity actually took place... */
1218                                         if ( mi->mi_idle_timeout != 0 && msc->msc_time < lastres_time ) {
1219                                                   msc->msc_time = lastres_time;
1220                                         }
1221                                         break;
1222                               }
1223 
1224                               for ( msg = ldap_first_message( msc->msc_ld, res );
1225                                         msg != NULL;
1226                                         msg = ldap_next_message( msc->msc_ld, msg ) )
1227                               {
1228                                         rc = ldap_msgtype( msg );
1229                                         if ( rc == LDAP_RES_SEARCH_ENTRY ) {
1230                                                   LDAPMessage         *e;
1231 
1232                                                   if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
1233                                                             /* don't retry any more... */
1234                                                             candidates[ i ].sr_type = REP_RESULT;
1235                                                   }
1236 
1237                                                   /* count entries returned by target */
1238                                                   candidates[ i ].sr_nentries++;
1239 
1240                                                   is_ok++;
1241 
1242                                                   e = ldap_first_entry( msc->msc_ld, msg );
1243                                                   savepriv = op->o_private;
1244                                                   op->o_private = (void *)i;
1245                                                   rs->sr_err = meta_send_entry( op, rs, mc, i, e );
1246 
1247                                                   switch ( rs->sr_err ) {
1248                                                   case LDAP_SIZELIMIT_EXCEEDED:
1249                                                             savepriv = op->o_private;
1250                                                             op->o_private = (void *)i;
1251                                                             send_ldap_result( op, rs );
1252                                                             op->o_private = savepriv;
1253                                                             rs->sr_err = LDAP_SUCCESS;
1254                                                             ldap_msgfree( res );
1255                                                             res = NULL;
1256                                                             goto finish;
1257 
1258                                                   case LDAP_UNAVAILABLE:
1259                                                             rs->sr_err = LDAP_OTHER;
1260                                                             ldap_msgfree( res );
1261                                                             res = NULL;
1262                                                             goto finish;
1263                                                   }
1264                                                   op->o_private = savepriv;
1265 
1266                                                   /* don't wait any longer... */
1267                                                   gotit = 1;
1268                                                   save_tv.tv_sec = 0;
1269                                                   save_tv.tv_usec = 0;
1270 
1271                                         } else if ( rc == LDAP_RES_SEARCH_REFERENCE ) {
1272                                                   char                **references = NULL;
1273                                                   int                 cnt;
1274 
1275                                                   if ( META_BACK_TGT_NOREFS( mi->mi_targets[ i ] ) ) {
1276                                                             continue;
1277                                                   }
1278 
1279                                                   if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
1280                                                             /* don't retry any more... */
1281                                                             candidates[ i ].sr_type = REP_RESULT;
1282                                                   }
1283 
1284                                                   is_ok++;
1285 
1286                                                   rc = ldap_parse_reference( msc->msc_ld, msg,
1287                                                                       &references, &rs->sr_ctrls, 0 );
1288 
1289                                                   if ( rc != LDAP_SUCCESS ) {
1290                                                             continue;
1291                                                   }
1292 
1293                                                   if ( references == NULL ) {
1294                                                             continue;
1295                                                   }
1296 
1297                                                   dc.ctx = "referralDN";
1298 
1299                                                   /* FIXME: merge all and return at the end */
1300 
1301                                                   for ( cnt = 0; references[ cnt ]; cnt++ )
1302                                                             ;
1303 
1304                                                   rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( cnt + 1 ),
1305                                                             op->o_tmpmemctx );
1306 
1307                                                   for ( cnt = 0; references[ cnt ]; cnt++ ) {
1308                                                             ber_str2bv_x( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ],
1309                                                             op->o_tmpmemctx );
1310                                                   }
1311                                                   BER_BVZERO( &rs->sr_ref[ cnt ] );
1312 
1313                                                   ( void )ldap_back_referral_result_rewrite( &dc, rs->sr_ref,
1314                                                             op->o_tmpmemctx );
1315 
1316                                                   if ( rs->sr_ref != NULL && !BER_BVISNULL( &rs->sr_ref[ 0 ] ) ) {
1317                                                             /* ignore return value by now */
1318                                                             savepriv = op->o_private;
1319                                                             op->o_private = (void *)i;
1320                                                             ( void )send_search_reference( op, rs );
1321                                                             op->o_private = savepriv;
1322 
1323                                                             ber_bvarray_free_x( rs->sr_ref, op->o_tmpmemctx );
1324                                                             rs->sr_ref = NULL;
1325                                                   }
1326 
1327                                                   /* cleanup */
1328                                                   if ( references ) {
1329                                                             ber_memvfree( (void **)references );
1330                                                   }
1331 
1332                                                   if ( rs->sr_ctrls ) {
1333                                                             ldap_controls_free( rs->sr_ctrls );
1334                                                             rs->sr_ctrls = NULL;
1335                                                   }
1336 
1337                                         } else if ( rc == LDAP_RES_INTERMEDIATE ) {
1338                                                   if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
1339                                                             /* don't retry any more... */
1340                                                             candidates[ i ].sr_type = REP_RESULT;
1341                                                   }
1342 
1343                                                   /* FIXME: response controls
1344                                                    * are passed without checks */
1345                                                   rs->sr_err = ldap_parse_intermediate( msc->msc_ld,
1346                                                             msg,
1347                                                             (char **)&rs->sr_rspoid,
1348                                                             &rs->sr_rspdata,
1349                                                             &rs->sr_ctrls,
1350                                                             0 );
1351                                                   if ( rs->sr_err != LDAP_SUCCESS ) {
1352                                                             candidates[ i ].sr_type = REP_RESULT;
1353                                                             ldap_msgfree( res );
1354                                                             res = NULL;
1355                                                             goto really_bad;
1356                                                   }
1357 
1358                                                   slap_send_ldap_intermediate( op, rs );
1359 
1360                                                   if ( rs->sr_rspoid != NULL ) {
1361                                                             ber_memfree( (char *)rs->sr_rspoid );
1362                                                             rs->sr_rspoid = NULL;
1363                                                   }
1364 
1365                                                   if ( rs->sr_rspdata != NULL ) {
1366                                                             ber_bvfree( rs->sr_rspdata );
1367                                                             rs->sr_rspdata = NULL;
1368                                                   }
1369 
1370                                                   if ( rs->sr_ctrls != NULL ) {
1371                                                             ldap_controls_free( rs->sr_ctrls );
1372                                                             rs->sr_ctrls = NULL;
1373                                                   }
1374 
1375                                         } else if ( rc == LDAP_RES_SEARCH_RESULT ) {
1376                                                   char                **references = NULL;
1377                                                   LDAPControl         **ctrls = NULL;
1378 
1379                                                   if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
1380                                                             /* don't retry any more... */
1381                                                             candidates[ i ].sr_type = REP_RESULT;
1382                                                   }
1383 
1384                                                   candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1385 
1386                                                   /* NOTE: ignores response controls
1387                                                    * (and intermediate response controls
1388                                                    * as well, except for those with search
1389                                                    * references); this may not be correct,
1390                                                    * but if they're not ignored then
1391                                                    * back-meta would need to merge them
1392                                                    * consistently (think of pagedResults...)
1393                                                    */
1394                                                   /* FIXME: response controls? */
1395                                                   rs->sr_err = ldap_parse_result( msc->msc_ld,
1396                                                             msg,
1397                                                             &candidates[ i ].sr_err,
1398                                                             (char **)&candidates[ i ].sr_matched,
1399                                                             (char **)&candidates[ i ].sr_text,
1400                                                             &references,
1401                                                             &ctrls /* &candidates[ i ].sr_ctrls (unused) */ ,
1402                                                             0 );
1403                                                   if ( rs->sr_err != LDAP_SUCCESS ) {
1404                                                             candidates[ i ].sr_err = rs->sr_err;
1405                                                             sres = slap_map_api2result( &candidates[ i ] );
1406                                                             candidates[ i ].sr_type = REP_RESULT;
1407                                                             ldap_msgfree( res );
1408                                                             res = NULL;
1409                                                             goto really_bad;
1410                                                   }
1411 
1412                                                   rs->sr_err = candidates[ i ].sr_err;
1413 
1414                                                   /* massage matchedDN if need be */
1415                                                   if ( candidates[ i ].sr_matched != NULL ) {
1416                                                             struct berval       match, mmatch;
1417 
1418                                                             ber_str2bv( candidates[ i ].sr_matched,
1419                                                                       0, 0, &match );
1420                                                             candidates[ i ].sr_matched = NULL;
1421 
1422                                                             dc.ctx = "matchedDN";
1423                                                             dc.target = mi->mi_targets[ i ];
1424                                                             if ( !ldap_back_dn_massage( &dc, &match, &mmatch ) ) {
1425                                                                       if ( mmatch.bv_val == match.bv_val ) {
1426                                                                                 candidates[ i ].sr_matched
1427                                                                                           = ch_strdup( mmatch.bv_val );
1428 
1429                                                                       } else {
1430                                                                                 candidates[ i ].sr_matched = mmatch.bv_val;
1431                                                                       }
1432 
1433                                                                       candidate_match++;
1434                                                             }
1435                                                             ldap_memfree( match.bv_val );
1436                                                   }
1437 
1438                                                   /* add references to array */
1439                                                   /* RFC 4511: referrals can only appear
1440                                                    * if result code is LDAP_REFERRAL */
1441                                                   if ( references != NULL
1442                                                             && references[ 0 ] != NULL
1443                                                             && references[ 0 ][ 0 ] != '\0' )
1444                                                   {
1445                                                             if ( rs->sr_err != LDAP_REFERRAL ) {
1446                                                                       Debug( LDAP_DEBUG_ANY,
1447                                                                                 "%s meta_back_search[%ld]: "
1448                                                                                 "got referrals with err=%d\n",
1449                                                                                 op->o_log_prefix,
1450                                                                                 i, rs->sr_err );
1451 
1452                                                             } else {
1453                                                                       BerVarray sr_ref;
1454                                                                       int                 cnt;
1455 
1456                                                                       for ( cnt = 0; references[ cnt ]; cnt++ )
1457                                                                                 ;
1458 
1459                                                                       sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( cnt + 1 ),
1460                                                                                 op->o_tmpmemctx );
1461 
1462                                                                       for ( cnt = 0; references[ cnt ]; cnt++ ) {
1463                                                                                 ber_str2bv_x( references[ cnt ], 0, 1, &sr_ref[ cnt ],
1464                                                                                           op->o_tmpmemctx );
1465                                                                       }
1466                                                                       BER_BVZERO( &sr_ref[ cnt ] );
1467 
1468                                                                       ( void )ldap_back_referral_result_rewrite( &dc, sr_ref,
1469                                                                                 op->o_tmpmemctx );
1470 
1471                                                                       if ( rs->sr_v2ref == NULL ) {
1472                                                                                 rs->sr_v2ref = sr_ref;
1473 
1474                                                                       } else {
1475                                                                                 for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) {
1476                                                                                           ber_bvarray_add_x( &rs->sr_v2ref, &sr_ref[ cnt ],
1477                                                                                                     op->o_tmpmemctx );
1478                                                                                 }
1479                                                                                 ber_memfree_x( sr_ref, op->o_tmpmemctx );
1480                                                                       }
1481                                                             }
1482 
1483                                                   } else if ( rs->sr_err == LDAP_REFERRAL ) {
1484                                                             Debug( LDAP_DEBUG_ANY,
1485                                                                       "%s meta_back_search[%ld]: "
1486                                                                       "got err=%d with null "
1487                                                                       "or empty referrals\n",
1488                                                                       op->o_log_prefix,
1489                                                                       i, rs->sr_err );
1490 
1491                                                             rs->sr_err = LDAP_NO_SUCH_OBJECT;
1492                                                   }
1493 
1494                                                   /* cleanup */
1495                                                   ber_memvfree( (void **)references );
1496 
1497                                                   sres = slap_map_api2result( rs );
1498 
1499                                                   if ( LogTest( LDAP_DEBUG_TRACE | LDAP_DEBUG_ANY ) ) {
1500                                                             char buf[ SLAP_TEXT_BUFLEN ];
1501                                                             snprintf( buf, sizeof( buf ),
1502                                                                       "%s meta_back_search[%ld] "
1503                                                                       "match=\"%s\" err=%ld",
1504                                                                       op->o_log_prefix, i,
1505                                                                       candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
1506                                                                       (long) candidates[ i ].sr_err );
1507                                                             if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
1508                                                                       Debug( LDAP_DEBUG_TRACE, "%s.\n", buf );
1509 
1510                                                             } else {
1511                                                                       Debug( LDAP_DEBUG_ANY, "%s (%s) text=\"%s\".\n",
1512                                                                                 buf, ldap_err2string( candidates[ i ].sr_err ),
1513                                                                                 candidates[ i ].sr_text ? candidates[i].sr_text : "" );
1514                                                             }
1515                                                   }
1516 
1517                                                   switch ( sres ) {
1518                                                   case LDAP_NO_SUCH_OBJECT:
1519                                                             /* is_ok is touched any time a valid
1520                                                              * (even intermediate) result is
1521                                                              * returned; as a consequence, if
1522                                                              * a candidate returns noSuchObject
1523                                                              * it is ignored and the candidate
1524                                                              * is simply demoted. */
1525                                                             if ( is_ok ) {
1526                                                                       sres = LDAP_SUCCESS;
1527                                                             }
1528                                                             break;
1529 
1530                                                   case LDAP_SUCCESS:
1531                                                             if ( ctrls != NULL && ctrls[0] != NULL ) {
1532 #ifdef SLAPD_META_CLIENT_PR
1533                                                                       LDAPControl *pr_c;
1534 
1535                                                                       pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, ctrls, NULL );
1536                                                                       if ( pr_c != NULL ) {
1537                                                                                 BerElementBuffer berbuf;
1538                                                                                 BerElement *ber = (BerElement *)&berbuf;
1539                                                                                 ber_tag_t tag;
1540                                                                                 ber_int_t prsize;
1541                                                                                 struct berval prcookie;
1542 
1543                                                                                 /* unsolicited, do not accept */
1544                                                                                 if ( mi->mi_targets[i]->mt_ps == 0 ) {
1545                                                                                           rs->sr_err = LDAP_OTHER;
1546                                                                                           goto err_pr;
1547                                                                                 }
1548 
1549                                                                                 ber_init2( ber, &pr_c->ldctl_value, LBER_USE_DER );
1550 
1551                                                                                 tag = ber_scanf( ber, "{im}", &prsize, &prcookie );
1552                                                                                 if ( tag == LBER_ERROR ) {
1553                                                                                           rs->sr_err = LDAP_OTHER;
1554                                                                                           goto err_pr;
1555                                                                                 }
1556 
1557                                                                                 /* more pages? new search request */
1558                                                                                 if ( !BER_BVISNULL( &prcookie ) && !BER_BVISEMPTY( &prcookie ) ) {
1559                                                                                           if ( mi->mi_targets[i]->mt_ps > 0 ) {
1560                                                                                                     /* ignore size if specified */
1561                                                                                                     prsize = 0;
1562 
1563                                                                                           } else if ( prsize == 0 ) {
1564                                                                                                     /* guess the page size from the entries returned so far */
1565                                                                                                     prsize = candidates[ i ].sr_nentries;
1566                                                                                           }
1567 
1568                                                                                           candidates[ i ].sr_nentries = 0;
1569                                                                                           candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1570                                                                                           candidates[ i ].sr_type = REP_INTERMEDIATE;
1571 
1572                                                                                           assert( candidates[ i ].sr_matched == NULL );
1573                                                                                           assert( candidates[ i ].sr_text == NULL );
1574                                                                                           assert( candidates[ i ].sr_ref == NULL );
1575 
1576                                                                                           switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, &prcookie, prsize ) )
1577                                                                                           {
1578                                                                                           case META_SEARCH_CANDIDATE:
1579                                                                                                     assert( candidates[ i ].sr_msgid >= 0 );
1580                                                                                                     ldap_controls_free( ctrls );
1581                                                                                                     goto free_message;
1582 
1583                                                                                           case META_SEARCH_ERR:
1584 err_pr:;
1585                                                                                                     candidates[ i ].sr_err = rs->sr_err;
1586                                                                                                     if ( META_BACK_ONERR_STOP( mi ) ) {
1587                                                                                                               savepriv = op->o_private;
1588                                                                                                               op->o_private = (void *)i;
1589                                                                                                               send_ldap_result( op, rs );
1590                                                                                                               op->o_private = savepriv;
1591                                                                                                               ldap_controls_free( ctrls );
1592                                                                                                               goto finish;
1593                                                                                                     }
1594                                                                                                     /* fallthru */
1595 
1596                                                                                           case META_SEARCH_NOT_CANDIDATE:
1597                                                                                                     /* means that meta_back_search_start()
1598                                                                                                      * failed but onerr == continue */
1599                                                                                                     candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1600                                                                                                     assert( ncandidates > 0 );
1601                                                                                                     --ncandidates;
1602                                                                                                     break;
1603 
1604                                                                                           default:
1605                                                                                                     /* impossible */
1606                                                                                                     assert( 0 );
1607                                                                                                     break;
1608                                                                                           }
1609                                                                                           break;
1610                                                                                 }
1611                                                                       }
1612 #endif /* SLAPD_META_CLIENT_PR */
1613                                                             }
1614                                                             /* fallthru */
1615 
1616                                                   case LDAP_REFERRAL:
1617                                                             is_ok++;
1618                                                             break;
1619 
1620                                                   case LDAP_SIZELIMIT_EXCEEDED:
1621                                                             /* if a target returned sizelimitExceeded
1622                                                              * and the entry count is equal to the
1623                                                              * proxy's limit, the target would have
1624                                                              * returned more, and the error must be
1625                                                              * propagated to the client; otherwise,
1626                                                              * the target enforced a limit lower
1627                                                              * than what requested by the proxy;
1628                                                              * ignore it */
1629                                                             candidates[ i ].sr_err = rs->sr_err;
1630                                                             if ( rs->sr_nentries == op->ors_slimit
1631                                                                       || META_BACK_ONERR_STOP( mi ) )
1632                                                             {
1633                                                                       const char *save_text;
1634 got_err:
1635                                                                       save_text = rs->sr_text;
1636                                                                       savepriv = op->o_private;
1637                                                                       op->o_private = (void *)i;
1638                                                                       rs->sr_text = candidates[ i ].sr_text;
1639                                                                       send_ldap_result( op, rs );
1640                                                                       rs->sr_text = save_text;
1641                                                                       op->o_private = savepriv;
1642                                                                       ldap_msgfree( res );
1643                                                                       res = NULL;
1644                                                                       ldap_controls_free( ctrls );
1645                                                                       goto finish;
1646                                                             }
1647                                                             break;
1648 
1649                                                   default:
1650                                                             candidates[ i ].sr_err = rs->sr_err;
1651                                                             if ( META_BACK_ONERR_STOP( mi ) )
1652                                                                       goto got_err;
1653                                                             break;
1654                                                   }
1655 
1656                                                   ldap_controls_free( ctrls );
1657                                                   last = i;
1658                                                   rc = 0;
1659 
1660                                                   /*
1661                                                    * When no candidates are left,
1662                                                    * the outer cycle finishes
1663                                                    */
1664                                                   assert( ncandidates > 0 );
1665                                                   --ncandidates;
1666 
1667                                         } else if ( rc == LDAP_RES_BIND ) {
1668                                                   meta_search_candidate_t       retcode;
1669 
1670                                                   retcode = meta_search_dobind_result( op, rs, &mc, i, candidates, msg );
1671                                                   if ( retcode == META_SEARCH_CANDIDATE ) {
1672                                                             candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1673                                                             retcode = meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 );
1674                                                   }
1675 
1676                                                   switch ( retcode ) {
1677                                                   case META_SEARCH_CANDIDATE:
1678                                                             break;
1679 
1680                                                             /* means that failed but onerr == continue */
1681                                                   case META_SEARCH_NOT_CANDIDATE:
1682                                                   case META_SEARCH_ERR:
1683                                                             candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1684                                                             assert( ncandidates > 0 );
1685                                                             --ncandidates;
1686 
1687                                                             candidates[ i ].sr_err = rs->sr_err;
1688                                                             if ( META_BACK_ONERR_STOP( mi ) ) {
1689                                                                       savepriv = op->o_private;
1690                                                                       op->o_private = (void *)i;
1691                                                                       send_ldap_result( op, rs );
1692                                                                       op->o_private = savepriv;
1693                                                                       ldap_msgfree( res );
1694                                                                       res = NULL;
1695                                                                       goto finish;
1696                                                             }
1697                                                             goto free_message;
1698 
1699                                                   default:
1700                                                             assert( 0 );
1701                                                             break;
1702                                                   }
1703 
1704                                         } else {
1705                                                   Debug( LDAP_DEBUG_ANY,
1706                                                             "%s meta_back_search[%ld]: "
1707                                                             "unrecognized response message tag=%d\n",
1708                                                             op->o_log_prefix,
1709                                                             i, rc );
1710 
1711                                                   ldap_msgfree( res );
1712                                                   res = NULL;
1713                                                   goto really_bad;
1714                                         }
1715                               }
1716 
1717 free_message:;
1718                               ldap_msgfree( res );
1719                               res = NULL;
1720                     }
1721 
1722                     /* check for abandon */
1723                     if ( op->o_abandon || LDAP_BACK_CONN_ABANDON( mc ) ) {
1724                               for ( i = 0; i < mi->mi_ntargets; i++ ) {
1725                                         if ( candidates[ i ].sr_msgid >= 0
1726                                                   || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
1727                                         {
1728                                                   if ( META_IS_BINDING( &candidates[ i ] )
1729                                                             || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
1730                                                   {
1731                                                             ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
1732                                                             if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] )
1733                                                                       || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
1734                                                             {
1735                                                                       /* if still binding, destroy */
1736 
1737 #ifdef DEBUG_205
1738                                                                       Debug(LDAP_DEBUG_ANY,
1739                                                                             "### %s meta_back_search(abandon) " "ldap_unbind_ext[%ld] mc=%p ld=%p\n",
1740                                                                             op->o_log_prefix,
1741                                                                             i, (void *)mc,
1742                                                                             (void *)mc->mc_conns[i].msc_ld );
1743 #endif /* DEBUG_205 */
1744 
1745                                                                       meta_clear_one_candidate( op, mc, i );
1746                                                             }
1747                                                             ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1748                                                             META_BINDING_CLEAR( &candidates[ i ] );
1749 
1750                                                   } else {
1751                                                             (void)meta_back_cancel( mc, op, rs,
1752                                                                       candidates[ i ].sr_msgid, i,
1753                                                                       LDAP_BACK_DONTSEND );
1754                                                   }
1755 
1756                                                   candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1757                                                   assert( ncandidates > 0 );
1758                                                   --ncandidates;
1759                                         }
1760                               }
1761 
1762                               if ( op->o_abandon ) {
1763                                         rc = SLAPD_ABANDON;
1764                               }
1765 
1766                               /* let send_ldap_result play cleanup handlers (ITS#4645) */
1767                               break;
1768                     }
1769 
1770                     /* if no entry was found during this loop,
1771                      * set a minimal timeout */
1772                     if ( ncandidates > 0 && gotit == 0 ) {
1773                               if ( save_tv.tv_sec == 0 && save_tv.tv_usec == 0 ) {
1774                                         save_tv.tv_usec = LDAP_BACK_RESULT_UTIMEOUT/initial_candidates;
1775 
1776                                         /* arbitrarily limit to something between 1 and 2 minutes */
1777                               } else if ( ( stoptime == -1 && save_tv.tv_sec < 60 )
1778                                         || save_tv.tv_sec < ( stoptime - slap_get_time() ) / ( 2 * ncandidates ) )
1779                               {
1780                                         /* double the timeout */
1781                                         lutil_timermul( &save_tv, 2, &save_tv );
1782                               }
1783 
1784                               if ( alreadybound == 0 ) {
1785                                         tv = save_tv;
1786                                         (void)select( 0, NULL, NULL, NULL, &tv );
1787 
1788                               } else {
1789                                         ldap_pvt_thread_yield();
1790                               }
1791                     }
1792           }
1793 
1794           if ( rc == -1 ) {
1795                     /*
1796                      * FIXME: need a better strategy to handle errors
1797                      */
1798                     if ( mc ) {
1799                               rc = meta_back_op_result( mc, op, rs, META_TARGET_NONE,
1800                                         -1, stoptime != -1 ? (stoptime - slap_get_time()) : 0,
1801                                         LDAP_BACK_SENDERR );
1802                     } else {
1803                               rc = rs->sr_err;
1804                     }
1805                     goto finish;
1806           }
1807 
1808           /*
1809            * Rewrite the matched portion of the search base, if required
1810            *
1811            * FIXME: only the last one gets caught!
1812            */
1813           savepriv = op->o_private;
1814           op->o_private = (void *)(long)mi->mi_ntargets;
1815           if ( candidate_match > 0 ) {
1816                     struct berval       pmatched = BER_BVNULL;
1817 
1818                     /* we use the first one */
1819                     for ( i = 0; i < mi->mi_ntargets; i++ ) {
1820                               if ( META_IS_CANDIDATE( &candidates[ i ] )
1821                                                   && candidates[ i ].sr_matched != NULL )
1822                               {
1823                                         struct berval       bv, pbv;
1824                                         int                 rc;
1825 
1826                                         /* if we got success, and this target
1827                                          * returned noSuchObject, and its suffix
1828                                          * is a superior of the searchBase,
1829                                          * ignore the matchedDN */
1830                                         if ( sres == LDAP_SUCCESS
1831                                                   && candidates[ i ].sr_err == LDAP_NO_SUCH_OBJECT
1832                                                   && op->o_req_ndn.bv_len > mi->mi_targets[ i ]->mt_nsuffix.bv_len )
1833                                         {
1834                                                   free( (char *)candidates[ i ].sr_matched );
1835                                                   candidates[ i ].sr_matched = NULL;
1836                                                   continue;
1837                                         }
1838 
1839                                         ber_str2bv( candidates[ i ].sr_matched, 0, 0, &bv );
1840                                         rc = dnPretty( NULL, &bv, &pbv, op->o_tmpmemctx );
1841 
1842                                         if ( rc == LDAP_SUCCESS ) {
1843 
1844                                                   /* NOTE: if they all are superiors
1845                                                    * of the baseDN, the shorter is also
1846                                                    * superior of the longer... */
1847                                                   if ( pbv.bv_len > pmatched.bv_len ) {
1848                                                             if ( !BER_BVISNULL( &pmatched ) ) {
1849                                                                       op->o_tmpfree( pmatched.bv_val, op->o_tmpmemctx );
1850                                                             }
1851                                                             pmatched = pbv;
1852                                                             op->o_private = (void *)i;
1853 
1854                                                   } else {
1855                                                             op->o_tmpfree( pbv.bv_val, op->o_tmpmemctx );
1856                                                   }
1857                                         }
1858 
1859                                         if ( candidates[ i ].sr_matched != NULL ) {
1860                                                   free( (char *)candidates[ i ].sr_matched );
1861                                                   candidates[ i ].sr_matched = NULL;
1862                                         }
1863                               }
1864                     }
1865 
1866                     if ( !BER_BVISNULL( &pmatched ) ) {
1867                               matched = pmatched.bv_val;
1868                     }
1869 
1870           } else if ( sres == LDAP_NO_SUCH_OBJECT ) {
1871                     matched = op->o_bd->be_suffix[ 0 ].bv_val;
1872           }
1873 
1874           /*
1875            * In case we returned at least one entry, we return LDAP_SUCCESS
1876            * otherwise, the latter error code we got
1877            */
1878 
1879           if ( sres == LDAP_SUCCESS ) {
1880                     if ( rs->sr_v2ref ) {
1881                               sres = LDAP_REFERRAL;
1882                     }
1883 
1884                     if ( META_BACK_ONERR_REPORT( mi ) ) {
1885                               /*
1886                                * Report errors, if any
1887                                *
1888                                * FIXME: we should handle error codes and return the more
1889                                * important/reasonable
1890                                */
1891                               for ( i = 0; i < mi->mi_ntargets; i++ ) {
1892                                         if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
1893                                                   continue;
1894                                         }
1895 
1896                                         if ( candidates[ i ].sr_err != LDAP_SUCCESS
1897                                                   && candidates[ i ].sr_err != LDAP_NO_SUCH_OBJECT )
1898                                         {
1899                                                   sres = candidates[ i ].sr_err;
1900                                                   break;
1901                                         }
1902                               }
1903                     }
1904           }
1905 
1906           rs->sr_err = sres;
1907           rs->sr_matched = ( sres == LDAP_SUCCESS ? NULL : matched );
1908           rs->sr_ref = ( sres == LDAP_REFERRAL ? rs->sr_v2ref : NULL );
1909           send_ldap_result( op, rs );
1910           op->o_private = savepriv;
1911           rs->sr_matched = NULL;
1912           rs->sr_ref = NULL;
1913 
1914 finish:;
1915           if ( matched && matched != op->o_bd->be_suffix[ 0 ].bv_val ) {
1916                     op->o_tmpfree( matched, op->o_tmpmemctx );
1917           }
1918 
1919           if ( rs->sr_v2ref ) {
1920                     ber_bvarray_free_x( rs->sr_v2ref, op->o_tmpmemctx );
1921           }
1922 
1923           for ( i = 0; i < mi->mi_ntargets; i++ ) {
1924                     if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
1925                               continue;
1926                     }
1927 
1928                     if ( mc ) {
1929                               if ( META_IS_BINDING( &candidates[ i ] )
1930                                         || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
1931                               {
1932                                         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
1933                                         if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] )
1934                                                   || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
1935                                         {
1936                                                   assert( candidates[ i ].sr_msgid >= 0
1937                                                             || candidates[ i ].sr_msgid == META_MSGID_CONNECTING );
1938                                                   assert( mc->mc_conns[ i ].msc_ld != NULL );
1939 
1940 #ifdef DEBUG_205
1941                                                   Debug( LDAP_DEBUG_ANY, "### %s meta_back_search(cleanup) "
1942                                                             "ldap_unbind_ext[%ld] ld=%p\n",
1943                                                             op->o_log_prefix, i, (void *)mc->mc_conns[i].msc_ld );
1944 #endif /* DEBUG_205 */
1945 
1946                                                   /* if still binding, destroy */
1947                                                   meta_clear_one_candidate( op, mc, i );
1948                                         }
1949                                         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
1950                                         META_BINDING_CLEAR( &candidates[ i ] );
1951 
1952                               } else if ( candidates[ i ].sr_msgid >= 0 ) {
1953                                         (void)meta_back_cancel( mc, op, rs,
1954                                                   candidates[ i ].sr_msgid, i,
1955                                                   LDAP_BACK_DONTSEND );
1956                               }
1957                     }
1958 
1959                     if ( candidates[ i ].sr_matched ) {
1960                               free( (char *)candidates[ i ].sr_matched );
1961                               candidates[ i ].sr_matched = NULL;
1962                     }
1963 
1964                     if ( candidates[ i ].sr_text ) {
1965                               ldap_memfree( (char *)candidates[ i ].sr_text );
1966                               candidates[ i ].sr_text = NULL;
1967                     }
1968 
1969                     if ( candidates[ i ].sr_ref ) {
1970                               ber_bvarray_free( candidates[ i ].sr_ref );
1971                               candidates[ i ].sr_ref = NULL;
1972                     }
1973 
1974                     if ( candidates[ i ].sr_ctrls ) {
1975                               ldap_controls_free( candidates[ i ].sr_ctrls );
1976                               candidates[ i ].sr_ctrls = NULL;
1977                     }
1978 
1979                     if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) {
1980                               meta_back_quarantine( op, &candidates[ i ], i );
1981                     }
1982 
1983                     /* only in case of timelimit exceeded, if the timelimit exceeded because
1984                      * one contacted target never responded, invalidate the connection
1985                      * NOTE: should we quarantine the target as well?  right now, the connection
1986                      * is invalidated; the next time it will be recreated and the target
1987                      * will be quarantined if it cannot be contacted */
1988                     if ( mi->mi_idle_timeout != 0
1989                               && rs->sr_err == LDAP_TIMELIMIT_EXCEEDED
1990                               && op->o_time > mc->mc_conns[ i ].msc_time )
1991                     {
1992                               /* don't let anyone else use this expired connection */
1993                               do_taint++;
1994                     }
1995           }
1996 
1997           if ( mc ) {
1998                     ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
1999                     if ( do_taint ) {
2000                               LDAP_BACK_CONN_TAINTED_SET( mc );
2001                     }
2002                     meta_back_release_conn_lock( mi, mc, 0 );
2003                     ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
2004           }
2005 
2006           return rs->sr_err;
2007 }
2008 
2009 static int
meta_send_entry(Operation * op,SlapReply * rs,metaconn_t * mc,int target,LDAPMessage * e)2010 meta_send_entry(
2011           Operation           *op,
2012           SlapReply *rs,
2013           metaconn_t          *mc,
2014           int                 target,
2015           LDAPMessage         *e )
2016 {
2017           metainfo_t                    *mi = ( metainfo_t * )op->o_bd->be_private;
2018           struct berval                 a, mapped;
2019           int                           check_duplicate_attrs = 0;
2020           int                           check_sorted_attrs = 0;
2021           Entry                         ent = { 0 };
2022           BerElement                    ber = *ldap_get_message_ber( e );
2023           Attribute                     *attr, **attrp;
2024           struct berval                 bdn,
2025                                         dn = BER_BVNULL;
2026           const char                    *text;
2027           dncookie            dc;
2028           ber_len_t           len;
2029           int                           rc;
2030 
2031           if ( ber_scanf( &ber, "l{", &len ) == LBER_ERROR ) {
2032                     return LDAP_DECODING_ERROR;
2033           }
2034 
2035           if ( ber_set_option( &ber, LBER_OPT_REMAINING_BYTES, &len ) != LBER_OPT_SUCCESS ) {
2036                     return LDAP_OTHER;
2037           }
2038 
2039           if ( ber_scanf( &ber, "m{", &bdn ) == LBER_ERROR ) {
2040                     return LDAP_DECODING_ERROR;
2041           }
2042 
2043           /*
2044            * Rewrite the dn of the result, if needed
2045            */
2046           dc.target = mi->mi_targets[ target ];
2047           dc.conn = op->o_conn;
2048           dc.rs = rs;
2049           dc.ctx = "searchResult";
2050 
2051           rs->sr_err = ldap_back_dn_massage( &dc, &bdn, &dn );
2052           if ( rs->sr_err != LDAP_SUCCESS) {
2053                     return rs->sr_err;
2054           }
2055 
2056           /*
2057            * Note: this may fail if the target host(s) schema differs
2058            * from the one known to the meta, and a DN with unknown
2059            * attributes is returned.
2060            *
2061            * FIXME: should we log anything, or delegate to dnNormalize?
2062            */
2063           rc = dnPrettyNormal( NULL, &dn, &ent.e_name, &ent.e_nname,
2064                     op->o_tmpmemctx );
2065           if ( dn.bv_val != bdn.bv_val ) {
2066                     free( dn.bv_val );
2067           }
2068           BER_BVZERO( &dn );
2069 
2070           if ( rc != LDAP_SUCCESS ) {
2071                     Debug( LDAP_DEBUG_ANY,
2072                               "%s meta_send_entry(\"%s\"): "
2073                               "invalid DN syntax\n",
2074                               op->o_log_prefix, ent.e_name.bv_val );
2075                     rc = LDAP_INVALID_DN_SYNTAX;
2076                     goto done;
2077           }
2078 
2079           /*
2080            * cache dn
2081            */
2082           if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) {
2083                     ( void )meta_dncache_update_entry( &mi->mi_cache,
2084                                         &ent.e_nname, target );
2085           }
2086 
2087           attrp = &ent.e_attrs;
2088 
2089           dc.ctx = "searchAttrDN";
2090           while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
2091                     int                                     last = 0;
2092                     slap_syntax_validate_func     *validate;
2093                     slap_syntax_transform_func    *pretty;
2094 
2095                     if ( ber_pvt_ber_remaining( &ber ) < 0 ) {
2096                               Debug( LDAP_DEBUG_ANY,
2097                                         "%s meta_send_entry(\"%s\"): "
2098                                         "unable to parse attr \"%s\".\n",
2099                                         op->o_log_prefix, ent.e_name.bv_val, a.bv_val );
2100 
2101                               rc = LDAP_OTHER;
2102                               goto done;
2103                     }
2104 
2105                     if ( ber_pvt_ber_remaining( &ber ) == 0 ) {
2106                               break;
2107                     }
2108 
2109                     ldap_back_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_at,
2110                                         &a, &mapped, BACKLDAP_REMAP );
2111                     if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) {
2112                               ( void )ber_scanf( &ber, "x" /* [W] */ );
2113                               continue;
2114                     }
2115                     if ( mapped.bv_val != a.bv_val ) {
2116                               /* will need to check for duplicate attrs */
2117                               check_duplicate_attrs++;
2118                     }
2119                     attr = attr_alloc( NULL );
2120                     if ( attr == NULL ) {
2121                               rc = LDAP_OTHER;
2122                               goto done;
2123                     }
2124                     if ( slap_bv2ad( &mapped, &attr->a_desc, &text )
2125                                         != LDAP_SUCCESS) {
2126                               if ( slap_bv2undef_ad( &mapped, &attr->a_desc, &text,
2127                                         SLAP_AD_PROXIED ) != LDAP_SUCCESS )
2128                               {
2129                                         Debug(LDAP_DEBUG_ANY,
2130                                               "%s meta_send_entry(\"%s\"): " "slap_bv2undef_ad(%s): %s\n",
2131                                               op->o_log_prefix, ent.e_name.bv_val,
2132                                               mapped.bv_val, text );
2133                                         ( void )ber_scanf( &ber, "x" /* [W] */ );
2134                                         attr_free( attr );
2135                                         continue;
2136                               }
2137                     }
2138 
2139                     if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL )
2140                               check_sorted_attrs = 1;
2141 
2142                     /* no subschemaSubentry */
2143                     if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry
2144                               || attr->a_desc == slap_schema.si_ad_entryDN )
2145                     {
2146 
2147                               /*
2148                                * We eat target's subschemaSubentry because
2149                                * a search for this value is likely not
2150                                * to resolve to the appropriate backend;
2151                                * later, the local subschemaSubentry is
2152                                * added.
2153                                *
2154                                * We also eat entryDN because the frontend
2155                                * will reattach it without checking if already
2156                                * present...
2157                                */
2158                               ( void )ber_scanf( &ber, "x" /* [W] */ );
2159                               attr_free(attr);
2160                               continue;
2161                     }
2162 
2163                     if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR
2164                                         || attr->a_vals == NULL )
2165                     {
2166                               attr->a_vals = (struct berval *)&slap_dummy_bv;
2167 
2168                     } else {
2169                               for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); ++last )
2170                                         ;
2171                     }
2172                     attr->a_numvals = last;
2173 
2174                     validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate;
2175                     pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty;
2176 
2177                     if ( !validate && !pretty ) {
2178                               attr_free( attr );
2179                               goto next_attr;
2180                     }
2181 
2182                     if ( attr->a_desc == slap_schema.si_ad_objectClass
2183                                         || attr->a_desc == slap_schema.si_ad_structuralObjectClass )
2184                     {
2185                               struct berval       *bv;
2186 
2187                               for ( bv = attr->a_vals; !BER_BVISNULL( bv ); bv++ ) {
2188                                         ObjectClass *oc;
2189 
2190                                         ldap_back_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_oc,
2191                                                             bv, &mapped, BACKLDAP_REMAP );
2192                                         if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0') {
2193 remove_oc:;
2194                                                   free( bv->bv_val );
2195                                                   BER_BVZERO( bv );
2196                                                   if ( --last < 0 ) {
2197                                                             break;
2198                                                   }
2199                                                   *bv = attr->a_vals[ last ];
2200                                                   BER_BVZERO( &attr->a_vals[ last ] );
2201                                                   bv--;
2202 
2203                                         } else if ( mapped.bv_val != bv->bv_val ) {
2204                                                   int       i;
2205 
2206                                                   for ( i = 0; !BER_BVISNULL( &attr->a_vals[ i ] ); i++ ) {
2207                                                             if ( &attr->a_vals[ i ] == bv ) {
2208                                                                       continue;
2209                                                             }
2210 
2211                                                             if ( ber_bvstrcasecmp( &mapped, &attr->a_vals[ i ] ) == 0 ) {
2212                                                                       break;
2213                                                             }
2214                                                   }
2215 
2216                                                   if ( !BER_BVISNULL( &attr->a_vals[ i ] ) ) {
2217                                                             goto remove_oc;
2218                                                   }
2219 
2220                                                   ber_bvreplace( bv, &mapped );
2221 
2222                                         } else if ( ( oc = oc_bvfind_undef( bv ) ) == NULL ) {
2223                                                   goto remove_oc;
2224 
2225                                         } else {
2226                                                   ber_bvreplace( bv, &oc->soc_cname );
2227                                         }
2228                               }
2229                     /*
2230                      * It is necessary to try to rewrite attributes with
2231                      * dn syntax because they might be used in ACLs as
2232                      * members of groups; since ACLs are applied to the
2233                      * rewritten stuff, no dn-based subecj clause could
2234                      * be used at the ldap backend side (see
2235                      * http://www.OpenLDAP.org/faq/data/cache/452.html)
2236                      * The problem can be overcome by moving the dn-based
2237                      * ACLs to the target directory server, and letting
2238                      * everything pass thru the ldap backend.
2239                      */
2240                     } else {
2241                               int       i;
2242 
2243                               if ( attr->a_desc->ad_type->sat_syntax ==
2244                                         slap_schema.si_syn_distinguishedName )
2245                               {
2246                                         ldap_dnattr_result_rewrite( &dc, attr->a_vals );
2247 
2248                               } else if ( attr->a_desc == slap_schema.si_ad_ref ) {
2249                                         ldap_back_referral_result_rewrite( &dc, attr->a_vals, NULL );
2250 
2251                               }
2252 
2253                               for ( i = 0; i < last; i++ ) {
2254                                         struct berval       pval;
2255                                         int                 rc;
2256 
2257                                         if ( pretty ) {
2258                                                   rc = ordered_value_pretty( attr->a_desc,
2259                                                             &attr->a_vals[i], &pval, NULL );
2260 
2261                                         } else {
2262                                                   rc = ordered_value_validate( attr->a_desc,
2263                                                             &attr->a_vals[i], 0 );
2264                                         }
2265 
2266                                         if ( rc ) {
2267                                                   ber_memfree( attr->a_vals[i].bv_val );
2268                                                   if ( --last == i ) {
2269                                                             BER_BVZERO( &attr->a_vals[ i ] );
2270                                                             break;
2271                                                   }
2272                                                   attr->a_vals[i] = attr->a_vals[last];
2273                                                   BER_BVZERO( &attr->a_vals[last] );
2274                                                   i--;
2275                                                   continue;
2276                                         }
2277 
2278                                         if ( pretty ) {
2279                                                   ber_memfree( attr->a_vals[i].bv_val );
2280                                                   attr->a_vals[i] = pval;
2281                                         }
2282                               }
2283 
2284                               if ( last == 0 && attr->a_vals != &slap_dummy_bv ) {
2285                                         attr_free( attr );
2286                                         goto next_attr;
2287                               }
2288                     }
2289 
2290                     if ( last && attr->a_desc->ad_type->sat_equality &&
2291                               attr->a_desc->ad_type->sat_equality->smr_normalize )
2292                     {
2293                               int i;
2294 
2295                               attr->a_nvals = ch_malloc( ( last + 1 ) * sizeof( struct berval ) );
2296                               for ( i = 0; i<last; i++ ) {
2297                                         /* if normalizer fails, drop this value */
2298                                         if ( ordered_value_normalize(
2299                                                   SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
2300                                                   attr->a_desc,
2301                                                   attr->a_desc->ad_type->sat_equality,
2302                                                   &attr->a_vals[i], &attr->a_nvals[i],
2303                                                   NULL )) {
2304                                                   ber_memfree( attr->a_vals[i].bv_val );
2305                                                   if ( --last == i ) {
2306                                                             BER_BVZERO( &attr->a_vals[ i ] );
2307                                                             break;
2308                                                   }
2309                                                   attr->a_vals[i] = attr->a_vals[last];
2310                                                   BER_BVZERO( &attr->a_vals[last] );
2311                                                   i--;
2312                                         }
2313                               }
2314                               BER_BVZERO( &attr->a_nvals[i] );
2315                               if ( last == 0 ) {
2316                                         attr_free( attr );
2317                                         goto next_attr;
2318                               }
2319 
2320                     } else {
2321                               attr->a_nvals = attr->a_vals;
2322                     }
2323 
2324                     attr->a_numvals = last;
2325                     *attrp = attr;
2326                     attrp = &attr->a_next;
2327 next_attr:;
2328           }
2329 
2330           /* only check if some mapping occurred */
2331           if ( check_duplicate_attrs ) {
2332                     Attribute **ap;
2333 
2334                     for ( ap = &ent.e_attrs; *ap != NULL; ap = &(*ap)->a_next ) {
2335                               Attribute **tap;
2336 
2337                               for ( tap = &(*ap)->a_next; *tap != NULL; ) {
2338                                         if ( (*tap)->a_desc == (*ap)->a_desc ) {
2339                                                   Entry               e = { 0 };
2340                                                   Modification        mod = { 0 };
2341                                                   const char          *text = NULL;
2342                                                   char                textbuf[ SLAP_TEXT_BUFLEN ];
2343                                                   Attribute *next = (*tap)->a_next;
2344 
2345                                                   BER_BVSTR( &e.e_name, "" );
2346                                                   BER_BVSTR( &e.e_nname, "" );
2347                                                   e.e_attrs = *ap;
2348                                                   mod.sm_op = LDAP_MOD_ADD;
2349                                                   mod.sm_desc = (*ap)->a_desc;
2350                                                   mod.sm_type = mod.sm_desc->ad_cname;
2351                                                   mod.sm_numvals = (*ap)->a_numvals;
2352                                                   mod.sm_values = (*tap)->a_vals;
2353                                                   if ( (*tap)->a_nvals != (*tap)->a_vals ) {
2354                                                             mod.sm_nvalues = (*tap)->a_nvals;
2355                                                   }
2356 
2357                                                   (void)modify_add_values( &e, &mod,
2358                                                             /* permissive */ 1,
2359                                                             &text, textbuf, sizeof( textbuf ) );
2360 
2361                                                   /* should not insert new attrs! */
2362                                                   assert( e.e_attrs == *ap );
2363 
2364                                                   attr_free( *tap );
2365                                                   *tap = next;
2366 
2367                                         } else {
2368                                                   tap = &(*tap)->a_next;
2369                                         }
2370                               }
2371                     }
2372           }
2373 
2374           /* Check for sorted attributes */
2375           if ( check_sorted_attrs ) {
2376                     for ( attr = ent.e_attrs; attr; attr = attr->a_next ) {
2377                               if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) {
2378                                         while ( attr->a_numvals > 1 ) {
2379                                                   int i;
2380                                                   int rc = slap_sort_vals( (Modifications *)attr, &text, &i, op->o_tmpmemctx );
2381                                                   if ( rc != LDAP_TYPE_OR_VALUE_EXISTS )
2382                                                             break;
2383 
2384                                                   /* Strip duplicate values */
2385                                                   if ( attr->a_nvals != attr->a_vals )
2386                                                             ber_memfree( attr->a_nvals[i].bv_val );
2387                                                   ber_memfree( attr->a_vals[i].bv_val );
2388                                                   attr->a_numvals--;
2389                                                   if ( (unsigned)i < attr->a_numvals ) {
2390                                                             attr->a_vals[i] = attr->a_vals[attr->a_numvals];
2391                                                             if ( attr->a_nvals != attr->a_vals )
2392                                                                       attr->a_nvals[i] = attr->a_nvals[attr->a_numvals];
2393                                                   }
2394                                                   BER_BVZERO(&attr->a_vals[attr->a_numvals]);
2395                                                   if ( attr->a_nvals != attr->a_vals )
2396                                                             BER_BVZERO(&attr->a_nvals[attr->a_numvals]);
2397                                         }
2398                                         attr->a_flags |= SLAP_ATTR_SORTED_VALS;
2399                               }
2400                     }
2401           }
2402 
2403           ldap_get_entry_controls( mc->mc_conns[target].msc_ld,
2404                     e, &rs->sr_ctrls );
2405           rs->sr_entry = &ent;
2406           rs->sr_attrs = op->ors_attrs;
2407           rs->sr_operational_attrs = NULL;
2408           rs->sr_flags = mi->mi_targets[ target ]->mt_rep_flags;
2409           rs->sr_err = LDAP_SUCCESS;
2410           rc = send_search_entry( op, rs );
2411           switch ( rc ) {
2412           case LDAP_UNAVAILABLE:
2413                     rc = LDAP_OTHER;
2414                     break;
2415           }
2416 
2417 done:;
2418           rs->sr_entry = NULL;
2419           rs->sr_attrs = NULL;
2420           if ( rs->sr_ctrls != NULL ) {
2421                     ldap_controls_free( rs->sr_ctrls );
2422                     rs->sr_ctrls = NULL;
2423           }
2424           if ( !BER_BVISNULL( &ent.e_name ) ) {
2425                     free( ent.e_name.bv_val );
2426                     BER_BVZERO( &ent.e_name );
2427           }
2428           if ( !BER_BVISNULL( &ent.e_nname ) ) {
2429                     free( ent.e_nname.bv_val );
2430                     BER_BVZERO( &ent.e_nname );
2431           }
2432           entry_clean( &ent );
2433 
2434           return rc;
2435 }
2436 
2437