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