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