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