]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/bind.c
make sure realloc'd memory is reset
[openldap] / servers / slapd / back-meta / bind.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2006 The OpenLDAP Foundation.
5  * Portions Copyright 2001-2003 Pierangelo Masarati.
6  * Portions Copyright 1999-2003 Howard Chu.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by the Howard Chu for inclusion
19  * in OpenLDAP Software and subsequently enhanced by Pierangelo
20  * Masarati.
21  */
22
23 #include "portable.h"
24
25 #include <stdio.h>
26
27 #include <ac/errno.h>
28 #include <ac/socket.h>
29 #include <ac/string.h>
30
31
32 #define AVL_INTERNAL
33 #include "slap.h"
34 #include "../back-ldap/back-ldap.h"
35 #include "back-meta.h"
36
37 int
38 meta_back_bind( Operation *op, SlapReply *rs )
39 {
40         metainfo_t      *mi = ( metainfo_t * )op->o_bd->be_private;
41         metaconn_t      *mc = NULL;
42
43         int             rc = LDAP_OTHER,
44                         i,
45                         gotit = 0,
46                         isroot = 0;
47
48         SlapReply       *candidates = meta_back_candidates_get( op );
49
50         rs->sr_err = LDAP_SUCCESS;
51
52         Debug( LDAP_DEBUG_ARGS, "%s meta_back_bind: dn=\"%s\".\n",
53                 op->o_log_prefix, op->o_req_dn.bv_val, 0 );
54
55         /* the test on the bind method should be superfluous */
56         if ( op->orb_method == LDAP_AUTH_SIMPLE
57                 && be_isroot_dn( op->o_bd, &op->o_req_ndn ) )
58         {
59                 if ( !be_isroot_pw( op ) ) {
60                         rs->sr_err = LDAP_INVALID_CREDENTIALS;
61                         rs->sr_text = NULL;
62                         send_ldap_result( op, rs );
63                         return rs->sr_err;
64                 }
65
66                 if ( META_BACK_DEFER_ROOTDN_BIND( mi ) ) {
67                         rs->sr_err = LDAP_SUCCESS;
68                         rs->sr_text = NULL;
69                         /* frontend will return success */
70                         return rs->sr_err;
71                 }
72
73                 isroot = 1;
74         }
75
76         /* we need meta_back_getconn() not send result even on error,
77          * because we want to intercept the error and make it
78          * invalidCredentials */
79         mc = meta_back_getconn( op, rs, NULL, LDAP_BACK_BIND_DONTSEND );
80         if ( !mc ) {
81                 char    buf[ SLAP_TEXT_BUFLEN ];
82
83                 snprintf( buf, sizeof( buf ),
84                         "meta_back_bind: no target "
85                         "for dn \"%s\" (%d%s%s).",
86                         op->o_req_dn.bv_val, rs->sr_err,
87                         rs->sr_text ? ". " : "",
88                         rs->sr_text ? rs->sr_text : "" );
89                 Debug( LDAP_DEBUG_ANY,
90                         "%s %s\n",
91                         op->o_log_prefix, buf, 0 );
92
93                 /* FIXME: there might be cases where we don't want
94                  * to map the error onto invalidCredentials */
95                 switch ( rs->sr_err ) {
96                 case LDAP_NO_SUCH_OBJECT:
97                 case LDAP_UNWILLING_TO_PERFORM:
98                         rs->sr_err = LDAP_INVALID_CREDENTIALS;
99                         rs->sr_text = NULL;
100                         break;
101                 }
102                 send_ldap_result( op, rs );
103                 return rs->sr_err;
104         }
105
106         /*
107          * Each target is scanned ...
108          */
109         mc->mc_authz_target = META_BOUND_NONE;
110         for ( i = 0; i < mi->mi_ntargets; i++ ) {
111                 metatarget_t    *mt = mi->mi_targets[ i ];
112                 int             lerr;
113                 Operation       op2 = *op;
114                 int             massage = 1;
115
116                 /*
117                  * Skip non-candidates
118                  */
119                 if ( candidates[ i ].sr_tag != META_CANDIDATE ) {
120                         continue;
121                 }
122
123                 if ( gotit == 0 ) {
124                         /* set rc to LDAP_SUCCESS only if at least
125                          * one candidate has been tried */
126                         rc = LDAP_SUCCESS;
127                         gotit = 1;
128
129                 } else if ( isroot == 0 ) {
130                         /*
131                          * A bind operation is expected to have
132                          * ONE CANDIDATE ONLY!
133                          */
134                         Debug( LDAP_DEBUG_ANY,
135                                 "### %s meta_back_bind: more than one"
136                                 " candidate selected...\n",
137                                 op->o_log_prefix, 0, 0 );
138                 }
139
140                 if ( isroot ) {
141                         if ( BER_BVISNULL( &mt->mt_pseudorootdn ) )
142                         {
143                                 metasingleconn_t        *msc = &mc->mc_conns[ i ];
144
145                                 /* skip the target if no pseudorootdn is provided */
146                                 if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
147                                         ch_free( msc->msc_bound_ndn.bv_val );
148                                         BER_BVZERO( &msc->msc_bound_ndn );
149                                 }
150
151                                 if ( LDAP_BACK_SAVECRED( mi ) &&
152                                         !BER_BVISNULL( &msc->msc_cred ) )
153                                 {
154                                         /* destroy sensitive data */
155                                         memset( msc->msc_cred.bv_val, 0,
156                                                 msc->msc_cred.bv_len );
157                                         ch_free( msc->msc_cred.bv_val );
158                                         BER_BVZERO( &msc->msc_cred );
159                                 }
160
161                                 continue;
162                         }
163
164                         op2.o_req_dn = mt->mt_pseudorootdn;
165                         op2.o_req_ndn = mt->mt_pseudorootdn;
166                         op2.orb_cred = mt->mt_pseudorootpw;
167                         op2.orb_method = LDAP_AUTH_SIMPLE;
168
169                         massage = 0;
170                 }
171                 
172                 lerr = meta_back_single_bind( &op2, rs, mc, i, massage );
173
174                 if ( lerr != LDAP_SUCCESS ) {
175                         rc = rs->sr_err = lerr;
176                         /* FIXME: in some cases (e.g. unavailable)
177                          * do not assume it's not candidate; rather
178                          * mark this as an error to be eventually
179                          * reported to client */
180                         candidates[ i ].sr_tag = META_NOT_CANDIDATE;
181                         break;
182                 }
183         }
184
185         /* must re-insert if local DN changed as result of bind */
186         if ( rc == LDAP_SUCCESS ) {
187                 if ( isroot ) {
188                         mc->mc_authz_target = META_BOUND_ALL;
189                         ber_dupbv( &op->orb_edn, be_root_dn( op->o_bd ) );
190                 }
191
192                 if ( !dn_match( &op->o_req_ndn, &mc->mc_local_ndn ) ) {
193                         metaconn_t      *tmpmc;
194                         int             lerr;
195
196                         /* wait for all other ops to release the connection */
197 retry_lock:;
198                         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
199                         if ( mc->mc_refcnt > 1 ) {
200                                 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
201                                 ldap_pvt_thread_yield();
202                                 goto retry_lock;
203                         }
204
205                         assert( mc->mc_refcnt == 1 );
206                         tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
207                                 meta_back_conndn_cmp );
208                         assert( tmpmc == mc );
209
210                         ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn );
211                         lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
212                                 meta_back_conndn_cmp, meta_back_conndn_dup );
213                         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
214                         if ( lerr == -1 ) {
215                                 meta_clear_candidates( op, mc );
216
217                                 /* we can do this because mc_refcnt == 1 */
218                                 mc->mc_refcnt = 0;
219                                 meta_back_conn_free( mc );
220                                 mc = NULL;
221                         }
222                 }
223         }
224
225         if ( mc != NULL ) {
226                 meta_back_release_conn( op, mc );
227         }
228
229         /*
230          * rc is LDAP_SUCCESS if at least one bind succeeded,
231          * err is the last error that occurred during a bind;
232          * if at least (and at most?) one bind succeeds, fine.
233          */
234         if ( rc != LDAP_SUCCESS ) {
235                 
236                 /*
237                  * deal with bind failure ...
238                  */
239
240                 /*
241                  * no target was found within the naming context, 
242                  * so bind must fail with invalid credentials
243                  */
244                 if ( rs->sr_err == LDAP_SUCCESS && gotit == 0 ) {
245                         rs->sr_err = LDAP_INVALID_CREDENTIALS;
246                 } else {
247                         rs->sr_err = slap_map_api2result( rs );
248                 }
249                 send_ldap_result( op, rs );
250                 return rs->sr_err;
251
252         }
253
254         return LDAP_SUCCESS;
255 }
256
257 /*
258  * meta_back_single_bind
259  *
260  * attempts to perform a bind with creds
261  */
262 int
263 meta_back_single_bind(
264         Operation               *op,
265         SlapReply               *rs,
266         metaconn_t              *mc,
267         int                     candidate,
268         int                     massage )
269 {
270         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
271         metatarget_t            *mt = mi->mi_targets[ candidate ];
272         struct berval           mdn = BER_BVNULL;
273         metasingleconn_t        *msc = &mc->mc_conns[ candidate ];
274         int                     msgid,
275                                 rebinding = 0;
276
277         
278         if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
279                 ch_free( msc->msc_bound_ndn.bv_val );
280                 BER_BVZERO( &msc->msc_bound_ndn );
281         }
282
283         if ( LDAP_BACK_SAVECRED( mi ) && !BER_BVISNULL( &msc->msc_cred ) ) {
284                 /* destroy sensitive data */
285                 memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
286                 ch_free( msc->msc_cred.bv_val );
287                 BER_BVZERO( &msc->msc_cred );
288         }
289
290         /*
291          * Rewrite the bind dn if needed
292          */
293         if ( massage ) {
294                 dncookie                dc;
295
296                 dc.target = mt;
297                 dc.conn = op->o_conn;
298                 dc.rs = rs;
299                 dc.ctx = "bindDN";
300
301                 if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
302                         rs->sr_text = "DN rewrite error";
303                         rs->sr_err = LDAP_OTHER;
304                         return rs->sr_err;
305                 }
306
307         } else {
308                 mdn = op->o_req_dn;
309         }
310
311         /* FIXME: this fixes the bind problem right now; we need
312          * to use the asynchronous version to get the "matched"
313          * and more in case of failure ... */
314         /* FIXME: should we check if at least some of the op->o_ctrls
315          * can/should be passed? */
316 rebind:;
317         rs->sr_err = ldap_sasl_bind( msc->msc_ld, mdn.bv_val,
318                         LDAP_SASL_SIMPLE, &op->orb_cred,
319                         op->o_ctrls, NULL, &msgid );
320         if ( rs->sr_err == LDAP_SUCCESS ) {
321                 LDAPMessage     *res;
322                 struct timeval  tv;
323                 int             rc;
324                 int             nretries = mt->mt_nretries;
325                 char            buf[ SLAP_TEXT_BUFLEN ];
326
327                 LDAP_BACK_TV_SET( &tv );
328
329                 /*
330                  * handle response!!!
331                  */
332 retry:;
333                 switch ( ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ) ) {
334                 case 0:
335                         snprintf( buf, sizeof( buf ),
336                                 "ldap_result=0 nretries=%d%s",
337                                 nretries, rebinding ? " rebinding" : "" );
338                         Debug( LDAP_DEBUG_ANY,
339                                 "%s meta_back_single_bind[%d]: %s.\n",
340                                 op->o_log_prefix, candidate, buf );
341
342                         if ( nretries != META_RETRY_NEVER ) {
343                                 ldap_pvt_thread_yield();
344                                 if ( nretries > 0 ) {
345                                         nretries--;
346                                 }
347                                 tv = mt->mt_bind_timeout;
348                                 goto retry;
349                         }
350
351                         rs->sr_err = LDAP_BUSY;
352                         if ( rebinding ) {
353                                 ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
354                                 break;
355                         }
356
357                         /* FIXME: some times the request times out
358                          * while the other party is not willing to
359                          * send a response any more.  Give it a second
360                          * chance with a freshly bound connection */
361                         rebinding = 1;
362                         nretries = mt->mt_nretries;
363                         /* fallthru */
364
365                 case -1:
366                         ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER,
367                                 &rs->sr_err );
368
369                         if ( rebinding ) {
370                                 ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
371                         }
372
373                         snprintf( buf, sizeof( buf ),
374                                 "err=%d (%s) nretries=%d",
375                                 rs->sr_err, ldap_err2string( rs->sr_err ), nretries );
376                         Debug( LDAP_DEBUG_ANY,
377                                 "### %s meta_back_single_bind[%d]: %s.\n",
378                                 op->o_log_prefix, candidate, buf );
379
380                         rc = slap_map_api2result( rs );
381                         if ( rs->sr_err == LDAP_UNAVAILABLE && nretries != META_RETRY_NEVER ) {
382                                 rc = meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND );
383                                 if ( rc ) {
384                                         if ( nretries > 0 ) {
385                                                 nretries--;
386                                         }
387                                         ldap_pvt_thread_yield();
388                                         goto rebind;
389                                 }
390                                 goto return_results;
391                         }
392                         break;
393
394                 default:
395                         rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
396                                         NULL, NULL, NULL, NULL, 1 );
397                         if ( rc != LDAP_SUCCESS ) {
398                                 rs->sr_err = rc;
399                         }
400                         break;
401                 }
402         }
403
404         if ( rs->sr_err != LDAP_SUCCESS ) {
405                 rs->sr_err = slap_map_api2result( rs );
406                 goto return_results;
407         }
408
409         ber_bvreplace( &msc->msc_bound_ndn, &op->o_req_dn );
410         LDAP_BACK_CONN_ISBOUND_SET( msc );
411         mc->mc_authz_target = candidate;
412
413         if ( LDAP_BACK_SAVECRED( mi ) ) {
414                 ber_bvreplace( &msc->msc_cred, &op->orb_cred );
415                 ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
416         }
417
418         if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED
419                         && op->o_req_ndn.bv_len != 0 )
420         {
421                 ( void )meta_dncache_update_entry( &mi->mi_cache,
422                                 &op->o_req_ndn, candidate );
423         }
424
425 return_results:;
426         if ( mdn.bv_val != op->o_req_dn.bv_val ) {
427                 free( mdn.bv_val );
428         }
429
430         return rs->sr_err;
431 }
432
433 /*
434  * meta_back_single_dobind
435  */
436 int
437 meta_back_single_dobind(
438         Operation               *op,
439         SlapReply               *rs,
440         metaconn_t              **mcp,
441         int                     candidate,
442         ldap_back_send_t        sendok,
443         int                     nretries,
444         int                     dolock )
445 {
446         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
447         metatarget_t            *mt = mi->mi_targets[ candidate ];
448         metaconn_t              *mc = *mcp;
449         metasingleconn_t        *msc = &mc->mc_conns[ candidate ];
450         int                     rc;
451         static struct berval    cred = BER_BVC( "" );
452         int                     msgid,
453                                 rebinding = 0,
454                                 save_nretries = nretries;
455
456         assert( !LDAP_BACK_CONN_ISBOUND( msc ) );
457
458         /*
459          * meta_back_single_dobind() calls meta_back_single_bind()
460          * if required.
461          */
462         if ( be_isroot( op ) && !BER_BVISNULL( &mt->mt_pseudorootdn ) )
463         {
464                 Operation       op2 = *op;
465
466                 op2.o_tag = LDAP_REQ_BIND;
467                 op2.o_req_dn = mt->mt_pseudorootdn;
468                 op2.o_req_ndn = mt->mt_pseudorootdn;
469                 op2.orb_cred = mt->mt_pseudorootpw;
470                 op2.orb_method = LDAP_AUTH_SIMPLE;
471
472                 rc = meta_back_single_bind( &op2, rs, *mcp, candidate, 0 );
473                 goto done;
474         }
475
476         /*
477          * Otherwise an anonymous bind is performed
478          * (note: if the target was already bound, the anonymous
479          * bind clears the previous bind).
480          */
481         if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
482                 ber_memfree( msc->msc_bound_ndn.bv_val );
483                 BER_BVZERO( &msc->msc_bound_ndn );
484         }
485                 
486         if ( LDAP_BACK_SAVECRED( mi ) && !BER_BVISNULL( &msc->msc_cred ) ) {
487                 /* destroy sensitive data */
488                 memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
489                 ber_memfree( msc->msc_cred.bv_val );
490                 BER_BVZERO( &msc->msc_cred );
491         }
492
493         /* FIXME: should we check if at least some of the op->o_ctrls
494          * can/should be passed? */
495 rebind:;
496         rc = ldap_sasl_bind( msc->msc_ld, "", LDAP_SASL_SIMPLE, &cred,
497                         NULL, NULL, &msgid );
498         if ( rc == LDAP_SUCCESS ) {
499                 LDAPMessage     *res;
500                 struct timeval  tv;
501                 char            buf[ SLAP_TEXT_BUFLEN ];
502
503                 LDAP_BACK_TV_SET( &tv );
504
505                 /*
506                  * handle response!!!
507                  */
508 retry:;
509                 switch ( ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ) ) {
510                 case 0:
511                         snprintf( buf, sizeof( buf ),
512                                 "ldap_result=0 nretries=%d%s",
513                                 nretries, rebinding ? " rebinding" : "" );
514                         Debug( LDAP_DEBUG_ANY,
515                                 "%s meta_back_single_dobind[%d]: %s.\n",
516                                 op->o_log_prefix, candidate, buf );
517
518                         if ( nretries != META_RETRY_NEVER ) {
519                                 ldap_pvt_thread_yield();
520                                 if ( nretries > 0 ) {
521                                         nretries--;
522                                 }
523                                 tv = mt->mt_bind_timeout;
524                                 goto retry;
525                         }
526
527                         rc = LDAP_BUSY;
528                         if ( rebinding ) {
529                                 ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
530                                 break;
531                         }
532
533                         /* FIXME: some times the request times out
534                          * while the other party is not willing to
535                          * send a response any more.  Give it a second
536                          * chance with a freshly bound connection */
537                         rebinding = 1;
538                         nretries = save_nretries;
539                         /* fallthru */
540
541                 case -1:
542                         ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER,
543                                 &rs->sr_err );
544
545                         if ( rebinding ) {
546                                 ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
547                         }
548
549                         snprintf( buf, sizeof( buf ),
550                                 "err=%d (%s) nretries=%d",
551                                 rs->sr_err, ldap_err2string( rs->sr_err ), nretries );
552                         Debug( LDAP_DEBUG_ANY,
553                                 "### %s meta_back_single_dobind[%d]: %s.\n",
554                                 op->o_log_prefix, candidate, buf );
555
556                         rc = slap_map_api2result( rs );
557                         if ( rc == LDAP_UNAVAILABLE && nretries != META_RETRY_NEVER ) {
558                                 if ( dolock ) {
559                                         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
560                                 }
561
562                                 if ( mc->mc_refcnt == 1 ) {
563                                         meta_clear_one_candidate( msc );
564                                         LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
565
566                                         ( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn );
567
568                                         /* mc here must be the regular mc,
569                                          * reset and ready for init */
570                                         rc = meta_back_init_one_conn( op, rs,
571                                                 mt, mc, candidate,
572                                                 LDAP_BACK_CONN_ISPRIV( mc ),
573                                                 LDAP_BACK_DONTSEND );
574                                         if ( rc == LDAP_SUCCESS ) {
575                                                 LDAP_BACK_CONN_BINDING_SET( msc );
576                                         }
577
578                                 } else {
579                                         /* can't do anything about it */
580                                         rc = LDAP_UNAVAILABLE;
581                                 }
582
583                                 if ( dolock ) {
584                                         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
585                                 }
586
587                                 if ( rc == LDAP_SUCCESS ) {
588                                         ldap_pvt_thread_yield();
589                                         if ( nretries > 0 ) {
590                                                 nretries--;
591                                         }
592                                         goto rebind;
593                                 }
594                         }
595                         break;
596
597                 default:
598                         rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
599                                         NULL, NULL, NULL, NULL, 1 );
600                         if ( rc == LDAP_SUCCESS ) {
601                                 rc = slap_map_api2result( rs );
602                         }
603                         break;
604                 }
605
606         } else {
607                 rs->sr_err = rc;
608                 rc = slap_map_api2result( rs );
609         }
610
611 done:;
612         rs->sr_err = rc;
613         if ( rc != LDAP_SUCCESS && META_BACK_ONERR_STOP( mi ) ) {
614                 LDAP_BACK_CONN_BINDING_CLEAR( msc );
615                 LDAP_BACK_CONN_TAINTED_SET( mc );
616                 meta_back_release_conn_lock( op, mc, dolock );
617                 *mcp = NULL;
618
619                 if ( sendok & LDAP_BACK_SENDERR ) {
620                         send_ldap_result( op, rs );
621                 }
622         }
623
624         return rc;
625 }
626
627 /*
628  * meta_back_dobind
629  */
630 int
631 meta_back_dobind(
632         Operation               *op,
633         SlapReply               *rs,
634         metaconn_t              *mc,
635         ldap_back_send_t        sendok )
636 {
637         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
638
639         int                     bound = 0,
640                                 i,
641                                 isroot = 0;
642
643         SlapReply               *candidates = meta_back_candidates_get( op );
644
645         if ( be_isroot( op ) ) {
646                 isroot = 1;
647         }
648
649         Debug( LDAP_DEBUG_TRACE,
650                 "%s meta_back_dobind: conn=%ld%s\n",
651                 op->o_log_prefix,
652                 LDAP_BACK_PCONN_ID( mc->mc_conn ),
653                 isroot ? " (isroot)" : "" );
654
655         /*
656          * all the targets are bound as pseudoroot
657          */
658         if ( mc->mc_authz_target == META_BOUND_ALL ) {
659                 bound = 1;
660                 goto done;
661         }
662
663         for ( i = 0; i < mi->mi_ntargets; i++ ) {
664                 metatarget_t            *mt = mi->mi_targets[ i ];
665                 metasingleconn_t        *msc = &mc->mc_conns[ i ];
666                 int                     rc, do_retry = 1;
667
668                 /*
669                  * Not a candidate
670                  */
671                 if ( candidates[ i ].sr_tag != META_CANDIDATE ) {
672                         continue;
673                 }
674
675                 assert( msc->msc_ld != NULL );
676
677                 /*
678                  * If the target is already bound it is skipped
679                  */
680
681 retry_binding:;
682                 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
683                 if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
684                         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
685                         ++bound;
686                         continue;
687
688                 } else if ( LDAP_BACK_CONN_BINDING( msc ) ) {
689                         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
690                         ldap_pvt_thread_yield();
691                         goto retry_binding;
692
693                 } else {
694                         LDAP_BACK_CONN_BINDING_SET( msc );
695                         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
696                 } 
697
698 retry:;
699                 rc = meta_back_single_dobind( op, rs, &mc, i,
700                         LDAP_BACK_DONTSEND, mt->mt_nretries, 1 );
701                 /*
702                  * NOTE: meta_back_single_dobind() already retries;
703                  * in case of failure, it resets mc...
704                  */
705                 if ( rc != LDAP_SUCCESS ) {
706                         char            buf[ SLAP_TEXT_BUFLEN ];
707
708                         if ( mc == NULL ) {
709                                 /* meta_back_single_dobind() already sent 
710                                  * response and released connection */
711                                 goto send_err;
712                         }
713
714
715                         if ( rc == LDAP_UNAVAILABLE && do_retry ) {
716                                 do_retry = 0;
717                                 if ( meta_back_retry( op, rs, &mc, i, sendok ) ) {
718                                         goto retry;
719                                 }
720
721                                 if ( mc != NULL ) {
722                                         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
723                                         LDAP_BACK_CONN_BINDING_CLEAR( msc );
724                                         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
725                                 }
726
727                                 return 0;
728                         }
729
730                         ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
731                         LDAP_BACK_CONN_BINDING_CLEAR( msc );
732                         ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
733
734                         snprintf( buf, sizeof( buf ),
735                                 "meta_back_dobind[%d]: (%s) err=%d (%s).",
736                                 i, isroot ? op->o_bd->be_rootdn.bv_val : "anonymous",
737                                 rc, ldap_err2string( rc ) );
738                         Debug( LDAP_DEBUG_ANY,
739                                 "%s %s\n",
740                                 op->o_log_prefix, buf, 0 );
741
742                         /*
743                          * null cred bind should always succeed
744                          * as anonymous, so a failure means
745                          * the target is no longer candidate possibly
746                          * due to technical reasons (remote host down?)
747                          * so better clear the handle
748                          */
749                         /* leave the target candidate, but record the error for later use */
750                         candidates[ i ].sr_err = rc;
751                         if ( META_BACK_ONERR_STOP( mi ) ) {
752                                 bound = 0;
753                                 goto done;
754                         }
755
756                         continue;
757                 } /* else */
758                 
759                 Debug( LDAP_DEBUG_TRACE,
760                         "%s meta_back_dobind[%d]: "
761                         "(%s)\n",
762                         op->o_log_prefix, i,
763                         isroot ? op->o_bd->be_rootdn.bv_val : "anonymous" );
764
765                 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
766                 LDAP_BACK_CONN_BINDING_CLEAR( msc );
767                 if ( isroot ) {
768                         LDAP_BACK_CONN_ISBOUND_SET( msc );
769                 } else {
770                         LDAP_BACK_CONN_ISANON_SET( msc );
771                 }
772                 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
773                 ++bound;
774         }
775
776 done:;
777         Debug( LDAP_DEBUG_TRACE,
778                 "%s meta_back_dobind: conn=%ld bound=%d\n",
779                 op->o_log_prefix, LDAP_BACK_PCONN_ID( mc->mc_conn ), bound );
780
781         if ( bound == 0 ) {
782                 meta_back_release_conn( op, mc );
783
784 send_err:;
785                 if ( sendok & LDAP_BACK_SENDERR ) {
786                         if ( rs->sr_err == LDAP_SUCCESS ) {
787                                 rs->sr_err = LDAP_BUSY;
788                         }
789                         send_ldap_result( op, rs );
790                 }
791
792                 return 0;
793         }
794
795         return ( bound > 0 );
796 }
797
798 /*
799  * meta_back_default_rebind
800  *
801  * This is a callback used for chasing referrals using the same
802  * credentials as the original user on this session.
803  */
804 int 
805 meta_back_default_rebind(
806         LDAP                    *ld,
807         LDAP_CONST char         *url,
808         ber_tag_t               request,
809         ber_int_t               msgid,
810         void                    *params )
811 {
812         metasingleconn_t        *msc = ( metasingleconn_t * )params;
813
814         return ldap_sasl_bind_s( ld, msc->msc_bound_ndn.bv_val,
815                         LDAP_SASL_SIMPLE, &msc->msc_cred,
816                         NULL, NULL, NULL );
817 }
818
819 /*
820  * meta_back_default_urllist
821  *
822  * This is a callback used for mucking with the urllist
823  */
824 int 
825 meta_back_default_urllist(
826         LDAP            *ld,
827         LDAPURLDesc     **urllist,
828         LDAPURLDesc     **url,
829         void            *params )
830 {
831         metatarget_t    *mt = (metatarget_t *)params;
832         LDAPURLDesc     **urltail;
833
834         if ( urllist == url ) {
835                 return LDAP_SUCCESS;
836         }
837
838         for ( urltail = &(*url)->lud_next; *urltail; urltail = &(*urltail)->lud_next )
839                 /* count */ ;
840
841         *urltail = *urllist;
842         *urllist = *url;
843         *url = NULL;
844
845         ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
846         if ( mt->mt_uri ) {
847                 ch_free( mt->mt_uri );
848         }
849
850         ldap_get_option( ld, LDAP_OPT_URI, (void *)&mt->mt_uri );
851         ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
852
853         return LDAP_SUCCESS;
854 }
855
856 /*
857  * FIXME: error return must be handled in a cleaner way ...
858  */
859 int
860 meta_back_op_result(
861         metaconn_t      *mc,
862         Operation       *op,
863         SlapReply       *rs,
864         int             candidate )
865 {
866         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
867
868         int                     i,
869                                 rerr = LDAP_SUCCESS;
870         char                    *rmsg = NULL,
871                                 *rmatch = NULL;
872         const char              *save_rmsg = NULL,
873                                 *save_rmatch = NULL;
874         void                    *rmatch_ctx = NULL;
875
876         assert( mc != NULL );
877
878         if ( candidate != META_TARGET_NONE ) {
879                 metasingleconn_t        *msc = &mc->mc_conns[ candidate ];
880
881                 rs->sr_err = LDAP_SUCCESS;
882
883                 ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER, &rs->sr_err );
884                 if ( rs->sr_err != LDAP_SUCCESS ) {
885                         /*
886                          * better check the type of error. In some cases
887                          * (search ?) it might be better to return a
888                          * success if at least one of the targets gave
889                          * positive result ...
890                          */
891                         ldap_get_option( msc->msc_ld,
892                                         LDAP_OPT_ERROR_STRING, &rmsg );
893                         if ( rmsg != NULL && rmsg[ 0 ] == '\0' ) {
894                                 ldap_memfree( rmsg );
895                                 rmsg = NULL;
896                         }
897
898                         ldap_get_option( msc->msc_ld,
899                                         LDAP_OPT_MATCHED_DN, &rmatch );
900                         if ( rmatch != NULL && rmatch[ 0 ] == '\0' ) {
901                                 ldap_memfree( rmatch );
902                                 rmatch = NULL;
903                         }
904
905                         rerr = rs->sr_err = slap_map_api2result( rs );
906
907                         Debug(LDAP_DEBUG_ANY,
908                                         "==> meta_back_op_result: target"
909                                         " <%d> sending msg \"%s\""
910                                         " (matched \"%s\")\n", 
911                                         candidate, ( rmsg ? rmsg : "" ),
912                                         ( rmatch ? rmatch : "" ) );
913                 }
914
915         } else {
916                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
917                         metasingleconn_t        *msc = &mc->mc_conns[ i ];
918                         char                    *msg = NULL;
919                         char                    *match = NULL;
920
921                         rs->sr_err = LDAP_SUCCESS;
922
923                         ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER, &rs->sr_err );
924                         if ( rs->sr_err != LDAP_SUCCESS ) {
925                                 /*
926                                  * better check the type of error. In some cases
927                                  * (search ?) it might be better to return a
928                                  * success if at least one of the targets gave
929                                  * positive result ...
930                                  */
931                                 ldap_get_option( msc->msc_ld,
932                                                 LDAP_OPT_ERROR_STRING, &msg );
933                                 if ( msg != NULL && msg[ 0 ] == '\0' ) {
934                                         ldap_memfree( msg );
935                                         msg = NULL;
936                                 }
937
938                                 ldap_get_option( msc->msc_ld,
939                                                 LDAP_OPT_MATCHED_DN, &match );
940                                 if ( match != NULL && match[ 0 ] == '\0' ) {
941                                         ldap_memfree( match );
942                                         match = NULL;
943                                 }
944
945                                 rs->sr_err = slap_map_api2result( rs );
946         
947                                 Debug(LDAP_DEBUG_ANY,
948                                                 "==> meta_back_op_result: target"
949                                                 " <%d> sending msg \"%s\""
950                                                 " (matched \"%s\")\n", 
951                                                 i, ( msg ? msg : "" ),
952                                                 ( match ? match : "" ) );
953         
954                                 /*
955                                  * FIXME: need to rewrite "match" (need rwinfo)
956                                  */
957                                 switch ( rs->sr_err ) {
958                                 default:
959                                         rerr = rs->sr_err;
960                                         if ( msg != NULL ) {
961                                                 if ( rmsg ) {
962                                                         ldap_memfree( rmsg );
963                                                 }
964                                                 rmsg = msg;
965                                                 msg = NULL;
966                                         }
967                                         if ( match != NULL ) {
968                                                 if ( rmatch ) {
969                                                         ldap_memfree( rmatch );
970                                                 }
971                                                 rmatch = match;
972                                                 match = NULL;
973                                         }
974                                         break;
975                                 }
976
977                                 if ( msg ) {
978                                         ldap_memfree( msg );
979                                 }
980         
981                                 if ( match ) {
982                                         ldap_memfree( match );
983                                 }
984                         }
985                 }
986         }
987         
988         rs->sr_err = rerr;
989         if ( rmsg != NULL ) {
990                 save_rmsg = rs->sr_text;
991                 rs->sr_text = rmsg;
992         }
993         if ( rmatch != NULL ) {
994                 struct berval   dn, pdn;
995
996                 ber_str2bv( rmatch, 0, 0, &dn );
997                 if ( dnPretty( NULL, &dn, &pdn, op->o_tmpmemctx ) == LDAP_SUCCESS ) {
998                         ldap_memfree( rmatch );
999                         rmatch_ctx = op->o_tmpmemctx;
1000                         rmatch = pdn.bv_val;
1001                 }
1002                 save_rmatch = rs->sr_matched;
1003                 rs->sr_matched = rmatch;
1004         }
1005         send_ldap_result( op, rs );
1006         if ( rmsg != NULL ) {
1007                 ber_memfree( rmsg );
1008                 rs->sr_text = save_rmsg;
1009         }
1010         if ( rmatch != NULL ) {
1011                 ber_memfree_x( rmatch, rmatch_ctx );
1012                 rs->sr_matched = save_rmatch;
1013         }
1014
1015         return ( ( rerr == LDAP_SUCCESS ) ? 0 : -1 );
1016 }
1017