]> git.sur5r.net Git - openldap/blob - servers/slapd/back-asyncmeta/meta_result.c
Happy New Year
[openldap] / servers / slapd / back-asyncmeta / meta_result.c
1 /* meta_result.c - target responses processing */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2016-2018 The OpenLDAP Foundation.
6  * Portions Copyright 2016 Symas Corporation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17
18 /* ACKNOWLEDGEMENTS:
19  * This work was developed by Symas Corporation
20  * based on back-meta module for inclusion in OpenLDAP Software.
21  * This work was sponsored by Ericsson. */
22
23 #include "portable.h"
24
25 #include <stdio.h>
26
27 #include <ac/string.h>
28 #include <ac/socket.h>
29
30 #include "slap.h"
31 #include "../back-ldap/back-ldap.h"
32 #include "back-asyncmeta.h"
33 #include "ldap_rq.h"
34 #include "../../../libraries/liblber/lber-int.h"
35
36 static int
37 asyncmeta_is_last_result(a_metaconn_t *mc, bm_context_t *bc, int candidate)
38 {
39         a_metainfo_t    *mi = mc->mc_info;
40         a_metatarget_t  *mt = mi->mi_targets[ candidate ];
41         int i,found = 0;
42         SlapReply *candidates = bc->candidates;
43         for ( i = 0; i < mi->mi_ntargets; i++ ) {
44                 if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
45                         continue;
46                 }
47                 if (candidates[ i ].sr_msgid != META_MSGID_IGNORE ||
48                     candidates[ i ].sr_type != REP_RESULT) {
49                         return 1;
50                 }
51         }
52         return 0;
53 }
54
55 meta_search_candidate_t
56 asyncmeta_dobind_result(
57         Operation               *op,
58         SlapReply               *rs,
59         a_metaconn_t            *mc,
60         int                     candidate,
61         SlapReply               *candidates,
62         LDAPMessage             *res )
63 {
64         a_metainfo_t            *mi = mc->mc_info;
65         a_metatarget_t          *mt = mi->mi_targets[ candidate ];
66         a_metasingleconn_t      *msc = &mc->mc_conns[ candidate ];
67
68         meta_search_candidate_t retcode = META_SEARCH_NOT_CANDIDATE;
69         int                     rc;
70
71         assert( msc->msc_ldr != NULL );
72
73         /* FIXME: matched? referrals? response controls? */
74         rc = ldap_parse_result( msc->msc_ldr, res,
75                 &candidates[ candidate ].sr_err,
76                 NULL, NULL, NULL, NULL, 0 );
77         if ( rc != LDAP_SUCCESS ) {
78                 candidates[ candidate ].sr_err = rc;
79         }
80         rc = slap_map_api2result( &candidates[ candidate ] );
81
82         LDAP_BACK_CONN_BINDING_CLEAR( msc );
83         if ( rc != LDAP_SUCCESS ) {
84                 candidates[ candidate ].sr_err = rc;
85                 if ( META_BACK_ONERR_STOP( mi ) || op->o_tag != LDAP_REQ_SEARCH) {
86                         asyncmeta_clear_one_msc(op, mc, candidate);
87                         retcode = META_SEARCH_ERR;
88                         rs->sr_err = rc;
89                 }
90
91         } else {
92                 /* FIXME: check if bound as idassert authcDN! */
93                 if ( BER_BVISNULL( &msc->msc_bound_ndn )
94                         || BER_BVISEMPTY( &msc->msc_bound_ndn ) )
95                 {
96                         LDAP_BACK_CONN_ISANON_SET( msc );
97
98                 } else {
99                         if ( META_BACK_TGT_SAVECRED( mt ) &&
100                                 !BER_BVISNULL( &msc->msc_cred ) &&
101                                 !BER_BVISEMPTY( &msc->msc_cred ) )
102                         {
103                                 ldap_set_rebind_proc( msc->msc_ldr, mt->mt_rebind_f, msc );
104                         }
105                         LDAP_BACK_CONN_ISBOUND_SET( msc );
106                 }
107                 retcode = META_SEARCH_CANDIDATE;
108
109                 /* connect must be async */
110                 //ldap_set_option( msc->msc_ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_OFF );
111         }
112
113         candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
114         META_BINDING_CLEAR( &candidates[ candidate ] );
115
116         return retcode;
117 }
118
119 static int
120 asyncmeta_send_entry(
121         Operation       *op,
122         SlapReply       *rs,
123         a_metaconn_t    *mc,
124         int             target,
125         LDAPMessage     *e )
126 {
127         a_metainfo_t            *mi = mc->mc_info;
128         struct berval           a, mapped;
129         int                     check_duplicate_attrs = 0;
130         int                     check_sorted_attrs = 0;
131         Entry                   ent = {0};
132         BerElement              ber = *ldap_get_message_ber( e );
133         Attribute               *attr, **attrp;
134         struct berval           bdn,
135                                 dn = BER_BVNULL;
136         const char              *text;
137         a_dncookie              dc;
138         ber_len_t               len;
139         int                     rc;
140
141         if ( ber_scanf( &ber, "l{", &len ) == LBER_ERROR ) {
142                 return LDAP_DECODING_ERROR;
143         }
144
145         if ( ber_set_option( &ber, LBER_OPT_REMAINING_BYTES, &len ) != LBER_OPT_SUCCESS ) {
146                 return LDAP_OTHER;
147         }
148
149         if ( ber_scanf( &ber, "m{", &bdn ) == LBER_ERROR ) {
150                 return LDAP_DECODING_ERROR;
151         }
152
153         /*
154          * Rewrite the dn of the result, if needed
155          */
156         dc.target = mi->mi_targets[ target ];
157         dc.conn = op->o_conn;
158         dc.rs = rs;
159         dc.ctx = "searchResult";
160
161         rs->sr_err = asyncmeta_dn_massage( &dc, &bdn, &dn );
162         if ( rs->sr_err != LDAP_SUCCESS) {
163                 return rs->sr_err;
164         }
165
166         /*
167          * Note: this may fail if the target host(s) schema differs
168          * from the one known to the meta, and a DN with unknown
169          * attributes is returned.
170          *
171          * FIXME: should we log anything, or delegate to dnNormalize?
172          */
173         rc = dnPrettyNormal( NULL, &dn, &ent.e_name, &ent.e_nname,
174                 op->o_tmpmemctx );
175         if ( dn.bv_val != bdn.bv_val ) {
176                         free( dn.bv_val );
177         }
178         BER_BVZERO( &dn );
179
180         if ( rc != LDAP_SUCCESS ) {
181                 Debug( LDAP_DEBUG_ANY,
182                         "%s asyncmeta_send_entry(\"%s\"): "
183                         "invalid DN syntax\n",
184                         op->o_log_prefix, ent.e_name.bv_val, 0 );
185                 rc = LDAP_INVALID_DN_SYNTAX;
186                 goto done;
187         }
188
189         /*
190          * cache dn
191          */
192         if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) {
193                 ( void )asyncmeta_dncache_update_entry( &mi->mi_cache,
194                                 &ent.e_nname, target );
195         }
196
197         attrp = &ent.e_attrs;
198
199         dc.ctx = "searchAttrDN";
200         while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
201                 int                             last = 0;
202                 slap_syntax_validate_func       *validate;
203                 slap_syntax_transform_func      *pretty;
204
205                 if ( ber_pvt_ber_remaining( &ber ) < 0 ) {
206                         Debug( LDAP_DEBUG_ANY,
207                                 "%s asyncmeta_send_entry(\"%s\"): "
208                                 "unable to parse attr \"%s\".\n",
209                                 op->o_log_prefix, ent.e_name.bv_val, a.bv_val );
210
211                         rc = LDAP_OTHER;
212                         goto done;
213                 }
214
215                 if ( ber_pvt_ber_remaining( &ber ) == 0 ) {
216                         break;
217                 }
218
219                 asyncmeta_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_at,
220                                 &a, &mapped, BACKLDAP_REMAP );
221                 if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) {
222                         ( void )ber_scanf( &ber, "x" /* [W] */ );
223                         continue;
224                 }
225                 if ( mapped.bv_val != a.bv_val ) {
226                         /* will need to check for duplicate attrs */
227                         check_duplicate_attrs++;
228                 }
229                 attr = op->o_tmpcalloc( 1, sizeof(Attribute), op->o_tmpmemctx );
230                 if ( slap_bv2ad( &mapped, &attr->a_desc, &text )
231                                 != LDAP_SUCCESS) {
232                         if ( slap_bv2undef_ad( &mapped, &attr->a_desc, &text,
233                                 SLAP_AD_PROXIED ) != LDAP_SUCCESS )
234                         {
235                                 char    buf[ SLAP_TEXT_BUFLEN ];
236
237                                 snprintf( buf, sizeof( buf ),
238                                         "%s meta_send_entry(\"%s\"): "
239                                         "slap_bv2undef_ad(%s): %s\n",
240                                         op->o_log_prefix, ent.e_name.bv_val,
241                                         mapped.bv_val, text );
242
243                                 Debug( LDAP_DEBUG_ANY, "%s", buf, 0, 0 );
244                                 ( void )ber_scanf( &ber, "x" /* [W] */ );
245                                 op->o_tmpfree( attr, op->o_tmpmemctx );
246                                 continue;
247                         }
248                 }
249
250                 if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL )
251                         check_sorted_attrs = 1;
252
253                 /* no subschemaSubentry */
254                 if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry
255                         || attr->a_desc == slap_schema.si_ad_entryDN )
256                 {
257
258                         /*
259                          * We eat target's subschemaSubentry because
260                          * a search for this value is likely not
261                          * to resolve to the appropriate backend;
262                          * later, the local subschemaSubentry is
263                          * added.
264                          *
265                          * We also eat entryDN because the frontend
266                          * will reattach it without checking if already
267                          * present...
268                          */
269                         ( void )ber_scanf( &ber, "x" /* [W] */ );
270                         op->o_tmpfree( attr, op->o_tmpmemctx );
271                         continue;
272                 }
273
274                 if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR
275                                 || attr->a_vals == NULL )
276                 {
277                         attr->a_vals = (struct berval *)&slap_dummy_bv;
278
279                 } else {
280                         for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); ++last )
281                                 ;
282                 }
283                 attr->a_numvals = last;
284
285                 validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate;
286                 pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty;
287
288                 if ( !validate && !pretty ) {
289                         attr_clean( attr );
290                         op->o_tmpfree( attr, op->o_tmpmemctx );
291                         goto next_attr;
292                 }
293
294                 if ( attr->a_desc == slap_schema.si_ad_objectClass
295                                 || attr->a_desc == slap_schema.si_ad_structuralObjectClass )
296                 {
297                         struct berval   *bv;
298
299                         for ( bv = attr->a_vals; !BER_BVISNULL( bv ); bv++ ) {
300                                 ObjectClass *oc;
301
302                                 asyncmeta_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_oc,
303                                                 bv, &mapped, BACKLDAP_REMAP );
304                                 if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0') {
305 remove_oc:;
306                                         free( bv->bv_val );
307                                         BER_BVZERO( bv );
308                                         if ( --last < 0 ) {
309                                                 break;
310                                         }
311                                         *bv = attr->a_vals[ last ];
312                                         BER_BVZERO( &attr->a_vals[ last ] );
313                                         bv--;
314
315                                 } else if ( mapped.bv_val != bv->bv_val ) {
316                                         int     i;
317
318                                         for ( i = 0; !BER_BVISNULL( &attr->a_vals[ i ] ); i++ ) {
319                                                 if ( &attr->a_vals[ i ] == bv ) {
320                                                         continue;
321                                                 }
322
323                                                 if ( ber_bvstrcasecmp( &mapped, &attr->a_vals[ i ] ) == 0 ) {
324                                                         break;
325                                                 }
326                                         }
327
328                                         if ( !BER_BVISNULL( &attr->a_vals[ i ] ) ) {
329                                                 goto remove_oc;
330                                         }
331
332                                         ber_bvreplace( bv, &mapped );
333
334                                 } else if ( ( oc = oc_bvfind_undef( bv ) ) == NULL ) {
335                                         goto remove_oc;
336
337                                 } else {
338                                         ber_bvreplace( bv, &oc->soc_cname );
339                                 }
340                         }
341                 /*
342                  * It is necessary to try to rewrite attributes with
343                  * dn syntax because they might be used in ACLs as
344                  * members of groups; since ACLs are applied to the
345                  * rewritten stuff, no dn-based subecj clause could
346                  * be used at the ldap backend side (see
347                  * http://www.OpenLDAP.org/faq/data/cache/452.html)
348                  * The problem can be overcome by moving the dn-based
349                  * ACLs to the target directory server, and letting
350                  * everything pass thru the ldap backend.
351                  */
352                 } else {
353                         int     i;
354
355                         if ( attr->a_desc->ad_type->sat_syntax ==
356                                 slap_schema.si_syn_distinguishedName )
357                         {
358                                 asyncmeta_dnattr_result_rewrite( &dc, attr->a_vals );
359
360                         } else if ( attr->a_desc == slap_schema.si_ad_ref ) {
361                                 asyncmeta_referral_result_rewrite( &dc, attr->a_vals, NULL );
362
363                         }
364
365                         for ( i = 0; i < last; i++ ) {
366                                 struct berval   pval;
367                                 int             rc;
368
369                                 if ( pretty ) {
370                                         rc = ordered_value_pretty( attr->a_desc,
371                                                 &attr->a_vals[i], &pval, NULL );
372
373                                 } else {
374                                         rc = ordered_value_validate( attr->a_desc,
375                                                 &attr->a_vals[i], 0 );
376                                 }
377
378                                 if ( rc ) {
379                                         ber_memfree( attr->a_vals[i].bv_val );
380                                         if ( --last == i ) {
381                                                 BER_BVZERO( &attr->a_vals[ i ] );
382                                                 break;
383                                         }
384                                         attr->a_vals[i] = attr->a_vals[last];
385                                         BER_BVZERO( &attr->a_vals[last] );
386                                         i--;
387                                         continue;
388                                 }
389
390                                 if ( pretty ) {
391                                         ber_memfree( attr->a_vals[i].bv_val );
392                                         attr->a_vals[i] = pval;
393                                 }
394                         }
395
396                         if ( last == 0 && attr->a_vals != &slap_dummy_bv ) {
397                                 attr_clean( attr );
398                                 op->o_tmpfree( attr, op->o_tmpmemctx );
399                                 goto next_attr;
400                         }
401                 }
402
403                 if ( last && attr->a_desc->ad_type->sat_equality &&
404                         attr->a_desc->ad_type->sat_equality->smr_normalize )
405                 {
406                         int i;
407
408                         attr->a_nvals = ch_malloc( ( last + 1 ) * sizeof( struct berval ) );
409                         for ( i = 0; i<last; i++ ) {
410                                 /* if normalizer fails, drop this value */
411                                 if ( ordered_value_normalize(
412                                         SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
413                                         attr->a_desc,
414                                         attr->a_desc->ad_type->sat_equality,
415                                         &attr->a_vals[i], &attr->a_nvals[i],
416                                         NULL )) {
417                                         ber_memfree( attr->a_vals[i].bv_val );
418                                         if ( --last == i ) {
419                                                 BER_BVZERO( &attr->a_vals[ i ] );
420                                                 break;
421                                         }
422                                         attr->a_vals[i] = attr->a_vals[last];
423                                         BER_BVZERO( &attr->a_vals[last] );
424                                         i--;
425                                 }
426                         }
427                         BER_BVZERO( &attr->a_nvals[i] );
428                         if ( last == 0 ) {
429                                 attr_clean( attr );
430                                 op->o_tmpfree( attr, op->o_tmpmemctx );
431                                 goto next_attr;
432                         }
433
434                 } else {
435                         attr->a_nvals = attr->a_vals;
436                 }
437
438                 attr->a_numvals = last;
439                 *attrp = attr;
440                 attrp = &attr->a_next;
441 next_attr:;
442         }
443
444         /* only check if some mapping occurred */
445         if ( check_duplicate_attrs ) {
446                 Attribute       **ap;
447
448                 for ( ap = &ent.e_attrs; *ap != NULL; ap = &(*ap)->a_next ) {
449                         Attribute       **tap;
450
451                         for ( tap = &(*ap)->a_next; *tap != NULL; ) {
452                                 if ( (*tap)->a_desc == (*ap)->a_desc ) {
453                                         Entry           e = { 0 };
454                                         Modification    mod = { 0 };
455                                         const char      *text = NULL;
456                                         char            textbuf[ SLAP_TEXT_BUFLEN ];
457                                         Attribute       *next = (*tap)->a_next;
458
459                                         BER_BVSTR( &e.e_name, "" );
460                                         BER_BVSTR( &e.e_nname, "" );
461                                         e.e_attrs = *ap;
462                                         mod.sm_op = LDAP_MOD_ADD;
463                                         mod.sm_desc = (*ap)->a_desc;
464                                         mod.sm_type = mod.sm_desc->ad_cname;
465                                         mod.sm_numvals = (*ap)->a_numvals;
466                                         mod.sm_values = (*tap)->a_vals;
467                                         if ( (*tap)->a_nvals != (*tap)->a_vals ) {
468                                                 mod.sm_nvalues = (*tap)->a_nvals;
469                                         }
470
471                                         (void)modify_add_values( &e, &mod,
472                                                 /* permissive */ 1,
473                                                 &text, textbuf, sizeof( textbuf ) );
474
475                                         /* should not insert new attrs! */
476                                         assert( e.e_attrs == *ap );
477
478                                         attr_clean( *tap );
479                                         op->o_tmpfree( *tap, op->o_tmpmemctx );
480                                         *tap = next;
481
482                                 } else {
483                                         tap = &(*tap)->a_next;
484                                 }
485                         }
486                 }
487         }
488
489         /* Check for sorted attributes */
490         if ( check_sorted_attrs ) {
491                 for ( attr = ent.e_attrs; attr; attr = attr->a_next ) {
492                         if ( attr->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) {
493                                 while ( attr->a_numvals > 1 ) {
494                                         int i;
495                                         int rc = slap_sort_vals( (Modifications *)attr, &text, &i, op->o_tmpmemctx );
496                                         if ( rc != LDAP_TYPE_OR_VALUE_EXISTS )
497                                                 break;
498
499                                         /* Strip duplicate values */
500                                         if ( attr->a_nvals != attr->a_vals )
501                                                 ber_memfree( attr->a_nvals[i].bv_val );
502                                         ber_memfree( attr->a_vals[i].bv_val );
503                                         attr->a_numvals--;
504                                         if ( (unsigned)i < attr->a_numvals ) {
505                                                 attr->a_vals[i] = attr->a_vals[attr->a_numvals];
506                                                 if ( attr->a_nvals != attr->a_vals )
507                                                         attr->a_nvals[i] = attr->a_nvals[attr->a_numvals];
508                                         }
509                                         BER_BVZERO(&attr->a_vals[attr->a_numvals]);
510                                         if ( attr->a_nvals != attr->a_vals )
511                                                 BER_BVZERO(&attr->a_nvals[attr->a_numvals]);
512                                 }
513                                 attr->a_flags |= SLAP_ATTR_SORTED_VALS;
514                         }
515                 }
516         }
517         Debug( LDAP_DEBUG_TRACE,
518                "%s asyncmeta_send_entry(\"%s\"): "
519                ".\n",
520                op->o_log_prefix, ent.e_name.bv_val, 0);
521         ldap_get_entry_controls( mc->mc_conns[target].msc_ldr,
522                 e, &rs->sr_ctrls );
523         rs->sr_entry = &ent;
524         rs->sr_attrs = op->ors_attrs;
525         rs->sr_operational_attrs = NULL;
526         rs->sr_flags = mi->mi_targets[ target ]->mt_rep_flags;
527         rs->sr_err = LDAP_SUCCESS;
528         rc = send_search_entry( op, rs );
529         switch ( rc ) {
530         case LDAP_UNAVAILABLE:
531                 rc = LDAP_OTHER;
532                 break;
533         }
534
535 done:;
536         if ( rs->sr_ctrls != NULL ) {
537                 ldap_controls_free( rs->sr_ctrls );
538                 rs->sr_ctrls = NULL;
539         }
540         while ( ent.e_attrs ) {
541                 attr = ent.e_attrs;
542                 ent.e_attrs = attr->a_next;
543                 attr_clean( attr );
544                 op->o_tmpfree( attr, op->o_tmpmemctx );
545         }
546         if (rs->sr_entry && rs->sr_entry != &ent) {
547                 entry_free( rs->sr_entry );
548         }
549         rs->sr_entry = NULL;
550         rs->sr_attrs = NULL;
551         return rc;
552 }
553
554 int
555 asyncmeta_search_last_result(a_metaconn_t *mc, bm_context_t *bc, int candidate, int sres)
556 {
557         a_metainfo_t    *mi = mc->mc_info;
558         a_metatarget_t  *mt = mi->mi_targets[ candidate ];
559         Operation *op = bc->op;
560         SlapReply *rs = &bc->rs;
561         int        rc, i;
562         SlapReply *candidates = bc->candidates;
563         char *matched = NULL;
564
565         if ( bc->candidate_match > 0 ) {
566                 struct berval   pmatched = BER_BVNULL;
567
568                 /* we use the first one */
569                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
570                         if ( META_IS_CANDIDATE( &candidates[ i ] )
571                                         && candidates[ i ].sr_matched != NULL )
572                         {
573                                 struct berval   bv, pbv;
574                                 int             rc;
575
576                                 /* if we got success, and this target
577                                  * returned noSuchObject, and its suffix
578                                  * is a superior of the searchBase,
579                                  * ignore the matchedDN */
580                                 if ( sres == LDAP_SUCCESS
581                                         && candidates[ i ].sr_err == LDAP_NO_SUCH_OBJECT
582                                         && op->o_req_ndn.bv_len > mi->mi_targets[ i ]->mt_nsuffix.bv_len )
583                                 {
584                                         free( (char *)candidates[ i ].sr_matched );
585                                         candidates[ i ].sr_matched = NULL;
586                                         continue;
587                                 }
588
589                                 ber_str2bv( candidates[ i ].sr_matched, 0, 0, &bv );
590                                 rc = dnPretty( NULL, &bv, &pbv, op->o_tmpmemctx );
591
592                                 if ( rc == LDAP_SUCCESS ) {
593
594                                         /* NOTE: if they all are superiors
595                                          * of the baseDN, the shorter is also
596                                          * superior of the longer... */
597                                         if ( pbv.bv_len > pmatched.bv_len ) {
598                                                 if ( !BER_BVISNULL( &pmatched ) ) {
599                                                         op->o_tmpfree( pmatched.bv_val, op->o_tmpmemctx );
600                                                 }
601                                                 pmatched = pbv;
602
603                                         } else {
604                                                 op->o_tmpfree( pbv.bv_val, op->o_tmpmemctx );
605                                         }
606                                 }
607
608                                 if ( candidates[ i ].sr_matched != NULL ) {
609                                         free( (char *)candidates[ i ].sr_matched );
610                                         candidates[ i ].sr_matched = NULL;
611                                 }
612                         }
613                 }
614
615                 if ( !BER_BVISNULL( &pmatched ) ) {
616                         matched = pmatched.bv_val;
617                 }
618
619         } else if ( sres == LDAP_NO_SUCH_OBJECT ) {
620                 matched = op->o_bd->be_suffix[ 0 ].bv_val;
621         }
622
623         /*
624          * In case we returned at least one entry, we return LDAP_SUCCESS
625          * otherwise, the latter error code we got
626          */
627
628         if ( sres == LDAP_SUCCESS ) {
629                 if ( rs->sr_v2ref ) {
630                         sres = LDAP_REFERRAL;
631                 }
632
633                 if ( META_BACK_ONERR_REPORT( mi ) ) {
634                         /*
635                          * Report errors, if any
636                          *
637                          * FIXME: we should handle error codes and return the more
638                          * important/reasonable
639                          */
640                         for ( i = 0; i < mi->mi_ntargets; i++ ) {
641                                 if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
642                                         continue;
643                                 }
644
645                                 if ( candidates[ i ].sr_err != LDAP_SUCCESS
646                                         && candidates[ i ].sr_err != LDAP_NO_SUCH_OBJECT )
647                                 {
648                                         sres = candidates[ i ].sr_err;
649                                         break;
650                                 }
651                         }
652                 }
653         }
654         Debug( LDAP_DEBUG_TRACE,
655                "%s asyncmeta_search_last_result(\"%s\"): "
656                ".\n",
657                op->o_log_prefix, 0, 0);
658         rs->sr_err = sres;
659         rs->sr_matched = ( sres == LDAP_SUCCESS ? NULL : matched );
660         rs->sr_ref = ( sres == LDAP_REFERRAL ? rs->sr_v2ref : NULL );
661         send_ldap_result(op, rs);
662         rs->sr_matched = NULL;
663         rs->sr_ref = NULL;
664 }
665
666
667 int
668 asyncmeta_search_finish(a_metaconn_t *mc, bm_context_t *bc, int candidate, char *matched)
669 {
670         a_metainfo_t    *mi = mc->mc_info;
671         a_metatarget_t  *mt = mi->mi_targets[ candidate ];
672         Operation *op = bc->op;
673         SlapReply *rs = &bc->rs;
674         SlapReply *candidates = bc->candidates;
675         int i;
676         int do_taint = 0;
677         if ( matched && matched != op->o_bd->be_suffix[ 0 ].bv_val ) {
678                 op->o_tmpfree( matched, op->o_tmpmemctx );
679         }
680
681         if ( rs->sr_v2ref ) {
682                 ber_bvarray_free_x( rs->sr_v2ref, op->o_tmpmemctx );
683         }
684
685         for ( i = 0; i < mi->mi_ntargets; i++ ) {
686                 if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
687                         continue;
688                 }
689
690                         if ( META_IS_BINDING( &candidates[ i ] )
691                                 || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
692                         {
693                                 if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] )
694                                         || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
695                                 {
696                                         assert( candidates[ i ].sr_msgid >= 0
697                                                 || candidates[ i ].sr_msgid == META_MSGID_CONNECTING );
698                                         assert( mc->mc_conns[ i ].msc_ldr != NULL );
699
700 #ifdef DEBUG_205
701                                         Debug( LDAP_DEBUG_ANY, "### %s asyncmeta_search_finish  "
702                                                 "ldap_unbind_ext[%ld] ld=%p\n",
703                                                 op->o_log_prefix, i, (void *)mc->mc_conns[i].msc_ldr );
704 #endif /* DEBUG_205 */
705
706                                 }
707                                 META_BINDING_CLEAR( &candidates[ i ] );
708
709                         } else if ( candidates[ i ].sr_msgid >= 0 ) {
710                                 (void)asyncmeta_back_cancel( mc, op,
711                                         candidates[ i ].sr_msgid, i );
712                         }
713
714                 if ( candidates[ i ].sr_matched ) {
715                         free( (char *)candidates[ i ].sr_matched );
716                         candidates[ i ].sr_matched = NULL;
717                 }
718
719                 if ( candidates[ i ].sr_text ) {
720                         ldap_memfree( (char *)candidates[ i ].sr_text );
721                         candidates[ i ].sr_text = NULL;
722                 }
723
724                 if ( candidates[ i ].sr_ref ) {
725                         ber_bvarray_free( candidates[ i ].sr_ref );
726                         candidates[ i ].sr_ref = NULL;
727                 }
728
729                 if ( candidates[ i ].sr_ctrls ) {
730                         ldap_controls_free( candidates[ i ].sr_ctrls );
731                         candidates[ i ].sr_ctrls = NULL;
732                 }
733
734                 if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) {
735                         asyncmeta_quarantine( op, mi, &candidates[ i ], i );
736                 }
737                 /* this remains as it is only for explicitly bound connections, for the time being */
738                 /* only in case of timelimit exceeded, if the timelimit exceeded because
739                  * one contacted target never responded, invalidate the connection
740                  * NOTE: should we quarantine the target as well?  right now, the connection
741                  * is invalidated; the next time it will be recreated and the target
742                  * will be quarantined if it cannot be contacted */
743                 if ( mi->mi_idle_timeout != 0
744                         && rs->sr_err == LDAP_TIMELIMIT_EXCEEDED
745                         && op->o_time > mc->mc_conns[ i ].msc_time )
746                 {
747                         /* don't let anyone else use this expired connection */
748                         do_taint++;
749                 }
750         }
751
752         if ( mc && do_taint) {
753                 LDAP_BACK_CONN_TAINTED_SET( mc );
754         }
755
756         return rs->sr_err;
757 }
758
759
760 int
761 asyncmeta_handle_bind_result(LDAPMessage *msg, a_metaconn_t *mc, bm_context_t *bc, int candidate)
762 {
763         meta_search_candidate_t retcode;
764         a_metainfo_t    *mi;
765         a_metatarget_t  *mt;
766         Operation *op;
767         SlapReply *rs;
768         int        rc;
769         SlapReply *candidates;
770
771         mi = mc->mc_info;
772         mt = mi->mi_targets[ candidate ];
773         op = bc->op;
774         rs = &bc->rs;
775         candidates = bc->candidates;
776         Debug( LDAP_DEBUG_TRACE,
777                "%s asyncmeta_handle_bind_result[%d]\n",
778                op->o_log_prefix, candidate, 0);
779         retcode = asyncmeta_dobind_result( op, rs, mc, candidate, candidates, msg );
780         if ( retcode == META_SEARCH_CANDIDATE ) {
781                 switch (op->o_tag) {
782                 case LDAP_REQ_SEARCH:
783                         retcode = asyncmeta_back_search_start( op, rs, mc, bc, candidate,  NULL, 0 );
784                         break;
785                 case LDAP_REQ_ADD:
786                         retcode = asyncmeta_back_add_start( op, rs, mc, bc, candidate);
787                         break;
788                 case LDAP_REQ_MODIFY:
789                         retcode = asyncmeta_back_modify_start( op, rs, mc, bc, candidate);
790                         break;
791                 case LDAP_REQ_MODRDN:
792                         retcode = asyncmeta_back_modrdn_start( op, rs, mc, bc, candidate);
793                         break;
794                 case LDAP_REQ_COMPARE:
795                         retcode = asyncmeta_back_compare_start( op, rs, mc, bc, candidate);
796                         break;
797                 case LDAP_REQ_DELETE:
798                         retcode = asyncmeta_back_delete_start( op, rs, mc, bc, candidate);
799                         break;
800                 default:
801                         retcode = META_SEARCH_NOT_CANDIDATE;
802                 }
803         }
804
805         switch ( retcode ) {
806         case META_SEARCH_CANDIDATE:
807                 break;
808                 /* means that failed but onerr == continue */
809         case META_SEARCH_NOT_CANDIDATE:
810         case META_SEARCH_ERR:
811                 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
812                 candidates[ candidate ].sr_type = REP_RESULT;
813                 candidates[ candidate ].sr_err = rs->sr_err;
814                 if ( META_BACK_ONERR_STOP( mi ) || op->o_tag != LDAP_REQ_SEARCH) {
815                         send_ldap_result(op, rs);
816                 }
817                 if (op->o_tag != LDAP_REQ_SEARCH) {
818                         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
819                         asyncmeta_drop_bc( mc, bc);
820                         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
821                         asyncmeta_clear_bm_context(bc);
822                         return retcode;
823                 }
824                 break;
825         default:
826                 assert( 0 );
827                 break;
828         }
829         bc->bc_active = 0;
830         return retcode;
831 }
832
833 int
834 asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc, int candidate)
835 {
836         a_metainfo_t    *mi;
837         a_metatarget_t  *mt;
838         a_metasingleconn_t *msc;
839         Operation op;
840         SlapReply *rs;
841         int        i, j, rc, sres;
842         SlapReply *candidates;
843         char            **references = NULL;
844         LDAPControl     **ctrls = NULL;
845         a_dncookie dc;
846         LDAPMessage *msg;
847         ber_int_t id;
848
849         op = *bc->op;
850         rs = &bc->rs;
851         mi = mc->mc_info;
852         mt = mi->mi_targets[ candidate ];
853         msc = &mc->mc_conns[ candidate ];
854         dc.target = mt;
855         dc.conn = op.o_conn;
856         dc.rs = rs;
857         id = ldap_msgid(res);
858
859         candidates = bc->candidates;
860         i = candidate;
861
862         while (res) {
863         for (msg = ldap_first_message(msc->msc_ldr, res); msg; msg = ldap_next_message(msc->msc_ldr, msg)) {
864                 switch(ldap_msgtype(msg)) {
865                 case LDAP_RES_SEARCH_ENTRY:
866                         Debug( LDAP_DEBUG_TRACE,
867                                 "%s asyncmeta_handle_search_msg: msc %p entry\n",
868                                 op.o_log_prefix, msc, 0);
869                         if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
870                                 /* don't retry any more... */
871                                 candidates[ i ].sr_type = REP_RESULT;
872                         }
873                         /* count entries returned by target */
874                         candidates[ i ].sr_nentries++;
875                         rs->sr_err = asyncmeta_send_entry( &op, rs, mc, i, msg );
876                         switch ( rs->sr_err ) {
877                         case LDAP_SIZELIMIT_EXCEEDED:
878                                 send_ldap_result(&op, rs);
879                                 rs->sr_err = LDAP_SUCCESS;
880                                 goto err_cleanup;
881                         case LDAP_UNAVAILABLE:
882                                 rs->sr_err = LDAP_OTHER;
883                         }
884                         bc->is_ok++;
885                         break;
886
887                 case LDAP_RES_SEARCH_REFERENCE:
888                         if ( META_BACK_TGT_NOREFS( mi->mi_targets[ i ] ) ) {
889                                 rs->sr_err = LDAP_OTHER;
890                                 send_ldap_result(&op, rs);
891                                 goto err_cleanup;
892                         }
893                         if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
894                                 /* don't retry any more... */
895                                 candidates[ i ].sr_type = REP_RESULT;
896                         }
897                         bc->is_ok++;
898                         rc = ldap_parse_reference( msc->msc_ldr, msg,
899                                    &references, &rs->sr_ctrls, 0 );
900
901                         if ( rc != LDAP_SUCCESS || references == NULL ) {
902                                 rs->sr_err = LDAP_OTHER;
903                                 send_ldap_result(&op, rs);
904                                 goto err_cleanup;
905                         }
906
907                         /* FIXME: merge all and return at the end */
908
909                         {
910                                 int cnt;
911                                 for ( cnt = 0; references[ cnt ]; cnt++ )
912                                         ;
913
914                                 rs->sr_ref = ber_memalloc_x( sizeof( struct berval ) * ( cnt + 1 ),
915                                                                  op.o_tmpmemctx );
916
917                                 for ( cnt = 0; references[ cnt ]; cnt++ ) {
918                                         ber_str2bv_x( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ],
919                                                           op.o_tmpmemctx );
920                                 }
921                                 BER_BVZERO( &rs->sr_ref[ cnt ] );
922                         }
923
924                         {
925                                 dc.ctx = "referralDN";
926                                 ( void )asyncmeta_referral_result_rewrite( &dc, rs->sr_ref,
927                                                                    op.o_tmpmemctx );
928                         }
929
930                         if ( rs->sr_ref != NULL ) {
931                                 if (!BER_BVISNULL( &rs->sr_ref[ 0 ] ) ) {
932                                         /* ignore return value by now */
933                                         ( void )send_search_reference( &op, rs );
934                                 }
935
936                                 ber_bvarray_free_x( rs->sr_ref, op.o_tmpmemctx );
937                                 rs->sr_ref = NULL;
938                         }
939
940                         /* cleanup */
941                         if ( references ) {
942                                 ber_memvfree( (void **)references );
943                         }
944
945                         if ( rs->sr_ctrls ) {
946                                 ldap_controls_free( rs->sr_ctrls );
947                                 rs->sr_ctrls = NULL;
948                         }
949                         break;
950
951                 case LDAP_RES_INTERMEDIATE:
952                         if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
953                                 /* don't retry any more... */
954                                 candidates[ i ].sr_type = REP_RESULT;
955                         }
956                         bc->is_ok++;
957
958                         /* FIXME: response controls
959                          * are passed without checks */
960                         rs->sr_err = ldap_parse_intermediate( msc->msc_ldr,
961                                                                   msg,
962                                                                   (char **)&rs->sr_rspoid,
963                                                                   &rs->sr_rspdata,
964                                                                   &rs->sr_ctrls,
965                                                                   0 );
966                         if ( rs->sr_err != LDAP_SUCCESS ) {
967                                 candidates[ i ].sr_type = REP_RESULT;
968                                 rs->sr_err = LDAP_OTHER;
969                                 send_ldap_result(&op, rs);
970                                 goto err_cleanup;
971                         }
972
973                         slap_send_ldap_intermediate( &op, rs );
974
975                         if ( rs->sr_rspoid != NULL ) {
976                                 ber_memfree( (char *)rs->sr_rspoid );
977                                 rs->sr_rspoid = NULL;
978                         }
979
980                         if ( rs->sr_rspdata != NULL ) {
981                                 ber_bvfree( rs->sr_rspdata );
982                                 rs->sr_rspdata = NULL;
983                         }
984
985                         if ( rs->sr_ctrls != NULL ) {
986                                 ldap_controls_free( rs->sr_ctrls );
987                                 rs->sr_ctrls = NULL;
988                         }
989                         break;
990
991                 case LDAP_RES_SEARCH_RESULT:
992                         Debug( LDAP_DEBUG_TRACE,
993                                 "%s asyncmeta_handle_search_msg: msc %p result\n",
994                                 op.o_log_prefix, msc, 0);
995                         candidates[ i ].sr_type = REP_RESULT;
996                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
997                         /* NOTE: ignores response controls
998                          * (and intermediate response controls
999                          * as well, except for those with search
1000                          * references); this may not be correct,
1001                          * but if they're not ignored then
1002                          * back-meta would need to merge them
1003                          * consistently (think of pagedResults...)
1004                          */
1005                         /* FIXME: response controls? */
1006                         rs->sr_err = ldap_parse_result( msc->msc_ldr,
1007                                                         msg,
1008                                                         &candidates[ i ].sr_err,
1009                                                                 (char **)&candidates[ i ].sr_matched,
1010                                                         (char **)&candidates[ i ].sr_text,
1011                                                         &references,
1012                                                         &ctrls /* &candidates[ i ].sr_ctrls (unused) */ ,
1013                                                         0 );
1014                         if ( rs->sr_err != LDAP_SUCCESS ) {
1015                                 candidates[ i ].sr_err = rs->sr_err;
1016                                 sres = slap_map_api2result( &candidates[ i ] );
1017                                 candidates[ i ].sr_type = REP_RESULT;
1018                                 goto finish;
1019                         }
1020
1021                         rs->sr_err = candidates[ i ].sr_err;
1022
1023                         /* massage matchedDN if need be */
1024                         if ( candidates[ i ].sr_matched != NULL ) {
1025                                 struct berval   match, mmatch;
1026
1027                                 ber_str2bv( candidates[ i ].sr_matched,
1028                                                 0, 0, &match );
1029                                 candidates[ i ].sr_matched = NULL;
1030
1031                                 dc.ctx = "matchedDN";
1032                                 dc.target = mi->mi_targets[ i ];
1033                                 if ( !asyncmeta_dn_massage( &dc, &match, &mmatch ) ) {
1034                                         if ( mmatch.bv_val == match.bv_val ) {
1035                                                 candidates[ i ].sr_matched
1036                                                         = ch_strdup( mmatch.bv_val );
1037
1038                                         } else {
1039                                                 candidates[ i ].sr_matched = mmatch.bv_val;
1040                                         }
1041
1042                                         bc->candidate_match++;
1043                                 }
1044                                 ldap_memfree( match.bv_val );
1045                         }
1046
1047                         /* add references to array */
1048                         /* RFC 4511: referrals can only appear
1049                          * if result code is LDAP_REFERRAL */
1050                         if ( references != NULL
1051                                  && references[ 0 ] != NULL
1052                                  && references[ 0 ][ 0 ] != '\0' )
1053                         {
1054                                 if ( rs->sr_err != LDAP_REFERRAL ) {
1055                                         Debug( LDAP_DEBUG_ANY,
1056                                                    "%s asncmeta_search_result[%d]: "
1057                                                    "got referrals with err=%d\n",
1058                                                    op.o_log_prefix,
1059                                                    i, rs->sr_err );
1060
1061                                 } else {
1062                                         BerVarray       sr_ref;
1063                                         int             cnt;
1064
1065                                         for ( cnt = 0; references[ cnt ]; cnt++ )
1066                                                 ;
1067
1068                                         sr_ref = ber_memalloc_x( sizeof( struct berval ) * ( cnt + 1 ),
1069                                                                  op.o_tmpmemctx );
1070
1071                                         for ( cnt = 0; references[ cnt ]; cnt++ ) {
1072                                                 ber_str2bv_x( references[ cnt ], 0, 1, &sr_ref[ cnt ],
1073                                                                   op.o_tmpmemctx );
1074                                         }
1075                                         BER_BVZERO( &sr_ref[ cnt ] );
1076
1077                                         ( void )asyncmeta_referral_result_rewrite( &dc, sr_ref,
1078                                                                                    op.o_tmpmemctx );
1079
1080                                         if ( rs->sr_v2ref == NULL ) {
1081                                                 rs->sr_v2ref = sr_ref;
1082
1083                                         } else {
1084                                                 for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) {
1085                                                         ber_bvarray_add_x( &rs->sr_v2ref, &sr_ref[ cnt ],
1086                                                                            op.o_tmpmemctx );
1087                                                 }
1088                                                 ber_memfree_x( sr_ref, op.o_tmpmemctx );
1089                                         }
1090                                 }
1091
1092                         } else if ( rs->sr_err == LDAP_REFERRAL ) {
1093                                 Debug( LDAP_DEBUG_ANY,
1094                                            "%s asyncmeta_search_result[%d]: "
1095                                            "got err=%d with null "
1096                                            "or empty referrals\n",
1097                                            op.o_log_prefix,
1098                                            i, rs->sr_err );
1099
1100                                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
1101                         }
1102
1103                         /* cleanup */
1104                         ber_memvfree( (void **)references );
1105
1106                         sres = slap_map_api2result( rs );
1107
1108                         if ( LogTest( LDAP_DEBUG_TRACE | LDAP_DEBUG_ANY ) ) {
1109                                 char buf[ SLAP_TEXT_BUFLEN ];
1110                                 snprintf( buf, sizeof( buf ),
1111                                           "%s asyncmeta_search_result[%ld] "
1112                                           "match=\"%s\" err=%d",
1113                                           op.o_log_prefix, i,
1114                                           candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
1115                                           (long) candidates[ i ].sr_err );
1116                                 if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
1117                                         Debug( LDAP_DEBUG_TRACE, "%s.\n", buf, 0, 0 );
1118
1119                                 } else {
1120                                         Debug( LDAP_DEBUG_ANY, "%s (%s).\n",
1121                                                    buf, ldap_err2string( candidates[ i ].sr_err ), 0 );
1122                                                                 }
1123                         }
1124
1125                         switch ( sres ) {
1126                         case LDAP_NO_SUCH_OBJECT:
1127                                 /* is_ok is touched any time a valid
1128                                  * (even intermediate) result is
1129                                  * returned; as a consequence, if
1130                                  * a candidate returns noSuchObject
1131                                  * it is ignored and the candidate
1132                                  * is simply demoted. */
1133                                 if ( bc->is_ok ) {
1134                                         sres = LDAP_SUCCESS;
1135                                 }
1136                                 break;
1137
1138                         case LDAP_SUCCESS:
1139                                 if ( ctrls != NULL && ctrls[0] != NULL ) {
1140 #ifdef SLAPD_META_CLIENT_PR
1141                                         LDAPControl *pr_c;
1142
1143                                         pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, ctrls, NULL );
1144                                         if ( pr_c != NULL ) {
1145                                                 BerElementBuffer berbuf;
1146                                                 BerElement *ber = (BerElement *)&berbuf;
1147                                                 ber_tag_t tag;
1148                                                 ber_int_t prsize;
1149                                                 struct berval prcookie;
1150
1151                                                 /* unsolicited, do not accept */
1152                                                 if ( mi->mi_targets[i]->mt_ps == 0 ) {
1153                                                         rs->sr_err = LDAP_OTHER;
1154                                                         goto err_pr;
1155                                                 }
1156
1157                                                 ber_init2( ber, &pr_c->ldctl_value, LBER_USE_DER );
1158
1159                                                 tag = ber_scanf( ber, "{im}", &prsize, &prcookie );
1160                                                 if ( tag == LBER_ERROR ) {
1161                                                         rs->sr_err = LDAP_OTHER;
1162                                                         goto err_pr;
1163                                                 }
1164
1165                                                 /* more pages? new search request */
1166                                                 if ( !BER_BVISNULL( &prcookie ) && !BER_BVISEMPTY( &prcookie ) ) {
1167                                                         if ( mi->mi_targets[i]->mt_ps > 0 ) {
1168                                                                 /* ignore size if specified */
1169                                                                 prsize = 0;
1170
1171                                                         } else if ( prsize == 0 ) {
1172                                                                 /* guess the page size from the entries returned so far */
1173                                                                 prsize = candidates[ i ].sr_nentries;
1174                                                         }
1175
1176                                                         candidates[ i ].sr_nentries = 0;
1177                                                         candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1178                                                         candidates[ i ].sr_type = REP_INTERMEDIATE;
1179
1180                                                         assert( candidates[ i ].sr_matched == NULL );
1181                                                         assert( candidates[ i ].sr_text == NULL );
1182                                                         assert( candidates[ i ].sr_ref == NULL );
1183
1184                                                         switch ( asyncmeta_back_search_start( &op, rs, mc, bc, i, &prcookie, prsize ) )
1185                                                         {
1186                                                         case META_SEARCH_CANDIDATE:
1187                                                                 assert( candidates[ i ].sr_msgid >= 0 );
1188                                                                 ldap_controls_free( ctrls );
1189                                                                 //      goto free_message;
1190
1191                                                         case META_SEARCH_ERR:
1192 err_pr:;
1193                                                                 candidates[ i ].sr_err = rs->sr_err;
1194                                                                 candidates[ i ].sr_type = REP_RESULT;
1195                                                                 if ( META_BACK_ONERR_STOP( mi ) ) {
1196                                                                         send_ldap_result(&op, rs);
1197                                                                         ldap_controls_free( ctrls );
1198                                                                         goto err_cleanup;
1199                                                                 }
1200                                                                 /* fallthru */
1201
1202                                                         case META_SEARCH_NOT_CANDIDATE:
1203                                                                 /* means that asyncmeta_back_search_start()
1204                                                                  * failed but onerr == continue */
1205                                                                 candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1206                                                                 candidates[ i ].sr_type = REP_RESULT;
1207                                                                 break;
1208
1209                                                         default:
1210                                                                 /* impossible */
1211                                                                 assert( 0 );
1212                                                                 break;
1213                                                         }
1214                                                         break;
1215                                                 }
1216                                         }
1217 #endif /* SLAPD_META_CLIENT_PR */
1218
1219                                         ldap_controls_free( ctrls );
1220                                 }
1221                                 /* fallthru */
1222
1223                         case LDAP_REFERRAL:
1224                                 bc->is_ok++;
1225                                 break;
1226
1227                         case LDAP_SIZELIMIT_EXCEEDED:
1228                                 /* if a target returned sizelimitExceeded
1229                                  * and the entry count is equal to the
1230                                  * proxy's limit, the target would have
1231                                  * returned more, and the error must be
1232                                  * propagated to the client; otherwise,
1233                                  * the target enforced a limit lower
1234                                  * than what requested by the proxy;
1235                                  * ignore it */
1236                                 candidates[ i ].sr_err = rs->sr_err;
1237                                 if ( rs->sr_nentries == op.ors_slimit
1238                                          || META_BACK_ONERR_STOP( mi ) )
1239                                 {
1240                                         const char *save_text;
1241 got_err:
1242                                         save_text = rs->sr_text;
1243                                         rs->sr_text = candidates[ i ].sr_text;
1244                                         send_ldap_result(&op, rs);
1245                                         ch_free( candidates[ i ].sr_text );
1246                                         candidates[ i ].sr_text = NULL;
1247                                         rs->sr_text = save_text;
1248                                         ldap_controls_free( ctrls );
1249                                         goto err_cleanup;
1250                                 }
1251                                 break;
1252
1253                         default:
1254                                 candidates[ i ].sr_err = rs->sr_err;
1255                                 if ( META_BACK_ONERR_STOP( mi ) ) {
1256                                         goto got_err;
1257                                 }
1258                                 break;
1259                         }
1260                         /* if this is the last result we will ever receive, send it back  */
1261                         rc = rs->sr_err;
1262                         if (asyncmeta_is_last_result(mc, bc, i) == 0) {
1263                                 Debug( LDAP_DEBUG_TRACE,
1264                                         "%s asyncmeta_handle_search_msg: msc %p last result\n",
1265                                         op.o_log_prefix, msc, 0);
1266                                 asyncmeta_search_last_result(mc, bc, i, sres);
1267 err_cleanup:
1268                                 rc = rs->sr_err;
1269                                 ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
1270                                 asyncmeta_drop_bc( mc, bc);
1271                                 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
1272                                 asyncmeta_clear_bm_context(bc);
1273                                 ldap_msgfree(res);
1274                                 return rc;
1275                         }
1276 finish:
1277                         break;
1278
1279                 default:
1280                         continue;
1281                 }
1282         }
1283                 ldap_msgfree(res);
1284                 res = NULL;
1285                 if (candidates[ i ].sr_type != REP_RESULT) {
1286                         struct timeval  tv = {0};
1287                         rc = ldap_result( msc->msc_ldr, id, LDAP_MSG_RECEIVED, &tv, &res );
1288                 }
1289         }
1290         bc->bc_active = 0;
1291
1292         return rc;
1293 }
1294
1295 /* handles the received result for add, modify, modrdn, compare and delete ops */
1296
1297 int asyncmeta_handle_common_result(LDAPMessage *msg, a_metaconn_t *mc, bm_context_t *bc, int candidate)
1298 {
1299         a_metainfo_t    *mi;
1300         a_metatarget_t  *mt;
1301         a_metasingleconn_t *msc;
1302         const char      *save_text = NULL,
1303                 *save_matched = NULL;
1304         BerVarray       save_ref = NULL;
1305         LDAPControl     **save_ctrls = NULL;
1306         void            *matched_ctx = NULL;
1307
1308         char            *matched = NULL;
1309         char            *text = NULL;
1310         char            **refs = NULL;
1311         LDAPControl     **ctrls = NULL;
1312         Operation *op;
1313         SlapReply *rs;
1314         int             rc;
1315
1316         mi = mc->mc_info;
1317         mt = mi->mi_targets[ candidate ];
1318         msc = &mc->mc_conns[ candidate ];
1319
1320         op = bc->op;
1321         rs = &bc->rs;
1322         save_text = rs->sr_text,
1323         save_matched = rs->sr_matched;
1324         save_ref = rs->sr_ref;
1325         save_ctrls = rs->sr_ctrls;
1326         rs->sr_text = NULL;
1327         rs->sr_matched = NULL;
1328         rs->sr_ref = NULL;
1329         rs->sr_ctrls = NULL;
1330
1331         /* only touch when activity actually took place... */
1332         if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
1333                 msc->msc_time = op->o_time;
1334         }
1335
1336         rc = ldap_parse_result( msc->msc_ldr, msg, &rs->sr_err,
1337                                 &matched, &text, &refs, &ctrls, 0 );
1338
1339         if ( rc == LDAP_SUCCESS ) {
1340                 rs->sr_text = text;
1341         } else {
1342                 rs->sr_err = rc;
1343         }
1344         rs->sr_err = slap_map_api2result( rs );
1345
1346         /* RFC 4511: referrals can only appear
1347          * if result code is LDAP_REFERRAL */
1348         if ( refs != NULL
1349              && refs[ 0 ] != NULL
1350              && refs[ 0 ][ 0 ] != '\0' )
1351         {
1352                 if ( rs->sr_err != LDAP_REFERRAL ) {
1353                         Debug( LDAP_DEBUG_ANY,
1354                                "%s asyncmeta_handle_common_result[%d]: "
1355                                "got referrals with err=%d\n",
1356                                op->o_log_prefix,
1357                                candidate, rs->sr_err );
1358
1359                 } else {
1360                         int     i;
1361
1362                         for ( i = 0; refs[ i ] != NULL; i++ )
1363                                 /* count */ ;
1364                         rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ),
1365                                                      op->o_tmpmemctx );
1366                         for ( i = 0; refs[ i ] != NULL; i++ ) {
1367                                 ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] );
1368                         }
1369                         BER_BVZERO( &rs->sr_ref[ i ] );
1370                 }
1371
1372         } else if ( rs->sr_err == LDAP_REFERRAL ) {
1373                 Debug( LDAP_DEBUG_ANY,
1374                        "%s asyncmeta_handle_common_result[%d]: "
1375                        "got err=%d with null "
1376                        "or empty referrals\n",
1377                        op->o_log_prefix,
1378                        candidate, rs->sr_err );
1379
1380                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
1381         }
1382
1383         if ( ctrls != NULL ) {
1384                 rs->sr_ctrls = ctrls;
1385         }
1386
1387         /* if the error in the reply structure is not
1388          * LDAP_SUCCESS, try to map it from client
1389          * to server error */
1390         if ( !LDAP_ERR_OK( rs->sr_err ) ) {
1391                 rs->sr_err = slap_map_api2result( rs );
1392
1393                 /* internal ops ( op->o_conn == NULL )
1394                  * must not reply to client */
1395                 if ( op->o_conn && !op->o_do_not_cache && matched ) {
1396
1397                         /* record the (massaged) matched
1398                          * DN into the reply structure */
1399                         rs->sr_matched = matched;
1400                 }
1401         }
1402
1403         if ( META_BACK_TGT_QUARANTINE( mt ) ) {
1404                 asyncmeta_quarantine( op, mi, rs, candidate );
1405         }
1406
1407         if ( matched != NULL ) {
1408                 struct berval   dn, pdn;
1409
1410                 ber_str2bv( matched, 0, 0, &dn );
1411                 if ( dnPretty( NULL, &dn, &pdn, op->o_tmpmemctx ) == LDAP_SUCCESS ) {
1412                         ldap_memfree( matched );
1413                         matched_ctx = op->o_tmpmemctx;
1414                         matched = pdn.bv_val;
1415                 }
1416                 rs->sr_matched = matched;
1417         }
1418
1419         if ( rs->sr_err == LDAP_UNAVAILABLE ) {
1420                 if ( !( bc->sendok & LDAP_BACK_RETRYING ) ) {
1421                         if ( op->o_conn && ( bc->sendok & LDAP_BACK_SENDERR ) ) {
1422                                 if ( rs->sr_text == NULL ) rs->sr_text = "Proxy operation retry failed";
1423                                         send_ldap_result( op, rs );
1424                         }
1425                 }
1426
1427         } else if ( op->o_conn &&
1428                 ( ( ( bc->sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) )
1429                         || ( ( bc->sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) )
1430         {
1431                         send_ldap_result( op, rs );
1432         }
1433         if ( matched ) {
1434                 op->o_tmpfree( (char *)rs->sr_matched, matched_ctx );
1435         }
1436         if ( text ) {
1437                 ldap_memfree( text );
1438         }
1439         if ( rs->sr_ref ) {
1440                 op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
1441                 rs->sr_ref = NULL;
1442         }
1443         if ( refs ) {
1444                 ber_memvfree( (void **)refs );
1445         }
1446         if ( ctrls ) {
1447                 assert( rs->sr_ctrls != NULL );
1448                 ldap_controls_free( ctrls );
1449         }
1450
1451         rs->sr_text = save_text;
1452         rs->sr_matched = save_matched;
1453         rs->sr_ref = save_ref;
1454         rs->sr_ctrls = save_ctrls;
1455         rc = (LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err);
1456         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
1457         asyncmeta_drop_bc( mc, bc);
1458         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
1459         asyncmeta_clear_bm_context(bc);
1460         return rc;
1461 }
1462
1463 /* This takes care to clean out the outbound queue in case we have a read error
1464  * sending back responses to the client */
1465 int
1466 asyncmeta_op_read_error(a_metaconn_t *mc, int candidate, int error)
1467 {
1468         bm_context_t *bc, *onext;
1469         int rc, cleanup;
1470         Operation *op;
1471         SlapReply *rs;
1472         SlapReply *candidates;
1473         /* no outstanding ops, nothing to do but log */
1474         Debug( LDAP_DEBUG_ANY,
1475                "asyncmeta_op_read_error: %x\n",
1476                error,0,0 );
1477 #if 0
1478         if (mc->mc_conns[candidate].conn) {
1479                 Connection *conn = mc->mc_conns[candidate].conn;
1480                 mc->mc_conns[candidate].conn = NULL;
1481                 connection_client_stop(conn);
1482         }
1483 #endif
1484         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
1485         asyncmeta_clear_one_msc(NULL, mc, candidate);
1486         if (mc->pending_ops <= 0) {
1487                 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
1488                 return LDAP_SUCCESS;
1489         }
1490
1491         for (bc = LDAP_SLIST_FIRST(&mc->mc_om_list); bc; bc = onext) {
1492                 onext = LDAP_SLIST_NEXT(bc, bc_next);
1493                 cleanup = 0;
1494                 candidates = bc->candidates;
1495                 /* was this op affected? */
1496                 if ( !META_IS_CANDIDATE( &candidates[ candidate ] ) )
1497                         continue;
1498
1499                 if (bc->op->o_abandon == 1) {
1500                         continue;
1501                 }
1502
1503                 op = bc->op;
1504                 rs = &bc->rs;
1505                 switch (op->o_tag) {
1506                 case LDAP_REQ_ADD:
1507                 case LDAP_REQ_MODIFY:
1508                 case LDAP_REQ_MODRDN:
1509                 case LDAP_REQ_COMPARE:
1510                 case LDAP_REQ_DELETE:
1511                         rs->sr_err = LDAP_UNAVAILABLE;
1512                         send_ldap_error( op, rs, rs->sr_err , "Read error on connection to target" );
1513                         cleanup = 1;
1514                         break;
1515                 case LDAP_REQ_SEARCH:
1516                 {
1517                         a_metainfo_t *mi = mc->mc_info;
1518                         rs->sr_err = LDAP_UNAVAILABLE;
1519                         candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
1520                         candidates[ candidate ].sr_type = REP_RESULT;
1521                         if ( META_BACK_ONERR_STOP( mi ) ||
1522                                 asyncmeta_is_last_result(mc, bc, candidate) && op->o_conn) {
1523                                 send_ldap_error(op, rs, rs->sr_err, "Read error on connection to target");
1524                                 cleanup = 1;
1525                         }
1526                 }
1527                         break;
1528                 default:
1529                         break;
1530                 }
1531
1532                 if (cleanup) {
1533                         int j;
1534                         a_metainfo_t *mi = mc->mc_info;
1535                         for (j=0; j<mi->mi_ntargets; j++) {
1536                                 if (j != candidate && bc->candidates[j].sr_msgid >= 0
1537                                     && mc->mc_conns[j].msc_ld != NULL) {
1538                                         asyncmeta_back_abandon_candidate( mc, op,
1539                                                                           bc->candidates[ j ].sr_msgid, j );
1540                                 }
1541                         }
1542                         asyncmeta_drop_bc( mc, bc);
1543                         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
1544                         asyncmeta_clear_bm_context(bc);
1545                 }
1546         }
1547         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
1548         return LDAP_SUCCESS;
1549 }
1550
1551 void *
1552 asyncmeta_op_handle_result(void *ctx, void *arg)
1553 {
1554         a_metaconn_t *mc = arg;
1555         int             i, j, rc, ntargets, processed;
1556         struct timeval  tv = {0};
1557         LDAPMessage     *msg;
1558         a_metasingleconn_t *msc;
1559         bm_context_t *bc;
1560         void *oldctx;
1561
1562         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
1563         rc = ++mc->mc_active;
1564         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
1565         if (rc > 1)
1566                 return NULL;
1567
1568         ntargets = mc->mc_info->mi_ntargets;
1569         i = ntargets;
1570         oldctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 0);   /* get existing memctx */
1571
1572 again:
1573         processed = 0;
1574         for (j=0; j<ntargets; j++) {
1575                 i++;
1576                 if (i >= ntargets) i = 0;
1577                 if (!mc->mc_conns[i].msc_ldr || mc->mc_conns[i].msc_pending_ops <= 0) continue;
1578                 rc = ldap_result( mc->mc_conns[i].msc_ldr, LDAP_RES_ANY, LDAP_MSG_RECEIVED, &tv, &msg );
1579                 msc = &mc->mc_conns[i];
1580                 if (rc < 1) {
1581                         if (rc < 0) {
1582                                 asyncmeta_op_read_error(mc, i, rc);
1583                         }
1584                         continue;
1585                 }
1586                 Debug(LDAP_DEBUG_TRACE, "asyncmeta_op_handle_result: got msgid %d on msc %p\n",
1587                         ldap_msgid(msg), msc, 0);
1588                 ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
1589                 bc = asyncmeta_find_message(ldap_msgid(msg), mc, i);
1590
1591                 if (bc)
1592                         bc->bc_active = 1;
1593                 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
1594                 if (!bc) {
1595                         Debug( LDAP_DEBUG_ANY,
1596                                 "asyncmeta_op_handle_result: Unable to find bc for msguid %d\n", ldap_msgid(msg), 0, 0 );
1597                         ldap_msgfree(msg);
1598                         continue;
1599                 }
1600
1601                 /* set our memctx */
1602                 bc->op->o_threadctx = ctx;
1603                 bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
1604                 slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);
1605                 if (bc->op->o_abandon == 1) {
1606                         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
1607                         asyncmeta_drop_bc( mc, bc);
1608                         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
1609                         asyncmeta_clear_bm_context(bc);
1610                         if (msg)
1611                                 ldap_msgfree(msg);
1612                         continue;
1613                 }
1614
1615                 rc = ldap_msgtype( msg );
1616                 switch (rc) {
1617                 case LDAP_RES_BIND:
1618                         asyncmeta_handle_bind_result(msg, mc, bc, i);
1619                         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
1620                         LDAP_SLIST_FOREACH( bc, &mc->mc_om_list, bc_next ) {
1621                                 if (bc->candidates[i].sr_msgid == META_MSGID_NEED_BIND) {
1622                                         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
1623                                         asyncmeta_handle_bind_result(msg, mc, bc, i);
1624                                         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
1625                                 }
1626                         }
1627                         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
1628                         msc->msc_timeout_ops = 0;
1629                         mc->mc_info->mi_targets[i]->mt_timeout_ops = 0;
1630                         break;
1631                 case LDAP_RES_SEARCH_ENTRY:
1632                 case LDAP_RES_SEARCH_REFERENCE:
1633                 case LDAP_RES_SEARCH_RESULT:
1634                 case LDAP_RES_INTERMEDIATE:
1635                         asyncmeta_handle_search_msg(msg, mc, bc, i);
1636                         msc->msc_timeout_ops = 0;
1637                         mc->mc_info->mi_targets[i]->mt_timeout_ops = 0;
1638                         msg = NULL;
1639                         break;
1640                 case LDAP_RES_ADD:
1641                 case LDAP_RES_DELETE:
1642                 case LDAP_RES_MODDN:
1643                 case LDAP_RES_COMPARE:
1644                 case LDAP_RES_MODIFY:
1645                         rc = asyncmeta_handle_common_result(msg, mc, bc, i);
1646                         msc->msc_timeout_ops = 0;
1647                         mc->mc_info->mi_targets[i]->mt_timeout_ops = 0;
1648                         break;
1649                 default:
1650                         {
1651                         Debug( LDAP_DEBUG_ANY,
1652                                    "asyncmeta_op_handle_result: "
1653                                    "unrecognized response message tag=%d\n",
1654                                    rc,0,0 );
1655
1656                         }
1657                 }
1658                 if (msg)
1659                         ldap_msgfree(msg);
1660         }
1661
1662         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
1663         rc = --mc->mc_active;
1664         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
1665         if (rc) {
1666                 i++;
1667                 goto again;
1668         }
1669         slap_sl_mem_setctx(ctx, oldctx);
1670         if (mc->mc_conns) {
1671                 for (i=0; i<ntargets; i++)
1672                         if (mc->mc_conns[i].msc_ldr && mc->mc_conns[i].conn)
1673                                 connection_client_enable(mc->mc_conns[i].conn);
1674         }
1675         return NULL;
1676 }
1677
1678 void asyncmeta_set_msc_time(a_metasingleconn_t *msc)
1679 {
1680         msc->msc_time = slap_get_time();
1681 }
1682
1683 void* asyncmeta_timeout_loop(void *ctx, void *arg)
1684 {
1685         struct re_s* rtask = arg;
1686         a_metainfo_t *mi = rtask->arg;
1687         a_metaconn_t *mc;
1688         bm_context_t *bc, *onext;
1689         time_t current_time = slap_get_time();
1690         int i, j;
1691
1692         for (i=0; i<mi->mi_num_conns; i++) {
1693                 mc = &mi->mi_conns[i];
1694                 ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
1695                 for (bc = LDAP_SLIST_FIRST(&mc->mc_om_list); bc; bc = onext) {
1696                         onext = LDAP_SLIST_NEXT(bc, bc_next);
1697                         if (!bc->bc_active && bc->timeout && bc->stoptime <= current_time) {
1698                                 Operation *op = bc->op;
1699                                 SlapReply *rs = &bc->rs;
1700                                 int             timeout_err;
1701                                 const char *timeout_text;
1702                                 LDAP_SLIST_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
1703                                 mc->pending_ops--;
1704
1705                                 if (bc->searchtime) {
1706                                         timeout_err = LDAP_TIMELIMIT_EXCEEDED;
1707                                         timeout_text = NULL;
1708                                 } else {
1709                                         timeout_err = op->o_protocol >= LDAP_VERSION3 ?
1710                                                 LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
1711                                         timeout_text = "Operation timed out";
1712                                 }
1713                                 for (j=0; j<mi->mi_ntargets; j++) {
1714                                         if (bc->candidates[j].sr_msgid >= 0) {
1715                                                 a_metasingleconn_t *msc = &mc->mc_conns[j];
1716                                                 a_metatarget_t     *mt = mi->mi_targets[j];
1717                                                 msc->msc_timeout_ops++;
1718                                                 if (bc->msgids[j] >= 0) {
1719                                                         msc->msc_pending_ops--;
1720                                                 }
1721                                                 asyncmeta_back_cancel( mc, op,
1722                                                                        bc->candidates[ j ].sr_msgid, j );
1723                                                 if (!META_BACK_TGT_QUARANTINE( mt ) ||
1724                                                     bc->candidates[j].sr_type == REP_RESULT) {
1725                                                         continue;
1726                                                 }
1727
1728                                                 if (mt->mt_isquarantined > LDAP_BACK_FQ_NO) {
1729                                                         timeout_err = LDAP_UNAVAILABLE;
1730                                                 } else {
1731                                                         mt->mt_timeout_ops++;
1732                                                         if ((mi->mi_max_timeout_ops > 0) &&
1733                                                             (mt->mt_timeout_ops > mi->mi_max_timeout_ops)) {
1734                                                                 timeout_err = LDAP_UNAVAILABLE;
1735                                                                 rs->sr_err = timeout_err;
1736                                                                 if (mt->mt_isquarantined == LDAP_BACK_FQ_NO)
1737                                                                         asyncmeta_quarantine(op, mi, rs, j);
1738                                                         }
1739                                                 }
1740                                         }
1741                                 }
1742                                 send_ldap_error( op, rs, timeout_err, timeout_text );
1743                                 asyncmeta_clear_bm_context(bc);
1744                         }
1745                 }
1746
1747                 if (mi->mi_idle_timeout) {
1748                         for (j=0; j<mi->mi_ntargets; j++) {
1749                                 a_metasingleconn_t *msc = &mc->mc_conns[j];
1750                                 if (msc->msc_pending_ops > 0) {
1751                                         continue;
1752                                 }
1753                                 if (msc->msc_ld && msc->msc_time > 0 && msc->msc_time + mi->mi_idle_timeout <= current_time) {
1754                                         asyncmeta_clear_one_msc(NULL, mc, j);
1755                                 }
1756                         }
1757                 }
1758                 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
1759         }
1760
1761         ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
1762         if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask )) {
1763                 ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
1764         }
1765         rtask->interval.tv_sec = 1;
1766         rtask->interval.tv_usec = 0;
1767         ldap_pvt_runqueue_resched(&slapd_rq, rtask, 0);
1768         ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
1769         return NULL;
1770 }
1771
1772 #if 0
1773 int
1774 asyncmeta_back_cleanup( Operation *op, SlapReply *rs, bm_context_t *bc )
1775 {
1776         if (bc->ctrls != NULL && bc->cl != NULL && bc->cl->mc != NULL) {
1777                 a_metainfo_t *mi = bc->cl->mc->mc_info;
1778                 (void)mi->mi_ldap_extra->controls_free(op, rs, &bc->ctrls );
1779         }
1780         asyncmeta_clear_bm_context(bc, 1, 1);
1781         return rs->sr_err;
1782 }
1783 #endif