]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/conn.c
d71a36be3fb43d4f15b3f37fafc11c67a4cf1147
[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 {
53         struct metaconn *lc1 = ( struct metaconn * )c1;
54         struct metaconn *lc2 = ( struct metaconn * )c2;
55         
56         return SLAP_PTRCMP( lc1->mc_conn, lc2->mc_conn );
57 }
58
59 /*
60  * meta_back_conn_dup
61  *
62  * returns -1 in case a duplicate struct metaconn has been inserted;
63  * used by avl stuff
64  */
65 int
66 meta_back_conn_dup(
67         void *c1,
68         void *c2
69         )
70 {
71         struct metaconn *lc1 = ( struct metaconn * )c1;
72         struct metaconn *lc2 = ( struct metaconn * )c2;
73
74         return( ( lc1->mc_conn == lc2->mc_conn ) ? -1 : 0 );
75 }
76
77 /*
78  * Debug stuff (got it from libavl)
79  */
80 #if PRINT_CONNTREE > 0
81 static void
82 ravl_print( Avlnode *root, int depth )
83 {
84         int     i;
85         
86         if ( root == 0 ) {
87                 return;
88         }
89         
90         ravl_print( root->avl_right, depth + 1 );
91         
92         for ( i = 0; i < depth; i++ ) {
93                 printf( "    " );
94         }
95
96         printf( "c(%d) %d\n", ( ( struct metaconn * )root->avl_data )->mc_conn->c_connid, root->avl_bf );
97         
98         ravl_print( root->avl_left, depth + 1 );
99 }
100
101 static void
102 myprint( Avlnode *root )
103 {
104         printf( "********\n" );
105         
106         if ( root == 0 ) {
107                 printf( "\tNULL\n" );
108         } else {
109                 ravl_print( root, 0 );
110         }
111         
112         printf( "********\n" );
113 }
114 #endif /* PRINT_CONNTREE */
115 /*
116  * End of debug stuff
117  */
118
119 /*
120  * metaconn_alloc
121  * 
122  * Allocates a connection structure, making room for all the referenced targets
123  */
124 static struct metaconn *
125 metaconn_alloc( int ntargets )
126 {
127         struct metaconn *lc;
128
129         assert( ntargets > 0 );
130
131         /* malloc once only; leave an extra one for one-past-end */
132         lc = ch_malloc( sizeof( struct metaconn )
133                         + sizeof( struct metasingleconn ) * ( ntargets + 1 ) );
134         if ( lc == NULL ) {
135                 return NULL;
136         }
137
138         lc->mc_conns = (struct metasingleconn *)&lc[ 1 ];
139
140         /* FIXME: needed by META_LAST() */
141         lc->mc_conns[ ntargets ].msc_candidate = META_LAST_CONN;
142
143         for ( ; ntargets-- > 0; ) {
144                 lc->mc_conns[ ntargets ].msc_ld = NULL;
145                 BER_BVZERO( &lc->mc_conns[ ntargets ].msc_bound_ndn );
146                 BER_BVZERO( &lc->mc_conns[ ntargets ].msc_cred );
147                 lc->mc_conns[ ntargets ].msc_bound = META_UNBOUND;
148         }
149
150         lc->mc_bound_target = META_BOUND_NONE;
151
152         return lc;
153 }
154
155 /*
156  * metaconn_free
157  *
158  * clears a metaconn
159  */
160 static void
161 metaconn_free(
162                 struct metaconn *lc
163 )
164 {
165         if ( !lc ) {
166                 return;
167         }
168         
169         free( lc );
170 }
171
172 /*
173  * init_one_conn
174  * 
175  * Initializes one connection
176  */
177 static int
178 init_one_conn(
179                 Operation               *op,
180                 SlapReply               *rs,
181                 struct metatarget       *lt, 
182                 struct metasingleconn   *lsc,
183                 char                    *candidate,
184                 ldap_back_send_t        sendok )
185 {
186         struct metainfo *li = ( struct metainfo * )op->o_bd->be_private;
187         int             vers;
188         dncookie        dc;
189
190         /*
191          * Already init'ed
192          */
193         if ( lsc->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( &lsc->msc_ld, lt->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( lsc->msc_ld, LDAP_OPT_PROTOCOL_VERSION, &vers );
212
213         /* automatically chase referrals ("chase-referrals"/"dont-chase-referrals" statement) */
214         if ( LDAP_BACK_CHASE_REFERRALS( li ) ) {
215                 ldap_set_option( lsc->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( li ) || ( op->o_conn->c_is_tls && LDAP_BACK_PROPAGATE_TLS( li ) ) )
221                         && !ldap_is_ldaps_url( lt->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( lsc->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( lsc->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( lsc->msc_ld, res,
254                                                 NULL, &data, 0 );
255                                 if ( rs->sr_err == LDAP_SUCCESS ) {
256                                         rs->sr_err = ldap_result2error( lsc->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( lsc->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( lsc->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( li ) ) )
300                 {
301                         ldap_unbind_ext_s( lsc->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 ( li->mi_network_timeout != 0 ) {
311                 struct timeval  network_timeout;
312
313                 network_timeout.tv_usec = 0;
314                 network_timeout.tv_sec = li->mi_network_timeout;
315
316                 ldap_set_option( lsc->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( lt->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 = &lt->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                                         &lsc->msc_bound_ndn ) )
339                 {
340                         goto error_return;
341                 }
342
343                 /* copy the DN idf needed */
344                 if ( lsc->msc_bound_ndn.bv_val == op->o_conn->c_dn.bv_val ) {
345                         ber_dupbv( &lsc->msc_bound_ndn, &op->o_conn->c_dn );
346                 }
347
348                 assert( !BER_BVISNULL( &lsc->msc_bound_ndn ) );
349
350         } else {
351                 ber_str2bv( "", 0, 1, &lsc->msc_bound_ndn );
352         }
353
354         lsc->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         } else {
365
366                 /*
367                  * The candidate is activated
368                  */
369                 *candidate = META_CANDIDATE;
370         }
371
372         return rs->sr_err;
373 }
374
375 /*
376  * callback for unique candidate selection
377  */
378 static int
379 meta_back_conn_cb( Operation *op, SlapReply *rs )
380 {
381         assert( op->o_tag == LDAP_REQ_SEARCH );
382
383         switch ( rs->sr_type ) {
384         case REP_SEARCH:
385                 ((int *)op->o_callback->sc_private)[0] = (int)op->o_private;
386                 break;
387
388         case REP_SEARCHREF:
389         case REP_RESULT:
390                 break;
391
392         default:
393                 return rs->sr_err;
394         }
395
396         return 0;
397 }
398
399
400 static int
401 meta_back_get_candidate(
402         Operation       *op,
403         SlapReply       *rs,
404         struct berval   *ndn )
405 {
406         struct metainfo *li = ( struct metainfo * )op->o_bd->be_private;
407         int             candidate;
408
409         /*
410          * tries to get a unique candidate
411          * (takes care of default target)
412          */
413         candidate = meta_back_select_unique_candidate( li, ndn );
414
415         /*
416          * if any is found, inits the connection
417          */
418         if ( candidate == META_TARGET_NONE ) {
419                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
420                 rs->sr_text = "no suitable candidate target found";
421
422         } else if ( candidate == META_TARGET_MULTIPLE ) {
423                 Filter          f = { 0 };
424                 Operation       op2 = *op;
425                 SlapReply       rs2 = { 0 };
426                 slap_callback   cb2 = { 0 };
427                 int             rc;
428
429                 /* try to get a unique match for the request ndn
430                  * among the multiple candidates available */
431                 op2.o_tag = LDAP_REQ_SEARCH;
432                 op2.o_req_dn = *ndn;
433                 op2.o_req_ndn = *ndn;
434                 op2.ors_scope = LDAP_SCOPE_BASE;
435                 op2.ors_deref = LDAP_DEREF_NEVER;
436                 op2.ors_attrs = slap_anlist_no_attrs;
437                 op2.ors_attrsonly = 0;
438                 op2.ors_limit = NULL;
439                 op2.ors_slimit = 1;
440                 op2.ors_tlimit = SLAP_NO_LIMIT;
441
442                 f.f_choice = LDAP_FILTER_PRESENT;
443                 f.f_desc = slap_schema.si_ad_objectClass;
444                 op2.ors_filter = &f;
445                 BER_BVSTR( &op2.ors_filterstr, "(objectClass=*)" );
446
447                 op2.o_callback = &cb2;
448                 cb2.sc_response = meta_back_conn_cb;
449                 cb2.sc_private = (void *)&candidate;
450
451                 rc = op->o_bd->be_search( &op2, &rs2 );
452
453                 switch ( rs2.sr_err ) {
454                 case LDAP_SUCCESS:
455                 default:
456                         rs->sr_err = rs2.sr_err;
457                         break;
458
459                 case LDAP_SIZELIMIT_EXCEEDED:
460                         /* if multiple candidates can serve the operation,
461                          * and a default target is defined, and it is
462                          * a candidate, try using it (FIXME: YMMV) */
463                         if ( li->mi_defaulttarget != META_DEFAULT_TARGET_NONE
464                                 && meta_back_is_candidate( &li->mi_targets[ li->mi_defaulttarget ]->mt_nsuffix, ndn ) )
465                         {
466                                 candidate = li->mi_defaulttarget;
467                                 rs->sr_err = LDAP_SUCCESS;
468                                 rs->sr_text = NULL;
469
470                         } else {
471                                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
472                                 rs->sr_text = "cannot select unique candidate target";
473                         }
474                         break;
475                 }
476         }
477
478         return candidate;
479 }
480
481 static void
482 meta_back_candidate_keyfree( void *key, void *data )
483 {
484         ber_memfree_x( data, NULL );
485 }
486
487 char *
488 meta_back_candidates_get( Operation *op )
489 {
490         struct metainfo *li = ( struct metainfo * )op->o_bd->be_private;
491         void            *data = NULL;
492
493         if ( op->o_threadctx ) {
494                 ldap_pvt_thread_pool_getkey( op->o_threadctx,
495                                 meta_back_candidate_keyfree, &data, NULL );
496         } else {
497                 data = (void *)li->mi_candidates;
498         }
499
500         if ( data == NULL ) {
501                 data = ber_memalloc_x( sizeof( char ) * li->mi_ntargets, NULL );
502                 if ( op->o_threadctx ) {
503                         ldap_pvt_thread_pool_setkey( op->o_threadctx,
504                                         meta_back_candidate_keyfree, data,
505                                         meta_back_candidate_keyfree );
506
507                 } else {
508                         li->mi_candidates = (char *)data;
509                 }
510         }
511
512         return (char *)data;
513 }
514
515 /*
516  * meta_back_getconn
517  * 
518  * Prepares the connection structure
519  * 
520  * RATIONALE:
521  *
522  * - determine what DN is being requested:
523  *
524  *      op      requires candidate      checks
525  *
526  *      add     unique                  parent of o_req_ndn
527  *      bind    unique^*[/all]          o_req_ndn [no check]
528  *      compare unique^+                o_req_ndn
529  *      delete  unique                  o_req_ndn
530  *      modify  unique                  o_req_ndn
531  *      search  any                     o_req_ndn
532  *      modrdn  unique[, unique]        o_req_ndn[, orr_nnewSup]
533  *
534  * - for ops that require the candidate to be unique, in case of multiple
535  *   occurrences an internal search with sizeLimit=1 is performed
536  *   if a unique candidate can actually be determined.  If none is found,
537  *   the operation aborts; if multiple are found, the default target
538  *   is used if defined and candidate; otherwise the operation aborts.
539  *
540  * *^note: actually, the bind operation is handled much like a search;
541  *   i.e. the bind is broadcast to all candidate targets.
542  *
543  * +^note: actually, the compare operation is handled much like a search;
544  *   i.e. the compare is broadcast to all candidate targets, while checking
545  *   that exactly none (noSuchObject) or one (TRUE/FALSE/UNDEFINED) is
546  *   returned.
547  */
548 struct metaconn *
549 meta_back_getconn(
550                 Operation               *op,
551                 SlapReply               *rs,
552                 int                     *candidate,
553                 ldap_back_send_t        sendok )
554 {
555         struct metainfo *li = ( struct metainfo * )op->o_bd->be_private;
556         struct metaconn *lc, lc_curr;
557         int             cached = META_TARGET_NONE,
558                         i = META_TARGET_NONE,
559                         err = LDAP_SUCCESS,
560                         new_conn = 0;
561
562         meta_op_type    op_type = META_OP_REQUIRE_SINGLE;
563         int             parent = 0,
564                         newparent = 0;
565         struct berval   ndn = op->o_req_ndn;
566
567         char            *candidates = meta_back_candidates_get( op );
568
569         /* Searches for a metaconn in the avl tree */
570         lc_curr.mc_conn = op->o_conn;
571         ldap_pvt_thread_mutex_lock( &li->mi_conn_mutex );
572         lc = (struct metaconn *)avl_find( li->mi_conntree, 
573                 (caddr_t)&lc_curr, meta_back_conn_cmp );
574         ldap_pvt_thread_mutex_unlock( &li->mi_conn_mutex );
575
576         switch ( op->o_tag ) {
577         case LDAP_REQ_ADD:
578                 /* if we go to selection, the entry must not exist,
579                  * and we must be able to resolve the parent */
580                 parent = 1;
581                 dnParent( &ndn, &ndn );
582                 break;
583
584         case LDAP_REQ_MODRDN:
585                 /* if nnewSuperior is not NULL, it must resolve
586                  * to the same candidate as the req_ndn */
587                 if ( op->orr_nnewSup ) {
588                         newparent = 1;
589                 }
590                 break;
591
592         case LDAP_REQ_BIND:
593                 /* if bound as rootdn, the backend must bind to all targets
594                  * with the administrative identity */
595                 if ( op->orb_method == LDAP_AUTH_SIMPLE && be_isroot_pw( op ) ) {
596                         op_type = META_OP_REQUIRE_ALL;
597                 }
598                 break;
599
600         case LDAP_REQ_DELETE:
601         case LDAP_REQ_MODIFY:
602                 /* just a unique candidate */
603                 break;
604
605         case LDAP_REQ_COMPARE:
606         case LDAP_REQ_SEARCH:
607                 /* allow multiple candidates for the searchBase */
608                 op_type = META_OP_ALLOW_MULTIPLE;
609                 break;
610
611         default:
612                 /* right now, just break (exop?) */
613                 break;
614         }
615
616         /*
617          * require all connections ...
618          */
619         if ( op_type == META_OP_REQUIRE_ALL ) {
620
621                 /* Looks like we didn't get a bind. Open a new session... */
622                 if ( !lc ) {
623                         lc = metaconn_alloc( li->mi_ntargets );
624                         lc->mc_conn = op->o_conn;
625                         new_conn = 1;
626                 }
627
628                 for ( i = 0; i < li->mi_ntargets; i++ ) {
629
630                         /*
631                          * The target is activated; if needed, it is
632                          * also init'd
633                          */
634                         int lerr = init_one_conn( op, rs, li->mi_targets[ i ],
635                                         &lc->mc_conns[ i ], &candidates[ i ],
636                                         sendok );
637                         if ( lerr != LDAP_SUCCESS ) {
638                                 
639                                 /*
640                                  * FIXME: in case one target cannot
641                                  * be init'd, should the other ones
642                                  * be tried?
643                                  */
644                                 candidates[ i ] = META_NOT_CANDIDATE;
645 #if 0
646                                 ( void )meta_clear_one_candidate( &lc->mc_conns[ i ] );
647 #endif
648                                 err = lerr;
649                                 continue;
650                         }
651                 }
652                 goto done;
653         }
654         
655         /*
656          * looks in cache, if any
657          */
658         if ( li->mi_cache.ttl != META_DNCACHE_DISABLED ) {
659                 cached = i = meta_dncache_get_target( &li->mi_cache, &op->o_req_ndn );
660         }
661
662         if ( op_type == META_OP_REQUIRE_SINGLE ) {
663
664                 memset( candidates, META_NOT_CANDIDATE, sizeof( char ) * li->mi_ntargets );
665
666                 /*
667                  * tries to get a unique candidate
668                  * (takes care of default target)
669                  */
670                 if ( i == META_TARGET_NONE ) {
671                         i = meta_back_get_candidate( op, rs, &ndn );
672
673                         if ( rs->sr_err != LDAP_SUCCESS ) {
674                                 if ( sendok & LDAP_BACK_SENDERR ) {
675                                         send_ldap_result( op, rs );
676                                         rs->sr_text = NULL;
677                                 }
678                                 return NULL;
679                         }
680                 }
681
682                 if ( newparent && meta_back_get_candidate( op, rs, op->orr_nnewSup ) != i )
683                 {
684                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
685                         rs->sr_text = "cross-target rename not supported";
686                         if ( sendok & LDAP_BACK_SENDERR ) {
687                                 send_ldap_result( op, rs );
688                                 rs->sr_text = NULL;
689                         }
690                         return NULL;
691                 }
692
693                 Debug( LDAP_DEBUG_CACHE,
694         "==>meta_back_getconn: got target %d for ndn=\"%s\" from cache\n",
695                                 i, op->o_req_ndn.bv_val, 0 );
696
697                 /* Retries searching for a metaconn in the avl tree */
698                 lc_curr.mc_conn = op->o_conn;
699                 ldap_pvt_thread_mutex_lock( &li->mi_conn_mutex );
700                 lc = (struct metaconn *)avl_find( li->mi_conntree, 
701                         (caddr_t)&lc_curr, meta_back_conn_cmp );
702                 ldap_pvt_thread_mutex_unlock( &li->mi_conn_mutex );
703
704                 /* Looks like we didn't get a bind. Open a new session... */
705                 if ( !lc ) {
706                         lc = metaconn_alloc( li->mi_ntargets );
707                         lc->mc_conn = op->o_conn;
708                         new_conn = 1;
709                 }
710
711                 /*
712                  * Clear all other candidates
713                  */
714                 ( void )meta_clear_unused_candidates( op, lc, i );
715
716                 /*
717                  * The target is activated; if needed, it is
718                  * also init'd. In case of error, init_one_conn
719                  * sends the appropriate result.
720                  */
721                 err = init_one_conn( op, rs, li->mi_targets[ i ],
722                                 &lc->mc_conns[ i ], &candidates[ i ],
723                                 sendok );
724                 if ( err != LDAP_SUCCESS ) {
725                 
726                         /*
727                          * FIXME: in case one target cannot
728                          * be init'd, should the other ones
729                          * be tried?
730                          */
731                         candidates[ i ] = META_NOT_CANDIDATE;
732                         if ( new_conn ) {
733                                 ( void )meta_clear_one_candidate( &lc->mc_conns[ i ] );
734                                 metaconn_free( lc );
735                         }
736                         return NULL;
737                 }
738
739                 if ( candidate ) {
740                         *candidate = i;
741                 }
742
743         /*
744          * if no unique candidate ...
745          */
746         } else {
747
748                 /* Looks like we didn't get a bind. Open a new session... */
749                 if ( !lc ) {
750                         lc = metaconn_alloc( li->mi_ntargets );
751                         lc->mc_conn = op->o_conn;
752                         new_conn = 1;
753                 }
754
755                 for ( i = 0; i < li->mi_ntargets; i++ ) {
756                         if ( i == cached 
757                                 || meta_back_is_candidate( &li->mi_targets[ i ]->mt_nsuffix,
758                                                 &op->o_req_ndn ) )
759                         {
760
761                                 /*
762                                  * The target is activated; if needed, it is
763                                  * also init'd
764                                  */
765                                 int lerr = init_one_conn( op, rs,
766                                                 li->mi_targets[ i ],
767                                                 &lc->mc_conns[ i ],
768                                                 &candidates[ i ],
769                                                 sendok );
770                                 if ( lerr != LDAP_SUCCESS ) {
771                                 
772                                         /*
773                                          * FIXME: in case one target cannot
774                                          * be init'd, should the other ones
775                                          * be tried?
776                                          */
777                                         candidates[ i ] = META_NOT_CANDIDATE;
778 #if 0
779                                         ( void )meta_clear_one_candidate( &lc->mc_conns[ i ] );
780 #endif
781                                         err = lerr;
782                                         continue;
783                                 }
784
785                         } else {
786                                 candidates[ i ] = META_NOT_CANDIDATE;
787                         }
788                 }
789         }
790
791 done:;
792         /* clear out init_one_conn non-fatal errors */
793         rs->sr_err = LDAP_SUCCESS;
794         rs->sr_text = NULL;
795
796         if ( new_conn ) {
797                 
798                 /*
799                  * Inserts the newly created metaconn in the avl tree
800                  */
801                 ldap_pvt_thread_mutex_lock( &li->mi_conn_mutex );
802                 err = avl_insert( &li->mi_conntree, ( caddr_t )lc,
803                                 meta_back_conn_cmp, meta_back_conn_dup );
804
805 #if PRINT_CONNTREE > 0
806                 myprint( li->mi_conntree );
807 #endif /* PRINT_CONNTREE */
808                 
809                 ldap_pvt_thread_mutex_unlock( &li->mi_conn_mutex );
810
811                 Debug( LDAP_DEBUG_TRACE,
812                         "=>meta_back_getconn: conn %ld inserted\n",
813                         lc->mc_conn->c_connid, 0, 0 );
814                 
815                 /*
816                  * Err could be -1 in case a duplicate metaconn is inserted
817                  */
818                 if ( err != 0 ) {
819                         rs->sr_err = LDAP_OTHER;
820                         rs->sr_text = "Internal server error";
821                         metaconn_free( lc );
822                         if ( sendok & LDAP_BACK_SENDERR ) {
823                                 send_ldap_result( op, rs );
824                                 rs->sr_text = NULL;
825                         }
826                         return NULL;
827                 }
828
829         } else {
830                 Debug( LDAP_DEBUG_TRACE,
831                         "=>meta_back_getconn: conn %ld fetched\n",
832                         lc->mc_conn->c_connid, 0, 0 );
833         }
834         
835         return lc;
836 }
837