1/* $NetBSD$ */ 2 3/* OpenLDAP: pkg/ldap/servers/slapd/back-meta/conn.c,v 1.86.2.20 2010/04/13 20:23:30 kurt Exp */ 4/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1999-2010 The OpenLDAP Foundation. 7 * Portions Copyright 2001-2003 Pierangelo Masarati. 8 * Portions Copyright 1999-2003 Howard Chu. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted only as authorized by the OpenLDAP 13 * Public License. 14 * 15 * A copy of this license is available in the file LICENSE in the 16 * top-level directory of the distribution or, alternatively, at 17 * <http://www.OpenLDAP.org/license.html>. 18 */ 19/* ACKNOWLEDGEMENTS: 20 * This work was initially developed by the Howard Chu for inclusion 21 * in OpenLDAP Software and subsequently enhanced by Pierangelo 22 * Masarati. 23 */ 24 25#include "portable.h" 26 27#include <stdio.h> 28 29#include <ac/errno.h> 30#include <ac/socket.h> 31#include <ac/string.h> 32 33 34#define AVL_INTERNAL 35#include "slap.h" 36#include "../back-ldap/back-ldap.h" 37#include "back-meta.h" 38 39/* 40 * meta_back_conndn_cmp 41 * 42 * compares two struct metaconn based on the value of the conn pointer 43 * and of the local DN; used by avl stuff 44 */ 45int 46meta_back_conndn_cmp( 47 const void *c1, 48 const void *c2 ) 49{ 50 metaconn_t *mc1 = ( metaconn_t * )c1; 51 metaconn_t *mc2 = ( metaconn_t * )c2; 52 int rc; 53 54 /* If local DNs don't match, it is definitely not a match */ 55 /* For shared sessions, conn is NULL. Only explicitly 56 * bound sessions will have non-NULL conn. 57 */ 58 rc = SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn ); 59 if ( rc == 0 ) { 60 rc = ber_bvcmp( &mc1->mc_local_ndn, &mc2->mc_local_ndn ); 61 } 62 63 return rc; 64} 65 66/* 67 * meta_back_conndnmc_cmp 68 * 69 * compares two struct metaconn based on the value of the conn pointer, 70 * the local DN and the struct pointer; used by avl stuff 71 */ 72static int 73meta_back_conndnmc_cmp( 74 const void *c1, 75 const void *c2 ) 76{ 77 metaconn_t *mc1 = ( metaconn_t * )c1; 78 metaconn_t *mc2 = ( metaconn_t * )c2; 79 int rc; 80 81 /* If local DNs don't match, it is definitely not a match */ 82 /* For shared sessions, conn is NULL. Only explicitly 83 * bound sessions will have non-NULL conn. 84 */ 85 rc = SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn ); 86 if ( rc == 0 ) { 87 rc = ber_bvcmp( &mc1->mc_local_ndn, &mc2->mc_local_ndn ); 88 if ( rc == 0 ) { 89 rc = SLAP_PTRCMP( mc1, mc2 ); 90 } 91 } 92 93 return rc; 94} 95 96/* 97 * meta_back_conn_cmp 98 * 99 * compares two struct metaconn based on the value of the conn pointer; 100 * used by avl stuff 101 */ 102int 103meta_back_conn_cmp( 104 const void *c1, 105 const void *c2 ) 106{ 107 metaconn_t *mc1 = ( metaconn_t * )c1; 108 metaconn_t *mc2 = ( metaconn_t * )c2; 109 110 /* For shared sessions, conn is NULL. Only explicitly 111 * bound sessions will have non-NULL conn. 112 */ 113 return SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn ); 114} 115 116/* 117 * meta_back_conndn_dup 118 * 119 * returns -1 in case a duplicate struct metaconn has been inserted; 120 * used by avl stuff 121 */ 122int 123meta_back_conndn_dup( 124 void *c1, 125 void *c2 ) 126{ 127 metaconn_t *mc1 = ( metaconn_t * )c1; 128 metaconn_t *mc2 = ( metaconn_t * )c2; 129 130 /* Cannot have more than one shared session with same DN */ 131 if ( mc1->mc_conn == mc2->mc_conn && 132 dn_match( &mc1->mc_local_ndn, &mc2->mc_local_ndn ) ) 133 { 134 return -1; 135 } 136 137 return 0; 138} 139 140/* 141 * Debug stuff (got it from libavl) 142 */ 143#if META_BACK_PRINT_CONNTREE > 0 144static void 145meta_back_print( metaconn_t *mc, char *avlstr ) 146{ 147 int i; 148 149 fputs( "targets=[", stderr ); 150 for ( i = 0; i < mc->mc_info->mi_ntargets; i++ ) { 151 fputc( mc->mc_conns[ i ].msc_ld ? '*' : 'o', stderr); 152 } 153 fputc( ']', stderr ); 154 155 fprintf( stderr, " mc=%p local=\"%s\" conn=%p refcnt=%d%s %s\n", 156 (void *)mc, 157 mc->mc_local_ndn.bv_val ? mc->mc_local_ndn.bv_val : "", 158 (void *)mc->mc_conn, 159 mc->mc_refcnt, 160 LDAP_BACK_CONN_TAINTED( mc ) ? " tainted" : "", 161 avlstr ); 162} 163 164static void 165meta_back_ravl_print( Avlnode *root, int depth ) 166{ 167 int i; 168 169 if ( root == 0 ) { 170 return; 171 } 172 173 meta_back_ravl_print( root->avl_right, depth + 1 ); 174 175 for ( i = 0; i < depth; i++ ) { 176 fprintf( stderr, "-" ); 177 } 178 fputc( ' ', stderr ); 179 180 meta_back_print( (metaconn_t *)root->avl_data, 181 avl_bf2str( root->avl_bf ) ); 182 183 meta_back_ravl_print( root->avl_left, depth + 1 ); 184} 185 186/* NOTE: duplicate from back-ldap/bind.c */ 187static char* priv2str[] = { 188 "privileged", 189 "privileged/TLS", 190 "anonymous", 191 "anonymous/TLS", 192 "bind", 193 "bind/TLS", 194 NULL 195}; 196 197void 198meta_back_print_conntree( metainfo_t *mi, char *msg ) 199{ 200 int c; 201 202 fprintf( stderr, "========> %s\n", msg ); 203 204 for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) { 205 int i = 0; 206 metaconn_t *mc; 207 208 fprintf( stderr, " %s[%d]\n", priv2str[ c ], mi->mi_conn_priv[ c ].mic_num ); 209 210 LDAP_TAILQ_FOREACH( mc, &mi->mi_conn_priv[ c ].mic_priv, mc_q ) 211 { 212 fprintf( stderr, " [%d] ", i ); 213 meta_back_print( mc, "" ); 214 i++; 215 } 216 } 217 218 if ( mi->mi_conninfo.lai_tree == NULL ) { 219 fprintf( stderr, "\t(empty)\n" ); 220 221 } else { 222 meta_back_ravl_print( mi->mi_conninfo.lai_tree, 0 ); 223 } 224 225 fprintf( stderr, "<======== %s\n", msg ); 226} 227#endif /* META_BACK_PRINT_CONNTREE */ 228/* 229 * End of debug stuff 230 */ 231 232/* 233 * metaconn_alloc 234 * 235 * Allocates a connection structure, making room for all the referenced targets 236 */ 237static metaconn_t * 238metaconn_alloc( 239 Operation *op ) 240{ 241 metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; 242 metaconn_t *mc; 243 int ntargets = mi->mi_ntargets; 244 245 assert( ntargets > 0 ); 246 247 /* malloc all in one */ 248 mc = ( metaconn_t * )ch_calloc( 1, sizeof( metaconn_t ) 249 + sizeof( metasingleconn_t ) * ( ntargets - 1 ) ); 250 if ( mc == NULL ) { 251 return NULL; 252 } 253 254 mc->mc_info = mi; 255 256 mc->mc_authz_target = META_BOUND_NONE; 257 mc->mc_refcnt = 1; 258 259 return mc; 260} 261 262/* 263 * meta_back_init_one_conn 264 * 265 * Initializes one connection 266 */ 267int 268meta_back_init_one_conn( 269 Operation *op, 270 SlapReply *rs, 271 metaconn_t *mc, 272 int candidate, 273 int ispriv, 274 ldap_back_send_t sendok, 275 int dolock ) 276{ 277 metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; 278 metatarget_t *mt = mi->mi_targets[ candidate ]; 279 metasingleconn_t *msc = &mc->mc_conns[ candidate ]; 280 int version; 281 dncookie dc; 282 int isauthz = ( candidate == mc->mc_authz_target ); 283 int do_return = 0; 284#ifdef HAVE_TLS 285 int is_ldaps = 0; 286#endif /* HAVE_TLS */ 287 288 /* if the server is quarantined, and 289 * - the current interval did not expire yet, or 290 * - no more retries should occur, 291 * don't return the connection */ 292 if ( mt->mt_isquarantined ) { 293 slap_retry_info_t *ri = &mt->mt_quarantine; 294 int dont_retry = 0; 295 296 if ( mt->mt_quarantine.ri_interval ) { 297 ldap_pvt_thread_mutex_lock( &mt->mt_quarantine_mutex ); 298 dont_retry = ( mt->mt_isquarantined > LDAP_BACK_FQ_NO ); 299 if ( dont_retry ) { 300 dont_retry = ( ri->ri_num[ ri->ri_idx ] == SLAP_RETRYNUM_TAIL 301 || slap_get_time() < ri->ri_last + ri->ri_interval[ ri->ri_idx ] ); 302 if ( !dont_retry ) { 303 if ( LogTest( LDAP_DEBUG_ANY ) ) { 304 char buf[ SLAP_TEXT_BUFLEN ]; 305 306 snprintf( buf, sizeof( buf ), 307 "meta_back_init_one_conn[%d]: quarantine " 308 "retry block #%d try #%d", 309 candidate, ri->ri_idx, ri->ri_count ); 310 Debug( LDAP_DEBUG_ANY, "%s %s.\n", 311 op->o_log_prefix, buf, 0 ); 312 } 313 314 mt->mt_isquarantined = LDAP_BACK_FQ_RETRYING; 315 } 316 317 } 318 ldap_pvt_thread_mutex_unlock( &mt->mt_quarantine_mutex ); 319 } 320 321 if ( dont_retry ) { 322 rs->sr_err = LDAP_UNAVAILABLE; 323 if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) { 324 rs->sr_text = "Target is quarantined"; 325 send_ldap_result( op, rs ); 326 } 327 return rs->sr_err; 328 } 329 } 330 331retry_lock:; 332 if ( dolock ) { 333 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 334 } 335 336 /* 337 * Already init'ed 338 */ 339 if ( LDAP_BACK_CONN_ISBOUND( msc ) 340 || LDAP_BACK_CONN_ISANON( msc ) ) 341 { 342 assert( msc->msc_ld != NULL ); 343 rs->sr_err = LDAP_SUCCESS; 344 do_return = 1; 345 346 } else if ( META_BACK_CONN_CREATING( msc ) 347 || LDAP_BACK_CONN_BINDING( msc ) ) 348 { 349 if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) { 350 if ( dolock ) { 351 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 352 } 353 354 ldap_pvt_thread_yield(); 355 goto retry_lock; 356 } 357 358 /* sounds more appropriate */ 359 rs->sr_err = LDAP_BUSY; 360 rs->sr_text = "No connections to target are available"; 361 do_return = 1; 362 363 } else if ( META_BACK_CONN_INITED( msc ) ) { 364 assert( msc->msc_ld != NULL ); 365 rs->sr_err = LDAP_SUCCESS; 366 do_return = 1; 367 368 } else { 369 /* 370 * creating... 371 */ 372 META_BACK_CONN_CREATING_SET( msc ); 373 } 374 375 if ( dolock ) { 376 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 377 } 378 379 if ( do_return ) { 380 if ( rs->sr_err != LDAP_SUCCESS 381 && op->o_conn 382 && ( sendok & LDAP_BACK_SENDERR ) ) 383 { 384 send_ldap_result( op, rs ); 385 } 386 387 return rs->sr_err; 388 } 389 390 assert( msc->msc_ld == NULL ); 391 392 /* 393 * Attempts to initialize the connection to the target ds 394 */ 395 ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex ); 396 rs->sr_err = ldap_initialize( &msc->msc_ld, mt->mt_uri ); 397#ifdef HAVE_TLS 398 is_ldaps = ldap_is_ldaps_url( mt->mt_uri ); 399#endif /* HAVE_TLS */ 400 ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex ); 401 if ( rs->sr_err != LDAP_SUCCESS ) { 402 goto error_return; 403 } 404 405 /* 406 * Set LDAP version. This will always succeed: If the client 407 * bound with a particular version, then so can we. 408 */ 409 if ( mt->mt_version != 0 ) { 410 version = mt->mt_version; 411 412 } else if ( op->o_conn->c_protocol != 0 ) { 413 version = op->o_conn->c_protocol; 414 415 } else { 416 version = LDAP_VERSION3; 417 } 418 ldap_set_option( msc->msc_ld, LDAP_OPT_PROTOCOL_VERSION, &version ); 419 ldap_set_urllist_proc( msc->msc_ld, mt->mt_urllist_f, mt->mt_urllist_p ); 420 421 /* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */ 422 ldap_set_option( msc->msc_ld, LDAP_OPT_REFERRALS, 423 META_BACK_TGT_CHASE_REFERRALS( mt ) ? LDAP_OPT_ON : LDAP_OPT_OFF ); 424 425#ifdef HAVE_TLS 426 /* start TLS ("tls [try-]{start|propagate}" statement) */ 427 if ( ( META_BACK_TGT_USE_TLS( mt ) 428 || ( op->o_conn->c_is_tls 429 && META_BACK_TGT_PROPAGATE_TLS( mt ) ) ) 430 && !is_ldaps ) 431 { 432#ifdef SLAP_STARTTLS_ASYNCHRONOUS 433 /* 434 * use asynchronous StartTLS; in case, chase referral 435 * FIXME: OpenLDAP does not return referral on StartTLS yet 436 */ 437 int msgid; 438 439 rs->sr_err = ldap_start_tls( msc->msc_ld, NULL, NULL, &msgid ); 440 if ( rs->sr_err == LDAP_SUCCESS ) { 441 LDAPMessage *res = NULL; 442 int rc, nretries = mt->mt_nretries; 443 struct timeval tv; 444 445 LDAP_BACK_TV_SET( &tv ); 446 447retry:; 448 rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ); 449 switch ( rc ) { 450 case -1: 451 rs->sr_err = LDAP_OTHER; 452 break; 453 454 case 0: 455 if ( nretries != 0 ) { 456 if ( nretries > 0 ) { 457 nretries--; 458 } 459 LDAP_BACK_TV_SET( &tv ); 460 goto retry; 461 } 462 rs->sr_err = LDAP_OTHER; 463 break; 464 465 default: 466 /* only touch when activity actually took place... */ 467 if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) { 468 msc->msc_time = op->o_time; 469 } 470 break; 471 } 472 473 if ( rc == LDAP_RES_EXTENDED ) { 474 struct berval *data = NULL; 475 476 /* NOTE: right now, data is unused, so don't get it */ 477 rs->sr_err = ldap_parse_extended_result( msc->msc_ld, 478 res, NULL, NULL /* &data */ , 0 ); 479 if ( rs->sr_err == LDAP_SUCCESS ) { 480 int err; 481 482 /* FIXME: matched? referrals? response controls? */ 483 rs->sr_err = ldap_parse_result( msc->msc_ld, 484 res, &err, NULL, NULL, NULL, NULL, 1 ); 485 res = NULL; 486 487 if ( rs->sr_err == LDAP_SUCCESS ) { 488 rs->sr_err = err; 489 } 490 491 /* FIXME: in case a referral 492 * is returned, should we try 493 * using it instead of the 494 * configured URI? */ 495 if ( rs->sr_err == LDAP_SUCCESS ) { 496 ldap_install_tls( msc->msc_ld ); 497 498 } else if ( rs->sr_err == LDAP_REFERRAL ) { 499 /* FIXME: LDAP_OPERATIONS_ERROR? */ 500 rs->sr_err = LDAP_OTHER; 501 rs->sr_text = "Unwilling to chase referral " 502 "returned by Start TLS exop"; 503 } 504 505 if ( data ) { 506 ber_bvfree( data ); 507 } 508 } 509 510 } else { 511 rs->sr_err = LDAP_OTHER; 512 } 513 514 if ( res != NULL ) { 515 ldap_msgfree( res ); 516 } 517 } 518#else /* ! SLAP_STARTTLS_ASYNCHRONOUS */ 519 /* 520 * use synchronous StartTLS 521 */ 522 rs->sr_err = ldap_start_tls_s( msc->msc_ld, NULL, NULL ); 523#endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */ 524 525 /* if StartTLS is requested, only attempt it if the URL 526 * is not "ldaps://"; this may occur not only in case 527 * of misconfiguration, but also when used in the chain 528 * overlay, where the "uri" can be parsed out of a referral */ 529 if ( rs->sr_err == LDAP_SERVER_DOWN 530 || ( rs->sr_err != LDAP_SUCCESS 531 && META_BACK_TGT_TLS_CRITICAL( mt ) ) ) 532 { 533 534#ifdef DEBUG_205 535 Debug( LDAP_DEBUG_ANY, 536 "### %s meta_back_init_one_conn(TLS) " 537 "ldap_unbind_ext[%d] ld=%p\n", 538 op->o_log_prefix, candidate, 539 (void *)msc->msc_ld ); 540#endif /* DEBUG_205 */ 541 542 /* need to trash a failed Start TLS */ 543 meta_clear_one_candidate( op, mc, candidate ); 544 goto error_return; 545 } 546 } 547#endif /* HAVE_TLS */ 548 549 /* 550 * Set the network timeout if set 551 */ 552 if ( mt->mt_network_timeout != 0 ) { 553 struct timeval network_timeout; 554 555 network_timeout.tv_usec = 0; 556 network_timeout.tv_sec = mt->mt_network_timeout; 557 558 ldap_set_option( msc->msc_ld, LDAP_OPT_NETWORK_TIMEOUT, 559 (void *)&network_timeout ); 560 } 561 562 /* 563 * If the connection DN is not null, an attempt to rewrite it is made 564 */ 565 566 if ( ispriv ) { 567 if ( !BER_BVISNULL( &mt->mt_idassert_authcDN ) ) { 568 ber_bvreplace( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN ); 569 if ( !BER_BVISNULL( &mt->mt_idassert_passwd ) ) { 570 if ( !BER_BVISNULL( &msc->msc_cred ) ) { 571 memset( msc->msc_cred.bv_val, 0, 572 msc->msc_cred.bv_len ); 573 } 574 ber_bvreplace( &msc->msc_cred, &mt->mt_idassert_passwd ); 575 } 576 577 } else { 578 ber_bvreplace( &msc->msc_bound_ndn, &slap_empty_bv ); 579 } 580 581 } else { 582 if ( !BER_BVISNULL( &msc->msc_cred ) ) { 583 memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); 584 ber_memfree_x( msc->msc_cred.bv_val, NULL ); 585 BER_BVZERO( &msc->msc_cred ); 586 } 587 if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) { 588 ber_memfree_x( msc->msc_bound_ndn.bv_val, NULL ); 589 BER_BVZERO( &msc->msc_bound_ndn ); 590 } 591 if ( !BER_BVISEMPTY( &op->o_ndn ) 592 && SLAP_IS_AUTHZ_BACKEND( op ) 593 && isauthz ) 594 { 595 dc.target = mt; 596 dc.conn = op->o_conn; 597 dc.rs = rs; 598 dc.ctx = "bindDN"; 599 600 /* 601 * Rewrite the bind dn if needed 602 */ 603 if ( ldap_back_dn_massage( &dc, &op->o_conn->c_dn, 604 &msc->msc_bound_ndn ) ) 605 { 606 607#ifdef DEBUG_205 608 Debug( LDAP_DEBUG_ANY, 609 "### %s meta_back_init_one_conn(rewrite) " 610 "ldap_unbind_ext[%d] ld=%p\n", 611 op->o_log_prefix, candidate, 612 (void *)msc->msc_ld ); 613#endif /* DEBUG_205 */ 614 615 /* need to trash a connection not fully established */ 616 meta_clear_one_candidate( op, mc, candidate ); 617 goto error_return; 618 } 619 620 /* copy the DN if needed */ 621 if ( msc->msc_bound_ndn.bv_val == op->o_conn->c_dn.bv_val ) { 622 ber_dupbv( &msc->msc_bound_ndn, &op->o_conn->c_dn ); 623 } 624 625 assert( !BER_BVISNULL( &msc->msc_bound_ndn ) ); 626 627 } else { 628 ber_dupbv( &msc->msc_bound_ndn, (struct berval *)&slap_empty_bv ); 629 } 630 } 631 632 assert( !BER_BVISNULL( &msc->msc_bound_ndn ) ); 633 634error_return:; 635 if ( dolock ) { 636 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 637 } 638 META_BACK_CONN_CREATING_CLEAR( msc ); 639 if ( rs->sr_err == LDAP_SUCCESS ) { 640 /* 641 * Sets a cookie for the rewrite session 642 */ 643 ( void )rewrite_session_init( mt->mt_rwmap.rwm_rw, op->o_conn ); 644 META_BACK_CONN_INITED_SET( msc ); 645 } 646 if ( dolock ) { 647 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 648 } 649 650 if ( rs->sr_err != LDAP_SUCCESS ) { 651 rs->sr_err = slap_map_api2result( rs ); 652 if ( sendok & LDAP_BACK_SENDERR ) { 653 send_ldap_result( op, rs ); 654 } 655 } 656 657 return rs->sr_err; 658} 659 660/* 661 * meta_back_retry 662 * 663 * Retries one connection 664 */ 665int 666meta_back_retry( 667 Operation *op, 668 SlapReply *rs, 669 metaconn_t **mcp, 670 int candidate, 671 ldap_back_send_t sendok ) 672{ 673 metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; 674 metatarget_t *mt = mi->mi_targets[ candidate ]; 675 metaconn_t *mc = *mcp; 676 metasingleconn_t *msc = &mc->mc_conns[ candidate ]; 677 int rc = LDAP_UNAVAILABLE, 678 binding, 679 quarantine = 1; 680 681 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 682 683 assert( !META_BACK_CONN_CREATING( msc ) ); 684 binding = LDAP_BACK_CONN_BINDING( msc ); 685 LDAP_BACK_CONN_BINDING_CLEAR( msc ); 686 687 assert( mc->mc_refcnt > 0 ); 688 if ( mc->mc_refcnt == 1 ) { 689 if ( LogTest( LDAP_DEBUG_ANY ) ) { 690 char buf[ SLAP_TEXT_BUFLEN ]; 691 692 /* this lock is required; however, 693 * it's invoked only when logging is on */ 694 ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex ); 695 snprintf( buf, sizeof( buf ), 696 "retrying URI=\"%s\" DN=\"%s\"", 697 mt->mt_uri, 698 BER_BVISNULL( &msc->msc_bound_ndn ) ? 699 "" : msc->msc_bound_ndn.bv_val ); 700 ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex ); 701 702 Debug( LDAP_DEBUG_ANY, 703 "%s meta_back_retry[%d]: %s.\n", 704 op->o_log_prefix, candidate, buf ); 705 } 706 707 meta_clear_one_candidate( op, mc, candidate ); 708 LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); 709 710 ( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn ); 711 712 /* mc here must be the regular mc, reset and ready for init */ 713 rc = meta_back_init_one_conn( op, rs, mc, candidate, 714 LDAP_BACK_CONN_ISPRIV( mc ), sendok, 0 ); 715 716 /* restore the "binding" flag, in case */ 717 if ( binding ) { 718 LDAP_BACK_CONN_BINDING_SET( msc ); 719 } 720 721 if ( rc == LDAP_SUCCESS ) { 722 quarantine = 0; 723 rc = meta_back_single_dobind( op, rs, mcp, candidate, 724 sendok, mt->mt_nretries, 0 ); 725 726 Debug( LDAP_DEBUG_ANY, 727 "%s meta_back_retry[%d]: " 728 "meta_back_single_dobind=%d\n", 729 op->o_log_prefix, candidate, rc ); 730 if ( rc == LDAP_SUCCESS ) { 731 if ( !BER_BVISNULL( &msc->msc_bound_ndn ) && 732 !BER_BVISEMPTY( &msc->msc_bound_ndn ) ) 733 { 734 LDAP_BACK_CONN_ISBOUND_SET( msc ); 735 736 } else { 737 LDAP_BACK_CONN_ISANON_SET( msc ); 738 } 739 740 /* when bound, dispose of the "binding" flag */ 741 if ( binding ) { 742 LDAP_BACK_CONN_BINDING_CLEAR( msc ); 743 } 744 } 745 } 746 747 /* don't send twice */ 748 sendok &= ~LDAP_BACK_SENDERR; 749 } 750 751 if ( rc != LDAP_SUCCESS ) { 752 SlapReply *candidates = meta_back_candidates_get( op ); 753 754 candidates[ candidate ].sr_err = rc; 755 756 if ( *mcp != NULL ) { 757 if ( mc->mc_refcnt == 1 ) { 758 if ( binding ) { 759 LDAP_BACK_CONN_BINDING_CLEAR( msc ); 760 } 761 (void)meta_clear_one_candidate( op, mc, candidate ); 762 } 763 764 LDAP_BACK_CONN_TAINTED_SET( mc ); 765 /* only release if mandatory; otherwise 766 * let the caller do what's best before 767 * releasing */ 768 if ( META_BACK_ONERR_STOP( mi ) ) { 769 meta_back_release_conn_lock( mi, mc, 0 ); 770 *mcp = NULL; 771 772 } else { 773#if META_BACK_PRINT_CONNTREE > 0 774 meta_back_print_conntree( mi, ">>> meta_back_retry" ); 775#endif /* META_BACK_PRINT_CONNTREE */ 776 777 /* FIXME: could be done better, reworking meta_back_release_conn_lock() */ 778 if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) { 779 if ( mc->mc_q.tqe_prev != NULL ) { 780 assert( LDAP_BACK_CONN_CACHED( mc ) ); 781 assert( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num > 0 ); 782 LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, 783 mc, mc_q ); 784 mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num--; 785 LDAP_TAILQ_ENTRY_INIT( mc, mc_q ); 786 787 } else { 788 assert( !LDAP_BACK_CONN_CACHED( mc ) ); 789 } 790 791 } else { 792 /* FIXME: check if in tree, for consistency? */ 793 (void)avl_delete( &mi->mi_conninfo.lai_tree, 794 ( caddr_t )mc, meta_back_conndnmc_cmp ); 795 } 796 LDAP_BACK_CONN_CACHED_CLEAR( mc ); 797 798#if META_BACK_PRINT_CONNTREE > 0 799 meta_back_print_conntree( mi, "<<< meta_back_retry" ); 800#endif /* META_BACK_PRINT_CONNTREE */ 801 } 802 } 803 804 if ( sendok & LDAP_BACK_SENDERR ) { 805 rs->sr_err = rc; 806 rs->sr_text = "Unable to retry"; 807 send_ldap_result( op, rs ); 808 } 809 } 810 811 if ( quarantine && META_BACK_TGT_QUARANTINE( mt ) ) { 812 meta_back_quarantine( op, rs, candidate ); 813 } 814 815 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 816 817 return rc == LDAP_SUCCESS ? 1 : 0; 818} 819 820/* 821 * callback for unique candidate selection 822 */ 823static int 824meta_back_conn_cb( Operation *op, SlapReply *rs ) 825{ 826 assert( op->o_tag == LDAP_REQ_SEARCH ); 827 828 switch ( rs->sr_type ) { 829 case REP_SEARCH: 830 ((long *)op->o_callback->sc_private)[0] = (long)op->o_private; 831 break; 832 833 case REP_SEARCHREF: 834 case REP_RESULT: 835 break; 836 837 default: 838 return rs->sr_err; 839 } 840 841 return 0; 842} 843 844 845static int 846meta_back_get_candidate( 847 Operation *op, 848 SlapReply *rs, 849 struct berval *ndn ) 850{ 851 metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; 852 long candidate; 853 854 /* 855 * tries to get a unique candidate 856 * (takes care of default target) 857 */ 858 candidate = meta_back_select_unique_candidate( mi, ndn ); 859 860 /* 861 * if any is found, inits the connection 862 */ 863 if ( candidate == META_TARGET_NONE ) { 864 rs->sr_err = LDAP_NO_SUCH_OBJECT; 865 rs->sr_text = "No suitable candidate target found"; 866 867 } else if ( candidate == META_TARGET_MULTIPLE ) { 868 Operation op2 = *op; 869 SlapReply rs2 = { 0 }; 870 slap_callback cb2 = { 0 }; 871 int rc; 872 873 /* try to get a unique match for the request ndn 874 * among the multiple candidates available */ 875 op2.o_tag = LDAP_REQ_SEARCH; 876 op2.o_req_dn = *ndn; 877 op2.o_req_ndn = *ndn; 878 op2.ors_scope = LDAP_SCOPE_BASE; 879 op2.ors_deref = LDAP_DEREF_NEVER; 880 op2.ors_attrs = slap_anlist_no_attrs; 881 op2.ors_attrsonly = 0; 882 op2.ors_limit = NULL; 883 op2.ors_slimit = 1; 884 op2.ors_tlimit = SLAP_NO_LIMIT; 885 886 op2.ors_filter = (Filter *)slap_filter_objectClass_pres; 887 op2.ors_filterstr = *slap_filterstr_objectClass_pres; 888 889 op2.o_callback = &cb2; 890 cb2.sc_response = meta_back_conn_cb; 891 cb2.sc_private = (void *)&candidate; 892 893 rc = op->o_bd->be_search( &op2, &rs2 ); 894 895 switch ( rs2.sr_err ) { 896 case LDAP_SUCCESS: 897 default: 898 rs->sr_err = rs2.sr_err; 899 break; 900 901 case LDAP_SIZELIMIT_EXCEEDED: 902 /* if multiple candidates can serve the operation, 903 * and a default target is defined, and it is 904 * a candidate, try using it (FIXME: YMMV) */ 905 if ( mi->mi_defaulttarget != META_DEFAULT_TARGET_NONE 906 && meta_back_is_candidate( mi->mi_targets[ mi->mi_defaulttarget ], 907 ndn, op->o_tag == LDAP_REQ_SEARCH ? op->ors_scope : LDAP_SCOPE_BASE ) ) 908 { 909 candidate = mi->mi_defaulttarget; 910 rs->sr_err = LDAP_SUCCESS; 911 rs->sr_text = NULL; 912 913 } else { 914 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 915 rs->sr_text = "Unable to select unique candidate target"; 916 } 917 break; 918 } 919 920 } else { 921 rs->sr_err = LDAP_SUCCESS; 922 } 923 924 return candidate; 925} 926 927static void *meta_back_candidates_dummy; 928 929static void 930meta_back_candidates_keyfree( 931 void *key, 932 void *data ) 933{ 934 metacandidates_t *mc = (metacandidates_t *)data; 935 936 ber_memfree_x( mc->mc_candidates, NULL ); 937 ber_memfree_x( data, NULL ); 938} 939 940SlapReply * 941meta_back_candidates_get( Operation *op ) 942{ 943 metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; 944 metacandidates_t *mc; 945 946 if ( op->o_threadctx ) { 947 void *data = NULL; 948 949 ldap_pvt_thread_pool_getkey( op->o_threadctx, 950 &meta_back_candidates_dummy, &data, NULL ); 951 mc = (metacandidates_t *)data; 952 953 } else { 954 mc = mi->mi_candidates; 955 } 956 957 if ( mc == NULL ) { 958 mc = ch_calloc( sizeof( metacandidates_t ), 1 ); 959 mc->mc_ntargets = mi->mi_ntargets; 960 mc->mc_candidates = ch_calloc( sizeof( SlapReply ), mc->mc_ntargets ); 961 if ( op->o_threadctx ) { 962 void *data = NULL; 963 964 data = (void *)mc; 965 ldap_pvt_thread_pool_setkey( op->o_threadctx, 966 &meta_back_candidates_dummy, data, 967 meta_back_candidates_keyfree, 968 NULL, NULL ); 969 970 } else { 971 mi->mi_candidates = mc; 972 } 973 974 } else if ( mc->mc_ntargets < mi->mi_ntargets ) { 975 /* NOTE: in the future, may want to allow back-config 976 * to add/remove targets from back-meta... */ 977 mc->mc_candidates = ch_realloc( mc->mc_candidates, 978 sizeof( SlapReply ) * mi->mi_ntargets ); 979 memset( &mc->mc_candidates[ mc->mc_ntargets ], 0, 980 sizeof( SlapReply ) * ( mi->mi_ntargets - mc->mc_ntargets ) ); 981 mc->mc_ntargets = mi->mi_ntargets; 982 } 983 984 return mc->mc_candidates; 985} 986 987/* 988 * meta_back_getconn 989 * 990 * Prepares the connection structure 991 * 992 * RATIONALE: 993 * 994 * - determine what DN is being requested: 995 * 996 * op requires candidate checks 997 * 998 * add unique parent of o_req_ndn 999 * bind unique^*[/all] o_req_ndn [no check] 1000 * compare unique^+ o_req_ndn 1001 * delete unique o_req_ndn 1002 * modify unique o_req_ndn 1003 * search any o_req_ndn 1004 * modrdn unique[, unique] o_req_ndn[, orr_nnewSup] 1005 * 1006 * - for ops that require the candidate to be unique, in case of multiple 1007 * occurrences an internal search with sizeLimit=1 is performed 1008 * if a unique candidate can actually be determined. If none is found, 1009 * the operation aborts; if multiple are found, the default target 1010 * is used if defined and candidate; otherwise the operation aborts. 1011 * 1012 * *^note: actually, the bind operation is handled much like a search; 1013 * i.e. the bind is broadcast to all candidate targets. 1014 * 1015 * +^note: actually, the compare operation is handled much like a search; 1016 * i.e. the compare is broadcast to all candidate targets, while checking 1017 * that exactly none (noSuchObject) or one (TRUE/FALSE/UNDEFINED) is 1018 * returned. 1019 */ 1020metaconn_t * 1021meta_back_getconn( 1022 Operation *op, 1023 SlapReply *rs, 1024 int *candidate, 1025 ldap_back_send_t sendok ) 1026{ 1027 metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; 1028 metaconn_t *mc = NULL, 1029 mc_curr = {{ 0 }}; 1030 int cached = META_TARGET_NONE, 1031 i = META_TARGET_NONE, 1032 err = LDAP_SUCCESS, 1033 new_conn = 0, 1034 ncandidates = 0; 1035 1036 1037 meta_op_type op_type = META_OP_REQUIRE_SINGLE; 1038 enum { 1039 META_DNTYPE_ENTRY, 1040 META_DNTYPE_PARENT, 1041 META_DNTYPE_NEWPARENT 1042 } dn_type = META_DNTYPE_ENTRY; 1043 struct berval ndn = op->o_req_ndn, 1044 pndn; 1045 1046 SlapReply *candidates = meta_back_candidates_get( op ); 1047 1048 /* Internal searches are privileged and shared. So is root. */ 1049 if ( ( !BER_BVISEMPTY( &op->o_ndn ) && META_BACK_PROXYAUTHZ_ALWAYS( mi ) ) 1050 || ( BER_BVISEMPTY( &op->o_ndn ) && META_BACK_PROXYAUTHZ_ANON( mi ) ) 1051 || op->o_do_not_cache || be_isroot( op ) ) 1052 { 1053 LDAP_BACK_CONN_ISPRIV_SET( &mc_curr ); 1054 mc_curr.mc_local_ndn = op->o_bd->be_rootndn; 1055 LDAP_BACK_PCONN_ROOTDN_SET( &mc_curr, op ); 1056 1057 } else if ( BER_BVISEMPTY( &op->o_ndn ) && META_BACK_PROXYAUTHZ_NOANON( mi ) ) 1058 { 1059 LDAP_BACK_CONN_ISANON_SET( &mc_curr ); 1060 BER_BVSTR( &mc_curr.mc_local_ndn, "" ); 1061 LDAP_BACK_PCONN_ANON_SET( &mc_curr, op ); 1062 1063 } else { 1064 mc_curr.mc_local_ndn = op->o_ndn; 1065 1066 /* Explicit binds must not be shared */ 1067 if ( !BER_BVISEMPTY( &op->o_ndn ) 1068 || op->o_tag == LDAP_REQ_BIND 1069 || SLAP_IS_AUTHZ_BACKEND( op ) ) 1070 { 1071 mc_curr.mc_conn = op->o_conn; 1072 1073 } else { 1074 LDAP_BACK_CONN_ISANON_SET( &mc_curr ); 1075 LDAP_BACK_PCONN_ANON_SET( &mc_curr, op ); 1076 } 1077 } 1078 1079 /* Explicit Bind requests always get their own conn */ 1080 if ( sendok & LDAP_BACK_BINDING ) { 1081 mc_curr.mc_conn = op->o_conn; 1082 1083 } else { 1084 /* Searches for a metaconn in the avl tree */ 1085retry_lock:; 1086 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 1087 if ( LDAP_BACK_PCONN_ISPRIV( &mc_curr ) ) { 1088 /* lookup a conn that's not binding */ 1089 LDAP_TAILQ_FOREACH( mc, 1090 &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( &mc_curr ) ].mic_priv, 1091 mc_q ) 1092 { 1093 if ( !LDAP_BACK_CONN_BINDING( mc ) && mc->mc_refcnt == 0 ) { 1094 break; 1095 } 1096 } 1097 1098 if ( mc != NULL ) { 1099 if ( mc != LDAP_TAILQ_LAST( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, 1100 metaconn_t, mc_q ) ) 1101 { 1102 LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, 1103 mc, mc_q ); 1104 LDAP_TAILQ_ENTRY_INIT( mc, mc_q ); 1105 LDAP_TAILQ_INSERT_TAIL( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, 1106 mc, mc_q ); 1107 } 1108 1109 } else if ( !LDAP_BACK_USE_TEMPORARIES( mi ) 1110 && mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( &mc_curr ) ].mic_num == mi->mi_conn_priv_max ) 1111 { 1112 mc = LDAP_TAILQ_FIRST( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( &mc_curr ) ].mic_priv ); 1113 } 1114 1115 1116 } else { 1117 mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree, 1118 (caddr_t)&mc_curr, meta_back_conndn_cmp ); 1119 } 1120 1121 if ( mc ) { 1122 /* catch taint errors */ 1123 assert( !LDAP_BACK_CONN_TAINTED( mc ) ); 1124 1125 /* Don't reuse connections while they're still binding 1126 * NOTE: only makes sense for binds */ 1127 if ( LDAP_BACK_CONN_BINDING( mc ) ) { 1128 if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) { 1129 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 1130 1131 ldap_pvt_thread_yield(); 1132 goto retry_lock; 1133 } 1134 1135 /* release conn, and create a temporary */ 1136 mc = NULL; 1137 1138 } else { 1139 if ( ( mi->mi_conn_ttl != 0 && op->o_time > mc->mc_create_time + mi->mi_conn_ttl ) 1140 || ( mi->mi_idle_timeout != 0 && op->o_time > mc->mc_time + mi->mi_idle_timeout ) ) 1141 { 1142#if META_BACK_PRINT_CONNTREE > 0 1143 meta_back_print_conntree( mi, 1144 ">>> meta_back_getconn(expired)" ); 1145#endif /* META_BACK_PRINT_CONNTREE */ 1146 1147 /* don't let anyone else use this expired connection */ 1148 if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) { 1149 if ( mc->mc_q.tqe_prev != NULL ) { 1150 assert( LDAP_BACK_CONN_CACHED( mc ) ); 1151 assert( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num > 0 ); 1152 LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, 1153 mc, mc_q ); 1154 mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num--; 1155 LDAP_TAILQ_ENTRY_INIT( mc, mc_q ); 1156 1157 } else { 1158 assert( !LDAP_BACK_CONN_CACHED( mc ) ); 1159 } 1160 1161 } else { 1162 (void)avl_delete( &mi->mi_conninfo.lai_tree, 1163 (caddr_t)mc, meta_back_conndnmc_cmp ); 1164 } 1165 1166#if META_BACK_PRINT_CONNTREE > 0 1167 meta_back_print_conntree( mi, 1168 "<<< meta_back_getconn(expired)" ); 1169#endif /* META_BACK_PRINT_CONNTREE */ 1170 LDAP_BACK_CONN_TAINTED_SET( mc ); 1171 LDAP_BACK_CONN_CACHED_CLEAR( mc ); 1172 1173 if ( LogTest( LDAP_DEBUG_TRACE ) ) { 1174 char buf[STRLENOF("4294967295U") + 1] = { 0 }; 1175 mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) ); 1176 1177 Debug( LDAP_DEBUG_TRACE, 1178 "%s meta_back_getconn: mc=%p conn=%s expired (tainted).\n", 1179 op->o_log_prefix, (void *)mc, buf ); 1180 } 1181 } 1182 1183 mc->mc_refcnt++; 1184 } 1185 } 1186 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 1187 } 1188 1189 switch ( op->o_tag ) { 1190 case LDAP_REQ_ADD: 1191 /* if we go to selection, the entry must not exist, 1192 * and we must be able to resolve the parent */ 1193 dn_type = META_DNTYPE_PARENT; 1194 dnParent( &ndn, &pndn ); 1195 break; 1196 1197 case LDAP_REQ_MODRDN: 1198 /* if nnewSuperior is not NULL, it must resolve 1199 * to the same candidate as the req_ndn */ 1200 if ( op->orr_nnewSup ) { 1201 dn_type = META_DNTYPE_NEWPARENT; 1202 } 1203 break; 1204 1205 case LDAP_REQ_BIND: 1206 /* if bound as rootdn, the backend must bind to all targets 1207 * with the administrative identity 1208 * (unless pseoudoroot-bind-defer is TRUE) */ 1209 if ( op->orb_method == LDAP_AUTH_SIMPLE && be_isroot_pw( op ) ) { 1210 op_type = META_OP_REQUIRE_ALL; 1211 } 1212 break; 1213 1214 case LDAP_REQ_COMPARE: 1215 case LDAP_REQ_DELETE: 1216 case LDAP_REQ_MODIFY: 1217 /* just a unique candidate */ 1218 break; 1219 1220 case LDAP_REQ_SEARCH: 1221 /* allow multiple candidates for the searchBase */ 1222 op_type = META_OP_ALLOW_MULTIPLE; 1223 break; 1224 1225 default: 1226 /* right now, just break (exop?) */ 1227 break; 1228 } 1229 1230 /* 1231 * require all connections ... 1232 */ 1233 if ( op_type == META_OP_REQUIRE_ALL ) { 1234 1235 /* Looks like we didn't get a bind. Open a new session... */ 1236 if ( mc == NULL ) { 1237 assert( new_conn == 0 ); 1238 mc = metaconn_alloc( op ); 1239 mc->mc_conn = mc_curr.mc_conn; 1240 ber_dupbv( &mc->mc_local_ndn, &mc_curr.mc_local_ndn ); 1241 new_conn = 1; 1242 if ( sendok & LDAP_BACK_BINDING ) { 1243 LDAP_BACK_CONN_BINDING_SET( mc ); 1244 } 1245 if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) { 1246 LDAP_BACK_CONN_ISPRIV_SET( mc ); 1247 1248 } else if ( LDAP_BACK_CONN_ISANON( &mc_curr ) ) { 1249 LDAP_BACK_CONN_ISANON_SET( mc ); 1250 } 1251 1252 } else if ( 0 ) { 1253 /* TODO: if any of the connections is binding, 1254 * release mc and create a new one */ 1255 } 1256 1257 for ( i = 0; i < mi->mi_ntargets; i++ ) { 1258 /* 1259 * The target is activated; if needed, it is 1260 * also init'd 1261 */ 1262 candidates[ i ].sr_err = meta_back_init_one_conn( op, 1263 rs, mc, i, LDAP_BACK_CONN_ISPRIV( &mc_curr ), 1264 LDAP_BACK_DONTSEND, !new_conn ); 1265 if ( candidates[ i ].sr_err == LDAP_SUCCESS ) { 1266 if ( new_conn && ( sendok & LDAP_BACK_BINDING ) ) { 1267 LDAP_BACK_CONN_BINDING_SET( &mc->mc_conns[ i ] ); 1268 } 1269 META_CANDIDATE_SET( &candidates[ i ] ); 1270 ncandidates++; 1271 1272 } else { 1273 1274 /* 1275 * FIXME: in case one target cannot 1276 * be init'd, should the other ones 1277 * be tried? 1278 */ 1279 META_CANDIDATE_RESET( &candidates[ i ] ); 1280 err = candidates[ i ].sr_err; 1281 continue; 1282 } 1283 } 1284 1285 if ( ncandidates == 0 ) { 1286 if ( new_conn ) { 1287 mc->mc_refcnt = 0; 1288 meta_back_conn_free( mc ); 1289 1290 } else { 1291 meta_back_release_conn( mi, mc ); 1292 } 1293 1294 rs->sr_err = LDAP_NO_SUCH_OBJECT; 1295 rs->sr_text = "Unable to select valid candidates"; 1296 1297 if ( sendok & LDAP_BACK_SENDERR ) { 1298 if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { 1299 rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val; 1300 } 1301 send_ldap_result( op, rs ); 1302 rs->sr_matched = NULL; 1303 } 1304 1305 return NULL; 1306 } 1307 1308 goto done; 1309 } 1310 1311 /* 1312 * looks in cache, if any 1313 */ 1314 if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) { 1315 cached = i = meta_dncache_get_target( &mi->mi_cache, &op->o_req_ndn ); 1316 } 1317 1318 if ( op_type == META_OP_REQUIRE_SINGLE ) { 1319 metatarget_t *mt = NULL; 1320 metasingleconn_t *msc = NULL; 1321 1322 int j; 1323 1324 for ( j = 0; j < mi->mi_ntargets; j++ ) { 1325 META_CANDIDATE_RESET( &candidates[ j ] ); 1326 } 1327 1328 /* 1329 * tries to get a unique candidate 1330 * (takes care of default target) 1331 */ 1332 if ( i == META_TARGET_NONE ) { 1333 i = meta_back_get_candidate( op, rs, &ndn ); 1334 1335 if ( rs->sr_err == LDAP_NO_SUCH_OBJECT && dn_type == META_DNTYPE_PARENT ) { 1336 i = meta_back_get_candidate( op, rs, &pndn ); 1337 } 1338 1339 if ( i < 0 || rs->sr_err != LDAP_SUCCESS ) { 1340 if ( mc != NULL ) { 1341 meta_back_release_conn( mi, mc ); 1342 } 1343 1344 if ( sendok & LDAP_BACK_SENDERR ) { 1345 if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { 1346 rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val; 1347 } 1348 send_ldap_result( op, rs ); 1349 rs->sr_matched = NULL; 1350 } 1351 1352 return NULL; 1353 } 1354 } 1355 1356 if ( dn_type == META_DNTYPE_NEWPARENT && meta_back_get_candidate( op, rs, op->orr_nnewSup ) != i ) 1357 { 1358 if ( mc != NULL ) { 1359 meta_back_release_conn( mi, mc ); 1360 } 1361 1362 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 1363 rs->sr_text = "Cross-target rename not supported"; 1364 if ( sendok & LDAP_BACK_SENDERR ) { 1365 send_ldap_result( op, rs ); 1366 } 1367 1368 return NULL; 1369 } 1370 1371 Debug( LDAP_DEBUG_TRACE, 1372 "==>meta_back_getconn: got target=%d for ndn=\"%s\" from cache\n", 1373 i, op->o_req_ndn.bv_val, 0 ); 1374 1375 if ( mc == NULL ) { 1376 /* Retries searching for a metaconn in the avl tree 1377 * the reason is that the connection might have been 1378 * created by meta_back_get_candidate() */ 1379 if ( !( sendok & LDAP_BACK_BINDING ) ) { 1380retry_lock2:; 1381 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 1382 mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree, 1383 (caddr_t)&mc_curr, meta_back_conndn_cmp ); 1384 if ( mc != NULL ) { 1385 /* catch taint errors */ 1386 assert( !LDAP_BACK_CONN_TAINTED( mc ) ); 1387 1388 /* Don't reuse connections while they're still binding */ 1389 if ( META_BACK_CONN_CREATING( &mc->mc_conns[ i ] ) 1390 || LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ) 1391 { 1392 if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) { 1393 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 1394 ldap_pvt_thread_yield(); 1395 goto retry_lock2; 1396 } 1397 1398 mc = NULL; 1399 1400 } else { 1401 mc->mc_refcnt++; 1402 } 1403 } 1404 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 1405 } 1406 1407 /* Looks like we didn't get a bind. Open a new session... */ 1408 if ( mc == NULL ) { 1409 assert( new_conn == 0 ); 1410 mc = metaconn_alloc( op ); 1411 mc->mc_conn = mc_curr.mc_conn; 1412 ber_dupbv( &mc->mc_local_ndn, &mc_curr.mc_local_ndn ); 1413 new_conn = 1; 1414 if ( sendok & LDAP_BACK_BINDING ) { 1415 LDAP_BACK_CONN_BINDING_SET( mc ); 1416 } 1417 if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) { 1418 LDAP_BACK_CONN_ISPRIV_SET( mc ); 1419 1420 } else if ( LDAP_BACK_CONN_ISANON( &mc_curr ) ) { 1421 LDAP_BACK_CONN_ISANON_SET( mc ); 1422 } 1423 } 1424 } 1425 1426 /* 1427 * Clear all other candidates 1428 */ 1429 ( void )meta_clear_unused_candidates( op, i ); 1430 1431 mt = mi->mi_targets[ i ]; 1432 msc = &mc->mc_conns[ i ]; 1433 1434 /* 1435 * The target is activated; if needed, it is 1436 * also init'd. In case of error, meta_back_init_one_conn 1437 * sends the appropriate result. 1438 */ 1439 err = meta_back_init_one_conn( op, rs, mc, i, 1440 LDAP_BACK_CONN_ISPRIV( &mc_curr ), sendok, !new_conn ); 1441 if ( err != LDAP_SUCCESS ) { 1442 /* 1443 * FIXME: in case one target cannot 1444 * be init'd, should the other ones 1445 * be tried? 1446 */ 1447 META_CANDIDATE_RESET( &candidates[ i ] ); 1448 if ( new_conn ) { 1449 mc->mc_refcnt = 0; 1450 meta_back_conn_free( mc ); 1451 1452 } else { 1453 meta_back_release_conn( mi, mc ); 1454 } 1455 return NULL; 1456 } 1457 1458 if ( new_conn && ( sendok & LDAP_BACK_BINDING ) ) { 1459 LDAP_BACK_CONN_BINDING_SET( &mc->mc_conns[ i ] ); 1460 } 1461 1462 candidates[ i ].sr_err = LDAP_SUCCESS; 1463 META_CANDIDATE_SET( &candidates[ i ] ); 1464 ncandidates++; 1465 1466 if ( candidate ) { 1467 *candidate = i; 1468 } 1469 1470 /* 1471 * if no unique candidate ... 1472 */ 1473 } else { 1474 1475 /* Looks like we didn't get a bind. Open a new session... */ 1476 if ( mc == NULL ) { 1477 assert( new_conn == 0 ); 1478 mc = metaconn_alloc( op ); 1479 mc->mc_conn = mc_curr.mc_conn; 1480 ber_dupbv( &mc->mc_local_ndn, &mc_curr.mc_local_ndn ); 1481 new_conn = 1; 1482 if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) { 1483 LDAP_BACK_CONN_ISPRIV_SET( mc ); 1484 1485 } else if ( LDAP_BACK_CONN_ISANON( &mc_curr ) ) { 1486 LDAP_BACK_CONN_ISANON_SET( mc ); 1487 } 1488 } 1489 1490 for ( i = 0; i < mi->mi_ntargets; i++ ) { 1491 metatarget_t *mt = mi->mi_targets[ i ]; 1492 1493 META_CANDIDATE_RESET( &candidates[ i ] ); 1494 1495 if ( i == cached 1496 || meta_back_is_candidate( mt, &op->o_req_ndn, 1497 LDAP_SCOPE_SUBTREE ) ) 1498 { 1499 1500 /* 1501 * The target is activated; if needed, it is 1502 * also init'd 1503 */ 1504 int lerr = meta_back_init_one_conn( op, rs, mc, i, 1505 LDAP_BACK_CONN_ISPRIV( &mc_curr ), 1506 LDAP_BACK_DONTSEND, !new_conn ); 1507 candidates[ i ].sr_err = lerr; 1508 if ( lerr == LDAP_SUCCESS ) { 1509 META_CANDIDATE_SET( &candidates[ i ] ); 1510 ncandidates++; 1511 1512 Debug( LDAP_DEBUG_TRACE, "%s: meta_back_getconn[%d]\n", 1513 op->o_log_prefix, i, 0 ); 1514 1515 } else if ( lerr == LDAP_UNAVAILABLE && !META_BACK_ONERR_STOP( mi ) ) { 1516 META_CANDIDATE_SET( &candidates[ i ] ); 1517 1518 Debug( LDAP_DEBUG_TRACE, "%s: meta_back_getconn[%d] %s\n", 1519 op->o_log_prefix, i, 1520 mt->mt_isquarantined != LDAP_BACK_FQ_NO ? "quarantined" : "unavailable" ); 1521 1522 } else { 1523 1524 /* 1525 * FIXME: in case one target cannot 1526 * be init'd, should the other ones 1527 * be tried? 1528 */ 1529 if ( new_conn ) { 1530 ( void )meta_clear_one_candidate( op, mc, i ); 1531 } 1532 /* leave the target candidate, but record the error for later use */ 1533 err = lerr; 1534 1535 if ( lerr == LDAP_UNAVAILABLE && mt->mt_isquarantined != LDAP_BACK_FQ_NO ) { 1536 Debug( LDAP_DEBUG_TRACE, "%s: meta_back_getconn[%d] quarantined err=%d\n", 1537 op->o_log_prefix, i, lerr ); 1538 1539 } else { 1540 Debug( LDAP_DEBUG_ANY, "%s: meta_back_getconn[%d] failed err=%d\n", 1541 op->o_log_prefix, i, lerr ); 1542 } 1543 1544 if ( META_BACK_ONERR_STOP( mi ) ) { 1545 if ( sendok & LDAP_BACK_SENDERR ) { 1546 send_ldap_result( op, rs ); 1547 } 1548 if ( new_conn ) { 1549 mc->mc_refcnt = 0; 1550 meta_back_conn_free( mc ); 1551 1552 } else { 1553 meta_back_release_conn( mi, mc ); 1554 } 1555 1556 return NULL; 1557 } 1558 1559 continue; 1560 } 1561 1562 } else { 1563 if ( new_conn ) { 1564 ( void )meta_clear_one_candidate( op, mc, i ); 1565 } 1566 } 1567 } 1568 1569 if ( ncandidates == 0 ) { 1570 if ( new_conn ) { 1571 mc->mc_refcnt = 0; 1572 meta_back_conn_free( mc ); 1573 1574 } else { 1575 meta_back_release_conn( mi, mc ); 1576 } 1577 1578 if ( rs->sr_err == LDAP_SUCCESS ) { 1579 rs->sr_err = LDAP_NO_SUCH_OBJECT; 1580 rs->sr_text = "Unable to select valid candidates"; 1581 } 1582 1583 if ( sendok & LDAP_BACK_SENDERR ) { 1584 if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) { 1585 rs->sr_matched = op->o_bd->be_suffix[ 0 ].bv_val; 1586 } 1587 send_ldap_result( op, rs ); 1588 rs->sr_matched = NULL; 1589 } 1590 1591 return NULL; 1592 } 1593 } 1594 1595done:; 1596 /* clear out meta_back_init_one_conn non-fatal errors */ 1597 rs->sr_err = LDAP_SUCCESS; 1598 rs->sr_text = NULL; 1599 1600 /* touch the timestamp */ 1601 if ( mi->mi_idle_timeout != 0 ) { 1602 mc->mc_time = op->o_time; 1603 } 1604 1605 if ( new_conn ) { 1606 if ( mi->mi_conn_ttl ) { 1607 mc->mc_create_time = op->o_time; 1608 } 1609 1610 /* 1611 * Inserts the newly created metaconn in the avl tree 1612 */ 1613 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 1614#if META_BACK_PRINT_CONNTREE > 0 1615 meta_back_print_conntree( mi, ">>> meta_back_getconn" ); 1616#endif /* META_BACK_PRINT_CONNTREE */ 1617 1618 err = 0; 1619 if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) { 1620 if ( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num < mi->mi_conn_priv_max ) { 1621 LDAP_TAILQ_INSERT_TAIL( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, mc, mc_q ); 1622 mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num++; 1623 LDAP_BACK_CONN_CACHED_SET( mc ); 1624 1625 } else { 1626 LDAP_BACK_CONN_TAINTED_SET( mc ); 1627 } 1628 rs->sr_err = 0; 1629 1630 } else if ( !( sendok & LDAP_BACK_BINDING ) ) { 1631 err = avl_insert( &mi->mi_conninfo.lai_tree, ( caddr_t )mc, 1632 meta_back_conndn_cmp, meta_back_conndn_dup ); 1633 LDAP_BACK_CONN_CACHED_SET( mc ); 1634 } 1635 1636#if META_BACK_PRINT_CONNTREE > 0 1637 meta_back_print_conntree( mi, "<<< meta_back_getconn" ); 1638#endif /* META_BACK_PRINT_CONNTREE */ 1639 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 1640 1641 if ( !LDAP_BACK_PCONN_ISPRIV( mc ) ) { 1642 /* 1643 * Err could be -1 in case a duplicate metaconn is inserted 1644 */ 1645 switch ( err ) { 1646 case 0: 1647 break; 1648 1649 case -1: 1650 LDAP_BACK_CONN_CACHED_CLEAR( mc ); 1651 /* duplicate: free and try to get the newly created one */ 1652 if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( mi ) ) { 1653 mc->mc_refcnt = 0; 1654 meta_back_conn_free( mc ); 1655 1656 new_conn = 0; 1657 goto retry_lock; 1658 } 1659 1660 LDAP_BACK_CONN_TAINTED_SET( mc ); 1661 break; 1662 1663 default: 1664 LDAP_BACK_CONN_CACHED_CLEAR( mc ); 1665 if ( LogTest( LDAP_DEBUG_ANY ) ) { 1666 char buf[STRLENOF("4294967295U") + 1] = { 0 }; 1667 mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) ); 1668 1669 Debug( LDAP_DEBUG_ANY, 1670 "%s meta_back_getconn: candidates=%d conn=%s insert failed\n", 1671 op->o_log_prefix, ncandidates, buf ); 1672 } 1673 1674 mc->mc_refcnt = 0; 1675 meta_back_conn_free( mc ); 1676 1677 rs->sr_err = LDAP_OTHER; 1678 rs->sr_text = "Proxy bind collision"; 1679 if ( sendok & LDAP_BACK_SENDERR ) { 1680 send_ldap_result( op, rs ); 1681 } 1682 return NULL; 1683 } 1684 } 1685 1686 if ( LogTest( LDAP_DEBUG_TRACE ) ) { 1687 char buf[STRLENOF("4294967295U") + 1] = { 0 }; 1688 mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) ); 1689 1690 Debug( LDAP_DEBUG_TRACE, 1691 "%s meta_back_getconn: candidates=%d conn=%s inserted\n", 1692 op->o_log_prefix, ncandidates, buf ); 1693 } 1694 1695 } else { 1696 if ( LogTest( LDAP_DEBUG_TRACE ) ) { 1697 char buf[STRLENOF("4294967295U") + 1] = { 0 }; 1698 mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) ); 1699 1700 Debug( LDAP_DEBUG_TRACE, 1701 "%s meta_back_getconn: candidates=%d conn=%s fetched\n", 1702 op->o_log_prefix, ncandidates, buf ); 1703 } 1704 } 1705 1706 return mc; 1707} 1708 1709void 1710meta_back_release_conn_lock( 1711 metainfo_t *mi, 1712 metaconn_t *mc, 1713 int dolock ) 1714{ 1715 assert( mc != NULL ); 1716 1717 if ( dolock ) { 1718 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 1719 } 1720 assert( mc->mc_refcnt > 0 ); 1721 mc->mc_refcnt--; 1722 /* NOTE: the connection is removed if either it is tainted 1723 * or if it is shared and no one else is using it. This needs 1724 * to occur because for intrinsic reasons cached connections 1725 * that are not privileged would live forever and pollute 1726 * the connection space (and eat up resources). Maybe this 1727 * should be configurable... */ 1728 if ( LDAP_BACK_CONN_TAINTED( mc ) || !LDAP_BACK_CONN_CACHED( mc ) ) { 1729#if META_BACK_PRINT_CONNTREE > 0 1730 meta_back_print_conntree( mi, ">>> meta_back_release_conn" ); 1731#endif /* META_BACK_PRINT_CONNTREE */ 1732 1733 if ( LDAP_BACK_PCONN_ISPRIV( mc ) ) { 1734 if ( mc->mc_q.tqe_prev != NULL ) { 1735 assert( LDAP_BACK_CONN_CACHED( mc ) ); 1736 assert( mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num > 0 ); 1737 LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_priv, mc, mc_q ); 1738 mi->mi_conn_priv[ LDAP_BACK_CONN2PRIV( mc ) ].mic_num--; 1739 LDAP_TAILQ_ENTRY_INIT( mc, mc_q ); 1740 1741 } else { 1742 assert( !LDAP_BACK_CONN_CACHED( mc ) ); 1743 } 1744 1745 } else if ( LDAP_BACK_CONN_CACHED( mc ) ) { 1746 metaconn_t *tmpmc; 1747 1748 tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, 1749 ( caddr_t )mc, meta_back_conndnmc_cmp ); 1750 1751 /* Overparanoid, but useful... */ 1752 assert( tmpmc == NULL || tmpmc == mc ); 1753 } 1754 1755 LDAP_BACK_CONN_CACHED_CLEAR( mc ); 1756 1757#if META_BACK_PRINT_CONNTREE > 0 1758 meta_back_print_conntree( mi, "<<< meta_back_release_conn" ); 1759#endif /* META_BACK_PRINT_CONNTREE */ 1760 1761 if ( mc->mc_refcnt == 0 ) { 1762 meta_back_conn_free( mc ); 1763 mc = NULL; 1764 } 1765 } 1766 1767 if ( mc != NULL && LDAP_BACK_CONN_BINDING( mc ) ) { 1768 LDAP_BACK_CONN_BINDING_CLEAR( mc ); 1769 } 1770 1771 if ( dolock ) { 1772 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 1773 } 1774} 1775 1776void 1777meta_back_quarantine( 1778 Operation *op, 1779 SlapReply *rs, 1780 int candidate ) 1781{ 1782 metainfo_t *mi = (metainfo_t *)op->o_bd->be_private; 1783 metatarget_t *mt = mi->mi_targets[ candidate ]; 1784 1785 slap_retry_info_t *ri = &mt->mt_quarantine; 1786 1787 ldap_pvt_thread_mutex_lock( &mt->mt_quarantine_mutex ); 1788 1789 if ( rs->sr_err == LDAP_UNAVAILABLE ) { 1790 time_t new_last = slap_get_time(); 1791 1792 switch ( mt->mt_isquarantined ) { 1793 case LDAP_BACK_FQ_NO: 1794 if ( ri->ri_last == new_last ) { 1795 goto done; 1796 } 1797 1798 Debug( LDAP_DEBUG_ANY, 1799 "%s meta_back_quarantine[%d]: enter.\n", 1800 op->o_log_prefix, candidate, 0 ); 1801 1802 ri->ri_idx = 0; 1803 ri->ri_count = 0; 1804 break; 1805 1806 case LDAP_BACK_FQ_RETRYING: 1807 if ( LogTest( LDAP_DEBUG_ANY ) ) { 1808 char buf[ SLAP_TEXT_BUFLEN ]; 1809 1810 snprintf( buf, sizeof( buf ), 1811 "meta_back_quarantine[%d]: block #%d try #%d failed", 1812 candidate, ri->ri_idx, ri->ri_count ); 1813 Debug( LDAP_DEBUG_ANY, "%s %s.\n", 1814 op->o_log_prefix, buf, 0 ); 1815 } 1816 1817 ++ri->ri_count; 1818 if ( ri->ri_num[ ri->ri_idx ] != SLAP_RETRYNUM_FOREVER 1819 && ri->ri_count == ri->ri_num[ ri->ri_idx ] ) 1820 { 1821 ri->ri_count = 0; 1822 ++ri->ri_idx; 1823 } 1824 break; 1825 1826 default: 1827 break; 1828 } 1829 1830 mt->mt_isquarantined = LDAP_BACK_FQ_YES; 1831 ri->ri_last = new_last; 1832 1833 } else if ( mt->mt_isquarantined == LDAP_BACK_FQ_RETRYING ) { 1834 Debug( LDAP_DEBUG_ANY, 1835 "%s meta_back_quarantine[%d]: exit.\n", 1836 op->o_log_prefix, candidate, 0 ); 1837 1838 if ( mi->mi_quarantine_f ) { 1839 (void)mi->mi_quarantine_f( mi, candidate, 1840 mi->mi_quarantine_p ); 1841 } 1842 1843 ri->ri_count = 0; 1844 ri->ri_idx = 0; 1845 mt->mt_isquarantined = LDAP_BACK_FQ_NO; 1846 } 1847 1848done:; 1849 ldap_pvt_thread_mutex_unlock( &mt->mt_quarantine_mutex ); 1850} 1851 1852