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