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