]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/conn.c
4d4bf13ed4f3198e4cefe563ce8375aaad5dadb9
[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         int             ntargets )
125 {
126         metaconn_t      *mc;
127
128         assert( ntargets > 0 );
129
130         /* malloc once only; leave an extra one for one-past-end */
131         mc = ( metaconn_t * )ch_malloc( sizeof( metaconn_t )
132                         + sizeof( metasingleconn_t ) * ( ntargets + 1 ) );
133         if ( mc == NULL ) {
134                 return NULL;
135         }
136
137         mc->mc_conns = ( metasingleconn_t * )&mc[ 1 ];
138
139         /* FIXME: needed by META_LAST() */
140         mc->mc_conns[ ntargets ].msc_candidate = META_LAST_CONN;
141
142         for ( ; ntargets-- > 0; ) {
143                 mc->mc_conns[ ntargets ].msc_ld = NULL;
144                 BER_BVZERO( &mc->mc_conns[ ntargets ].msc_bound_ndn );
145                 BER_BVZERO( &mc->mc_conns[ ntargets ].msc_cred );
146                 mc->mc_conns[ ntargets ].msc_bound = META_UNBOUND;
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, retries = 1;
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 ( retries ) {
243                                         retries--;
244                                         tv.tv_sec = 0;
245                                         tv.tv_usec = 100000;
246                                         goto retry;
247                                 }
248                                 rs->sr_err = LDAP_OTHER;
249
250                         } else if ( rc == LDAP_RES_EXTENDED ) {
251                                 struct berval   *data = NULL;
252
253                                 rs->sr_err = ldap_parse_extended_result( msc->msc_ld, res,
254                                                 NULL, &data, 0 );
255                                 if ( rs->sr_err == LDAP_SUCCESS ) {
256                                         rs->sr_err = ldap_result2error( msc->msc_ld, res, 1 );
257                                         res = NULL;
258                                         
259                                         /* FIXME: in case a referral 
260                                          * is returned, should we try
261                                          * using it instead of the 
262                                          * configured URI? */
263                                         if ( rs->sr_err == LDAP_SUCCESS ) {
264                                                 ldap_install_tls( msc->msc_ld );
265
266                                         } else if ( rs->sr_err == LDAP_REFERRAL ) {
267                                                 rs->sr_err = LDAP_OTHER;
268                                                 rs->sr_text = "unwilling to chase referral returned by Start TLS exop";
269                                         }
270
271                                         if ( data ) {
272                                                 if ( data->bv_val ) {
273                                                         ber_memfree( data->bv_val );
274                                                 }
275                                                 ber_memfree( data );
276                                         }
277                                 }
278
279                         } else {
280                                 rs->sr_err = LDAP_OTHER;
281                         }
282
283                         if ( res != NULL ) {
284                                 ldap_msgfree( res );
285                         }
286                 }
287 #else /* ! SLAP_STARTTLS_ASYNCHRONOUS */
288                 /*
289                  * use synchronous StartTLS
290                  */
291                 rs->sr_err = ldap_start_tls_s( msc->msc_ld, NULL, NULL );
292 #endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */
293
294                 /* if StartTLS is requested, only attempt it if the URL
295                  * is not "ldaps://"; this may occur not only in case
296                  * of misconfiguration, but also when used in the chain 
297                  * overlay, where the "uri" can be parsed out of a referral */
298                 if ( rs->sr_err == LDAP_SERVER_DOWN
299                                 || ( rs->sr_err != LDAP_SUCCESS && LDAP_BACK_TLS_CRITICAL( mi ) ) )
300                 {
301                         ldap_unbind_ext_s( msc->msc_ld, NULL, NULL );
302                         goto error_return;
303                 }
304         }
305 #endif /* HAVE_TLS */
306
307         /*
308          * Set the network timeout if set
309          */
310         if ( mi->mi_network_timeout != 0 ) {
311                 struct timeval  network_timeout;
312
313                 network_timeout.tv_usec = 0;
314                 network_timeout.tv_sec = mi->mi_network_timeout;
315
316                 ldap_set_option( msc->msc_ld, LDAP_OPT_NETWORK_TIMEOUT,
317                                 (void *)&network_timeout );
318         }
319
320         /*
321          * Sets a cookie for the rewrite session
322          */
323         ( void )rewrite_session_init( mt->mt_rwmap.rwm_rw, op->o_conn );
324
325         /*
326          * If the connection DN is not null, an attempt to rewrite it is made
327          */
328         if ( !BER_BVISEMPTY( &op->o_conn->c_dn ) ) {
329                 dc.rwmap = &mt->mt_rwmap;
330                 dc.conn = op->o_conn;
331                 dc.rs = rs;
332                 dc.ctx = "bindDN";
333                 
334                 /*
335                  * Rewrite the bind dn if needed
336                  */
337                 if ( ldap_back_dn_massage( &dc, &op->o_conn->c_dn,
338                                         &msc->msc_bound_ndn ) )
339                 {
340                         goto error_return;
341                 }
342
343                 /* copy the DN idf needed */
344                 if ( msc->msc_bound_ndn.bv_val == op->o_conn->c_dn.bv_val ) {
345                         ber_dupbv( &msc->msc_bound_ndn, &op->o_conn->c_dn );
346                 }
347
348                 assert( !BER_BVISNULL( &msc->msc_bound_ndn ) );
349
350         } else {
351                 ber_str2bv( "", 0, 1, &msc->msc_bound_ndn );
352         }
353
354         msc->msc_bound = META_UNBOUND;
355
356 error_return:;
357         if ( rs->sr_err != LDAP_SUCCESS ) {
358                 rs->sr_err = slap_map_api2result( rs );
359                 if ( sendok & LDAP_BACK_SENDERR ) {
360                         send_ldap_result( op, rs );
361                         rs->sr_text = NULL;
362                 }
363         }
364
365         return rs->sr_err;
366 }
367
368 /*
369  * meta_back_retry
370  * 
371  * Retries one connection
372  */
373 int
374 meta_back_retry(
375         Operation               *op,
376         SlapReply               *rs,
377         metaconn_t              *mc,
378         int                     candidate,
379         ldap_back_send_t        sendok )
380 {
381         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
382         metatarget_t            *mt = mi->mi_targets[ candidate ];
383         int                     rc;
384         metasingleconn_t        *msc = &mc->mc_conns[ candidate ];
385
386         ldap_pvt_thread_mutex_lock( &mc->mc_mutex );
387
388         ldap_unbind_ext_s( msc->msc_ld, NULL, NULL );
389         msc->msc_ld = NULL;
390         msc->msc_bound = 0;
391
392         /* mc here must be the regular mc, reset and ready for init */
393         rc = meta_back_init_one_conn( op, rs, mt, msc, sendok );
394
395         if ( rc == LDAP_SUCCESS ) {
396                 rc = meta_back_single_dobind( op, rs, mc, candidate, sendok,
397                                 META_BIND_NRETRIES );
398         }
399
400         ldap_pvt_thread_mutex_unlock( &mc->mc_mutex );
401
402         return rc == LDAP_SUCCESS ? 1 : 0;
403 }
404
405 /*
406  * callback for unique candidate selection
407  */
408 static int
409 meta_back_conn_cb( Operation *op, SlapReply *rs )
410 {
411         assert( op->o_tag == LDAP_REQ_SEARCH );
412
413         switch ( rs->sr_type ) {
414         case REP_SEARCH:
415                 ((int *)op->o_callback->sc_private)[0] = (int)op->o_private;
416                 break;
417
418         case REP_SEARCHREF:
419         case REP_RESULT:
420                 break;
421
422         default:
423                 return rs->sr_err;
424         }
425
426         return 0;
427 }
428
429
430 static int
431 meta_back_get_candidate(
432         Operation       *op,
433         SlapReply       *rs,
434         struct berval   *ndn )
435 {
436         metainfo_t      *mi = ( metainfo_t * )op->o_bd->be_private;
437         int             candidate;
438
439         /*
440          * tries to get a unique candidate
441          * (takes care of default target)
442          */
443         candidate = meta_back_select_unique_candidate( mi, ndn );
444
445         /*
446          * if any is found, inits the connection
447          */
448         if ( candidate == META_TARGET_NONE ) {
449                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
450                 rs->sr_text = "no suitable candidate target found";
451
452         } else if ( candidate == META_TARGET_MULTIPLE ) {
453                 Filter          f = { 0 };
454                 Operation       op2 = *op;
455                 SlapReply       rs2 = { 0 };
456                 slap_callback   cb2 = { 0 };
457                 int             rc;
458
459                 /* try to get a unique match for the request ndn
460                  * among the multiple candidates available */
461                 op2.o_tag = LDAP_REQ_SEARCH;
462                 op2.o_req_dn = *ndn;
463                 op2.o_req_ndn = *ndn;
464                 op2.ors_scope = LDAP_SCOPE_BASE;
465                 op2.ors_deref = LDAP_DEREF_NEVER;
466                 op2.ors_attrs = slap_anlist_no_attrs;
467                 op2.ors_attrsonly = 0;
468                 op2.ors_limit = NULL;
469                 op2.ors_slimit = 1;
470                 op2.ors_tlimit = SLAP_NO_LIMIT;
471
472                 f.f_choice = LDAP_FILTER_PRESENT;
473                 f.f_desc = slap_schema.si_ad_objectClass;
474                 op2.ors_filter = &f;
475                 BER_BVSTR( &op2.ors_filterstr, "(objectClass=*)" );
476
477                 op2.o_callback = &cb2;
478                 cb2.sc_response = meta_back_conn_cb;
479                 cb2.sc_private = (void *)&candidate;
480
481                 rc = op->o_bd->be_search( &op2, &rs2 );
482
483                 switch ( rs2.sr_err ) {
484                 case LDAP_SUCCESS:
485                 default:
486                         rs->sr_err = rs2.sr_err;
487                         break;
488
489                 case LDAP_SIZELIMIT_EXCEEDED:
490                         /* if multiple candidates can serve the operation,
491                          * and a default target is defined, and it is
492                          * a candidate, try using it (FIXME: YMMV) */
493                         if ( mi->mi_defaulttarget != META_DEFAULT_TARGET_NONE
494                                 && meta_back_is_candidate( &mi->mi_targets[ mi->mi_defaulttarget ]->mt_nsuffix,
495                                                 ndn, op->o_tag == LDAP_REQ_SEARCH ? op->ors_scope : LDAP_SCOPE_BASE ) )
496                         {
497                                 candidate = mi->mi_defaulttarget;
498                                 rs->sr_err = LDAP_SUCCESS;
499                                 rs->sr_text = NULL;
500
501                         } else {
502                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
503                                 rs->sr_text = "cannot select unique candidate target";
504                         }
505                         break;
506                 }
507         }
508
509         return candidate;
510 }
511
512 static void
513 meta_back_candidate_keyfree(
514         void            *key,
515         void            *data )
516 {
517         ber_memfree_x( data, NULL );
518 }
519
520 SlapReply *
521 meta_back_candidates_get( Operation *op )
522 {
523         metainfo_t      *mi = ( metainfo_t * )op->o_bd->be_private;
524         void            *data = NULL;
525
526         if ( op->o_threadctx ) {
527                 ldap_pvt_thread_pool_getkey( op->o_threadctx,
528                                 meta_back_candidate_keyfree, &data, NULL );
529         } else {
530                 data = (void *)mi->mi_candidates;
531         }
532
533         if ( data == NULL ) {
534                 data = ber_memalloc( sizeof( SlapReply ) * mi->mi_ntargets );
535                 if ( op->o_threadctx ) {
536                         ldap_pvt_thread_pool_setkey( op->o_threadctx,
537                                         meta_back_candidate_keyfree, data,
538                                         meta_back_candidate_keyfree );
539
540                 } else {
541                         mi->mi_candidates = (SlapReply *)data;
542                 }
543         }
544
545         return (SlapReply *)data;
546 }
547
548 /*
549  * meta_back_getconn
550  * 
551  * Prepares the connection structure
552  * 
553  * RATIONALE:
554  *
555  * - determine what DN is being requested:
556  *
557  *      op      requires candidate      checks
558  *
559  *      add     unique                  parent of o_req_ndn
560  *      bind    unique^*[/all]          o_req_ndn [no check]
561  *      compare unique^+                o_req_ndn
562  *      delete  unique                  o_req_ndn
563  *      modify  unique                  o_req_ndn
564  *      search  any                     o_req_ndn
565  *      modrdn  unique[, unique]        o_req_ndn[, orr_nnewSup]
566  *
567  * - for ops that require the candidate to be unique, in case of multiple
568  *   occurrences an internal search with sizeLimit=1 is performed
569  *   if a unique candidate can actually be determined.  If none is found,
570  *   the operation aborts; if multiple are found, the default target
571  *   is used if defined and candidate; otherwise the operation aborts.
572  *
573  * *^note: actually, the bind operation is handled much like a search;
574  *   i.e. the bind is broadcast to all candidate targets.
575  *
576  * +^note: actually, the compare operation is handled much like a search;
577  *   i.e. the compare is broadcast to all candidate targets, while checking
578  *   that exactly none (noSuchObject) or one (TRUE/FALSE/UNDEFINED) is
579  *   returned.
580  */
581 metaconn_t *
582 meta_back_getconn(
583         Operation               *op,
584         SlapReply               *rs,
585         int                     *candidate,
586         ldap_back_send_t        sendok )
587 {
588         metainfo_t      *mi = ( metainfo_t * )op->o_bd->be_private;
589         metaconn_t      *mc, mc_curr;
590         int             cached = META_TARGET_NONE,
591                         i = META_TARGET_NONE,
592                         err = LDAP_SUCCESS,
593                         new_conn = 0;
594
595         meta_op_type    op_type = META_OP_REQUIRE_SINGLE;
596         int             parent = 0,
597                         newparent = 0;
598         struct berval   ndn = op->o_req_ndn,
599                         pndn;
600
601         SlapReply       *candidates = meta_back_candidates_get( op );
602
603         /* Searches for a metaconn in the avl tree */
604         mc_curr.mc_conn = op->o_conn;
605         ldap_pvt_thread_mutex_lock( &mi->mi_conn_mutex );
606         mc = (metaconn_t *)avl_find( mi->mi_conntree, 
607                 (caddr_t)&mc_curr, meta_back_conn_cmp );
608         ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex );
609
610         switch ( op->o_tag ) {
611         case LDAP_REQ_ADD:
612                 /* if we go to selection, the entry must not exist,
613                  * and we must be able to resolve the parent */
614                 parent = 1;
615                 dnParent( &ndn, &pndn );
616                 break;
617
618         case LDAP_REQ_MODRDN:
619                 /* if nnewSuperior is not NULL, it must resolve
620                  * to the same candidate as the req_ndn */
621                 if ( op->orr_nnewSup ) {
622                         newparent = 1;
623                 }
624                 break;
625
626         case LDAP_REQ_BIND:
627                 /* if bound as rootdn, the backend must bind to all targets
628                  * with the administrative identity */
629                 if ( op->orb_method == LDAP_AUTH_SIMPLE && be_isroot_pw( op ) ) {
630                         op_type = META_OP_REQUIRE_ALL;
631                 }
632                 break;
633
634         case LDAP_REQ_DELETE:
635         case LDAP_REQ_MODIFY:
636                 /* just a unique candidate */
637                 break;
638
639         case LDAP_REQ_COMPARE:
640         case LDAP_REQ_SEARCH:
641                 /* allow multiple candidates for the searchBase */
642                 op_type = META_OP_ALLOW_MULTIPLE;
643                 break;
644
645         default:
646                 /* right now, just break (exop?) */
647                 break;
648         }
649
650         /*
651          * require all connections ...
652          */
653         if ( op_type == META_OP_REQUIRE_ALL ) {
654
655                 /* Looks like we didn't get a bind. Open a new session... */
656                 if ( !mc ) {
657                         mc = metaconn_alloc( mi->mi_ntargets );
658                         mc->mc_conn = op->o_conn;
659                         new_conn = 1;
660                 }
661
662                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
663
664                         /*
665                          * The target is activated; if needed, it is
666                          * also init'd
667                          */
668                         int lerr = meta_back_init_one_conn( op, rs, mi->mi_targets[ i ],
669                                         &mc->mc_conns[ i ], sendok );
670                         if ( lerr == LDAP_SUCCESS ) {
671                                 candidates[ i ].sr_tag = META_CANDIDATE;
672                                 
673                         } else {
674                                 
675                                 /*
676                                  * FIXME: in case one target cannot
677                                  * be init'd, should the other ones
678                                  * be tried?
679                                  */
680                                 candidates[ i ].sr_tag = META_NOT_CANDIDATE;
681                                 err = lerr;
682                                 continue;
683                         }
684                 }
685                 goto done;
686         }
687         
688         /*
689          * looks in cache, if any
690          */
691         if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) {
692                 cached = i = meta_dncache_get_target( &mi->mi_cache, &op->o_req_ndn );
693         }
694
695         if ( op_type == META_OP_REQUIRE_SINGLE ) {
696                 int     j;
697
698                 for ( j = 0; j < mi->mi_ntargets; j++ ) {
699                         candidates[ j ].sr_tag = META_NOT_CANDIDATE;
700                 }
701
702                 /*
703                  * tries to get a unique candidate
704                  * (takes care of default target)
705                  */
706                 if ( i == META_TARGET_NONE ) {
707                         i = meta_back_get_candidate( op, rs, &ndn );
708
709                         if ( rs->sr_err == LDAP_NO_SUCH_OBJECT && parent ) {
710                                 i = meta_back_get_candidate( op, rs, &pndn );
711                         }
712         
713                         if ( rs->sr_err != LDAP_SUCCESS ) {
714                                 if ( sendok & LDAP_BACK_SENDERR ) {
715                                         send_ldap_result( op, rs );
716                                         rs->sr_text = NULL;
717                                 }
718                                 return NULL;
719                         }
720                 }
721
722                 if ( newparent && meta_back_get_candidate( op, rs, op->orr_nnewSup ) != i )
723                 {
724                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
725                         rs->sr_text = "cross-target rename not supported";
726                         if ( sendok & LDAP_BACK_SENDERR ) {
727                                 send_ldap_result( op, rs );
728                                 rs->sr_text = NULL;
729                         }
730                         return NULL;
731                 }
732
733                 Debug( LDAP_DEBUG_CACHE,
734         "==>meta_back_getconn: got target %d for ndn=\"%s\" from cache\n",
735                                 i, op->o_req_ndn.bv_val, 0 );
736
737                 /* Retries searching for a metaconn in the avl tree */
738                 mc_curr.mc_conn = op->o_conn;
739                 ldap_pvt_thread_mutex_lock( &mi->mi_conn_mutex );
740                 mc = (metaconn_t *)avl_find( mi->mi_conntree, 
741                         (caddr_t)&mc_curr, meta_back_conn_cmp );
742                 ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex );
743
744                 /* Looks like we didn't get a bind. Open a new session... */
745                 if ( !mc ) {
746                         mc = metaconn_alloc( mi->mi_ntargets );
747                         mc->mc_conn = op->o_conn;
748                         new_conn = 1;
749                 }
750
751                 /*
752                  * Clear all other candidates
753                  */
754                 ( void )meta_clear_unused_candidates( op, i );
755
756                 /*
757                  * The target is activated; if needed, it is
758                  * also init'd. In case of error, meta_back_init_one_conn
759                  * sends the appropriate result.
760                  */
761                 err = meta_back_init_one_conn( op, rs, mi->mi_targets[ i ],
762                                 &mc->mc_conns[ i ], sendok );
763                 if ( err == LDAP_SUCCESS ) {
764                         candidates[ i ].sr_tag = META_CANDIDATE;
765
766                 } else {
767                 
768                         /*
769                          * FIXME: in case one target cannot
770                          * be init'd, should the other ones
771                          * be tried?
772                          */
773                         candidates[ i ].sr_tag = META_NOT_CANDIDATE;
774                         if ( new_conn ) {
775                                 ( void )meta_clear_one_candidate( &mc->mc_conns[ i ] );
776                                 meta_back_conn_free( mc );
777                         }
778                         return NULL;
779                 }
780
781                 if ( candidate ) {
782                         *candidate = i;
783                 }
784
785         /*
786          * if no unique candidate ...
787          */
788         } else {
789
790                 /* Looks like we didn't get a bind. Open a new session... */
791                 if ( !mc ) {
792                         mc = metaconn_alloc( mi->mi_ntargets );
793                         mc->mc_conn = op->o_conn;
794                         new_conn = 1;
795                 }
796
797                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
798                         if ( i == cached 
799                                 || meta_back_is_candidate( &mi->mi_targets[ i ]->mt_nsuffix,
800                                                 &op->o_req_ndn, LDAP_SCOPE_SUBTREE ) )
801                         {
802
803                                 /*
804                                  * The target is activated; if needed, it is
805                                  * also init'd
806                                  */
807                                 int lerr = meta_back_init_one_conn( op, rs,
808                                                 mi->mi_targets[ i ],
809                                                 &mc->mc_conns[ i ], sendok );
810                                 if ( lerr == LDAP_SUCCESS ) {
811                                         candidates[ i ].sr_tag = META_CANDIDATE;
812
813                                 } else {
814                                 
815                                         /*
816                                          * FIXME: in case one target cannot
817                                          * be init'd, should the other ones
818                                          * be tried?
819                                          */
820                                         candidates[ i ].sr_tag = META_NOT_CANDIDATE;
821                                         err = lerr;
822
823                                         Debug( LDAP_DEBUG_ANY, "%s: meta_back_init_one_conn(%d) failed: %d\n",
824                                                 op->o_log_prefix, i, lerr );
825
826                                         continue;
827                                 }
828
829                         } else {
830                                 candidates[ i ].sr_tag = META_NOT_CANDIDATE;
831                         }
832                 }
833         }
834
835 done:;
836         /* clear out meta_back_init_one_conn non-fatal errors */
837         rs->sr_err = LDAP_SUCCESS;
838         rs->sr_text = NULL;
839
840         if ( new_conn ) {
841                 
842                 /*
843                  * Inserts the newly created metaconn in the avl tree
844                  */
845                 ldap_pvt_thread_mutex_lock( &mi->mi_conn_mutex );
846                 err = avl_insert( &mi->mi_conntree, ( caddr_t )mc,
847                                 meta_back_conn_cmp, meta_back_conn_dup );
848
849 #if PRINT_CONNTREE > 0
850                 myprint( mi->mi_conntree );
851 #endif /* PRINT_CONNTREE */
852                 
853                 ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex );
854
855                 /*
856                  * Err could be -1 in case a duplicate metaconn is inserted
857                  */
858                 if ( err == 0 ) {
859                         Debug( LDAP_DEBUG_TRACE,
860                                 "%s meta_back_getconn: conn %ld inserted\n",
861                                 op->o_log_prefix, mc->mc_conn->c_connid, 0 );
862
863                 } else {
864                         Debug( LDAP_DEBUG_TRACE,
865                                 "%s meta_back_getconn: conn %ld insert failed\n",
866                                 op->o_log_prefix, mc->mc_conn->c_connid, 0 );
867                 
868                         rs->sr_err = LDAP_OTHER;
869                         rs->sr_text = "Internal server error";
870                         meta_back_conn_free( mc );
871                         if ( sendok & LDAP_BACK_SENDERR ) {
872                                 send_ldap_result( op, rs );
873                                 rs->sr_text = NULL;
874                         }
875                         return NULL;
876                 }
877
878         } else {
879                 Debug( LDAP_DEBUG_TRACE,
880                         "%s meta_back_getconn: conn %ld fetched\n",
881                         op->o_log_prefix, mc->mc_conn->c_connid, 0 );
882         }
883         
884         return mc;
885 }
886