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