]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/conn.c
1cf911331e7c5cfcf5d063f1662dc617656ca182
[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 all in one */
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_candidates_keyfree(
516         void            *key,
517         void            *data )
518 {
519         metacandidates_t        *mc = (metacandidates_t *)data;
520
521         ber_memfree_x( mc->mc_candidates, NULL );
522         ber_memfree_x( data, NULL );
523 }
524
525 SlapReply *
526 meta_back_candidates_get( Operation *op )
527 {
528         metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
529         metacandidates_t        *mc;
530         SlapReply               *rs;
531
532         if ( op->o_threadctx ) {
533                 void            *data = NULL;
534
535                 ldap_pvt_thread_pool_getkey( op->o_threadctx,
536                                 meta_back_candidates_keyfree, &data, NULL );
537                 mc = (metacandidates_t *)data;
538
539         } else {
540                 mc = mi->mi_candidates;
541         }
542
543         if ( mc == NULL ) {
544                 mc = ch_calloc( sizeof( metacandidates_t ), 1 );
545                 mc->mc_ntargets = mi->mi_ntargets;
546                 mc->mc_candidates = ch_calloc( sizeof( SlapReply ), mc->mc_ntargets );
547                 if ( op->o_threadctx ) {
548                         void            *data = NULL;
549
550                         data = (void *)mc;
551                         ldap_pvt_thread_pool_setkey( op->o_threadctx,
552                                         meta_back_candidates_keyfree, data,
553                                         meta_back_candidates_keyfree );
554
555                 } else {
556                         mi->mi_candidates = mc;
557                 }
558
559         } else if ( mc->mc_ntargets < mi->mi_ntargets ) {
560                 /* NOTE: in the future, may want to allow back-config
561                  * to add/remove targets from back-meta... */
562                 mc->mc_ntargets = mi->mi_ntargets;
563                 mc->mc_candidates = ch_realloc( mc->mc_candidates,
564                                 sizeof( SlapReply ) * mc->mc_ntargets );
565         }
566
567         return mc->mc_candidates;
568 }
569
570 /*
571  * meta_back_getconn
572  * 
573  * Prepares the connection structure
574  * 
575  * RATIONALE:
576  *
577  * - determine what DN is being requested:
578  *
579  *      op      requires candidate      checks
580  *
581  *      add     unique                  parent of o_req_ndn
582  *      bind    unique^*[/all]          o_req_ndn [no check]
583  *      compare unique^+                o_req_ndn
584  *      delete  unique                  o_req_ndn
585  *      modify  unique                  o_req_ndn
586  *      search  any                     o_req_ndn
587  *      modrdn  unique[, unique]        o_req_ndn[, orr_nnewSup]
588  *
589  * - for ops that require the candidate to be unique, in case of multiple
590  *   occurrences an internal search with sizeLimit=1 is performed
591  *   if a unique candidate can actually be determined.  If none is found,
592  *   the operation aborts; if multiple are found, the default target
593  *   is used if defined and candidate; otherwise the operation aborts.
594  *
595  * *^note: actually, the bind operation is handled much like a search;
596  *   i.e. the bind is broadcast to all candidate targets.
597  *
598  * +^note: actually, the compare operation is handled much like a search;
599  *   i.e. the compare is broadcast to all candidate targets, while checking
600  *   that exactly none (noSuchObject) or one (TRUE/FALSE/UNDEFINED) is
601  *   returned.
602  */
603 metaconn_t *
604 meta_back_getconn(
605         Operation               *op,
606         SlapReply               *rs,
607         int                     *candidate,
608         ldap_back_send_t        sendok )
609 {
610         metainfo_t      *mi = ( metainfo_t * )op->o_bd->be_private;
611         metaconn_t      *mc, mc_curr;
612         int             cached = META_TARGET_NONE,
613                         i = META_TARGET_NONE,
614                         err = LDAP_SUCCESS,
615                         new_conn = 0,
616                         ncandidates = 0;
617
618
619         meta_op_type    op_type = META_OP_REQUIRE_SINGLE;
620         int             parent = 0,
621                         newparent = 0;
622         struct berval   ndn = op->o_req_ndn,
623                         pndn;
624
625         SlapReply       *candidates = meta_back_candidates_get( op );
626
627         /* Searches for a metaconn in the avl tree */
628         mc_curr.mc_conn = op->o_conn;
629         ldap_pvt_thread_mutex_lock( &mi->mi_conn_mutex );
630         mc = (metaconn_t *)avl_find( mi->mi_conntree, 
631                 (caddr_t)&mc_curr, meta_back_conn_cmp );
632         ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex );
633
634         switch ( op->o_tag ) {
635         case LDAP_REQ_ADD:
636                 /* if we go to selection, the entry must not exist,
637                  * and we must be able to resolve the parent */
638                 parent = 1;
639                 dnParent( &ndn, &pndn );
640                 break;
641
642         case LDAP_REQ_MODRDN:
643                 /* if nnewSuperior is not NULL, it must resolve
644                  * to the same candidate as the req_ndn */
645                 if ( op->orr_nnewSup ) {
646                         newparent = 1;
647                 }
648                 break;
649
650         case LDAP_REQ_BIND:
651                 /* if bound as rootdn, the backend must bind to all targets
652                  * with the administrative identity */
653                 if ( op->orb_method == LDAP_AUTH_SIMPLE && be_isroot_pw( op ) ) {
654                         op_type = META_OP_REQUIRE_ALL;
655                 }
656                 break;
657
658         case LDAP_REQ_DELETE:
659         case LDAP_REQ_MODIFY:
660                 /* just a unique candidate */
661                 break;
662
663         case LDAP_REQ_COMPARE:
664         case LDAP_REQ_SEARCH:
665                 /* allow multiple candidates for the searchBase */
666                 op_type = META_OP_ALLOW_MULTIPLE;
667                 break;
668
669         default:
670                 /* right now, just break (exop?) */
671                 break;
672         }
673
674         /*
675          * require all connections ...
676          */
677         if ( op_type == META_OP_REQUIRE_ALL ) {
678
679                 /* Looks like we didn't get a bind. Open a new session... */
680                 if ( !mc ) {
681                         mc = metaconn_alloc( op );
682                         mc->mc_conn = op->o_conn;
683                         new_conn = 1;
684                 }
685
686                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
687
688                         /*
689                          * The target is activated; if needed, it is
690                          * also init'd
691                          */
692                         int lerr = meta_back_init_one_conn( op, rs, &mi->mi_targets[ i ],
693                                         &mc->mc_conns[ i ], sendok );
694                         if ( lerr == LDAP_SUCCESS ) {
695                                 candidates[ i ].sr_tag = META_CANDIDATE;
696                                 ncandidates++;
697                                 
698                         } else {
699                                 
700                                 /*
701                                  * FIXME: in case one target cannot
702                                  * be init'd, should the other ones
703                                  * be tried?
704                                  */
705                                 candidates[ i ].sr_tag = META_NOT_CANDIDATE;
706                                 err = lerr;
707                                 continue;
708                         }
709                 }
710
711                 if ( ncandidates == 0 ) {
712                         if ( new_conn ) {
713                                 meta_back_conn_free( mc );
714                         }
715
716                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
717                         rs->sr_text = "Unable to select valid candidates";
718
719                         if ( sendok & LDAP_BACK_SENDERR ) {
720                                 if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
721                                         rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val;
722                                 }
723                                 send_ldap_result( op, rs );
724                                 rs->sr_text = NULL;
725                                 rs->sr_matched = NULL;
726                         }
727
728                         return NULL;
729                 }
730
731                 goto done;
732         }
733         
734         /*
735          * looks in cache, if any
736          */
737         if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) {
738                 cached = i = meta_dncache_get_target( &mi->mi_cache, &op->o_req_ndn );
739         }
740
741         if ( op_type == META_OP_REQUIRE_SINGLE ) {
742                 int     j;
743
744                 for ( j = 0; j < mi->mi_ntargets; j++ ) {
745                         candidates[ j ].sr_tag = META_NOT_CANDIDATE;
746                 }
747
748                 /*
749                  * tries to get a unique candidate
750                  * (takes care of default target)
751                  */
752                 if ( i == META_TARGET_NONE ) {
753                         i = meta_back_get_candidate( op, rs, &ndn );
754
755                         if ( rs->sr_err == LDAP_NO_SUCH_OBJECT && parent ) {
756                                 i = meta_back_get_candidate( op, rs, &pndn );
757                         }
758         
759                         if ( rs->sr_err != LDAP_SUCCESS ) {
760                                 if ( sendok & LDAP_BACK_SENDERR ) {
761                                         if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
762                                                 rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val;
763                                         }
764                                         send_ldap_result( op, rs );
765                                         rs->sr_text = NULL;
766                                         rs->sr_matched = NULL;
767                                 }
768                                 return NULL;
769                         }
770                 }
771
772                 if ( newparent && meta_back_get_candidate( op, rs, op->orr_nnewSup ) != i )
773                 {
774                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
775                         rs->sr_text = "cross-target rename not supported";
776                         if ( sendok & LDAP_BACK_SENDERR ) {
777                                 send_ldap_result( op, rs );
778                                 rs->sr_text = NULL;
779                         }
780                         return NULL;
781                 }
782
783                 Debug( LDAP_DEBUG_TRACE,
784         "==>meta_back_getconn: got target %d for ndn=\"%s\" from cache\n",
785                                 i, op->o_req_ndn.bv_val, 0 );
786
787                 /* Retries searching for a metaconn in the avl tree */
788                 mc_curr.mc_conn = op->o_conn;
789                 ldap_pvt_thread_mutex_lock( &mi->mi_conn_mutex );
790                 mc = (metaconn_t *)avl_find( mi->mi_conntree, 
791                         (caddr_t)&mc_curr, meta_back_conn_cmp );
792                 ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex );
793
794                 /* Looks like we didn't get a bind. Open a new session... */
795                 if ( !mc ) {
796                         mc = metaconn_alloc( op );
797                         mc->mc_conn = op->o_conn;
798                         new_conn = 1;
799                 }
800
801                 /*
802                  * Clear all other candidates
803                  */
804                 ( void )meta_clear_unused_candidates( op, i );
805
806                 /*
807                  * The target is activated; if needed, it is
808                  * also init'd. In case of error, meta_back_init_one_conn
809                  * sends the appropriate result.
810                  */
811                 err = meta_back_init_one_conn( op, rs, &mi->mi_targets[ i ],
812                                 &mc->mc_conns[ i ], sendok );
813                 if ( err == LDAP_SUCCESS ) {
814                         candidates[ i ].sr_tag = META_CANDIDATE;
815                         ncandidates++;
816
817                 } else {
818                 
819                         /*
820                          * FIXME: in case one target cannot
821                          * be init'd, should the other ones
822                          * be tried?
823                          */
824                         candidates[ i ].sr_tag = META_NOT_CANDIDATE;
825                         if ( new_conn ) {
826                                 ( void )meta_clear_one_candidate( &mc->mc_conns[ i ] );
827                                 meta_back_conn_free( mc );
828                         }
829                         return NULL;
830                 }
831
832                 if ( candidate ) {
833                         *candidate = i;
834                 }
835
836         /*
837          * if no unique candidate ...
838          */
839         } else {
840
841                 /* Looks like we didn't get a bind. Open a new session... */
842                 if ( !mc ) {
843                         mc = metaconn_alloc( op );
844                         mc->mc_conn = op->o_conn;
845                         new_conn = 1;
846                 }
847
848                 for ( i = 0; i < mi->mi_ntargets; i++ ) {
849                         if ( i == cached 
850                                 || meta_back_is_candidate( &mi->mi_targets[ i ].mt_nsuffix,
851                                                 &op->o_req_ndn, LDAP_SCOPE_SUBTREE ) )
852                         {
853
854                                 /*
855                                  * The target is activated; if needed, it is
856                                  * also init'd
857                                  */
858                                 int lerr = meta_back_init_one_conn( op, rs,
859                                                 &mi->mi_targets[ i ],
860                                                 &mc->mc_conns[ i ], sendok );
861                                 if ( lerr == LDAP_SUCCESS ) {
862                                         candidates[ i ].sr_tag = META_CANDIDATE;
863                                         ncandidates++;
864
865                                         Debug( LDAP_DEBUG_TRACE, "%s: meta_back_init_one_conn(%d)\n",
866                                                 op->o_log_prefix, i, 0 );
867
868                                 } else {
869                                 
870                                         /*
871                                          * FIXME: in case one target cannot
872                                          * be init'd, should the other ones
873                                          * be tried?
874                                          */
875                                         if ( new_conn ) {
876                                                 ( void )meta_clear_one_candidate( &mc->mc_conns[ i ] );
877                                         }
878                                         candidates[ i ].sr_tag = META_NOT_CANDIDATE;
879                                         err = lerr;
880
881                                         Debug( LDAP_DEBUG_ANY, "%s: meta_back_init_one_conn(%d) failed: %d\n",
882                                                 op->o_log_prefix, i, lerr );
883
884                                         continue;
885                                 }
886
887                         } else {
888                                 if ( new_conn ) {
889                                         ( void )meta_clear_one_candidate( &mc->mc_conns[ i ] );
890                                 }
891                                 candidates[ i ].sr_tag = META_NOT_CANDIDATE;
892                         }
893                 }
894
895                 if ( ncandidates == 0 ) {
896                         if ( new_conn ) {
897                                 meta_back_conn_free( mc );
898                         }
899
900                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
901                         rs->sr_text = "Unable to select valid candidates";
902
903                         if ( sendok & LDAP_BACK_SENDERR ) {
904                                 if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
905                                         rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val;
906                                 }
907                                 send_ldap_result( op, rs );
908                                 rs->sr_text = NULL;
909                                 rs->sr_matched = NULL;
910                         }
911
912                         return NULL;
913                 }
914         }
915
916 done:;
917         /* clear out meta_back_init_one_conn non-fatal errors */
918         rs->sr_err = LDAP_SUCCESS;
919         rs->sr_text = NULL;
920
921         if ( new_conn ) {
922                 
923                 /*
924                  * Inserts the newly created metaconn in the avl tree
925                  */
926                 ldap_pvt_thread_mutex_lock( &mi->mi_conn_mutex );
927                 err = avl_insert( &mi->mi_conntree, ( caddr_t )mc,
928                                 meta_back_conn_cmp, meta_back_conn_dup );
929
930 #if PRINT_CONNTREE > 0
931                 myprint( mi->mi_conntree );
932 #endif /* PRINT_CONNTREE */
933                 
934                 ldap_pvt_thread_mutex_unlock( &mi->mi_conn_mutex );
935
936                 /*
937                  * Err could be -1 in case a duplicate metaconn is inserted
938                  */
939                 if ( err == 0 ) {
940                         Debug( LDAP_DEBUG_TRACE,
941                                 "%s meta_back_getconn: candidates=%d conn=%ld inserted\n",
942                                 op->o_log_prefix, ncandidates, mc->mc_conn->c_connid );
943
944                 } else {
945                         Debug( LDAP_DEBUG_ANY,
946                                 "%s meta_back_getconn: candidates=%d conn=%ld insert failed\n",
947                                 op->o_log_prefix, ncandidates, mc->mc_conn->c_connid );
948                 
949                         rs->sr_err = LDAP_OTHER;
950                         rs->sr_text = "Internal server error";
951                         meta_back_conn_free( mc );
952                         if ( sendok & LDAP_BACK_SENDERR ) {
953                                 send_ldap_result( op, rs );
954                                 rs->sr_text = NULL;
955                         }
956                         return NULL;
957                 }
958
959         } else {
960                 Debug( LDAP_DEBUG_TRACE,
961                         "%s meta_back_getconn: candidates=%d conn=%ld fetched\n",
962                         op->o_log_prefix, ncandidates, mc->mc_conn->c_connid );
963         }
964         
965         return mc;
966 }
967