1 /* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/bind.c,v 1.95.2.15 2008/04/14 21:24:34 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 #undef ldap_debug /* silence a warning in ldap-int.h */ 37 #include "../../../libraries/libldap/ldap-int.h" 38 39 #include "lutil_ldap.h" 40 41 static int 42 meta_back_proxy_authz_bind( 43 metaconn_t *mc, 44 int candidate, 45 Operation *op, 46 SlapReply *rs, 47 ldap_back_send_t sendok ); 48 49 static int 50 meta_back_single_bind( 51 Operation *op, 52 SlapReply *rs, 53 metaconn_t *mc, 54 int candidate ); 55 56 int 57 meta_back_bind( Operation *op, SlapReply *rs ) 58 { 59 metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; 60 metaconn_t *mc = NULL; 61 62 int rc = LDAP_OTHER, 63 i, 64 gotit = 0, 65 isroot = 0; 66 67 SlapReply *candidates; 68 69 rs->sr_err = LDAP_SUCCESS; 70 71 Debug( LDAP_DEBUG_ARGS, "%s meta_back_bind: dn=\"%s\".\n", 72 op->o_log_prefix, op->o_req_dn.bv_val, 0 ); 73 74 /* the test on the bind method should be superfluous */ 75 switch ( be_rootdn_bind( op, rs ) ) { 76 case LDAP_SUCCESS: 77 if ( META_BACK_DEFER_ROOTDN_BIND( mi ) ) { 78 /* frontend will return success */ 79 return rs->sr_err; 80 } 81 82 isroot = 1; 83 /* fallthru */ 84 85 case SLAP_CB_CONTINUE: 86 break; 87 88 default: 89 /* be_rootdn_bind() sent result */ 90 return rs->sr_err; 91 } 92 93 /* we need meta_back_getconn() not send result even on error, 94 * because we want to intercept the error and make it 95 * invalidCredentials */ 96 mc = meta_back_getconn( op, rs, NULL, LDAP_BACK_BIND_DONTSEND ); 97 if ( !mc ) { 98 if ( LogTest( LDAP_DEBUG_ANY ) ) { 99 char buf[ SLAP_TEXT_BUFLEN ]; 100 101 snprintf( buf, sizeof( buf ), 102 "meta_back_bind: no target " 103 "for dn \"%s\" (%d%s%s).", 104 op->o_req_dn.bv_val, rs->sr_err, 105 rs->sr_text ? ". " : "", 106 rs->sr_text ? rs->sr_text : "" ); 107 Debug( LDAP_DEBUG_ANY, 108 "%s %s\n", 109 op->o_log_prefix, buf, 0 ); 110 } 111 112 /* FIXME: there might be cases where we don't want 113 * to map the error onto invalidCredentials */ 114 switch ( rs->sr_err ) { 115 case LDAP_NO_SUCH_OBJECT: 116 case LDAP_UNWILLING_TO_PERFORM: 117 rs->sr_err = LDAP_INVALID_CREDENTIALS; 118 rs->sr_text = NULL; 119 break; 120 } 121 send_ldap_result( op, rs ); 122 return rs->sr_err; 123 } 124 125 candidates = meta_back_candidates_get( op ); 126 127 /* 128 * Each target is scanned ... 129 */ 130 mc->mc_authz_target = META_BOUND_NONE; 131 for ( i = 0; i < mi->mi_ntargets; i++ ) { 132 metatarget_t *mt = mi->mi_targets[ i ]; 133 int lerr; 134 135 /* 136 * Skip non-candidates 137 */ 138 if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) { 139 continue; 140 } 141 142 if ( gotit == 0 ) { 143 /* set rc to LDAP_SUCCESS only if at least 144 * one candidate has been tried */ 145 rc = LDAP_SUCCESS; 146 gotit = 1; 147 148 } else if ( !isroot ) { 149 /* 150 * A bind operation is expected to have 151 * ONE CANDIDATE ONLY! 152 */ 153 Debug( LDAP_DEBUG_ANY, 154 "### %s meta_back_bind: more than one" 155 " candidate selected...\n", 156 op->o_log_prefix, 0, 0 ); 157 } 158 159 if ( isroot ) { 160 if ( mt->mt_idassert_authmethod == LDAP_AUTH_NONE 161 || BER_BVISNULL( &mt->mt_idassert_authcDN ) ) 162 { 163 metasingleconn_t *msc = &mc->mc_conns[ i ]; 164 165 /* skip the target if no pseudorootdn is provided */ 166 if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) { 167 ch_free( msc->msc_bound_ndn.bv_val ); 168 BER_BVZERO( &msc->msc_bound_ndn ); 169 } 170 171 if ( !BER_BVISNULL( &msc->msc_cred ) ) { 172 /* destroy sensitive data */ 173 memset( msc->msc_cred.bv_val, 0, 174 msc->msc_cred.bv_len ); 175 ch_free( msc->msc_cred.bv_val ); 176 BER_BVZERO( &msc->msc_cred ); 177 } 178 179 continue; 180 } 181 182 183 (void)meta_back_proxy_authz_bind( mc, i, op, rs, LDAP_BACK_DONTSEND ); 184 lerr = rs->sr_err; 185 186 } else { 187 lerr = meta_back_single_bind( op, rs, mc, i ); 188 } 189 190 if ( lerr != LDAP_SUCCESS ) { 191 rc = rs->sr_err = lerr; 192 193 /* FIXME: in some cases (e.g. unavailable) 194 * do not assume it's not candidate; rather 195 * mark this as an error to be eventually 196 * reported to client */ 197 META_CANDIDATE_CLEAR( &candidates[ i ] ); 198 break; 199 } 200 } 201 202 /* must re-insert if local DN changed as result of bind */ 203 if ( rc == LDAP_SUCCESS ) { 204 if ( isroot ) { 205 mc->mc_authz_target = META_BOUND_ALL; 206 } 207 208 if ( !LDAP_BACK_PCONN_ISPRIV( mc ) 209 && !dn_match( &op->o_req_ndn, &mc->mc_local_ndn ) ) 210 { 211 int lerr; 212 213 /* wait for all other ops to release the connection */ 214 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 215 assert( mc->mc_refcnt == 1 ); 216 #if META_BACK_PRINT_CONNTREE > 0 217 meta_back_print_conntree( mi, ">>> meta_back_bind" ); 218 #endif /* META_BACK_PRINT_CONNTREE */ 219 220 /* delete all cached connections with the current connection */ 221 if ( LDAP_BACK_SINGLECONN( mi ) ) { 222 metaconn_t *tmpmc; 223 224 while ( ( tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conn_cmp ) ) != NULL ) 225 { 226 Debug( LDAP_DEBUG_TRACE, 227 "=>meta_back_bind: destroying conn %ld (refcnt=%u)\n", 228 LDAP_BACK_PCONN_ID( mc ), mc->mc_refcnt, 0 ); 229 230 if ( tmpmc->mc_refcnt != 0 ) { 231 /* taint it */ 232 LDAP_BACK_CONN_TAINTED_SET( tmpmc ); 233 234 } else { 235 /* 236 * Needs a test because the handler may be corrupted, 237 * and calling ldap_unbind on a corrupted header results 238 * in a segmentation fault 239 */ 240 meta_back_conn_free( tmpmc ); 241 } 242 } 243 } 244 245 ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn ); 246 lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc, 247 meta_back_conndn_cmp, meta_back_conndn_dup ); 248 #if META_BACK_PRINT_CONNTREE > 0 249 meta_back_print_conntree( mi, "<<< meta_back_bind" ); 250 #endif /* META_BACK_PRINT_CONNTREE */ 251 if ( lerr == 0 ) { 252 #if 0 253 /* NOTE: a connection cannot be privileged 254 * and be in the avl tree at the same time 255 */ 256 if ( isroot ) { 257 LDAP_BACK_CONN_ISPRIV_SET( mc ); 258 LDAP_BACK_PCONN_SET( mc, op ); 259 } 260 #endif 261 LDAP_BACK_CONN_CACHED_SET( mc ); 262 263 } else { 264 LDAP_BACK_CONN_CACHED_CLEAR( mc ); 265 } 266 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 267 } 268 } 269 270 if ( mc != NULL ) { 271 meta_back_release_conn( mi, mc ); 272 } 273 274 /* 275 * rc is LDAP_SUCCESS if at least one bind succeeded, 276 * err is the last error that occurred during a bind; 277 * if at least (and at most?) one bind succeeds, fine. 278 */ 279 if ( rc != LDAP_SUCCESS ) { 280 281 /* 282 * deal with bind failure ... 283 */ 284 285 /* 286 * no target was found within the naming context, 287 * so bind must fail with invalid credentials 288 */ 289 if ( rs->sr_err == LDAP_SUCCESS && gotit == 0 ) { 290 rs->sr_err = LDAP_INVALID_CREDENTIALS; 291 } else { 292 rs->sr_err = slap_map_api2result( rs ); 293 } 294 send_ldap_result( op, rs ); 295 return rs->sr_err; 296 297 } 298 299 return LDAP_SUCCESS; 300 } 301 302 static int 303 meta_back_bind_op_result( 304 Operation *op, 305 SlapReply *rs, 306 metaconn_t *mc, 307 int candidate, 308 int msgid, 309 ldap_back_send_t sendok ) 310 { 311 metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; 312 metatarget_t *mt = mi->mi_targets[ candidate ]; 313 metasingleconn_t *msc = &mc->mc_conns[ candidate ]; 314 LDAPMessage *res; 315 struct timeval tv; 316 int rc; 317 int nretries = mt->mt_nretries; 318 char buf[ SLAP_TEXT_BUFLEN ]; 319 320 Debug( LDAP_DEBUG_TRACE, 321 ">>> %s meta_back_bind_op_result[%d]\n", 322 op->o_log_prefix, candidate, 0 ); 323 324 /* make sure this is clean */ 325 assert( rs->sr_ctrls == NULL ); 326 327 if ( rs->sr_err == LDAP_SUCCESS ) { 328 time_t stoptime = (time_t)(-1), 329 timeout; 330 int timeout_err = op->o_protocol >= LDAP_VERSION3 ? 331 LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; 332 const char *timeout_text = "Operation timed out"; 333 slap_op_t opidx = slap_req2op( op->o_tag ); 334 335 /* since timeout is not specified, compute and use 336 * the one specific to the ongoing operation */ 337 if ( opidx == LDAP_REQ_SEARCH ) { 338 if ( op->ors_tlimit <= 0 ) { 339 timeout = 0; 340 341 } else { 342 timeout = op->ors_tlimit; 343 timeout_err = LDAP_TIMELIMIT_EXCEEDED; 344 timeout_text = NULL; 345 } 346 347 } else { 348 timeout = mt->mt_timeout[ opidx ]; 349 } 350 351 /* better than nothing :) */ 352 if ( timeout == 0 ) { 353 if ( mi->mi_idle_timeout ) { 354 timeout = mi->mi_idle_timeout; 355 356 } else if ( mi->mi_conn_ttl ) { 357 timeout = mi->mi_conn_ttl; 358 } 359 } 360 361 if ( timeout ) { 362 stoptime = op->o_time + timeout; 363 } 364 365 LDAP_BACK_TV_SET( &tv ); 366 367 /* 368 * handle response!!! 369 */ 370 retry:; 371 rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ); 372 switch ( rc ) { 373 case 0: 374 if ( nretries != META_RETRY_NEVER 375 || ( timeout && slap_get_time() <= stoptime ) ) 376 { 377 ldap_pvt_thread_yield(); 378 if ( nretries > 0 ) { 379 nretries--; 380 } 381 tv = mt->mt_bind_timeout; 382 goto retry; 383 } 384 385 /* don't let anyone else use this handler, 386 * because there's a pending bind that will not 387 * be acknowledged */ 388 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 389 assert( LDAP_BACK_CONN_BINDING( msc ) ); 390 391 #ifdef DEBUG_205 392 Debug( LDAP_DEBUG_ANY, "### %s meta_back_bind_op_result ldap_unbind_ext[%d] ld=%p\n", 393 op->o_log_prefix, candidate, (void *)msc->msc_ld ); 394 #endif /* DEBUG_205 */ 395 396 meta_clear_one_candidate( op, mc, candidate ); 397 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 398 399 rs->sr_err = timeout_err; 400 rs->sr_text = timeout_text; 401 break; 402 403 case -1: 404 ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER, 405 &rs->sr_err ); 406 407 snprintf( buf, sizeof( buf ), 408 "err=%d (%s) nretries=%d", 409 rs->sr_err, ldap_err2string( rs->sr_err ), nretries ); 410 Debug( LDAP_DEBUG_ANY, 411 "### %s meta_back_bind_op_result[%d]: %s.\n", 412 op->o_log_prefix, candidate, buf ); 413 break; 414 415 default: 416 /* only touch when activity actually took place... */ 417 if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) { 418 msc->msc_time = op->o_time; 419 } 420 421 /* FIXME: matched? referrals? response controls? */ 422 rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err, 423 NULL, NULL, NULL, NULL, 1 ); 424 if ( rc != LDAP_SUCCESS ) { 425 rs->sr_err = rc; 426 } 427 break; 428 } 429 } 430 431 rs->sr_err = slap_map_api2result( rs ); 432 433 Debug( LDAP_DEBUG_TRACE, 434 "<<< %s meta_back_bind_op_result[%d] err=%d\n", 435 op->o_log_prefix, candidate, rs->sr_err ); 436 437 return rs->sr_err; 438 } 439 440 /* 441 * meta_back_single_bind 442 * 443 * attempts to perform a bind with creds 444 */ 445 static int 446 meta_back_single_bind( 447 Operation *op, 448 SlapReply *rs, 449 metaconn_t *mc, 450 int candidate ) 451 { 452 metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; 453 metatarget_t *mt = mi->mi_targets[ candidate ]; 454 struct berval mdn = BER_BVNULL; 455 metasingleconn_t *msc = &mc->mc_conns[ candidate ]; 456 int msgid; 457 dncookie dc; 458 struct berval save_o_dn; 459 int save_o_do_not_cache; 460 LDAPControl **ctrls = NULL; 461 462 if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) { 463 ch_free( msc->msc_bound_ndn.bv_val ); 464 BER_BVZERO( &msc->msc_bound_ndn ); 465 } 466 467 if ( !BER_BVISNULL( &msc->msc_cred ) ) { 468 /* destroy sensitive data */ 469 memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); 470 ch_free( msc->msc_cred.bv_val ); 471 BER_BVZERO( &msc->msc_cred ); 472 } 473 474 /* 475 * Rewrite the bind dn if needed 476 */ 477 dc.target = mt; 478 dc.conn = op->o_conn; 479 dc.rs = rs; 480 dc.ctx = "bindDN"; 481 482 if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) { 483 rs->sr_text = "DN rewrite error"; 484 rs->sr_err = LDAP_OTHER; 485 return rs->sr_err; 486 } 487 488 /* don't add proxyAuthz; set the bindDN */ 489 save_o_dn = op->o_dn; 490 save_o_do_not_cache = op->o_do_not_cache; 491 op->o_do_not_cache = 1; 492 op->o_dn = op->o_req_dn; 493 494 ctrls = op->o_ctrls; 495 rs->sr_err = meta_back_controls_add( op, rs, mc, candidate, &ctrls ); 496 op->o_dn = save_o_dn; 497 op->o_do_not_cache = save_o_do_not_cache; 498 if ( rs->sr_err != LDAP_SUCCESS ) { 499 goto return_results; 500 } 501 502 /* FIXME: this fixes the bind problem right now; we need 503 * to use the asynchronous version to get the "matched" 504 * and more in case of failure ... */ 505 /* FIXME: should we check if at least some of the op->o_ctrls 506 * can/should be passed? */ 507 for (;;) { 508 rs->sr_err = ldap_sasl_bind( msc->msc_ld, mdn.bv_val, 509 LDAP_SASL_SIMPLE, &op->orb_cred, 510 ctrls, NULL, &msgid ); 511 if ( rs->sr_err != LDAP_X_CONNECTING ) { 512 break; 513 } 514 ldap_pvt_thread_yield(); 515 } 516 517 mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); 518 519 meta_back_bind_op_result( op, rs, mc, candidate, msgid, LDAP_BACK_DONTSEND ); 520 if ( rs->sr_err != LDAP_SUCCESS ) { 521 goto return_results; 522 } 523 524 /* If defined, proxyAuthz will be used also when 525 * back-ldap is the authorizing backend; for this 526 * purpose, a successful bind is followed by a 527 * bind with the configured identity assertion */ 528 /* NOTE: use with care */ 529 if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) { 530 meta_back_proxy_authz_bind( mc, candidate, op, rs, LDAP_BACK_SENDERR ); 531 if ( !LDAP_BACK_CONN_ISBOUND( msc ) ) { 532 goto return_results; 533 } 534 goto cache_refresh; 535 } 536 537 ber_bvreplace( &msc->msc_bound_ndn, &op->o_req_ndn ); 538 LDAP_BACK_CONN_ISBOUND_SET( msc ); 539 mc->mc_authz_target = candidate; 540 541 if ( LDAP_BACK_SAVECRED( mi ) ) { 542 if ( !BER_BVISNULL( &msc->msc_cred ) ) { 543 memset( msc->msc_cred.bv_val, 0, 544 msc->msc_cred.bv_len ); 545 } 546 ber_bvreplace( &msc->msc_cred, &op->orb_cred ); 547 ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc ); 548 } 549 550 cache_refresh:; 551 if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED 552 && !BER_BVISEMPTY( &op->o_req_ndn ) ) 553 { 554 ( void )meta_dncache_update_entry( &mi->mi_cache, 555 &op->o_req_ndn, candidate ); 556 } 557 558 return_results:; 559 if ( mdn.bv_val != op->o_req_dn.bv_val ) { 560 free( mdn.bv_val ); 561 } 562 563 if ( META_BACK_TGT_QUARANTINE( mt ) ) { 564 meta_back_quarantine( op, rs, candidate ); 565 } 566 567 return rs->sr_err; 568 } 569 570 /* 571 * meta_back_single_dobind 572 */ 573 int 574 meta_back_single_dobind( 575 Operation *op, 576 SlapReply *rs, 577 metaconn_t **mcp, 578 int candidate, 579 ldap_back_send_t sendok, 580 int nretries, 581 int dolock ) 582 { 583 metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; 584 metatarget_t *mt = mi->mi_targets[ candidate ]; 585 metaconn_t *mc = *mcp; 586 metasingleconn_t *msc = &mc->mc_conns[ candidate ]; 587 static struct berval cred = BER_BVC( "" ); 588 int msgid; 589 590 assert( !LDAP_BACK_CONN_ISBOUND( msc ) ); 591 592 /* NOTE: this obsoletes pseudorootdn */ 593 if ( op->o_conn != NULL && 594 !op->o_do_not_cache && 595 ( BER_BVISNULL( &msc->msc_bound_ndn ) || 596 BER_BVISEMPTY( &msc->msc_bound_ndn ) || 597 ( LDAP_BACK_CONN_ISPRIV( mc ) && dn_match( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN ) ) || 598 ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) ) 599 { 600 (void)meta_back_proxy_authz_bind( mc, candidate, op, rs, sendok ); 601 602 } else { 603 604 /* FIXME: should we check if at least some of the op->o_ctrls 605 * can/should be passed? */ 606 for (;;) { 607 rs->sr_err = ldap_sasl_bind( msc->msc_ld, 608 "", LDAP_SASL_SIMPLE, &cred, 609 NULL, NULL, &msgid ); 610 if ( rs->sr_err != LDAP_X_CONNECTING ) { 611 break; 612 } 613 ldap_pvt_thread_yield(); 614 } 615 616 rs->sr_err = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok ); 617 } 618 619 if ( rs->sr_err != LDAP_SUCCESS ) { 620 if ( dolock ) { 621 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 622 } 623 LDAP_BACK_CONN_BINDING_CLEAR( msc ); 624 if ( META_BACK_ONERR_STOP( mi ) ) { 625 LDAP_BACK_CONN_TAINTED_SET( mc ); 626 meta_back_release_conn_lock( mi, mc, 0 ); 627 *mcp = NULL; 628 } 629 if ( dolock ) { 630 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 631 } 632 } 633 634 if ( META_BACK_TGT_QUARANTINE( mt ) ) { 635 meta_back_quarantine( op, rs, candidate ); 636 } 637 638 return rs->sr_err; 639 } 640 641 /* 642 * meta_back_dobind 643 */ 644 int 645 meta_back_dobind( 646 Operation *op, 647 SlapReply *rs, 648 metaconn_t *mc, 649 ldap_back_send_t sendok ) 650 { 651 metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; 652 653 int bound = 0, 654 i, 655 isroot = 0; 656 657 SlapReply *candidates; 658 659 if ( be_isroot( op ) ) { 660 isroot = 1; 661 } 662 663 Debug( LDAP_DEBUG_TRACE, 664 "%s meta_back_dobind: conn=%ld%s\n", 665 op->o_log_prefix, 666 LDAP_BACK_PCONN_ID( mc ), 667 isroot ? " (isroot)" : "" ); 668 669 /* 670 * all the targets are bound as pseudoroot 671 */ 672 if ( mc->mc_authz_target == META_BOUND_ALL ) { 673 bound = 1; 674 goto done; 675 } 676 677 candidates = meta_back_candidates_get( op ); 678 679 for ( i = 0; i < mi->mi_ntargets; i++ ) { 680 metatarget_t *mt = mi->mi_targets[ i ]; 681 metasingleconn_t *msc = &mc->mc_conns[ i ]; 682 int rc; 683 684 /* 685 * Not a candidate 686 */ 687 if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) { 688 continue; 689 } 690 691 assert( msc->msc_ld != NULL ); 692 693 /* 694 * If the target is already bound it is skipped 695 */ 696 697 retry_binding:; 698 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 699 if ( LDAP_BACK_CONN_ISBOUND( msc ) 700 || ( LDAP_BACK_CONN_ISANON( msc ) 701 && mt->mt_idassert_authmethod == LDAP_AUTH_NONE ) ) 702 { 703 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 704 ++bound; 705 continue; 706 707 } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) ) 708 { 709 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 710 ldap_pvt_thread_yield(); 711 goto retry_binding; 712 713 } 714 715 LDAP_BACK_CONN_BINDING_SET( msc ); 716 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 717 718 rc = meta_back_single_dobind( op, rs, &mc, i, 719 LDAP_BACK_DONTSEND, mt->mt_nretries, 1 ); 720 /* 721 * NOTE: meta_back_single_dobind() already retries; 722 * in case of failure, it resets mc... 723 */ 724 if ( rc != LDAP_SUCCESS ) { 725 char buf[ SLAP_TEXT_BUFLEN ]; 726 727 if ( mc == NULL ) { 728 /* meta_back_single_dobind() already sent 729 * response and released connection */ 730 goto send_err; 731 } 732 733 734 if ( rc == LDAP_UNAVAILABLE ) { 735 /* FIXME: meta_back_retry() already re-calls 736 * meta_back_single_dobind() */ 737 if ( meta_back_retry( op, rs, &mc, i, sendok ) ) { 738 goto retry_ok; 739 } 740 741 if ( mc != NULL ) { 742 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 743 LDAP_BACK_CONN_BINDING_CLEAR( msc ); 744 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 745 meta_back_release_conn( mi, mc ); 746 } 747 748 return 0; 749 } 750 751 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 752 LDAP_BACK_CONN_BINDING_CLEAR( msc ); 753 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 754 755 snprintf( buf, sizeof( buf ), 756 "meta_back_dobind[%d]: (%s) err=%d (%s).", 757 i, isroot ? op->o_bd->be_rootdn.bv_val : "anonymous", 758 rc, ldap_err2string( rc ) ); 759 Debug( LDAP_DEBUG_ANY, 760 "%s %s\n", 761 op->o_log_prefix, buf, 0 ); 762 763 /* 764 * null cred bind should always succeed 765 * as anonymous, so a failure means 766 * the target is no longer candidate possibly 767 * due to technical reasons (remote host down?) 768 * so better clear the handle 769 */ 770 /* leave the target candidate, but record the error for later use */ 771 candidates[ i ].sr_err = rc; 772 if ( META_BACK_ONERR_STOP( mi ) ) { 773 bound = 0; 774 goto done; 775 } 776 777 continue; 778 } /* else */ 779 780 retry_ok:; 781 Debug( LDAP_DEBUG_TRACE, 782 "%s meta_back_dobind[%d]: " 783 "(%s)\n", 784 op->o_log_prefix, i, 785 isroot ? op->o_bd->be_rootdn.bv_val : "anonymous" ); 786 787 ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); 788 LDAP_BACK_CONN_BINDING_CLEAR( msc ); 789 if ( isroot ) { 790 LDAP_BACK_CONN_ISBOUND_SET( msc ); 791 } else { 792 LDAP_BACK_CONN_ISANON_SET( msc ); 793 } 794 ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); 795 ++bound; 796 } 797 798 done:; 799 Debug( LDAP_DEBUG_TRACE, 800 "%s meta_back_dobind: conn=%ld bound=%d\n", 801 op->o_log_prefix, LDAP_BACK_PCONN_ID( mc ), bound ); 802 803 if ( bound == 0 ) { 804 meta_back_release_conn( mi, mc ); 805 806 send_err:; 807 if ( sendok & LDAP_BACK_SENDERR ) { 808 if ( rs->sr_err == LDAP_SUCCESS ) { 809 rs->sr_err = LDAP_BUSY; 810 } 811 send_ldap_result( op, rs ); 812 } 813 814 return 0; 815 } 816 817 return ( bound > 0 ); 818 } 819 820 /* 821 * meta_back_default_rebind 822 * 823 * This is a callback used for chasing referrals using the same 824 * credentials as the original user on this session. 825 */ 826 int 827 meta_back_default_rebind( 828 LDAP *ld, 829 LDAP_CONST char *url, 830 ber_tag_t request, 831 ber_int_t msgid, 832 void *params ) 833 { 834 metasingleconn_t *msc = ( metasingleconn_t * )params; 835 836 return ldap_sasl_bind_s( ld, msc->msc_bound_ndn.bv_val, 837 LDAP_SASL_SIMPLE, &msc->msc_cred, 838 NULL, NULL, NULL ); 839 } 840 841 /* 842 * meta_back_default_urllist 843 * 844 * This is a callback used for mucking with the urllist 845 */ 846 int 847 meta_back_default_urllist( 848 LDAP *ld, 849 LDAPURLDesc **urllist, 850 LDAPURLDesc **url, 851 void *params ) 852 { 853 metatarget_t *mt = (metatarget_t *)params; 854 LDAPURLDesc **urltail; 855 856 if ( urllist == url ) { 857 return LDAP_SUCCESS; 858 } 859 860 for ( urltail = &(*url)->lud_next; *urltail; urltail = &(*urltail)->lud_next ) 861 /* count */ ; 862 863 *urltail = *urllist; 864 *urllist = *url; 865 *url = NULL; 866 867 ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex ); 868 if ( mt->mt_uri ) { 869 ch_free( mt->mt_uri ); 870 } 871 872 ldap_get_option( ld, LDAP_OPT_URI, (void *)&mt->mt_uri ); 873 ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex ); 874 875 return LDAP_SUCCESS; 876 } 877 878 int 879 meta_back_cancel( 880 metaconn_t *mc, 881 Operation *op, 882 SlapReply *rs, 883 ber_int_t msgid, 884 int candidate, 885 ldap_back_send_t sendok ) 886 { 887 metainfo_t *mi = (metainfo_t *)op->o_bd->be_private; 888 889 metatarget_t *mt = mi->mi_targets[ candidate ]; 890 metasingleconn_t *msc = &mc->mc_conns[ candidate ]; 891 892 int rc = LDAP_OTHER; 893 894 Debug( LDAP_DEBUG_TRACE, ">>> %s meta_back_cancel[%d] msgid=%d\n", 895 op->o_log_prefix, candidate, msgid ); 896 897 /* default behavior */ 898 if ( META_BACK_TGT_ABANDON( mt ) ) { 899 rc = ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL ); 900 901 } else if ( META_BACK_TGT_IGNORE( mt ) ) { 902 rc = ldap_pvt_discard( msc->msc_ld, msgid ); 903 904 } else if ( META_BACK_TGT_CANCEL( mt ) ) { 905 rc = ldap_cancel_s( msc->msc_ld, msgid, NULL, NULL ); 906 907 } else { 908 assert( 0 ); 909 } 910 911 Debug( LDAP_DEBUG_TRACE, "<<< %s meta_back_cancel[%d] err=%d\n", 912 op->o_log_prefix, candidate, rc ); 913 914 return rc; 915 } 916 917 918 919 /* 920 * FIXME: error return must be handled in a cleaner way ... 921 */ 922 int 923 meta_back_op_result( 924 metaconn_t *mc, 925 Operation *op, 926 SlapReply *rs, 927 int candidate, 928 ber_int_t msgid, 929 time_t timeout, 930 ldap_back_send_t sendok ) 931 { 932 metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; 933 934 const char *save_text = rs->sr_text, 935 *save_matched = rs->sr_matched; 936 BerVarray save_ref = rs->sr_ref; 937 LDAPControl **save_ctrls = rs->sr_ctrls; 938 void *matched_ctx = NULL; 939 940 char *matched = NULL; 941 char *text = NULL; 942 char **refs = NULL; 943 LDAPControl **ctrls = NULL; 944 945 assert( mc != NULL ); 946 947 rs->sr_text = NULL; 948 rs->sr_matched = NULL; 949 rs->sr_ref = NULL; 950 rs->sr_ctrls = NULL; 951 952 if ( candidate != META_TARGET_NONE ) { 953 metatarget_t *mt = mi->mi_targets[ candidate ]; 954 metasingleconn_t *msc = &mc->mc_conns[ candidate ]; 955 956 #define ERR_OK(err) ((err) == LDAP_SUCCESS || (err) == LDAP_COMPARE_FALSE || (err) == LDAP_COMPARE_TRUE) 957 958 if ( ERR_OK( rs->sr_err ) ) { 959 int rc; 960 struct timeval tv; 961 LDAPMessage *res = NULL; 962 time_t stoptime = (time_t)(-1); 963 int timeout_err = op->o_protocol >= LDAP_VERSION3 ? 964 LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; 965 const char *timeout_text = "Operation timed out"; 966 967 /* if timeout is not specified, compute and use 968 * the one specific to the ongoing operation */ 969 if ( timeout == (time_t)(-1) ) { 970 slap_op_t opidx = slap_req2op( op->o_tag ); 971 972 if ( opidx == SLAP_OP_SEARCH ) { 973 if ( op->ors_tlimit <= 0 ) { 974 timeout = 0; 975 976 } else { 977 timeout = op->ors_tlimit; 978 timeout_err = LDAP_TIMELIMIT_EXCEEDED; 979 timeout_text = NULL; 980 } 981 982 } else { 983 timeout = mt->mt_timeout[ opidx ]; 984 } 985 } 986 987 /* better than nothing :) */ 988 if ( timeout == 0 ) { 989 if ( mi->mi_idle_timeout ) { 990 timeout = mi->mi_idle_timeout; 991 992 } else if ( mi->mi_conn_ttl ) { 993 timeout = mi->mi_conn_ttl; 994 } 995 } 996 997 if ( timeout ) { 998 stoptime = op->o_time + timeout; 999 } 1000 1001 LDAP_BACK_TV_SET( &tv ); 1002 1003 retry:; 1004 rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ); 1005 switch ( rc ) { 1006 case 0: 1007 if ( timeout && slap_get_time() > stoptime ) { 1008 (void)meta_back_cancel( mc, op, rs, msgid, candidate, sendok ); 1009 rs->sr_err = timeout_err; 1010 rs->sr_text = timeout_text; 1011 break; 1012 } 1013 1014 LDAP_BACK_TV_SET( &tv ); 1015 ldap_pvt_thread_yield(); 1016 goto retry; 1017 1018 case -1: 1019 ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, 1020 &rs->sr_err ); 1021 break; 1022 1023 1024 /* otherwise get the result; if it is not 1025 * LDAP_SUCCESS, record it in the reply 1026 * structure (this includes 1027 * LDAP_COMPARE_{TRUE|FALSE}) */ 1028 default: 1029 /* only touch when activity actually took place... */ 1030 if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) { 1031 msc->msc_time = op->o_time; 1032 } 1033 1034 rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err, 1035 &matched, &text, &refs, &ctrls, 1 ); 1036 res = NULL; 1037 rs->sr_text = text; 1038 if ( rc != LDAP_SUCCESS ) { 1039 rs->sr_err = rc; 1040 } 1041 1042 /* RFC 4511: referrals can only appear 1043 * if result code is LDAP_REFERRAL */ 1044 if ( refs != NULL 1045 && refs[ 0 ] != NULL 1046 && refs[ 0 ][ 0 ] != '\0' ) 1047 { 1048 if ( rs->sr_err != LDAP_REFERRAL ) { 1049 Debug( LDAP_DEBUG_ANY, 1050 "%s meta_back_op_result[%d]: " 1051 "got referrals with err=%d\n", 1052 op->o_log_prefix, 1053 candidate, rs->sr_err ); 1054 1055 } else { 1056 int i; 1057 1058 for ( i = 0; refs[ i ] != NULL; i++ ) 1059 /* count */ ; 1060 rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ), 1061 op->o_tmpmemctx ); 1062 for ( i = 0; refs[ i ] != NULL; i++ ) { 1063 ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] ); 1064 } 1065 BER_BVZERO( &rs->sr_ref[ i ] ); 1066 } 1067 1068 } else if ( rs->sr_err == LDAP_REFERRAL ) { 1069 Debug( LDAP_DEBUG_ANY, 1070 "%s meta_back_op_result[%d]: " 1071 "got err=%d with null " 1072 "or empty referrals\n", 1073 op->o_log_prefix, 1074 candidate, rs->sr_err ); 1075 1076 rs->sr_err = LDAP_NO_SUCH_OBJECT; 1077 } 1078 1079 if ( ctrls != NULL ) { 1080 rs->sr_ctrls = ctrls; 1081 } 1082 } 1083 1084 assert( res == NULL ); 1085 } 1086 1087 /* if the error in the reply structure is not 1088 * LDAP_SUCCESS, try to map it from client 1089 * to server error */ 1090 if ( !ERR_OK( rs->sr_err ) ) { 1091 rs->sr_err = slap_map_api2result( rs ); 1092 1093 /* internal ops ( op->o_conn == NULL ) 1094 * must not reply to client */ 1095 if ( op->o_conn && !op->o_do_not_cache && matched ) { 1096 1097 /* record the (massaged) matched 1098 * DN into the reply structure */ 1099 rs->sr_matched = matched; 1100 } 1101 } 1102 1103 if ( META_BACK_TGT_QUARANTINE( mt ) ) { 1104 meta_back_quarantine( op, rs, candidate ); 1105 } 1106 1107 } else { 1108 int i, 1109 err = rs->sr_err; 1110 1111 for ( i = 0; i < mi->mi_ntargets; i++ ) { 1112 metasingleconn_t *msc = &mc->mc_conns[ i ]; 1113 char *xtext = NULL; 1114 char *xmatched = NULL; 1115 1116 rs->sr_err = LDAP_SUCCESS; 1117 1118 ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rs->sr_err ); 1119 if ( rs->sr_err != LDAP_SUCCESS ) { 1120 /* 1121 * better check the type of error. In some cases 1122 * (search ?) it might be better to return a 1123 * success if at least one of the targets gave 1124 * positive result ... 1125 */ 1126 ldap_get_option( msc->msc_ld, 1127 LDAP_OPT_DIAGNOSTIC_MESSAGE, &xtext ); 1128 if ( xtext != NULL && xtext [ 0 ] == '\0' ) { 1129 ldap_memfree( xtext ); 1130 xtext = NULL; 1131 } 1132 1133 ldap_get_option( msc->msc_ld, 1134 LDAP_OPT_MATCHED_DN, &xmatched ); 1135 if ( xmatched != NULL && xmatched[ 0 ] == '\0' ) { 1136 ldap_memfree( xmatched ); 1137 xmatched = NULL; 1138 } 1139 1140 rs->sr_err = slap_map_api2result( rs ); 1141 1142 if ( LogTest( LDAP_DEBUG_ANY ) ) { 1143 char buf[ SLAP_TEXT_BUFLEN ]; 1144 1145 snprintf( buf, sizeof( buf ), 1146 "meta_back_op_result[%d] " 1147 "err=%d text=\"%s\" matched=\"%s\"", 1148 i, rs->sr_err, 1149 ( xtext ? xtext : "" ), 1150 ( xmatched ? xmatched : "" ) ); 1151 Debug( LDAP_DEBUG_ANY, "%s %s.\n", 1152 op->o_log_prefix, buf, 0 ); 1153 } 1154 1155 /* 1156 * FIXME: need to rewrite "match" (need rwinfo) 1157 */ 1158 switch ( rs->sr_err ) { 1159 default: 1160 err = rs->sr_err; 1161 if ( xtext != NULL ) { 1162 if ( text ) { 1163 ldap_memfree( text ); 1164 } 1165 text = xtext; 1166 xtext = NULL; 1167 } 1168 if ( xmatched != NULL ) { 1169 if ( matched ) { 1170 ldap_memfree( matched ); 1171 } 1172 matched = xmatched; 1173 xmatched = NULL; 1174 } 1175 break; 1176 } 1177 1178 if ( xtext ) { 1179 ldap_memfree( xtext ); 1180 } 1181 1182 if ( xmatched ) { 1183 ldap_memfree( xmatched ); 1184 } 1185 } 1186 1187 if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) { 1188 meta_back_quarantine( op, rs, i ); 1189 } 1190 } 1191 1192 if ( err != LDAP_SUCCESS ) { 1193 rs->sr_err = err; 1194 } 1195 } 1196 1197 if ( matched != NULL ) { 1198 struct berval dn, pdn; 1199 1200 ber_str2bv( matched, 0, 0, &dn ); 1201 if ( dnPretty( NULL, &dn, &pdn, op->o_tmpmemctx ) == LDAP_SUCCESS ) { 1202 ldap_memfree( matched ); 1203 matched_ctx = op->o_tmpmemctx; 1204 matched = pdn.bv_val; 1205 } 1206 rs->sr_matched = matched; 1207 } 1208 1209 if ( op->o_conn && 1210 ( ( sendok & LDAP_BACK_SENDOK ) 1211 || ( ( sendok & LDAP_BACK_SENDERR ) && rs->sr_err != LDAP_SUCCESS ) ) ) 1212 { 1213 send_ldap_result( op, rs ); 1214 } 1215 if ( matched ) { 1216 op->o_tmpfree( (char *)rs->sr_matched, matched_ctx ); 1217 } 1218 if ( text ) { 1219 ldap_memfree( text ); 1220 } 1221 if ( rs->sr_ref ) { 1222 op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx ); 1223 rs->sr_ref = NULL; 1224 } 1225 if ( refs ) { 1226 ber_memvfree( (void **)refs ); 1227 } 1228 if ( ctrls ) { 1229 assert( rs->sr_ctrls != NULL ); 1230 ldap_controls_free( ctrls ); 1231 } 1232 1233 rs->sr_text = save_text; 1234 rs->sr_matched = save_matched; 1235 rs->sr_ref = save_ref; 1236 rs->sr_ctrls = save_ctrls; 1237 1238 return( ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err ); 1239 } 1240 1241 /* 1242 * meta_back_proxy_authz_cred() 1243 * 1244 * prepares credentials & method for meta_back_proxy_authz_bind(); 1245 * or, if method is SASL, performs the SASL bind directly. 1246 */ 1247 int 1248 meta_back_proxy_authz_cred( 1249 metaconn_t *mc, 1250 int candidate, 1251 Operation *op, 1252 SlapReply *rs, 1253 ldap_back_send_t sendok, 1254 struct berval *binddn, 1255 struct berval *bindcred, 1256 int *method ) 1257 { 1258 metainfo_t *mi = (metainfo_t *)op->o_bd->be_private; 1259 metatarget_t *mt = mi->mi_targets[ candidate ]; 1260 metasingleconn_t *msc = &mc->mc_conns[ candidate ]; 1261 struct berval ndn; 1262 int dobind = 0; 1263 1264 /* don't proxyAuthz if protocol is not LDAPv3 */ 1265 switch ( mt->mt_version ) { 1266 case LDAP_VERSION3: 1267 break; 1268 1269 case 0: 1270 if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) { 1271 break; 1272 } 1273 /* fall thru */ 1274 1275 default: 1276 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 1277 if ( sendok & LDAP_BACK_SENDERR ) { 1278 send_ldap_result( op, rs ); 1279 } 1280 LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); 1281 goto done; 1282 } 1283 1284 if ( op->o_tag == LDAP_REQ_BIND ) { 1285 ndn = op->o_req_ndn; 1286 1287 } else if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) { 1288 ndn = op->o_conn->c_ndn; 1289 1290 } else { 1291 ndn = op->o_ndn; 1292 } 1293 1294 /* 1295 * FIXME: we need to let clients use proxyAuthz 1296 * otherwise we cannot do symmetric pools of servers; 1297 * we have to live with the fact that a user can 1298 * authorize itself as any ID that is allowed 1299 * by the authzTo directive of the "proxyauthzdn". 1300 */ 1301 /* 1302 * NOTE: current Proxy Authorization specification 1303 * and implementation do not allow proxy authorization 1304 * control to be provided with Bind requests 1305 */ 1306 /* 1307 * if no bind took place yet, but the connection is bound 1308 * and the "proxyauthzdn" is set, then bind as 1309 * "proxyauthzdn" and explicitly add the proxyAuthz 1310 * control to every operation with the dn bound 1311 * to the connection as control value. 1312 */ 1313 1314 /* bind as proxyauthzdn only if no idassert mode 1315 * is requested, or if the client's identity 1316 * is authorized */ 1317 switch ( mt->mt_idassert_mode ) { 1318 case LDAP_BACK_IDASSERT_LEGACY: 1319 if ( !BER_BVISNULL( &ndn ) && !BER_BVISEMPTY( &ndn ) ) { 1320 if ( !BER_BVISNULL( &mt->mt_idassert_authcDN ) && !BER_BVISEMPTY( &mt->mt_idassert_authcDN ) ) 1321 { 1322 *binddn = mt->mt_idassert_authcDN; 1323 *bindcred = mt->mt_idassert_passwd; 1324 dobind = 1; 1325 } 1326 } 1327 break; 1328 1329 default: 1330 /* NOTE: rootdn can always idassert */ 1331 if ( BER_BVISNULL( &ndn ) 1332 && mt->mt_idassert_authz == NULL 1333 && !( mt->mt_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) ) 1334 { 1335 if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) { 1336 rs->sr_err = LDAP_INAPPROPRIATE_AUTH; 1337 if ( sendok & LDAP_BACK_SENDERR ) { 1338 send_ldap_result( op, rs ); 1339 } 1340 LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); 1341 goto done; 1342 1343 } 1344 1345 rs->sr_err = LDAP_SUCCESS; 1346 *binddn = slap_empty_bv; 1347 *bindcred = slap_empty_bv; 1348 break; 1349 1350 } else if ( mt->mt_idassert_authz && !be_isroot( op ) ) { 1351 struct berval authcDN; 1352 1353 if ( BER_BVISNULL( &ndn ) ) { 1354 authcDN = slap_empty_bv; 1355 1356 } else { 1357 authcDN = ndn; 1358 } 1359 rs->sr_err = slap_sasl_matches( op, mt->mt_idassert_authz, 1360 &authcDN, &authcDN ); 1361 if ( rs->sr_err != LDAP_SUCCESS ) { 1362 if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) { 1363 if ( sendok & LDAP_BACK_SENDERR ) { 1364 send_ldap_result( op, rs ); 1365 } 1366 LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); 1367 goto done; 1368 } 1369 1370 rs->sr_err = LDAP_SUCCESS; 1371 *binddn = slap_empty_bv; 1372 *bindcred = slap_empty_bv; 1373 break; 1374 } 1375 } 1376 1377 *binddn = mt->mt_idassert_authcDN; 1378 *bindcred = mt->mt_idassert_passwd; 1379 dobind = 1; 1380 break; 1381 } 1382 1383 if ( dobind && mt->mt_idassert_authmethod == LDAP_AUTH_SASL ) { 1384 #ifdef HAVE_CYRUS_SASL 1385 void *defaults = NULL; 1386 struct berval authzID = BER_BVNULL; 1387 int freeauthz = 0; 1388 1389 /* if SASL supports native authz, prepare for it */ 1390 if ( ( !op->o_do_not_cache || !op->o_is_auth_check ) && 1391 ( mt->mt_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) ) 1392 { 1393 switch ( mt->mt_idassert_mode ) { 1394 case LDAP_BACK_IDASSERT_OTHERID: 1395 case LDAP_BACK_IDASSERT_OTHERDN: 1396 authzID = mt->mt_idassert_authzID; 1397 break; 1398 1399 case LDAP_BACK_IDASSERT_ANONYMOUS: 1400 BER_BVSTR( &authzID, "dn:" ); 1401 break; 1402 1403 case LDAP_BACK_IDASSERT_SELF: 1404 if ( BER_BVISNULL( &ndn ) ) { 1405 /* connection is not authc'd, so don't idassert */ 1406 BER_BVSTR( &authzID, "dn:" ); 1407 break; 1408 } 1409 authzID.bv_len = STRLENOF( "dn:" ) + ndn.bv_len; 1410 authzID.bv_val = slap_sl_malloc( authzID.bv_len + 1, op->o_tmpmemctx ); 1411 AC_MEMCPY( authzID.bv_val, "dn:", STRLENOF( "dn:" ) ); 1412 AC_MEMCPY( authzID.bv_val + STRLENOF( "dn:" ), 1413 ndn.bv_val, ndn.bv_len + 1 ); 1414 freeauthz = 1; 1415 break; 1416 1417 default: 1418 break; 1419 } 1420 } 1421 1422 if ( mt->mt_idassert_secprops != NULL ) { 1423 rs->sr_err = ldap_set_option( msc->msc_ld, 1424 LDAP_OPT_X_SASL_SECPROPS, 1425 (void *)mt->mt_idassert_secprops ); 1426 1427 if ( rs->sr_err != LDAP_OPT_SUCCESS ) { 1428 rs->sr_err = LDAP_OTHER; 1429 if ( sendok & LDAP_BACK_SENDERR ) { 1430 send_ldap_result( op, rs ); 1431 } 1432 LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); 1433 goto done; 1434 } 1435 } 1436 1437 defaults = lutil_sasl_defaults( msc->msc_ld, 1438 mt->mt_idassert_sasl_mech.bv_val, 1439 mt->mt_idassert_sasl_realm.bv_val, 1440 mt->mt_idassert_authcID.bv_val, 1441 mt->mt_idassert_passwd.bv_val, 1442 authzID.bv_val ); 1443 if ( defaults == NULL ) { 1444 rs->sr_err = LDAP_OTHER; 1445 LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); 1446 if ( sendok & LDAP_BACK_SENDERR ) { 1447 send_ldap_result( op, rs ); 1448 } 1449 goto done; 1450 } 1451 1452 rs->sr_err = ldap_sasl_interactive_bind_s( msc->msc_ld, binddn->bv_val, 1453 mt->mt_idassert_sasl_mech.bv_val, NULL, NULL, 1454 LDAP_SASL_QUIET, lutil_sasl_interact, 1455 defaults ); 1456 1457 rs->sr_err = slap_map_api2result( rs ); 1458 if ( rs->sr_err != LDAP_SUCCESS ) { 1459 LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); 1460 if ( sendok & LDAP_BACK_SENDERR ) { 1461 send_ldap_result( op, rs ); 1462 } 1463 1464 } else { 1465 LDAP_BACK_CONN_ISBOUND_SET( msc ); 1466 } 1467 1468 lutil_sasl_freedefs( defaults ); 1469 if ( freeauthz ) { 1470 slap_sl_free( authzID.bv_val, op->o_tmpmemctx ); 1471 } 1472 1473 goto done; 1474 #endif /* HAVE_CYRUS_SASL */ 1475 } 1476 1477 *method = mt->mt_idassert_authmethod; 1478 switch ( mt->mt_idassert_authmethod ) { 1479 case LDAP_AUTH_NONE: 1480 BER_BVSTR( binddn, "" ); 1481 BER_BVSTR( bindcred, "" ); 1482 /* fallthru */ 1483 1484 case LDAP_AUTH_SIMPLE: 1485 break; 1486 1487 default: 1488 /* unsupported! */ 1489 LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); 1490 rs->sr_err = LDAP_AUTH_METHOD_NOT_SUPPORTED; 1491 if ( sendok & LDAP_BACK_SENDERR ) { 1492 send_ldap_result( op, rs ); 1493 } 1494 break; 1495 } 1496 1497 done:; 1498 return rs->sr_err; 1499 } 1500 1501 static int 1502 meta_back_proxy_authz_bind( metaconn_t *mc, int candidate, Operation *op, SlapReply *rs, ldap_back_send_t sendok ) 1503 { 1504 metainfo_t *mi = (metainfo_t *)op->o_bd->be_private; 1505 metatarget_t *mt = mi->mi_targets[ candidate ]; 1506 metasingleconn_t *msc = &mc->mc_conns[ candidate ]; 1507 struct berval binddn = BER_BVC( "" ), 1508 cred = BER_BVC( "" ); 1509 int method = LDAP_AUTH_NONE, 1510 rc; 1511 1512 rc = meta_back_proxy_authz_cred( mc, candidate, op, rs, sendok, &binddn, &cred, &method ); 1513 if ( rc == LDAP_SUCCESS && !LDAP_BACK_CONN_ISBOUND( msc ) ) { 1514 int msgid; 1515 1516 switch ( method ) { 1517 case LDAP_AUTH_NONE: 1518 case LDAP_AUTH_SIMPLE: 1519 for (;;) { 1520 rs->sr_err = ldap_sasl_bind( msc->msc_ld, 1521 binddn.bv_val, LDAP_SASL_SIMPLE, 1522 &cred, NULL, NULL, &msgid ); 1523 if ( rs->sr_err != LDAP_X_CONNECTING ) { 1524 break; 1525 } 1526 ldap_pvt_thread_yield(); 1527 } 1528 rc = meta_back_bind_op_result( op, rs, mc, candidate, msgid, sendok ); 1529 if ( rc == LDAP_SUCCESS ) { 1530 /* set rebind stuff in case of successful proxyAuthz bind, 1531 * so that referral chasing is attempted using the right 1532 * identity */ 1533 LDAP_BACK_CONN_ISBOUND_SET( msc ); 1534 ber_bvreplace( &msc->msc_bound_ndn, &binddn ); 1535 1536 if ( LDAP_BACK_SAVECRED( mi ) ) { 1537 if ( !BER_BVISNULL( &msc->msc_cred ) ) { 1538 memset( msc->msc_cred.bv_val, 0, 1539 msc->msc_cred.bv_len ); 1540 } 1541 ber_bvreplace( &msc->msc_cred, &cred ); 1542 ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc ); 1543 } 1544 } 1545 break; 1546 1547 default: 1548 assert( 0 ); 1549 break; 1550 } 1551 } 1552 1553 return LDAP_BACK_CONN_ISBOUND( msc ); 1554 } 1555 1556 /* 1557 * Add controls; 1558 * 1559 * if any needs to be added, it is prepended to existing ones, 1560 * in a newly allocated array. The companion function 1561 * mi->mi_ldap_extra->controls_free() must be used to restore the original 1562 * status of op->o_ctrls. 1563 */ 1564 int 1565 meta_back_controls_add( 1566 Operation *op, 1567 SlapReply *rs, 1568 metaconn_t *mc, 1569 int candidate, 1570 LDAPControl ***pctrls ) 1571 { 1572 metainfo_t *mi = (metainfo_t *)op->o_bd->be_private; 1573 metatarget_t *mt = mi->mi_targets[ candidate ]; 1574 metasingleconn_t *msc = &mc->mc_conns[ candidate ]; 1575 1576 LDAPControl **ctrls = NULL; 1577 /* set to the maximum number of controls this backend can add */ 1578 LDAPControl c[ 2 ] = { 0 }; 1579 int n = 0, i, j1 = 0, j2 = 0; 1580 1581 *pctrls = NULL; 1582 1583 rs->sr_err = LDAP_SUCCESS; 1584 1585 /* don't add controls if protocol is not LDAPv3 */ 1586 switch ( mt->mt_version ) { 1587 case LDAP_VERSION3: 1588 break; 1589 1590 case 0: 1591 if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) { 1592 break; 1593 } 1594 /* fall thru */ 1595 1596 default: 1597 goto done; 1598 } 1599 1600 /* put controls that go __before__ existing ones here */ 1601 1602 /* proxyAuthz for identity assertion */ 1603 switch ( mi->mi_ldap_extra->proxy_authz_ctrl( op, rs, &msc->msc_bound_ndn, 1604 mt->mt_version, &mt->mt_idassert, &c[ j1 ] ) ) 1605 { 1606 case SLAP_CB_CONTINUE: 1607 break; 1608 1609 case LDAP_SUCCESS: 1610 j1++; 1611 break; 1612 1613 default: 1614 goto done; 1615 } 1616 1617 /* put controls that go __after__ existing ones here */ 1618 1619 #ifdef SLAP_CONTROL_X_SESSION_TRACKING 1620 /* session tracking */ 1621 if ( META_BACK_TGT_ST_REQUEST( mt ) ) { 1622 switch ( slap_ctrl_session_tracking_request_add( op, rs, &c[ j1 + j2 ] ) ) { 1623 case SLAP_CB_CONTINUE: 1624 break; 1625 1626 case LDAP_SUCCESS: 1627 j2++; 1628 break; 1629 1630 default: 1631 goto done; 1632 } 1633 } 1634 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */ 1635 1636 if ( rs->sr_err == SLAP_CB_CONTINUE ) { 1637 rs->sr_err = LDAP_SUCCESS; 1638 } 1639 1640 /* if nothing to do, just bail out */ 1641 if ( j1 == 0 && j2 == 0 ) { 1642 goto done; 1643 } 1644 1645 assert( j1 + j1 <= sizeof( c )/sizeof(LDAPControl) ); 1646 1647 if ( op->o_ctrls ) { 1648 for ( n = 0; op->o_ctrls[ n ]; n++ ) 1649 /* just count ctrls */ ; 1650 } 1651 1652 ctrls = op->o_tmpalloc( (n + j1 + j2 + 1) * sizeof( LDAPControl * ) + ( j1 + j2 ) * sizeof( LDAPControl ), 1653 op->o_tmpmemctx ); 1654 if ( j1 ) { 1655 ctrls[ 0 ] = (LDAPControl *)&ctrls[ n + j1 + j2 + 1 ]; 1656 *ctrls[ 0 ] = c[ 0 ]; 1657 for ( i = 1; i < j1; i++ ) { 1658 ctrls[ i ] = &ctrls[ 0 ][ i ]; 1659 *ctrls[ i ] = c[ i ]; 1660 } 1661 } 1662 1663 i = 0; 1664 if ( op->o_ctrls ) { 1665 for ( i = 0; op->o_ctrls[ i ]; i++ ) { 1666 ctrls[ i + j1 ] = op->o_ctrls[ i ]; 1667 } 1668 } 1669 1670 n += j1; 1671 if ( j2 ) { 1672 ctrls[ n ] = (LDAPControl *)&ctrls[ n + j2 + 1 ] + j1; 1673 *ctrls[ n ] = c[ j1 ]; 1674 for ( i = 1; i < j2; i++ ) { 1675 ctrls[ n + i ] = &ctrls[ n ][ i ]; 1676 *ctrls[ n + i ] = c[ i ]; 1677 } 1678 } 1679 1680 ctrls[ n + j2 ] = NULL; 1681 1682 done:; 1683 if ( ctrls == NULL ) { 1684 ctrls = op->o_ctrls; 1685 } 1686 1687 *pctrls = ctrls; 1688 1689 return rs->sr_err; 1690 } 1691 1692