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