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