]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/conn.c
587bd15d98bc38ed5f388d5ceb6d07eea0c5865f
[openldap] / servers / slapd / back-meta / conn.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2005 The OpenLDAP Foundation.
5  * Portions Copyright 2001-2003 Pierangelo Masarati.
6  * Portions Copyright 1999-2003 Howard Chu.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by the Howard Chu for inclusion
19  * in OpenLDAP Software and subsequently enhanced by Pierangelo
20  * Masarati.
21  */
22
23 #include "portable.h"
24
25 #include <stdio.h>
26
27 #include <ac/socket.h>
28 #include <ac/string.h>
29
30
31 #define AVL_INTERNAL
32 #include "slap.h"
33 #include "../back-ldap/back-ldap.h"
34 #include "back-meta.h"
35
36 /*
37  * Set PRINT_CONNTREE larger than 0 to dump the connection tree (debug only)
38  */
39 #define PRINT_CONNTREE 0
40
41 /*
42  * meta_back_conn_cmp
43  *
44  * compares two struct metaconn based on the value of the conn pointer;
45  * used by avl stuff
46  */
47 int
48 meta_back_conn_cmp(
49         const void *c1,
50         const void *c2 )
51 {
52         metaconn_t      *mc1 = ( metaconn_t * )c1;
53         metaconn_t      *mc2 = ( metaconn_t * )c2;
54         
55         return SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn );
56 }
57
58 /*
59  * meta_back_conn_dup
60  *
61  * returns -1 in case a duplicate struct metaconn has been inserted;
62  * used by avl stuff
63  */
64 int
65 meta_back_conn_dup(
66         void *c1,
67         void *c2 )
68 {
69         metaconn_t      *mc1 = ( metaconn_t * )c1;
70         metaconn_t      *mc2 = ( metaconn_t * )c2;
71
72         return( ( mc1->mc_conn == mc2->mc_conn ) ? -1 : 0 );
73 }
74
75 /*
76  * Debug stuff (got it from libavl)
77  */
78 #if PRINT_CONNTREE > 0
79 static void
80 ravl_print( Avlnode *root, int depth )
81 {
82         int     i;
83         
84         if ( root == 0 ) {
85                 return;
86         }
87         
88         ravl_print( root->avl_right, depth + 1 );
89         
90         for ( i = 0; i < depth; i++ ) {
91                 printf( "    " );
92         }
93
94         printf( "c(%d) %d\n", ( ( metaconn_t * )root->avl_data )->mc_conn->c_connid, root->avl_bf );
95         
96         ravl_print( root->avl_left, depth + 1 );
97 }
98
99 static void
100 myprint( Avlnode *root )
101 {
102         printf( "********\n" );
103         
104         if ( root == 0 ) {
105                 printf( "\tNULL\n" );
106         } else {
107                 ravl_print( root, 0 );
108         }
109         
110         printf( "********\n" );
111 }
112 #endif /* PRINT_CONNTREE */
113 /*
114  * End of debug stuff
115  */
116
117 /*
118  * metaconn_alloc
119  * 
120  * Allocates a connection structure, making room for all the referenced targets
121  */
122 static metaconn_t *
123 metaconn_alloc(
124         Operation               *op )
125 {
126         metainfo_t      *mi = ( metainfo_t * )op->o_bd->be_private;
127         metaconn_t      *mc;
128         int             i, ntargets = mi->mi_ntargets;
129
130         assert( ntargets > 0 );
131
132         /* malloc once only; leave an extra one for one-past-end */
133         mc = ( metaconn_t * )ch_malloc( sizeof( metaconn_t )
134                         + sizeof( metasingleconn_t ) * ntargets );
135         if ( mc == NULL ) {
136                 return NULL;
137         }
138
139         mc->mc_conns = ( metasingleconn_t * )&mc[ 1 ];
140
141         for ( i = 0; i < ntargets; i++ ) {
142                 mc->mc_conns[ i ].msc_ld = NULL;
143                 BER_BVZERO( &mc->mc_conns[ i ].msc_bound_ndn );
144                 BER_BVZERO( &mc->mc_conns[ i ].msc_cred );
145                 mc->mc_conns[ i ].msc_bound = META_UNBOUND;
146                 mc->mc_conns[ i ].msc_info = mi;
147         }
148
149         mc->mc_auth_target = META_BOUND_NONE;
150         ldap_pvt_thread_mutex_init( &mc->mc_mutex );
151
152         return mc;
153 }
154
155 /*
156  * meta_back_conn_free
157  *
158  * clears a metaconn
159  */
160 void
161 meta_back_conn_free(
162         metaconn_t      *mc )
163 {
164         if ( mc == NULL ) {
165                 return;
166         }
167
168         ldap_pvt_thread_mutex_destroy( &mc->mc_mutex );
169         
170         free( mc );
171 }
172
173 /*
174  * meta_back_init_one_conn
175  * 
176  * Initializes one connection
177  */
178 int
179 meta_back_init_one_conn(
180         Operation               *op,
181         SlapReply               *rs,
182         metatarget_t            *mt, 
183         metasingleconn_t        *msc,
184         ldap_back_send_t        sendok )
185 {
186         metainfo_t      *mi = ( metainfo_t * )op->o_bd->be_private;
187         int             vers;
188         dncookie        dc;
189
190         /*
191          * Already init'ed
192          */
193         if ( msc->msc_ld != NULL ) {
194                 rs->sr_err = LDAP_SUCCESS;
195                 goto error_return;
196         }
197        
198         /*
199          * Attempts to initialize the connection to the target ds
200          */
201         rs->sr_err = ldap_initialize( &msc->msc_ld, mt->mt_uri );
202         if ( rs->sr_err != LDAP_SUCCESS ) {
203                 goto error_return;
204         }
205
206         /*
207          * Set LDAP version. This will always succeed: If the client
208          * bound with a particular version, then so can we.
209          */
210         vers = op->o_conn->c_protocol;
211         ldap_set_option( msc->msc_ld, LDAP_OPT_PROTOCOL_VERSION, &vers );
212
213         /* automatically chase referrals ("chase-referrals"/"dont-chase-referrals" statement) */
214         if ( LDAP_BACK_CHASE_REFERRALS( mi ) ) {
215                 ldap_set_option( msc->msc_ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON );
216         }
217
218 #ifdef HAVE_TLS
219         /* start TLS ("start-tls"/"try-start-tls" statements) */
220         if ( ( LDAP_BACK_USE_TLS( mi ) || ( op->o_conn->c_is_tls && LDAP_BACK_PROPAGATE_TLS( mi ) ) )
221                         && !ldap_is_ldaps_url( mt->mt_uri ) )
222         {
223 #ifdef SLAP_STARTTLS_ASYNCHRONOUS
224                 /*
225                  * use asynchronous StartTLS
226                  * in case, chase referral (not implemented yet)
227                  */
228                 int             msgid;
229
230                 rs->sr_err = ldap_start_tls( msc->msc_ld, NULL, NULL, &msgid );
231                 if ( rs->sr_err == LDAP_SUCCESS ) {
232                         LDAPMessage     *res = NULL;
233                         int             rc, nretries = mt->mt_nretries;
234                         struct timeval  tv = { 0, 0 };
235
236 retry:;
237                         rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
238                         if ( rc < 0 ) {
239                                 rs->sr_err = LDAP_OTHER;
240
241                         } else if ( rc == 0 ) {
242                                 if ( nretries != 0 ) {
243                                         if ( nretries > 0 ) {
244                                                 nretries--;
245                                         }
246                                         tv.tv_sec = 0;
247                                         tv.tv_usec = 100000;
248                                         goto retry;
249                                 }
250                                 rs->sr_err = LDAP_OTHER;
251
252                         } else if ( rc == LDAP_RES_EXTENDED ) {
253                                 struct berval   *data = NULL;
254
255                                 rs->sr_err = ldap_parse_extended_result( msc->msc_ld, res,
256                                                 NULL, &data, 0 );
257                                 if ( rs->sr_err == LDAP_SUCCESS ) {
258                                         rs->sr_err = ldap_result2error( msc->msc_ld, res, 1 );
259                                         res = NULL;
260                                         
261                                         /* FIXME: in case a referral 
262                                          * is returned, should we try
263                                          * using it instead of the 
264                                          * configured URI? */
265                                         if ( rs->sr_err == LDAP_SUCCESS ) {
266                                                 ldap_install_tls( msc->msc_ld );
267
268                                         } else if ( rs->sr_err == LDAP_REFERRAL ) {
269                                                 rs->sr_err = LDAP_OTHER;
270                                                 rs->sr_text = "unwilling to chase referral returned by Start TLS exop";
271                                         }
272
273                                         if ( data ) {
274                                                 if ( data->bv_val ) {
275                                                         ber_memfree( data->bv_val );
276                                                 }
277                                                 ber_memfree( data );
278                                         }
279                                 }
280
281                         } else {
282                                 rs->sr_err = LDAP_OTHER;
283                         }
284
285                         if ( res != NULL ) {
286                                 ldap_msgfree( res );
287                         }
288                 }
289 #else /* ! SLAP_STARTTLS_ASYNCHRONOUS */
290                 /*
291                  * use synchronous StartTLS
292                  */
293                 rs->sr_err = ldap_start_tls_s( msc->msc_ld, NULL, NULL );
294 #endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */
295
296                 /* if StartTLS is requested, only attempt it if the URL
297                  * is not "ldaps://"; this may occur not only in case
298                  * of misconfiguration, but also when used in the chain 
299                  * overlay, where the "uri" can be parsed out of a referral */
300                 if ( rs->sr_err == LDAP_SERVER_DOWN
301                                 || ( rs->sr_err != LDAP_SUCCESS && LDAP_BACK_TLS_CRITICAL( mi ) ) )
302                 {
303                         ldap_unbind_ext_s( msc->msc_ld, NULL, NULL );
304                         goto error_return;
305                 }
306         }
307 #endif /* HAVE_TLS */
308
309         /*
310          * Set the network timeout if set
311          */
312         if ( mi->mi_network_timeout != 0 ) {
313                 struct timeval  network_timeout;
314
315                 network_timeout.tv_usec = 0;
316                 network_timeout.tv_sec = mi->mi_network_timeout;
317
318                 ldap_set_option( msc->msc_ld, LDAP_OPT_NETWORK_TIMEOUT,
319                                 (void *)&network_timeout );
320         }
321
322         /*
323          * Sets a cookie for the rewrite session
324          */
325         ( void )rewrite_session_init( mt->mt_rwmap.rwm_rw, op->o_conn );
326
327         /*
328          * If the connection DN is not null, an attempt to rewrite it is made
329          */
330         if ( !BER_BVISEMPTY( &op->o_conn->c_dn ) ) {
331                 dc.target = mt;
332                 dc.conn = op->o_conn;
333                 dc.rs = rs;
334                 dc.ctx = "bindDN";
335                 
336                 /*
337                  * Rewrite the bind dn if needed
338                  */
339                 if ( ldap_back_dn_massage( &dc, &op->o_conn->c_dn,
340                                         &msc->msc_bound_ndn ) )
341                 {
342                         goto error_return;
343                 }
344
345                 /* copy the DN idf needed */
346                 if ( msc->msc_bound_ndn.bv_val == op->o_conn->c_dn.bv_val ) {
347                         ber_dupbv( &msc->msc_bound_ndn, &op->o_conn->c_dn );
348                 }
349
350                 assert( !BER_BVISNULL( &msc->msc_bound_ndn ) );
351
352         } else {
353                 ber_str2bv( "", 0, 1, &msc->msc_bound_ndn );
354         }
355
356         msc->msc_bound = META_UNBOUND;
357
358 error_return:;
359         if ( rs->sr_err != LDAP_SUCCESS ) {
360                 rs->sr_err = slap_map_api2result( rs );
361                 if ( sendok & LDAP_BACK_SENDERR ) {
362                         send_ldap_result( op, rs );
363                         rs->sr_text = NULL;
364                 }
365         }
366
367         return rs->sr_err;
368 }
369
370 /*
371  * meta_back_retry
372  * 
373  * Retries one connection
374  */
375 int
376 meta_back_retry(
377         Operation               *op,
378         SlapReply               *rs,
379         metaconn_t              *mc,
380         int                     candidate,
381         ldap_back_send_t        sendok )
382 {
383         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
384         metatarget_t            *mt = &mi->mi_targets[ candidate ];
385         int                     rc;
386         metasingleconn_t        *msc = &mc->mc_conns[ candidate ];
387
388         ldap_pvt_thread_mutex_lock( &mc->mc_mutex );
389
390         ldap_unbind_ext_s( msc->msc_ld, NULL, NULL );
391         msc->msc_ld = NULL;
392         msc->msc_bound = 0;
393
394         /* mc here must be the regular mc, reset and ready for init */
395         rc = meta_back_init_one_conn( op, rs, mt, msc, sendok );
396
397         if ( rc == LDAP_SUCCESS ) {
398                 rc = meta_back_single_dobind( op, rs, mc, candidate,
399                                 sendok, mt->mt_nretries );
400         }
401
402         ldap_pvt_thread_mutex_unlock( &mc->mc_mutex );
403
404         return rc == LDAP_SUCCESS ? 1 : 0;
405 }
406
407 /*
408  * callback for unique candidate selection
409  */
410 static int
411 meta_back_conn_cb( Operation *op, SlapReply *rs )
412 {
413         assert( op->o_tag == LDAP_REQ_SEARCH );
414
415         switch ( rs->sr_type ) {
416         case REP_SEARCH:
417                 ((int *)op->o_callback->sc_private)[0] = (int)op->o_private;
418                 break;
419
420         case REP_SEARCHREF:
421         case REP_RESULT:
422                 break;
423
424         default:
425                 return rs->sr_err;
426         }
427
428         return 0;
429 }
430
431
432 static int
433 meta_back_get_candidate(
434         Operation       *op,
435         SlapReply       *rs,
436         struct berval   *ndn )
437 {
438         metainfo_t      *mi = ( metainfo_t * )op->o_bd->be_private;
439         int             candidate;
440
441         /*
442          * tries to get a unique candidate
443          * (takes care of default target)
444          */
445         candidate = meta_back_select_unique_candidate( mi, ndn );
446
447         /*
448          * if any is found, inits the connection
449          */
450         if ( candidate == META_TARGET_NONE ) {
451                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
452                 rs->sr_text = "no suitable candidate target found";
453
454         } else if ( candidate == META_TARGET_MULTIPLE ) {
455                 Filter          f = { 0 };
456                 Operation       op2 = *op;
457                 SlapReply       rs2 = { 0 };
458                 slap_callback   cb2 = { 0 };
459                 int             rc;
460
461                 /* try to get a unique match for the request ndn
462                  * among the multiple candidates available */
463                 op2.o_tag = LDAP_REQ_SEARCH;
464                 op2.o_req_dn = *ndn;
465                 op2.o_req_ndn = *ndn;
466                 op2.ors_scope = LDAP_SCOPE_BASE;
467                 op2.ors_deref = LDAP_DEREF_NEVER;
468                 op2.ors_attrs = slap_anlist_no_attrs;
469                 op2.ors_attrsonly = 0;
470                 op2.ors_limit = NULL;
471                 op2.ors_slimit = 1;
472                 op2.ors_tlimit = SLAP_NO_LIMIT;
473
474                 f.f_choice = LDAP_FILTER_PRESENT;
475                 f.f_desc = slap_schema.si_ad_objectClass;
476                 op2.ors_filter = &f;
477                 BER_BVSTR( &op2.ors_filterstr, "(objectClass=*)" );
478
479                 op2.o_callback = &cb2;
480                 cb2.sc_response = meta_back_conn_cb;
481                 cb2.sc_private = (void *)&candidate;
482
483                 rc = op->o_bd->be_search( &op2, &rs2 );
484
485                 switch ( rs2.sr_err ) {
486                 case LDAP_SUCCESS:
487                 default:
488                         rs->sr_err = rs2.sr_err;
489                         break;
490
491                 case LDAP_SIZELIMIT_EXCEEDED:
492                         /* if multiple candidates can serve the operation,
493                          * and a default target is defined, and it is
494                          * a candidate, try using it (FIXME: YMMV) */
495                         if ( mi->mi_defaulttarget != META_DEFAULT_TARGET_NONE
496                                 && meta_back_is_candidate( &mi->mi_targets[ mi->mi_defaulttarget ].mt_nsuffix,
497                                                 ndn, op->o_tag == LDAP_REQ_SEARCH ? op->ors_scope : LDAP_SCOPE_BASE ) )
498                         {
499                                 candidate = mi->mi_defaulttarget;
500                                 rs->sr_err = LDAP_SUCCESS;
501                                 rs->sr_text = NULL;
502
503                         } else {
504                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
505                                 rs->sr_text = "cannot select unique candidate target";
506                         }
507                         break;
508                 }
509         }
510
511         return candidate;
512 }
513
514 static void
515 meta_back_candidate_keyfree(
516         void            *key,
517         void            *data )
518 {
519         ber_memfree_x( data, NULL );
520 }
521
522 SlapReply *
523 meta_back_candidates_get( Operation *op )
524 {
525         metainfo_t      *mi = ( metainfo_t * )op->o_bd->be_private;
526         void            *data = NULL;
527
528         if ( op->o_threadctx ) {
529                 ldap_pvt_thread_pool_getkey( op->o_threadctx,
530                                 meta_back_candidate_keyfree, &data, NULL );
531         } else {
532                 data = (void *)mi->mi_candidates;
533         }
534
535         if ( data == NULL ) {
536                 data = ber_memalloc( sizeof( SlapReply ) * mi->mi_ntargets );
537                 if ( op->o_threadctx ) {
538                         ldap_pvt_thread_pool_setkey( op->o_threadctx,
539                                         meta_back_candidate_keyfree, data,
540                                         meta_back_candidate_keyfree );
541
542                 } else {
543                         mi->mi_candidates = (SlapReply *)data;
544                 }
545         }
546
547         return (SlapReply *)data;
548 }
549
550 /*
551  * meta_back_getconn
552  * 
553  * Prepares the connection structure
554  * 
555  * RATIONALE:
556  *
557  * - determine what DN is being requested:
558  *
559  *      op      requires candidate      checks
560  *
561  *      add     unique                  parent of o_req_ndn
562  *      bind    unique^*[/all]          o_req_ndn [no check]
563  *      compare unique^+                o_req_ndn
564  *      delete  unique                  o_req_ndn
565  *      modify  unique                  o_req_ndn
566  *      search  any                     o_req_ndn
567  *      modrdn  unique[, unique]        o_req_ndn[, orr_nnewSup]
568  *
569  * - for ops that require the candidate to be unique, in case of multiple
570  *   occurrences an internal search with sizeLimit=1 is performed
571  *   if a unique candidate can actually be determined.  If none is found,
572  *   the operation aborts; if multiple are found, the default target
573  *   is used if defined and candidate; otherwise the operation aborts.
574  *
575  * *^note: actually, the bind operation is handled much like a search;
576  *   i.e. the bind is broadcast to all candidate targets.
577  *
578  * +^note: actually, the compare operation is handled much like a search;
579  *   i.e. the compare is broadcast to all candidate targets, while checking
580  *   that exactly none (noSuchObject) or one (TRUE/FALSE/UNDEFINED) is
581  *   returned.
582  */
583 metaconn_t *
584 meta_back_getconn(
585         Operation               *op,
586         SlapReply               *rs,
587         int                     *candidate,
588         ldap_back_send_t        sendok )
589 {
590         metainfo_t      *mi = ( metainfo_t * )op->o_bd->be_private;
591         metaconn_t      *mc, mc_curr;
592         int             cached = META_TARGET_NONE,
593                         i = META_TARGET_NONE,
594                         err = LDAP_SUCCESS,
595                         new_conn = 0,
596                         ncandidates = 0;
597
598
599         meta_op_type    op_type = META_OP_REQUIRE_SINGLE;
600         int             parent = 0,
601                         newparent = 0;
602         struct berval   ndn = op->o_req_ndn,
603                         pndn;
604
605         SlapReply       *candidates = meta_back_candidates_get( op );
606
607         /* Searches for a metaconn in the avl tree */
608         mc_curr.mc_conn = op->o_conn;
609         ldap_pvt_thread_mutex_lock( &mi->mi_conn_mutex );
610         mc = (metaconn_t *)avl_find( mi->mi_conntree, 
611                 (caddr_t)&mc_curr, meta_back_conn_cmp );
612         ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex );
613
614         switch ( op->o_tag ) {
615         case LDAP_REQ_ADD:
616                 /* if we go to selection, the entry must not exist,
617                  * and we must be able to resolve the parent */
618                 parent = 1;
619                 dnParent( &ndn, &pndn );
620                 break;
621
622         case LDAP_REQ_MODRDN:
623                 /* if nnewSuperior is not NULL, it must resolve
624                  * to the same candidate as the req_ndn */
625                 if ( op->orr_nnewSup ) {
626                         newparent = 1;
627                 }
628                 break;
629
630         case LDAP_REQ_BIND:
631                 /* if bound as rootdn, the backend must bind to all targets
632                  * with the administrative identity */
633                 if ( op->orb_method == LDAP_AUTH_SIMPLE && be_isroot_pw( op ) ) {
634                         op_type = META_OP_REQUIRE_ALL;
635                 }
636                 break;
637
638         case LDAP_REQ_DELETE:
639         case LDAP_REQ_MODIFY:
640                 /* just a unique candidate */
641                 break;
642
643         case LDAP_REQ_COMPARE:
644         case LDAP_REQ_SEARCH:
645                 /* allow multiple candidates for the searchBase */
646                 op_type = META_OP_ALLOW_MULTIPLE;
647                 break;
648
649         default:
650                 /* right now, just break (exop?) */
651                 break;
652         }
653
654         /*
655          * require all connections ...
656          */
657         if ( op_type == META_OP_REQUIRE_ALL ) {
658
659                 /* Looks like we didn't get a bind. Open a new session... */
660                 if ( !mc ) {
661                         mc = metaconn_alloc( op );
662                         mc->mc_conn = op->o_conn;
663                         new_conn = 1;
664                 }
665
666                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
667
668                         /*
669                          * The target is activated; if needed, it is
670                          * also init'd
671                          */
672                         int lerr = meta_back_init_one_conn( op, rs, &mi->mi_targets[ i ],
673                                         &mc->mc_conns[ i ], sendok );
674                         if ( lerr == LDAP_SUCCESS ) {
675                                 candidates[ i ].sr_tag = META_CANDIDATE;
676                                 ncandidates++;
677                                 
678                         } else {
679                                 
680                                 /*
681                                  * FIXME: in case one target cannot
682                                  * be init'd, should the other ones
683                                  * be tried?
684                                  */
685                                 candidates[ i ].sr_tag = META_NOT_CANDIDATE;
686                                 err = lerr;
687                                 continue;
688                         }
689                 }
690                 goto done;
691         }
692         
693         /*
694          * looks in cache, if any
695          */
696         if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) {
697                 cached = i = meta_dncache_get_target( &mi->mi_cache, &op->o_req_ndn );
698         }
699
700         if ( op_type == META_OP_REQUIRE_SINGLE ) {
701                 int     j;
702
703                 for ( j = 0; j < mi->mi_ntargets; j++ ) {
704                         candidates[ j ].sr_tag = META_NOT_CANDIDATE;
705                 }
706
707                 /*
708                  * tries to get a unique candidate
709                  * (takes care of default target)
710                  */
711                 if ( i == META_TARGET_NONE ) {
712                         i = meta_back_get_candidate( op, rs, &ndn );
713
714                         if ( rs->sr_err == LDAP_NO_SUCH_OBJECT && parent ) {
715                                 i = meta_back_get_candidate( op, rs, &pndn );
716                         }
717         
718                         if ( rs->sr_err != LDAP_SUCCESS ) {
719                                 if ( sendok & LDAP_BACK_SENDERR ) {
720                                         send_ldap_result( op, rs );
721                                         rs->sr_text = NULL;
722                                 }
723                                 return NULL;
724                         }
725                 }
726
727                 if ( newparent && meta_back_get_candidate( op, rs, op->orr_nnewSup ) != i )
728                 {
729                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
730                         rs->sr_text = "cross-target rename not supported";
731                         if ( sendok & LDAP_BACK_SENDERR ) {
732                                 send_ldap_result( op, rs );
733                                 rs->sr_text = NULL;
734                         }
735                         return NULL;
736                 }
737
738                 Debug( LDAP_DEBUG_TRACE,
739         "==>meta_back_getconn: got target %d for ndn=\"%s\" from cache\n",
740                                 i, op->o_req_ndn.bv_val, 0 );
741
742                 /* Retries searching for a metaconn in the avl tree */
743                 mc_curr.mc_conn = op->o_conn;
744                 ldap_pvt_thread_mutex_lock( &mi->mi_conn_mutex );
745                 mc = (metaconn_t *)avl_find( mi->mi_conntree, 
746                         (caddr_t)&mc_curr, meta_back_conn_cmp );
747                 ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex );
748
749                 /* Looks like we didn't get a bind. Open a new session... */
750                 if ( !mc ) {
751                         mc = metaconn_alloc( op );
752                         mc->mc_conn = op->o_conn;
753                         new_conn = 1;
754                 }
755
756                 /*
757                  * Clear all other candidates
758                  */
759                 ( void )meta_clear_unused_candidates( op, i );
760
761                 /*
762                  * The target is activated; if needed, it is
763                  * also init'd. In case of error, meta_back_init_one_conn
764                  * sends the appropriate result.
765                  */
766                 err = meta_back_init_one_conn( op, rs, &mi->mi_targets[ i ],
767                                 &mc->mc_conns[ i ], sendok );
768                 if ( err == LDAP_SUCCESS ) {
769                         candidates[ i ].sr_tag = META_CANDIDATE;
770                         ncandidates++;
771
772                 } else {
773                 
774                         /*
775                          * FIXME: in case one target cannot
776                          * be init'd, should the other ones
777                          * be tried?
778                          */
779                         candidates[ i ].sr_tag = META_NOT_CANDIDATE;
780                         if ( new_conn ) {
781                                 ( void )meta_clear_one_candidate( &mc->mc_conns[ i ] );
782                                 meta_back_conn_free( mc );
783                         }
784                         return NULL;
785                 }
786
787                 if ( candidate ) {
788                         *candidate = i;
789                 }
790
791         /*
792          * if no unique candidate ...
793          */
794         } else {
795
796                 /* Looks like we didn't get a bind. Open a new session... */
797                 if ( !mc ) {
798                         mc = metaconn_alloc( op );
799                         mc->mc_conn = op->o_conn;
800                         new_conn = 1;
801                 }
802
803                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
804                         if ( i == cached 
805                                 || meta_back_is_candidate( &mi->mi_targets[ i ].mt_nsuffix,
806                                                 &op->o_req_ndn, LDAP_SCOPE_SUBTREE ) )
807                         {
808
809                                 /*
810                                  * The target is activated; if needed, it is
811                                  * also init'd
812                                  */
813                                 int lerr = meta_back_init_one_conn( op, rs,
814                                                 &mi->mi_targets[ i ],
815                                                 &mc->mc_conns[ i ], sendok );
816                                 if ( lerr == LDAP_SUCCESS ) {
817                                         candidates[ i ].sr_tag = META_CANDIDATE;
818                                         ncandidates++;
819
820                                         Debug( LDAP_DEBUG_TRACE, "%s: meta_back_init_one_conn(%d)\n",
821                                                 op->o_log_prefix, i, 0 );
822
823                                 } else {
824                                 
825                                         /*
826                                          * FIXME: in case one target cannot
827                                          * be init'd, should the other ones
828                                          * be tried?
829                                          */
830                                         if ( new_conn ) {
831                                                 ( void )meta_clear_one_candidate( &mc->mc_conns[ i ] );
832                                         }
833                                         candidates[ i ].sr_tag = META_NOT_CANDIDATE;
834                                         err = lerr;
835
836                                         Debug( LDAP_DEBUG_ANY, "%s: meta_back_init_one_conn(%d) failed: %d\n",
837                                                 op->o_log_prefix, i, lerr );
838
839                                         continue;
840                                 }
841
842                         } else {
843                                 if ( new_conn ) {
844                                         ( void )meta_clear_one_candidate( &mc->mc_conns[ i ] );
845                                 }
846                                 candidates[ i ].sr_tag = META_NOT_CANDIDATE;
847                         }
848                 }
849
850                 if ( ncandidates == 0 ) {
851                         if ( new_conn ) {
852                                 meta_back_conn_free( mc );
853                         }
854
855                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
856                         rs->sr_text = "Unable to select valid candidates";
857
858                         if ( sendok & LDAP_BACK_SENDERR ) {
859                                 send_ldap_result( op, rs );
860                                 rs->sr_text = NULL;
861                         }
862
863                         return NULL;
864                 }
865         }
866
867 done:;
868         /* clear out meta_back_init_one_conn non-fatal errors */
869         rs->sr_err = LDAP_SUCCESS;
870         rs->sr_text = NULL;
871
872         if ( new_conn ) {
873                 
874                 /*
875                  * Inserts the newly created metaconn in the avl tree
876                  */
877                 ldap_pvt_thread_mutex_lock( &mi->mi_conn_mutex );
878                 err = avl_insert( &mi->mi_conntree, ( caddr_t )mc,
879                                 meta_back_conn_cmp, meta_back_conn_dup );
880
881 #if PRINT_CONNTREE > 0
882                 myprint( mi->mi_conntree );
883 #endif /* PRINT_CONNTREE */
884                 
885                 ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex );
886
887                 /*
888                  * Err could be -1 in case a duplicate metaconn is inserted
889                  */
890                 if ( err == 0 ) {
891                         Debug( LDAP_DEBUG_TRACE,
892                                 "%s meta_back_getconn: candidates=%d conn=%ld inserted\n",
893                                 op->o_log_prefix, ncandidates, mc->mc_conn->c_connid );
894
895                 } else {
896                         Debug( LDAP_DEBUG_ANY,
897                                 "%s meta_back_getconn: candidates=%d conn=%ld insert failed\n",
898                                 op->o_log_prefix, ncandidates, mc->mc_conn->c_connid );
899                 
900                         rs->sr_err = LDAP_OTHER;
901                         rs->sr_text = "Internal server error";
902                         meta_back_conn_free( mc );
903                         if ( sendok & LDAP_BACK_SENDERR ) {
904                                 send_ldap_result( op, rs );
905                                 rs->sr_text = NULL;
906                         }
907                         return NULL;
908                 }
909
910         } else {
911                 Debug( LDAP_DEBUG_TRACE,
912                         "%s meta_back_getconn: candidates=%d conn=%ld fetched\n",
913                         op->o_log_prefix, ncandidates, mc->mc_conn->c_connid );
914         }
915         
916         return mc;
917 }
918