1/* $NetBSD: bind.c,v 1.3 2021/08/14 16:14:59 christos Exp $ */ 2 3/* bind.c - ldap backend bind function */ 4/* $OpenLDAP$ */ 5/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 1999-2021 The OpenLDAP Foundation. 8 * Portions Copyright 2000-2003 Pierangelo Masarati. 9 * Portions Copyright 1999-2003 Howard Chu. 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/* ACKNOWLEDGEMENTS: 21 * This work was initially developed by Howard Chu for inclusion 22 * in OpenLDAP Software and subsequently enhanced by Pierangelo 23 * Masarati. 24 */ 25 26#include <sys/cdefs.h> 27__RCSID("$NetBSD: bind.c,v 1.3 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 37#define AVL_INTERNAL 38#include "slap.h" 39#include "back-ldap.h" 40#include "lutil.h" 41#include "lutil_ldap.h" 42#include "ldap_rq.h" 43 44#define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ "2.16.840.1.113730.3.4.12" 45 46#ifdef LDAP_DEVEL 47#define SLAP_AUTH_DN 1 48#endif 49 50#if LDAP_BACK_PRINT_CONNTREE > 0 51 52static const struct { 53 slap_mask_t f; 54 char c; 55} flagsmap[] = { 56 { LDAP_BACK_FCONN_ISBOUND, 'B' }, 57 { LDAP_BACK_FCONN_ISANON, 'A' }, 58 { LDAP_BACK_FCONN_ISPRIV, 'P' }, 59 { LDAP_BACK_FCONN_ISTLS, 'T' }, 60 { LDAP_BACK_FCONN_BINDING, 'X' }, 61 { LDAP_BACK_FCONN_TAINTED, 'E' }, 62 { LDAP_BACK_FCONN_ABANDON, 'N' }, 63 { LDAP_BACK_FCONN_ISIDASR, 'S' }, 64 { LDAP_BACK_FCONN_CACHED, 'C' }, 65 { 0, '\0' } 66}; 67 68static void 69ldap_back_conn_print( ldapconn_t *lc ) 70{ 71 char buf[ SLAP_TEXT_BUFLEN ]; 72 char fbuf[ sizeof("BAPTIENSC") ]; 73 int i; 74 75 ldap_back_conn2str( &lc->lc_base, buf, sizeof( buf ) ); 76 for ( i = 0; flagsmap[ i ].c != '\0'; i++ ) { 77 if ( lc->lc_lcflags & flagsmap[i].f ) { 78 fbuf[i] = flagsmap[i].c; 79 80 } else { 81 fbuf[i] = '.'; 82 } 83 } 84 fbuf[i] = '\0'; 85 86 fprintf( stderr, "lc=%p %s flags=0x%08x (%s)\n", 87 (void *)lc, buf, lc->lc_lcflags, fbuf ); 88} 89 90 91static char* priv2str[] = { 92 "privileged", 93 "privileged/TLS", 94 "anonymous", 95 "anonymous/TLS", 96 "bind", 97 "bind/TLS", 98 NULL 99}; 100 101void 102ldap_back_print_conntree( ldapinfo_t *li, char *msg ) 103{ 104 int c; 105 106 fprintf( stderr, "========> %s\n", msg ); 107 108 for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) { 109 int i = 0; 110 ldapconn_t *lc; 111 112 fprintf( stderr, " %s[%d]\n", priv2str[ c ], li->li_conn_priv[ c ].lic_num ); 113 114 LDAP_TAILQ_FOREACH( lc, &li->li_conn_priv[ c ].lic_priv, lc_q ) 115 { 116 fprintf( stderr, " [%d] ", i ); 117 ldap_back_conn_print( lc ); 118 i++; 119 } 120 } 121 122 if ( li->li_conninfo.lai_tree == 0 ) { 123 fprintf( stderr, "\t(empty)\n" ); 124 125 } else { 126 TAvlnode *edge = ldap_tavl_end( li->li_conninfo.lai_tree, TAVL_DIR_LEFT ); 127 while ( edge ) { 128 ldap_back_conn_print( (ldapconn_t *)edge->avl_data ); 129 edge = ldap_tavl_next( edge, TAVL_DIR_RIGHT ); 130 } 131 } 132 133 fprintf( stderr, "<======== %s\n", msg ); 134} 135#endif /* LDAP_BACK_PRINT_CONNTREE */ 136 137static int 138ldap_back_freeconn( ldapinfo_t *li, ldapconn_t *lc, int dolock ); 139 140static ldapconn_t * 141ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok, 142 struct berval *binddn, struct berval *bindcred ); 143 144static int 145ldap_back_is_proxy_authz( Operation *op, SlapReply *rs, ldap_back_send_t sendok, 146 struct berval *binddn, struct berval *bindcred ); 147 148static int 149ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs, 150 ldap_back_send_t sendok, struct berval *binddn, struct berval *bindcred ); 151 152static int 153ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs, 154 ldap_back_send_t sendok ); 155 156static int 157ldap_back_conndnlc_cmp( const void *c1, const void *c2 ); 158 159static void 160ldap_back_conn_prune( ldapinfo_t *li ); 161 162static void 163ldap_back_schedule_conn_expiry( ldapinfo_t *li, ldapconn_t *lc ); 164 165ldapconn_t * 166ldap_back_conn_delete( ldapinfo_t *li, ldapconn_t *lc ) 167{ 168 if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) { 169 if ( LDAP_BACK_CONN_CACHED( lc ) ) { 170 assert( lc->lc_q.tqe_prev != NULL ); 171 assert( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num > 0 ); 172 li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num--; 173 LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q ); 174 LDAP_TAILQ_ENTRY_INIT( lc, lc_q ); 175 LDAP_BACK_CONN_CACHED_CLEAR( lc ); 176 177 } else { 178 assert( LDAP_BACK_CONN_TAINTED( lc ) ); 179 assert( lc->lc_q.tqe_prev == NULL ); 180 } 181 182 } else { 183 ldapconn_t *tmplc = NULL; 184 185 if ( LDAP_BACK_CONN_CACHED( lc ) ) { 186 assert( !LDAP_BACK_CONN_TAINTED( lc ) ); 187 tmplc = ldap_tavl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc, 188 ldap_back_conndnlc_cmp ); 189 assert( tmplc == lc ); 190 LDAP_BACK_CONN_CACHED_CLEAR( lc ); 191 } 192 193 assert( LDAP_BACK_CONN_TAINTED( lc ) || tmplc == lc ); 194 } 195 196 return lc; 197} 198 199int 200ldap_back_bind( Operation *op, SlapReply *rs ) 201{ 202 ldapinfo_t *li = (ldapinfo_t *) op->o_bd->be_private; 203 ldapconn_t *lc; 204 205 LDAPControl **ctrls = NULL; 206 struct berval save_o_dn; 207 int save_o_do_not_cache, 208 rc = 0; 209 ber_int_t msgid; 210 ldap_back_send_t retrying = LDAP_BACK_RETRYING; 211 212 /* allow rootdn as a means to auth without the need to actually 213 * contact the proxied DSA */ 214 switch ( be_rootdn_bind( op, rs ) ) { 215 case SLAP_CB_CONTINUE: 216 break; 217 218 default: 219 return rs->sr_err; 220 } 221 222 lc = ldap_back_getconn( op, rs, LDAP_BACK_BIND_SERR, NULL, NULL ); 223 if ( !lc ) { 224 return rs->sr_err; 225 } 226 227 /* we can do (almost) whatever we want with this conn, 228 * because either it's temporary, or it's marked as binding */ 229 if ( !BER_BVISNULL( &lc->lc_bound_ndn ) ) { 230 ch_free( lc->lc_bound_ndn.bv_val ); 231 BER_BVZERO( &lc->lc_bound_ndn ); 232 } 233 if ( !BER_BVISNULL( &lc->lc_cred ) ) { 234 memset( lc->lc_cred.bv_val, 0, lc->lc_cred.bv_len ); 235 ch_free( lc->lc_cred.bv_val ); 236 BER_BVZERO( &lc->lc_cred ); 237 } 238 LDAP_BACK_CONN_ISBOUND_CLEAR( lc ); 239 240 /* don't add proxyAuthz; set the bindDN */ 241 save_o_dn = op->o_dn; 242 save_o_do_not_cache = op->o_do_not_cache; 243 op->o_dn = op->o_req_dn; 244 op->o_do_not_cache = 1; 245 246 ctrls = op->o_ctrls; 247 rc = ldap_back_controls_add( op, rs, lc, &ctrls ); 248 op->o_dn = save_o_dn; 249 op->o_do_not_cache = save_o_do_not_cache; 250 if ( rc != LDAP_SUCCESS ) { 251 send_ldap_result( op, rs ); 252 ldap_back_release_conn( li, lc ); 253 return( rc ); 254 } 255 256retry:; 257 /* method is always LDAP_AUTH_SIMPLE if we got here */ 258 rs->sr_err = ldap_sasl_bind( lc->lc_ld, op->o_req_dn.bv_val, 259 LDAP_SASL_SIMPLE, 260 &op->orb_cred, ctrls, NULL, &msgid ); 261 /* FIXME: should we always retry, or only when piping the bind 262 * in the "override" connection pool? */ 263 rc = ldap_back_op_result( lc, op, rs, msgid, 264 li->li_timeout[ SLAP_OP_BIND ], 265 LDAP_BACK_BIND_SERR | retrying ); 266 if ( rc == LDAP_UNAVAILABLE && retrying ) { 267 retrying &= ~LDAP_BACK_RETRYING; 268 if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_BIND_SERR ) ) { 269 goto retry; 270 } 271 if ( !lc ) 272 return( rc ); 273 } 274 275 ldap_pvt_thread_mutex_lock( &li->li_counter_mutex ); 276 ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_BIND ], 1 ); 277 ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex ); 278 279 ldap_back_controls_free( op, rs, &ctrls ); 280 281 if ( rc == LDAP_SUCCESS ) { 282 op->o_conn->c_authz_cookie = op->o_bd->be_private; 283 284 /* If defined, proxyAuthz will be used also when 285 * back-ldap is the authorizing backend; for this 286 * purpose, after a successful bind the connection 287 * is left for further binds, and further operations 288 * on this client connection will use a default 289 * connection with identity assertion */ 290 /* NOTE: use with care */ 291 if ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) { 292 ldap_back_release_conn( li, lc ); 293 return( rc ); 294 } 295 296 /* rebind is now done inside ldap_back_proxy_authz_bind() 297 * in case of success */ 298 LDAP_BACK_CONN_ISBOUND_SET( lc ); 299 ber_dupbv( &lc->lc_bound_ndn, &op->o_req_ndn ); 300 301 if ( !BER_BVISNULL( &lc->lc_cred ) ) { 302 memset( lc->lc_cred.bv_val, 0, 303 lc->lc_cred.bv_len ); 304 } 305 306 if ( LDAP_BACK_SAVECRED( li ) ) { 307 ber_bvreplace( &lc->lc_cred, &op->orb_cred ); 308 ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc ); 309 310 } else { 311 lc->lc_cred.bv_len = 0; 312 } 313 } 314 315 /* must re-insert if local DN changed as result of bind */ 316 if ( !LDAP_BACK_CONN_ISBOUND( lc ) 317 || ( !dn_match( &op->o_req_ndn, &lc->lc_local_ndn ) 318 && !LDAP_BACK_PCONN_ISPRIV( lc ) ) ) 319 { 320 int lerr = -1; 321 ldapconn_t *tmplc; 322 323 /* wait for all other ops to release the connection */ 324retry_lock:; 325 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); 326 if ( lc->lc_refcnt > 1 ) { 327 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); 328 ldap_pvt_thread_yield(); 329 goto retry_lock; 330 } 331 332#if LDAP_BACK_PRINT_CONNTREE > 0 333 ldap_back_print_conntree( li, ">>> ldap_back_bind" ); 334#endif /* LDAP_BACK_PRINT_CONNTREE */ 335 336 assert( lc->lc_refcnt == 1 ); 337 ldap_back_conn_delete( li, lc ); 338 339 /* delete all cached connections with the current connection */ 340 if ( LDAP_BACK_SINGLECONN( li ) ) { 341 while ( ( tmplc = ldap_tavl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc, ldap_back_conn_cmp ) ) != NULL ) 342 { 343 assert( !LDAP_BACK_PCONN_ISPRIV( lc ) ); 344 Debug( LDAP_DEBUG_TRACE, 345 "=>ldap_back_bind: destroying conn %lu (refcnt=%u)\n", 346 lc->lc_conn->c_connid, lc->lc_refcnt ); 347 348 if ( tmplc->lc_refcnt != 0 ) { 349 /* taint it */ 350 LDAP_BACK_CONN_TAINTED_SET( tmplc ); 351 LDAP_BACK_CONN_CACHED_CLEAR( tmplc ); 352 353 } else { 354 /* 355 * Needs a test because the handler may be corrupted, 356 * and calling ldap_unbind on a corrupted header results 357 * in a segmentation fault 358 */ 359 ldap_back_conn_free( tmplc ); 360 } 361 } 362 } 363 364 if ( LDAP_BACK_CONN_ISBOUND( lc ) ) { 365 ber_bvreplace( &lc->lc_local_ndn, &op->o_req_ndn ); 366 if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) { 367 LDAP_BACK_PCONN_ROOTDN_SET( lc, op ); 368 } 369 lerr = ldap_tavl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc, 370 ldap_back_conndn_cmp, ldap_back_conndn_dup ); 371 } 372 373#if LDAP_BACK_PRINT_CONNTREE > 0 374 ldap_back_print_conntree( li, "<<< ldap_back_bind" ); 375#endif /* LDAP_BACK_PRINT_CONNTREE */ 376 377 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); 378 switch ( lerr ) { 379 case 0: 380 LDAP_BACK_CONN_CACHED_SET( lc ); 381 break; 382 383 case -1: 384 /* duplicate; someone else successfully bound 385 * on the same connection with the same identity; 386 * we can do this because lc_refcnt == 1 */ 387 ldap_back_conn_free( lc ); 388 lc = NULL; 389 } 390 } 391 392 if ( lc != NULL ) { 393 ldap_back_release_conn( li, lc ); 394 } 395 396 return( rc ); 397} 398 399/* 400 * ldap_back_conndn_cmp 401 * 402 * compares two ldapconn_t based on the value of the conn pointer 403 * and of the local DN; used by avl stuff for insert, lookup 404 * and direct delete 405 */ 406int 407ldap_back_conndn_cmp( const void *c1, const void *c2 ) 408{ 409 const ldapconn_t *lc1 = (const ldapconn_t *)c1; 410 const ldapconn_t *lc2 = (const ldapconn_t *)c2; 411 int rc; 412 413 /* If local DNs don't match, it is definitely not a match */ 414 /* For shared sessions, conn is NULL. Only explicitly 415 * bound sessions will have non-NULL conn. 416 */ 417 rc = SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn ); 418 if ( rc == 0 ) { 419 rc = ber_bvcmp( &lc1->lc_local_ndn, &lc2->lc_local_ndn ); 420 } 421 422 return rc; 423} 424 425/* 426 * ldap_back_conndnlc_cmp 427 * 428 * compares two ldapconn_t based on the value of the conn pointer, 429 * the local DN and the lc pointer; used by avl stuff for insert, lookup 430 * and direct delete 431 */ 432static int 433ldap_back_conndnlc_cmp( const void *c1, const void *c2 ) 434{ 435 const ldapconn_t *lc1 = (const ldapconn_t *)c1; 436 const ldapconn_t *lc2 = (const ldapconn_t *)c2; 437 int rc; 438 439 /* If local DNs don't match, it is definitely not a match */ 440 /* For shared sessions, conn is NULL. Only explicitly 441 * bound sessions will have non-NULL conn. 442 */ 443 rc = SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn ); 444 if ( rc == 0 ) { 445 rc = ber_bvcmp( &lc1->lc_local_ndn, &lc2->lc_local_ndn ); 446 if ( rc == 0 ) { 447 rc = SLAP_PTRCMP( lc1, lc2 ); 448 } 449 } 450 451 return rc; 452} 453 454/* 455 * ldap_back_conn_cmp 456 * 457 * compares two ldapconn_t based on the value of the conn pointer; 458 * used by avl stuff for delete of all conns with the same connid 459 */ 460int 461ldap_back_conn_cmp( const void *c1, const void *c2 ) 462{ 463 const ldapconn_t *lc1 = (const ldapconn_t *)c1; 464 const ldapconn_t *lc2 = (const ldapconn_t *)c2; 465 466 /* For shared sessions, conn is NULL. Only explicitly 467 * bound sessions will have non-NULL conn. 468 */ 469 return SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn ); 470} 471 472/* 473 * ldap_back_conndn_dup 474 * 475 * returns -1 in case a duplicate ldapconn_t has been inserted; 476 * used by avl stuff 477 */ 478int 479ldap_back_conndn_dup( void *c1, void *c2 ) 480{ 481 ldapconn_t *lc1 = (ldapconn_t *)c1; 482 ldapconn_t *lc2 = (ldapconn_t *)c2; 483 484 /* Cannot have more than one shared session with same DN */ 485 if ( lc1->lc_conn == lc2->lc_conn && 486 dn_match( &lc1->lc_local_ndn, &lc2->lc_local_ndn ) ) 487 { 488 return -1; 489 } 490 491 return 0; 492} 493 494static int 495ldap_back_freeconn( ldapinfo_t *li, ldapconn_t *lc, int dolock ) 496{ 497 if ( dolock ) { 498 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); 499 } 500 501#if LDAP_BACK_PRINT_CONNTREE > 0 502 ldap_back_print_conntree( li, ">>> ldap_back_freeconn" ); 503#endif /* LDAP_BACK_PRINT_CONNTREE */ 504 505 (void)ldap_back_conn_delete( li, lc ); 506 507 if ( lc->lc_refcnt == 0 ) { 508 ldap_back_conn_free( (void *)lc ); 509 } 510 511#if LDAP_BACK_PRINT_CONNTREE > 0 512 ldap_back_print_conntree( li, "<<< ldap_back_freeconn" ); 513#endif /* LDAP_BACK_PRINT_CONNTREE */ 514 515 if ( dolock ) { 516 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); 517 } 518 519 return 0; 520} 521 522#ifdef HAVE_TLS 523static int 524ldap_back_start_tls( 525 LDAP *ld, 526 int protocol, 527 int *is_tls, 528 const char *url, 529 unsigned flags, 530 int timeout, 531 const char **text ) 532{ 533 int rc = LDAP_SUCCESS; 534 535 /* start TLS ("tls-[try-]{start,propagate}" statements) */ 536 if ( ( LDAP_BACK_USE_TLS_F( flags ) || ( *is_tls && LDAP_BACK_PROPAGATE_TLS_F( flags ) ) ) 537 && !ldap_is_ldaps_url( url ) ) 538 { 539#ifdef SLAP_STARTTLS_ASYNCHRONOUS 540 /* 541 * use asynchronous StartTLS 542 * in case, chase referral (not implemented yet) 543 */ 544 int msgid; 545 546 if ( protocol == 0 ) { 547 ldap_get_option( ld, LDAP_OPT_PROTOCOL_VERSION, 548 (void *)&protocol ); 549 } 550 551 if ( protocol < LDAP_VERSION3 ) { 552 /* we should rather bail out... */ 553 rc = LDAP_UNWILLING_TO_PERFORM; 554 *text = "invalid protocol version"; 555 } 556 557 if ( rc == LDAP_SUCCESS ) { 558 rc = ldap_start_tls( ld, NULL, NULL, &msgid ); 559 } 560 561 if ( rc == LDAP_SUCCESS ) { 562 LDAPMessage *res = NULL; 563 struct timeval tv; 564 565 if ( timeout ) { 566 tv.tv_sec = timeout; 567 tv.tv_usec = 0; 568 } else { 569 LDAP_BACK_TV_SET( &tv ); 570 } 571 rc = ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res ); 572 if ( rc <= 0 ) { 573 rc = LDAP_UNAVAILABLE; 574 575 } else if ( rc == LDAP_RES_EXTENDED ) { 576 struct berval *data = NULL; 577 578 rc = ldap_parse_extended_result( ld, res, 579 NULL, &data, 0 ); 580 if ( rc == LDAP_SUCCESS ) { 581 SlapReply rs; 582 rc = ldap_parse_result( ld, res, &rs.sr_err, 583 NULL, NULL, NULL, NULL, 1 ); 584 if ( rc != LDAP_SUCCESS ) { 585 rs.sr_err = rc; 586 } 587 rc = slap_map_api2result( &rs ); 588 res = NULL; 589 590 /* FIXME: in case a referral 591 * is returned, should we try 592 * using it instead of the 593 * configured URI? */ 594 if ( rc == LDAP_SUCCESS ) { 595 rc = ldap_install_tls( ld ); 596 597 } else if ( rc == LDAP_REFERRAL ) { 598 rc = LDAP_UNWILLING_TO_PERFORM; 599 *text = "unwilling to chase referral returned by Start TLS exop"; 600 } 601 602 if ( data ) { 603 if ( data->bv_val ) { 604 ber_memfree( data->bv_val ); 605 } 606 ber_memfree( data ); 607 } 608 } 609 610 } else { 611 rc = LDAP_OTHER; 612 } 613 614 if ( res != NULL ) { 615 ldap_msgfree( res ); 616 } 617 } 618#else /* ! SLAP_STARTTLS_ASYNCHRONOUS */ 619 /* 620 * use synchronous StartTLS 621 */ 622 rc = ldap_start_tls_s( ld, NULL, NULL ); 623#endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */ 624 625 /* if StartTLS is requested, only attempt it if the URL 626 * is not "ldaps://"; this may occur not only in case 627 * of misconfiguration, but also when used in the chain 628 * overlay, where the "uri" can be parsed out of a referral */ 629 switch ( rc ) { 630 case LDAP_SUCCESS: 631 *is_tls = 1; 632 break; 633 634 case LDAP_SERVER_DOWN: 635 break; 636 637 default: 638 if ( LDAP_BACK_TLS_CRITICAL_F( flags ) ) { 639 *text = "could not start TLS"; 640 break; 641 } 642 643 /* in case Start TLS is not critical */ 644 *is_tls = 0; 645 rc = LDAP_SUCCESS; 646 break; 647 } 648 649 } else { 650 *is_tls = 0; 651 } 652 653 return rc; 654} 655#endif /* HAVE_TLS */ 656 657static int 658ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok ) 659{ 660 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; 661 int version; 662 LDAP *ld = NULL; 663#ifdef HAVE_TLS 664 int is_tls = op->o_conn->c_is_tls; 665 int flags = li->li_flags; 666 time_t lctime = (time_t)(-1); 667 slap_bindconf *sb; 668#endif /* HAVE_TLS */ 669 670 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex ); 671 rs->sr_err = ldap_initialize( &ld, li->li_uri ); 672 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex ); 673 if ( rs->sr_err != LDAP_SUCCESS ) { 674 goto error_return; 675 } 676 677 if ( li->li_urllist_f ) { 678 ldap_set_urllist_proc( ld, li->li_urllist_f, li->li_urllist_p ); 679 } 680 681 /* Set LDAP version. This will always succeed: If the client 682 * bound with a particular version, then so can we. 683 */ 684 if ( li->li_version != 0 ) { 685 version = li->li_version; 686 687 } else if ( op->o_protocol != 0 ) { 688 version = op->o_protocol; 689 690 } else { 691 /* assume it's an internal op; set to LDAPv3 */ 692 version = LDAP_VERSION3; 693 } 694 ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&version ); 695 696 /* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */ 697 ldap_set_option( ld, LDAP_OPT_REFERRALS, 698 LDAP_BACK_CHASE_REFERRALS( li ) ? LDAP_OPT_ON : LDAP_OPT_OFF ); 699 700 if ( li->li_network_timeout > 0 ) { 701 struct timeval tv; 702 703 tv.tv_sec = li->li_network_timeout; 704 tv.tv_usec = 0; 705 ldap_set_option( ld, LDAP_OPT_NETWORK_TIMEOUT, (const void *)&tv ); 706 } 707 708 /* turn on network keepalive, if configured so */ 709 slap_client_keepalive(ld, &li->li_tls.sb_keepalive); 710 711 if ( li->li_tls.sb_tcp_user_timeout > 0 ) { 712 ldap_set_option( ld, LDAP_OPT_TCP_USER_TIMEOUT, 713 &li->li_tls.sb_tcp_user_timeout ); 714 } 715 716#ifdef HAVE_TLS 717 if ( LDAP_BACK_CONN_ISPRIV( lc ) ) { 718 /* See "rationale" comment in ldap_back_getconn() */ 719 if ( li->li_acl_authmethod == LDAP_AUTH_NONE && 720 li->li_idassert_authmethod != LDAP_AUTH_NONE ) 721 sb = &li->li_idassert.si_bc; 722 else 723 sb = &li->li_acl; 724 725 } else if ( LDAP_BACK_CONN_ISIDASSERT( lc ) ) { 726 sb = &li->li_idassert.si_bc; 727 728 } else { 729 sb = &li->li_tls; 730 } 731 732 bindconf_tls_set( sb, ld ); 733 734 /* if required by the bindconf configuration, force TLS */ 735 if ( ( sb == &li->li_acl || sb == &li->li_idassert.si_bc ) && 736 sb->sb_tls_ctx ) 737 { 738 flags |= LDAP_BACK_F_USE_TLS; 739 } 740 741 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex ); 742 assert( li->li_uri_mutex_do_not_lock == 0 ); 743 li->li_uri_mutex_do_not_lock = 1; 744 rs->sr_err = ldap_back_start_tls( ld, op->o_protocol, &is_tls, 745 li->li_uri, flags, li->li_timeout[ SLAP_OP_BIND ], &rs->sr_text ); 746 li->li_uri_mutex_do_not_lock = 0; 747 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex ); 748 if ( rs->sr_err != LDAP_SUCCESS ) { 749 ldap_unbind_ext( ld, NULL, NULL ); 750 rs->sr_text = "Start TLS failed"; 751 goto error_return; 752 753 } else if ( li->li_idle_timeout ) { 754 /* only touch when activity actually took place... */ 755 lctime = op->o_time; 756 } 757#endif /* HAVE_TLS */ 758 759 lc->lc_ld = ld; 760 lc->lc_refcnt = 1; 761#ifdef HAVE_TLS 762 if ( is_tls ) { 763 LDAP_BACK_CONN_ISTLS_SET( lc ); 764 } else { 765 LDAP_BACK_CONN_ISTLS_CLEAR( lc ); 766 } 767 if ( lctime != (time_t)(-1) ) { 768 lc->lc_time = lctime; 769 } 770#endif /* HAVE_TLS */ 771 772error_return:; 773 if ( rs->sr_err != LDAP_SUCCESS ) { 774 rs->sr_err = slap_map_api2result( rs ); 775 if ( sendok & LDAP_BACK_SENDERR ) { 776 if ( rs->sr_text == NULL ) { 777 rs->sr_text = "Proxy connection initialization failed"; 778 } 779 send_ldap_result( op, rs ); 780 } 781 782 } else { 783 if ( li->li_conn_ttl > 0 ) { 784 lc->lc_create_time = op->o_time; 785 } 786 } 787 788 return rs->sr_err; 789} 790 791static ldapconn_t * 792ldap_back_getconn( 793 Operation *op, 794 SlapReply *rs, 795 ldap_back_send_t sendok, 796 struct berval *binddn, 797 struct berval *bindcred ) 798{ 799 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; 800 ldapconn_t *lc = NULL, 801 lc_curr = {{ 0 }}; 802 int refcnt = 1, 803 lookupconn = !( sendok & LDAP_BACK_BINDING ); 804 805 /* if the server is quarantined, and 806 * - the current interval did not expire yet, or 807 * - no more retries should occur, 808 * don't return the connection */ 809 if ( li->li_isquarantined ) { 810 slap_retry_info_t *ri = &li->li_quarantine; 811 int dont_retry = 1; 812 813 if ( li->li_quarantine.ri_interval ) { 814 ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex ); 815 if ( li->li_isquarantined == LDAP_BACK_FQ_YES ) { 816 dont_retry = ( ri->ri_num[ ri->ri_idx ] == SLAP_RETRYNUM_TAIL 817 || slap_get_time() < ri->ri_last + ri->ri_interval[ ri->ri_idx ] ); 818 if ( !dont_retry ) { 819 Debug( LDAP_DEBUG_ANY, 820 "%s: ldap_back_getconn quarantine " 821 "retry block #%d try #%d.\n", 822 op->o_log_prefix, ri->ri_idx, ri->ri_count ); 823 li->li_isquarantined = LDAP_BACK_FQ_RETRYING; 824 } 825 } 826 ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex ); 827 } 828 829 if ( dont_retry ) { 830 rs->sr_err = LDAP_UNAVAILABLE; 831 if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) { 832 rs->sr_text = "Target is quarantined"; 833 send_ldap_result( op, rs ); 834 } 835 return NULL; 836 } 837 } 838 839 /* Internal searches are privileged and shared. So is root. */ 840 if ( op->o_do_not_cache || be_isroot( op ) ) { 841 LDAP_BACK_CONN_ISPRIV_SET( &lc_curr ); 842 lc_curr.lc_local_ndn = op->o_bd->be_rootndn; 843 LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op ); 844 845 } else { 846 struct berval tmpbinddn, 847 tmpbindcred, 848 save_o_dn, 849 save_o_ndn; 850 int isproxyauthz; 851 852 /* need cleanup */ 853 if ( binddn == NULL ) { 854 binddn = &tmpbinddn; 855 } 856 if ( bindcred == NULL ) { 857 bindcred = &tmpbindcred; 858 } 859 if ( op->o_tag == LDAP_REQ_BIND ) { 860 save_o_dn = op->o_dn; 861 save_o_ndn = op->o_ndn; 862 op->o_dn = op->o_req_dn; 863 op->o_ndn = op->o_req_ndn; 864 } 865 isproxyauthz = ldap_back_is_proxy_authz( op, rs, sendok, binddn, bindcred ); 866 if ( op->o_tag == LDAP_REQ_BIND ) { 867 op->o_dn = save_o_dn; 868 op->o_ndn = save_o_ndn; 869 } 870 if ( isproxyauthz == -1 ) { 871 return NULL; 872 } 873 874 lc_curr.lc_local_ndn = op->o_ndn; 875 /* Explicit binds must not be shared; 876 * however, explicit binds are piped in a special connection 877 * when idassert is to occur with "override" set */ 878 if ( op->o_tag == LDAP_REQ_BIND && !isproxyauthz ) { 879 lc_curr.lc_conn = op->o_conn; 880 881 } else { 882 if ( isproxyauthz && !( sendok & LDAP_BACK_BINDING ) ) { 883 lc_curr.lc_local_ndn = *binddn; 884 LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op ); 885 LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr ); 886 887 } else if ( isproxyauthz && ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) { 888 lc_curr.lc_local_ndn = slap_empty_bv; 889 LDAP_BACK_PCONN_BIND_SET( &lc_curr, op ); 890 LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr ); 891 lookupconn = 1; 892 893 } else if ( SLAP_IS_AUTHZ_BACKEND( op ) ) { 894 lc_curr.lc_conn = op->o_conn; 895 896 } else { 897 LDAP_BACK_PCONN_ANON_SET( &lc_curr, op ); 898 } 899 } 900 } 901 902 /* Explicit Bind requests always get their own conn */ 903 if ( lookupconn ) { 904retry_lock: 905 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); 906 if ( LDAP_BACK_PCONN_ISPRIV( &lc_curr ) ) { 907 /* lookup a conn that's not binding */ 908 LDAP_TAILQ_FOREACH( lc, 909 &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv, 910 lc_q ) 911 { 912 if ( !LDAP_BACK_CONN_BINDING( lc ) && lc->lc_refcnt == 0 ) { 913 break; 914 } 915 } 916 917 if ( lc != NULL ) { 918 if ( lc != LDAP_TAILQ_LAST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, 919 lc_conn_priv_q ) ) 920 { 921 LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, 922 lc, lc_q ); 923 LDAP_TAILQ_ENTRY_INIT( lc, lc_q ); 924 LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, 925 lc, lc_q ); 926 } 927 928 } else if ( !LDAP_BACK_USE_TEMPORARIES( li ) 929 && li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_num == li->li_conn_priv_max ) 930 { 931 lc = LDAP_TAILQ_FIRST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv ); 932 } 933 934 } else { 935 936 /* Searches for a ldapconn in the avl tree */ 937 lc = (ldapconn_t *)ldap_tavl_find( li->li_conninfo.lai_tree, 938 (caddr_t)&lc_curr, ldap_back_conndn_cmp ); 939 } 940 941 if ( lc != NULL ) { 942 /* Don't reuse connections while they're still binding */ 943 if ( LDAP_BACK_CONN_BINDING( lc ) ) { 944 if ( !LDAP_BACK_USE_TEMPORARIES( li ) ) { 945 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); 946 947 ldap_pvt_thread_yield(); 948 goto retry_lock; 949 } 950 lc = NULL; 951 } 952 953 if ( lc != NULL ) { 954 if ( op->o_tag == LDAP_REQ_BIND ) { 955 /* right now, this is the only possible case */ 956 assert( ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ); 957 LDAP_BACK_CONN_BINDING_SET( lc ); 958 } 959 960 refcnt = ++lc->lc_refcnt; 961 } 962 } 963 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); 964 } 965 966 /* Looks like we didn't get a bind. Open a new session... */ 967 if ( lc == NULL ) { 968 lc = (ldapconn_t *)ch_calloc( 1, sizeof( ldapconn_t ) ); 969 lc->lc_flags = li->li_flags; 970 lc->lc_lcflags = lc_curr.lc_lcflags; 971 lc->lc_ldapinfo = li; 972 if ( ldap_back_prepare_conn( lc, op, rs, sendok ) != LDAP_SUCCESS ) { 973 ch_free( lc ); 974 return NULL; 975 } 976 977 if ( sendok & LDAP_BACK_BINDING ) { 978 LDAP_BACK_CONN_BINDING_SET( lc ); 979 } 980 981 lc->lc_conn = lc_curr.lc_conn; 982 ber_dupbv( &lc->lc_local_ndn, &lc_curr.lc_local_ndn ); 983 984 /* 985 * the rationale is: connections as the rootdn are privileged, 986 * so li_acl is to be used; however, in some cases 987 * one already configured identity assertion with a highly 988 * privileged idassert_authcDN, so if li_acl is not configured 989 * and idassert is, use idassert instead. 990 * 991 * might change in the future, because it's preferable 992 * to make clear what identity is being used, since 993 * the only drawback is that one risks to configure 994 * the same identity twice... 995 */ 996 if ( LDAP_BACK_CONN_ISPRIV( &lc_curr ) ) { 997 if ( li->li_acl_authmethod == LDAP_AUTH_NONE && 998 li->li_idassert_authmethod != LDAP_AUTH_NONE ) { 999 ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN ); 1000 ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd ); 1001 1002 } else { 1003 ber_dupbv( &lc->lc_bound_ndn, &li->li_acl_authcDN ); 1004 ber_dupbv( &lc->lc_cred, &li->li_acl_passwd ); 1005 } 1006 LDAP_BACK_CONN_ISPRIV_SET( lc ); 1007 1008 } else if ( LDAP_BACK_CONN_ISIDASSERT( &lc_curr ) ) { 1009 if ( !LDAP_BACK_PCONN_ISBIND( &lc_curr ) ) { 1010 ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN ); 1011 ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd ); 1012 } 1013 LDAP_BACK_CONN_ISIDASSERT_SET( lc ); 1014 1015 } else { 1016 BER_BVZERO( &lc->lc_cred ); 1017 BER_BVZERO( &lc->lc_bound_ndn ); 1018 if ( !BER_BVISEMPTY( &op->o_ndn ) 1019 && SLAP_IS_AUTHZ_BACKEND( op ) ) 1020 { 1021 ber_dupbv( &lc->lc_bound_ndn, &op->o_ndn ); 1022 } 1023 } 1024 1025#ifdef HAVE_TLS 1026 /* if start TLS failed but it was not mandatory, 1027 * check if the non-TLS connection was already 1028 * in cache; in case, destroy the newly created 1029 * connection and use the existing one */ 1030 if ( LDAP_BACK_PCONN_ISTLS( lc ) 1031 && !ldap_tls_inplace( lc->lc_ld ) ) 1032 { 1033 ldapconn_t *tmplc = NULL; 1034 int idx = LDAP_BACK_CONN2PRIV( &lc_curr ) - 1; 1035 1036 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); 1037 LDAP_TAILQ_FOREACH( tmplc, 1038 &li->li_conn_priv[ idx ].lic_priv, 1039 lc_q ) 1040 { 1041 if ( !LDAP_BACK_CONN_BINDING( tmplc ) ) { 1042 break; 1043 } 1044 } 1045 1046 if ( tmplc != NULL ) { 1047 refcnt = ++tmplc->lc_refcnt; 1048 ldap_back_conn_free( lc ); 1049 lc = tmplc; 1050 } 1051 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); 1052 1053 if ( tmplc != NULL ) { 1054 goto done; 1055 } 1056 } 1057#endif /* HAVE_TLS */ 1058 1059 /* Inserts the newly created ldapconn in the avl tree */ 1060 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); 1061 1062 LDAP_BACK_CONN_ISBOUND_CLEAR( lc ); 1063 lc->lc_connid = li->li_conn_nextid++; 1064 1065 assert( lc->lc_refcnt == 1 ); 1066 1067#if LDAP_BACK_PRINT_CONNTREE > 0 1068 ldap_back_print_conntree( li, ">>> ldap_back_getconn(insert)" ); 1069#endif /* LDAP_BACK_PRINT_CONNTREE */ 1070 1071 if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) { 1072 if ( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num < li->li_conn_priv_max ) { 1073 LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q ); 1074 li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num++; 1075 LDAP_BACK_CONN_CACHED_SET( lc ); 1076 1077 } else { 1078 LDAP_BACK_CONN_TAINTED_SET( lc ); 1079 } 1080 rs->sr_err = 0; 1081 1082 } else { 1083 rs->sr_err = ldap_tavl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc, 1084 ldap_back_conndn_cmp, ldap_back_conndn_dup ); 1085 LDAP_BACK_CONN_CACHED_SET( lc ); 1086 } 1087 1088#if LDAP_BACK_PRINT_CONNTREE > 0 1089 ldap_back_print_conntree( li, "<<< ldap_back_getconn(insert)" ); 1090#endif /* LDAP_BACK_PRINT_CONNTREE */ 1091 1092 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); 1093 1094 Debug(LDAP_DEBUG_TRACE, 1095 "=>ldap_back_getconn: %s: lc=%p inserted refcnt=%u rc=%d\n", 1096 op->o_log_prefix, (void *)lc, refcnt, 1097 rs->sr_err ); 1098 1099 if ( !LDAP_BACK_PCONN_ISPRIV( lc ) ) { 1100 /* Err could be -1 in case a duplicate ldapconn is inserted */ 1101 switch ( rs->sr_err ) { 1102 case 0: 1103 break; 1104 1105 case -1: 1106 LDAP_BACK_CONN_CACHED_CLEAR( lc ); 1107 if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( li ) ) { 1108 /* duplicate: free and try to get the newly created one */ 1109 ldap_back_conn_free( lc ); 1110 lc = NULL; 1111 goto retry_lock; 1112 } 1113 1114 /* taint connection, so that it'll be freed when released */ 1115 LDAP_BACK_CONN_TAINTED_SET( lc ); 1116 break; 1117 1118 default: 1119 LDAP_BACK_CONN_CACHED_CLEAR( lc ); 1120 ldap_back_conn_free( lc ); 1121 rs->sr_err = LDAP_OTHER; 1122 rs->sr_text = "Proxy bind collision"; 1123 if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) { 1124 send_ldap_result( op, rs ); 1125 } 1126 return NULL; 1127 } 1128 } 1129 ldap_back_schedule_conn_expiry( li, lc ); 1130 1131 } else { 1132 int expiring = 0; 1133 1134 if ( ( li->li_idle_timeout != 0 && op->o_time > lc->lc_time + li->li_idle_timeout ) 1135 || ( li->li_conn_ttl != 0 && op->o_time > lc->lc_create_time + li->li_conn_ttl ) ) 1136 { 1137 expiring = 1; 1138 1139 /* let it be used, but taint/delete it so that 1140 * no-one else can look it up any further */ 1141 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); 1142 1143#if LDAP_BACK_PRINT_CONNTREE > 0 1144 ldap_back_print_conntree( li, ">>> ldap_back_getconn(timeout)" ); 1145#endif /* LDAP_BACK_PRINT_CONNTREE */ 1146 1147 (void)ldap_back_conn_delete( li, lc ); 1148 LDAP_BACK_CONN_TAINTED_SET( lc ); 1149 1150#if LDAP_BACK_PRINT_CONNTREE > 0 1151 ldap_back_print_conntree( li, "<<< ldap_back_getconn(timeout)" ); 1152#endif /* LDAP_BACK_PRINT_CONNTREE */ 1153 1154 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); 1155 } 1156 1157 Debug(LDAP_DEBUG_TRACE, 1158 "=>ldap_back_getconn: conn %p fetched refcnt=%u%s.\n", 1159 (void *)lc, refcnt, expiring ? " expiring" : "" ); 1160 } 1161 1162#ifdef HAVE_TLS 1163done:; 1164#endif /* HAVE_TLS */ 1165 1166 return lc; 1167} 1168 1169void 1170ldap_back_release_conn_lock( 1171 ldapinfo_t *li, 1172 ldapconn_t **lcp, 1173 int dolock ) 1174{ 1175 1176 ldapconn_t *lc = *lcp; 1177 1178 if ( dolock ) { 1179 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); 1180 } 1181 assert( lc->lc_refcnt > 0 ); 1182 LDAP_BACK_CONN_BINDING_CLEAR( lc ); 1183 lc->lc_refcnt--; 1184 if ( LDAP_BACK_CONN_TAINTED( lc ) ) { 1185 ldap_back_freeconn( li, lc, 0 ); 1186 *lcp = NULL; 1187 } 1188 if ( dolock ) { 1189 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); 1190 } 1191} 1192 1193void 1194ldap_back_quarantine( 1195 Operation *op, 1196 SlapReply *rs ) 1197{ 1198 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; 1199 1200 slap_retry_info_t *ri = &li->li_quarantine; 1201 1202 ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex ); 1203 1204 if ( rs->sr_err == LDAP_UNAVAILABLE ) { 1205 time_t new_last = slap_get_time(); 1206 1207 switch ( li->li_isquarantined ) { 1208 case LDAP_BACK_FQ_NO: 1209 if ( ri->ri_last == new_last ) { 1210 goto done; 1211 } 1212 1213 Debug( LDAP_DEBUG_ANY, 1214 "%s: ldap_back_quarantine enter.\n", 1215 op->o_log_prefix ); 1216 1217 ri->ri_idx = 0; 1218 ri->ri_count = 0; 1219 break; 1220 1221 case LDAP_BACK_FQ_RETRYING: 1222 Debug( LDAP_DEBUG_ANY, 1223 "%s: ldap_back_quarantine block #%d try #%d failed.\n", 1224 op->o_log_prefix, ri->ri_idx, ri->ri_count ); 1225 1226 ++ri->ri_count; 1227 if ( ri->ri_num[ ri->ri_idx ] != SLAP_RETRYNUM_FOREVER 1228 && ri->ri_count == ri->ri_num[ ri->ri_idx ] ) 1229 { 1230 ri->ri_count = 0; 1231 ++ri->ri_idx; 1232 } 1233 break; 1234 1235 default: 1236 goto done; 1237 } 1238 1239 li->li_isquarantined = LDAP_BACK_FQ_YES; 1240 ri->ri_last = new_last; 1241 1242 } else if ( li->li_isquarantined != LDAP_BACK_FQ_NO ) { 1243 if ( ri->ri_last == slap_get_time() ) { 1244 goto done; 1245 } 1246 1247 Debug( LDAP_DEBUG_ANY, 1248 "%s: ldap_back_quarantine exit (%d) err=%d.\n", 1249 op->o_log_prefix, li->li_isquarantined, rs->sr_err ); 1250 1251 if ( li->li_quarantine_f ) { 1252 (void)li->li_quarantine_f( li, li->li_quarantine_p ); 1253 } 1254 1255 ri->ri_count = 0; 1256 ri->ri_idx = 0; 1257 li->li_isquarantined = LDAP_BACK_FQ_NO; 1258 } 1259 1260done:; 1261 ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex ); 1262} 1263 1264static int 1265ldap_back_dobind_cb( 1266 Operation *op, 1267 SlapReply *rs 1268) 1269{ 1270 ber_tag_t *tptr = op->o_callback->sc_private; 1271 op->o_tag = *tptr; 1272 rs->sr_tag = slap_req2res( op->o_tag ); 1273 1274 return SLAP_CB_CONTINUE; 1275} 1276 1277/* 1278 * ldap_back_dobind_int 1279 * 1280 * Note: dolock indicates whether li->li_conninfo.lai_mutex must be locked or not 1281 */ 1282static int 1283ldap_back_dobind_int( 1284 ldapconn_t **lcp, 1285 Operation *op, 1286 SlapReply *rs, 1287 ldap_back_send_t sendok, 1288 int retries, 1289 int dolock ) 1290{ 1291 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; 1292 1293 ldapconn_t *lc; 1294 struct berval binddn = slap_empty_bv, 1295 bindcred = slap_empty_bv; 1296 1297 int rc = 0, 1298 isbound, 1299 binding = 0; 1300 ber_int_t msgid; 1301 ber_tag_t o_tag = op->o_tag; 1302 slap_callback cb = {0}; 1303 char *tmp_dn; 1304 1305 assert( lcp != NULL ); 1306 assert( retries >= 0 ); 1307 1308 if ( sendok & LDAP_BACK_GETCONN ) { 1309 assert( *lcp == NULL ); 1310 1311 lc = ldap_back_getconn( op, rs, sendok, &binddn, &bindcred ); 1312 if ( lc == NULL ) { 1313 return 0; 1314 } 1315 *lcp = lc; 1316 1317 } else { 1318 lc = *lcp; 1319 } 1320 1321 assert( lc != NULL ); 1322 1323retry_lock:; 1324 if ( dolock ) { 1325 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); 1326 } 1327 1328 if ( binding == 0 ) { 1329 /* check if already bound */ 1330 rc = isbound = LDAP_BACK_CONN_ISBOUND( lc ); 1331 if ( isbound ) { 1332 if ( dolock ) { 1333 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); 1334 } 1335 return rc; 1336 } 1337 1338 if ( LDAP_BACK_CONN_BINDING( lc ) ) { 1339 /* if someone else is about to bind it, give up and retry */ 1340 if ( dolock ) { 1341 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); 1342 } 1343 ldap_pvt_thread_yield(); 1344 goto retry_lock; 1345 1346 } else { 1347 /* otherwise this thread will bind it */ 1348 LDAP_BACK_CONN_BINDING_SET( lc ); 1349 binding = 1; 1350 } 1351 } 1352 1353 if ( dolock ) { 1354 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); 1355 } 1356 1357 /* 1358 * FIXME: we need to let clients use proxyAuthz 1359 * otherwise we cannot do symmetric pools of servers; 1360 * we have to live with the fact that a user can 1361 * authorize itself as any ID that is allowed 1362 * by the authzTo directive of the "proxyauthzdn". 1363 */ 1364 /* 1365 * NOTE: current Proxy Authorization specification 1366 * and implementation do not allow proxy authorization 1367 * control to be provided with Bind requests 1368 */ 1369 /* 1370 * if no bind took place yet, but the connection is bound 1371 * and the "idassert-authcDN" (or other ID) is set, 1372 * then bind as the asserting identity and explicitly 1373 * add the proxyAuthz control to every operation with the 1374 * dn bound to the connection as control value. 1375 * This is done also if this is the authorizing backend, 1376 * but the "override" flag is given to idassert. 1377 * It allows to use SASL bind and yet proxyAuthz users 1378 */ 1379 op->o_tag = LDAP_REQ_BIND; 1380 cb.sc_next = op->o_callback; 1381 cb.sc_private = &o_tag; 1382 cb.sc_response = ldap_back_dobind_cb; 1383 op->o_callback = &cb; 1384 1385 if ( LDAP_BACK_CONN_ISIDASSERT( lc ) ) { 1386 if ( BER_BVISEMPTY( &binddn ) && BER_BVISEMPTY( &bindcred ) ) { 1387 /* if we got here, it shouldn't return result */ 1388 rc = ldap_back_is_proxy_authz( op, rs, 1389 LDAP_BACK_DONTSEND, &binddn, &bindcred ); 1390 if ( rc != 1 ) { 1391 Debug( LDAP_DEBUG_ANY, "Error: ldap_back_is_proxy_authz " 1392 "returned %d, misconfigured URI?\n", rc ); 1393 rs->sr_err = LDAP_OTHER; 1394 rs->sr_text = "misconfigured URI?"; 1395 LDAP_BACK_CONN_ISBOUND_CLEAR( lc ); 1396 if ( sendok & LDAP_BACK_SENDERR ) { 1397 send_ldap_result( op, rs ); 1398 } 1399 goto done; 1400 } 1401 } 1402 rc = ldap_back_proxy_authz_bind( lc, op, rs, sendok, &binddn, &bindcred ); 1403 goto done; 1404 } 1405 1406#ifdef HAVE_CYRUS_SASL 1407 if ( LDAP_BACK_CONN_ISPRIV( lc )) { 1408 slap_bindconf *sb; 1409 if ( li->li_acl_authmethod != LDAP_AUTH_NONE ) 1410 sb = &li->li_acl; 1411 else 1412 sb = &li->li_idassert.si_bc; 1413 1414 if ( sb->sb_method == LDAP_AUTH_SASL ) { 1415 void *defaults = NULL; 1416 1417 if ( sb->sb_secprops != NULL ) { 1418 rc = ldap_set_option( lc->lc_ld, 1419 LDAP_OPT_X_SASL_SECPROPS, sb->sb_secprops ); 1420 1421 if ( rc != LDAP_OPT_SUCCESS ) { 1422 Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option " 1423 "(SECPROPS,\"%s\") failed!\n", 1424 sb->sb_secprops ); 1425 goto done; 1426 } 1427 } 1428 1429 defaults = lutil_sasl_defaults( lc->lc_ld, 1430 sb->sb_saslmech.bv_val, 1431 sb->sb_realm.bv_val, 1432 sb->sb_authcId.bv_val, 1433 sb->sb_cred.bv_val, 1434 NULL ); 1435 if ( defaults == NULL ) { 1436 rs->sr_err = LDAP_OTHER; 1437 LDAP_BACK_CONN_ISBOUND_CLEAR( lc ); 1438 if ( sendok & LDAP_BACK_SENDERR ) { 1439 send_ldap_result( op, rs ); 1440 } 1441 goto done; 1442 } 1443 1444 rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld, 1445 sb->sb_binddn.bv_val, 1446 sb->sb_saslmech.bv_val, NULL, NULL, 1447 LDAP_SASL_QUIET, lutil_sasl_interact, 1448 defaults ); 1449 1450 ldap_pvt_thread_mutex_lock( &li->li_counter_mutex ); 1451 ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_BIND ], 1 ); 1452 ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex ); 1453 1454 lutil_sasl_freedefs( defaults ); 1455 1456 switch ( rs->sr_err ) { 1457 case LDAP_SUCCESS: 1458 LDAP_BACK_CONN_ISBOUND_SET( lc ); 1459 break; 1460 1461 case LDAP_LOCAL_ERROR: 1462 /* list client API error codes that require 1463 * to taint the connection */ 1464 /* FIXME: should actually retry? */ 1465 LDAP_BACK_CONN_TAINTED_SET( lc ); 1466 1467 /* fallthru */ 1468 1469 default: 1470 LDAP_BACK_CONN_ISBOUND_CLEAR( lc ); 1471 rs->sr_err = slap_map_api2result( rs ); 1472 if ( sendok & LDAP_BACK_SENDERR ) { 1473 send_ldap_result( op, rs ); 1474 } 1475 break; 1476 } 1477 1478 if ( LDAP_BACK_QUARANTINE( li ) ) { 1479 ldap_back_quarantine( op, rs ); 1480 } 1481 1482 goto done; 1483 } 1484 } 1485#endif /* HAVE_CYRUS_SASL */ 1486 1487retry:; 1488 if ( BER_BVISNULL( &lc->lc_cred ) ) { 1489 tmp_dn = ""; 1490 if ( !BER_BVISNULL( &lc->lc_bound_ndn ) && !BER_BVISEMPTY( &lc->lc_bound_ndn ) ) { 1491 Debug( LDAP_DEBUG_ANY, "%s ldap_back_dobind_int: DN=\"%s\" without creds, binding anonymously", 1492 op->o_log_prefix, lc->lc_bound_ndn.bv_val ); 1493 } 1494 1495 } else { 1496 tmp_dn = lc->lc_bound_ndn.bv_val; 1497 } 1498 rs->sr_err = ldap_sasl_bind( lc->lc_ld, 1499 tmp_dn, 1500 LDAP_SASL_SIMPLE, &lc->lc_cred, 1501 NULL, NULL, &msgid ); 1502 1503 ldap_pvt_thread_mutex_lock( &li->li_counter_mutex ); 1504 ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_BIND ], 1 ); 1505 ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex ); 1506 1507 if ( rs->sr_err == LDAP_SERVER_DOWN ) { 1508 if ( retries != LDAP_BACK_RETRY_NEVER ) { 1509 if ( dolock ) { 1510 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); 1511 } 1512 1513 assert( lc->lc_refcnt > 0 ); 1514 if ( lc->lc_refcnt == 1 ) { 1515 ldap_unbind_ext( lc->lc_ld, NULL, NULL ); 1516 lc->lc_ld = NULL; 1517 1518 /* lc here must be the regular lc, reset and ready for init */ 1519 rs->sr_err = ldap_back_prepare_conn( lc, op, rs, sendok ); 1520 if ( rs->sr_err != LDAP_SUCCESS ) { 1521 sendok &= ~LDAP_BACK_SENDERR; 1522 lc->lc_refcnt = 0; 1523 } 1524 } 1525 1526 if ( dolock ) { 1527 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); 1528 } 1529 1530 if ( rs->sr_err == LDAP_SUCCESS ) { 1531 if ( retries > 0 ) { 1532 retries--; 1533 } 1534 goto retry; 1535 } 1536 } 1537 1538 assert( lc->lc_refcnt == 1 ); 1539 lc->lc_refcnt = 0; 1540 ldap_back_freeconn( li, lc, dolock ); 1541 *lcp = NULL; 1542 rs->sr_err = slap_map_api2result( rs ); 1543 1544 if ( LDAP_BACK_QUARANTINE( li ) ) { 1545 ldap_back_quarantine( op, rs ); 1546 } 1547 1548 if ( rs->sr_err != LDAP_SUCCESS && 1549 ( sendok & LDAP_BACK_SENDERR ) ) 1550 { 1551 if ( op->o_callback == &cb ) 1552 op->o_callback = cb.sc_next; 1553 op->o_tag = o_tag; 1554 rs->sr_text = "Proxy can't contact remote server"; 1555 send_ldap_result( op, rs ); 1556 /* if we originally bound and wanted rebind-as-user, must drop 1557 * the connection now because we just discarded the credentials. 1558 * ITS#7464, #8142 1559 */ 1560 if ( LDAP_BACK_SAVECRED( li ) && SLAP_IS_AUTHZ_BACKEND( op ) ) 1561 rs->sr_err = SLAPD_DISCONNECT; 1562 } 1563 1564 rc = 0; 1565 goto func_leave; 1566 } 1567 1568 rc = ldap_back_op_result( lc, op, rs, msgid, 1569 -1, ( sendok | LDAP_BACK_BINDING ) ); 1570 if ( rc == LDAP_SUCCESS ) { 1571 LDAP_BACK_CONN_ISBOUND_SET( lc ); 1572 } 1573 1574done:; 1575 LDAP_BACK_CONN_BINDING_CLEAR( lc ); 1576 rc = LDAP_BACK_CONN_ISBOUND( lc ); 1577 if ( !rc ) { 1578 ldap_back_release_conn_lock( li, lcp, dolock ); 1579 1580 } else if ( LDAP_BACK_SAVECRED( li ) ) { 1581 ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc ); 1582 } 1583 1584func_leave:; 1585 if ( op->o_callback == &cb ) 1586 op->o_callback = cb.sc_next; 1587 op->o_tag = o_tag; 1588 1589 return rc; 1590} 1591 1592/* 1593 * ldap_back_dobind 1594 * 1595 * Note: dolock indicates whether li->li_conninfo.lai_mutex must be locked or not 1596 */ 1597int 1598ldap_back_dobind( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok ) 1599{ 1600 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; 1601 1602 return ldap_back_dobind_int( lcp, op, rs, 1603 ( sendok | LDAP_BACK_GETCONN ), li->li_nretries, 1 ); 1604} 1605 1606/* 1607 * ldap_back_default_rebind 1608 * 1609 * This is a callback used for chasing referrals using the same 1610 * credentials as the original user on this session. 1611 */ 1612int 1613ldap_back_default_rebind( LDAP *ld, LDAP_CONST char *url, ber_tag_t request, 1614 ber_int_t msgid, void *params ) 1615{ 1616 ldapconn_t *lc = (ldapconn_t *)params; 1617 1618#ifdef HAVE_TLS 1619 /* ... otherwise we couldn't get here */ 1620 assert( lc != NULL ); 1621 1622 if ( !ldap_tls_inplace( ld ) ) { 1623 int is_tls = LDAP_BACK_CONN_ISTLS( lc ), 1624 rc; 1625 const char *text = NULL; 1626 1627 rc = ldap_back_start_tls( ld, 0, &is_tls, url, lc->lc_flags, 1628 lc->lc_ldapinfo->li_timeout[ SLAP_OP_BIND ], &text ); 1629 if ( rc != LDAP_SUCCESS ) { 1630 return rc; 1631 } 1632 } 1633#endif /* HAVE_TLS */ 1634 1635 /* FIXME: add checks on the URL/identity? */ 1636 /* TODO: would like to count this bind operation for monitoring 1637 * too, but where do we get the ldapinfo_t? */ 1638 1639 return ldap_sasl_bind_s( ld, 1640 BER_BVISNULL( &lc->lc_cred ) ? "" : lc->lc_bound_ndn.bv_val, 1641 LDAP_SASL_SIMPLE, &lc->lc_cred, NULL, NULL, NULL ); 1642} 1643 1644/* 1645 * ldap_back_default_urllist 1646 */ 1647int 1648ldap_back_default_urllist( 1649 LDAP *ld, 1650 LDAPURLDesc **urllist, 1651 LDAPURLDesc **url, 1652 void *params ) 1653{ 1654 ldapinfo_t *li = (ldapinfo_t *)params; 1655 LDAPURLDesc **urltail; 1656 1657 if ( urllist == url ) { 1658 return LDAP_SUCCESS; 1659 } 1660 1661 for ( urltail = &(*url)->lud_next; *urltail; urltail = &(*urltail)->lud_next ) 1662 /* count */ ; 1663 1664 *urltail = *urllist; 1665 *urllist = *url; 1666 *url = NULL; 1667 1668 if ( !li->li_uri_mutex_do_not_lock ) { 1669 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex ); 1670 } 1671 1672 if ( li->li_uri ) { 1673 ch_free( li->li_uri ); 1674 } 1675 1676 ldap_get_option( ld, LDAP_OPT_URI, (void *)&li->li_uri ); 1677 1678 if ( !li->li_uri_mutex_do_not_lock ) { 1679 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex ); 1680 } 1681 1682 return LDAP_SUCCESS; 1683} 1684 1685int 1686ldap_back_cancel( 1687 ldapconn_t *lc, 1688 Operation *op, 1689 SlapReply *rs, 1690 ber_int_t msgid, 1691 ldap_back_send_t sendok ) 1692{ 1693 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; 1694 1695 /* default behavior */ 1696 if ( LDAP_BACK_ABANDON( li ) ) { 1697 return ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL ); 1698 } 1699 1700 if ( LDAP_BACK_IGNORE( li ) ) { 1701 return ldap_pvt_discard( lc->lc_ld, msgid ); 1702 } 1703 1704 if ( LDAP_BACK_CANCEL( li ) ) { 1705 /* FIXME: asynchronous? */ 1706 return ldap_cancel_s( lc->lc_ld, msgid, NULL, NULL ); 1707 } 1708 1709 assert( 0 ); 1710 1711 return LDAP_OTHER; 1712} 1713 1714int 1715ldap_back_op_result( 1716 ldapconn_t *lc, 1717 Operation *op, 1718 SlapReply *rs, 1719 ber_int_t msgid, 1720 time_t timeout, 1721 ldap_back_send_t sendok ) 1722{ 1723 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; 1724 1725 char *match = NULL; 1726 char *text = NULL; 1727 char **refs = NULL; 1728 LDAPControl **ctrls = NULL; 1729 1730 rs->sr_text = NULL; 1731 rs->sr_matched = NULL; 1732 rs->sr_ref = NULL; 1733 rs->sr_ctrls = NULL; 1734 1735 /* if the error recorded in the reply corresponds 1736 * to a successful state, get the error from the 1737 * remote server response */ 1738 if ( LDAP_ERR_OK( rs->sr_err ) ) { 1739 int rc; 1740 struct timeval tv; 1741 LDAPMessage *res = NULL; 1742 time_t stoptime = (time_t)(-1); 1743 int timeout_err = op->o_protocol >= LDAP_VERSION3 ? 1744 LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER; 1745 const char *timeout_text = "Operation timed out"; 1746 1747 /* if timeout is not specified, compute and use 1748 * the one specific to the ongoing operation */ 1749 if ( timeout == (time_t)(-1) ) { 1750 slap_op_t opidx = slap_req2op( op->o_tag ); 1751 1752 if ( opidx == SLAP_OP_SEARCH ) { 1753 if ( op->ors_tlimit <= 0 ) { 1754 timeout = 0; 1755 1756 } else { 1757 timeout = op->ors_tlimit; 1758 timeout_err = LDAP_TIMELIMIT_EXCEEDED; 1759 timeout_text = NULL; 1760 } 1761 1762 } else { 1763 timeout = li->li_timeout[ opidx ]; 1764 } 1765 } 1766 1767 /* better than nothing :) */ 1768 if ( timeout == 0 ) { 1769 if ( li->li_idle_timeout ) { 1770 timeout = li->li_idle_timeout; 1771 1772 } else if ( li->li_conn_ttl ) { 1773 timeout = li->li_conn_ttl; 1774 } 1775 } 1776 1777 if ( timeout ) { 1778 stoptime = op->o_time + timeout; 1779 } 1780 1781 LDAP_BACK_TV_SET( &tv ); 1782 1783retry:; 1784 /* if result parsing fails, note the failure reason */ 1785 rc = ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, &tv, &res ); 1786 switch ( rc ) { 1787 case 0: 1788 if ( timeout && slap_get_time() > stoptime ) { 1789 if ( sendok & LDAP_BACK_BINDING ) { 1790 ldap_unbind_ext( lc->lc_ld, NULL, NULL ); 1791 lc->lc_ld = NULL; 1792 1793 /* let it be used, but taint/delete it so that 1794 * no-one else can look it up any further */ 1795 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); 1796 1797#if LDAP_BACK_PRINT_CONNTREE > 0 1798 ldap_back_print_conntree( li, ">>> ldap_back_getconn(timeout)" ); 1799#endif /* LDAP_BACK_PRINT_CONNTREE */ 1800 1801 (void)ldap_back_conn_delete( li, lc ); 1802 LDAP_BACK_CONN_TAINTED_SET( lc ); 1803 1804#if LDAP_BACK_PRINT_CONNTREE > 0 1805 ldap_back_print_conntree( li, "<<< ldap_back_getconn(timeout)" ); 1806#endif /* LDAP_BACK_PRINT_CONNTREE */ 1807 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); 1808 1809 } else { 1810 (void)ldap_back_cancel( lc, op, rs, msgid, sendok ); 1811 } 1812 rs->sr_err = timeout_err; 1813 rs->sr_text = timeout_text; 1814 break; 1815 } 1816 1817 /* timeout == 0 */ 1818 LDAP_BACK_TV_SET( &tv ); 1819 ldap_pvt_thread_yield(); 1820 goto retry; 1821 1822 case -1: 1823 ldap_get_option( lc->lc_ld, LDAP_OPT_ERROR_NUMBER, 1824 &rs->sr_err ); 1825 break; 1826 1827 1828 /* otherwise get the result; if it is not 1829 * LDAP_SUCCESS, record it in the reply 1830 * structure (this includes 1831 * LDAP_COMPARE_{TRUE|FALSE}) */ 1832 default: 1833 /* only touch when activity actually took place... */ 1834 if ( li->li_idle_timeout ) { 1835 lc->lc_time = op->o_time; 1836 } 1837 1838 rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err, 1839 &match, &text, &refs, &ctrls, 1 ); 1840 if ( rc == LDAP_SUCCESS ) { 1841 rs->sr_text = text; 1842 } else { 1843 rs->sr_err = rc; 1844 } 1845 rs->sr_err = slap_map_api2result( rs ); 1846 1847 /* RFC 4511: referrals can only appear 1848 * if result code is LDAP_REFERRAL */ 1849 if ( refs != NULL 1850 && refs[ 0 ] != NULL 1851 && refs[ 0 ][ 0 ] != '\0' ) 1852 { 1853 if ( rs->sr_err != LDAP_REFERRAL ) { 1854 Debug( LDAP_DEBUG_ANY, 1855 "%s ldap_back_op_result: " 1856 "got referrals with err=%d\n", 1857 op->o_log_prefix, 1858 rs->sr_err ); 1859 1860 } else { 1861 int i; 1862 1863 for ( i = 0; refs[ i ] != NULL; i++ ) 1864 /* count */ ; 1865 rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ), 1866 op->o_tmpmemctx ); 1867 for ( i = 0; refs[ i ] != NULL; i++ ) { 1868 ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] ); 1869 } 1870 BER_BVZERO( &rs->sr_ref[ i ] ); 1871 } 1872 1873 } else if ( rs->sr_err == LDAP_REFERRAL ) { 1874 Debug( LDAP_DEBUG_ANY, 1875 "%s ldap_back_op_result: " 1876 "got err=%d with null " 1877 "or empty referrals\n", 1878 op->o_log_prefix, 1879 rs->sr_err ); 1880 1881 rs->sr_err = LDAP_NO_SUCH_OBJECT; 1882 } 1883 1884 if ( ctrls != NULL ) { 1885 rs->sr_ctrls = ctrls; 1886 } 1887 } 1888 } 1889 1890 /* if the error in the reply structure is not 1891 * LDAP_SUCCESS, try to map it from client 1892 * to server error */ 1893 if ( !LDAP_ERR_OK( rs->sr_err ) ) { 1894 rs->sr_err = slap_map_api2result( rs ); 1895 1896 /* internal ops ( op->o_conn == NULL ) 1897 * must not reply to client */ 1898 if ( op->o_conn && !op->o_do_not_cache && match ) { 1899 1900 /* record the (massaged) matched 1901 * DN into the reply structure */ 1902 rs->sr_matched = match; 1903 } 1904 } 1905 1906 if ( rs->sr_err == LDAP_UNAVAILABLE ) { 1907 if ( !( sendok & LDAP_BACK_RETRYING ) ) { 1908 if ( LDAP_BACK_QUARANTINE( li ) ) { 1909 ldap_back_quarantine( op, rs ); 1910 } 1911 if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) { 1912 if ( rs->sr_text == NULL ) rs->sr_text = "Proxy operation retry failed"; 1913 send_ldap_result( op, rs ); 1914 } 1915 } 1916 1917 } else if ( op->o_conn && 1918 ( ( ( sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) ) 1919 || ( ( sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) ) 1920 { 1921 send_ldap_result( op, rs ); 1922 } 1923 1924 if ( text ) { 1925 ldap_memfree( text ); 1926 } 1927 rs->sr_text = NULL; 1928 1929 /* there can't be refs with a (successful) bind */ 1930 if ( rs->sr_ref ) { 1931 op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx ); 1932 rs->sr_ref = NULL; 1933 } 1934 1935 if ( refs ) { 1936 ber_memvfree( (void **)refs ); 1937 } 1938 1939 /* match should not be possible with a successful bind */ 1940 if ( match ) { 1941 if ( rs->sr_matched != match ) { 1942 free( (char *)rs->sr_matched ); 1943 } 1944 rs->sr_matched = NULL; 1945 ldap_memfree( match ); 1946 } 1947 1948 if ( ctrls != NULL ) { 1949 if ( op->o_tag == LDAP_REQ_BIND && rs->sr_err == LDAP_SUCCESS ) { 1950 int i; 1951 1952 for ( i = 0; ctrls[i] != NULL; i++ ); 1953 1954 rs->sr_ctrls = op->o_tmpalloc( sizeof( LDAPControl * )*( i + 1 ), 1955 op->o_tmpmemctx ); 1956 for ( i = 0; ctrls[ i ] != NULL; i++ ) { 1957 char *ptr; 1958 ber_len_t oidlen = strlen( ctrls[i]->ldctl_oid ); 1959 ber_len_t size = sizeof( LDAPControl ) 1960 + oidlen + 1 1961 + ctrls[i]->ldctl_value.bv_len + 1; 1962 1963 rs->sr_ctrls[ i ] = op->o_tmpalloc( size, op->o_tmpmemctx ); 1964 rs->sr_ctrls[ i ]->ldctl_oid = (char *)&rs->sr_ctrls[ i ][ 1 ]; 1965 lutil_strcopy( rs->sr_ctrls[ i ]->ldctl_oid, ctrls[i]->ldctl_oid ); 1966 rs->sr_ctrls[ i ]->ldctl_value.bv_val 1967 = (char *)&rs->sr_ctrls[ i ]->ldctl_oid[oidlen + 1]; 1968 rs->sr_ctrls[ i ]->ldctl_value.bv_len 1969 = ctrls[i]->ldctl_value.bv_len; 1970 ptr = lutil_memcopy( rs->sr_ctrls[ i ]->ldctl_value.bv_val, 1971 ctrls[i]->ldctl_value.bv_val, ctrls[i]->ldctl_value.bv_len ); 1972 *ptr = '\0'; 1973 } 1974 rs->sr_ctrls[ i ] = NULL; 1975 rs->sr_flags |= REP_CTRLS_MUSTBEFREED; 1976 1977 } else { 1978 assert( rs->sr_ctrls != NULL ); 1979 rs->sr_ctrls = NULL; 1980 } 1981 1982 ldap_controls_free( ctrls ); 1983 } 1984 1985 return( LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err ); 1986} 1987 1988/* return true if bound, false if failed */ 1989int 1990ldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok ) 1991{ 1992 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; 1993 int rc = 0; 1994 1995 assert( lcp != NULL ); 1996 assert( *lcp != NULL ); 1997 1998 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); 1999 2000 if ( (*lcp)->lc_refcnt == 1 ) { 2001 int binding = LDAP_BACK_CONN_BINDING( *lcp ); 2002 2003 ldap_pvt_thread_mutex_lock( &li->li_uri_mutex ); 2004 Debug( LDAP_DEBUG_ANY, 2005 "%s ldap_back_retry: retrying URI=\"%s\" DN=\"%s\"\n", 2006 op->o_log_prefix, li->li_uri, 2007 BER_BVISNULL( &(*lcp)->lc_bound_ndn ) ? 2008 "" : (*lcp)->lc_bound_ndn.bv_val ); 2009 ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex ); 2010 2011 ldap_unbind_ext( (*lcp)->lc_ld, NULL, NULL ); 2012 (*lcp)->lc_ld = NULL; 2013 LDAP_BACK_CONN_ISBOUND_CLEAR( (*lcp) ); 2014 2015 /* lc here must be the regular lc, reset and ready for init */ 2016 rc = ldap_back_prepare_conn( *lcp, op, rs, sendok ); 2017 if ( rc != LDAP_SUCCESS ) { 2018 /* freeit, because lc_refcnt == 1 */ 2019 (*lcp)->lc_refcnt = 0; 2020 (void)ldap_back_freeconn( li, *lcp, 0 ); 2021 *lcp = NULL; 2022 rc = 0; 2023 2024 } else if ( ( sendok & LDAP_BACK_BINDING ) ) { 2025 if ( binding ) { 2026 LDAP_BACK_CONN_BINDING_SET( *lcp ); 2027 } 2028 rc = 1; 2029 2030 } else { 2031 rc = ldap_back_dobind_int( lcp, op, rs, sendok, 0, 0 ); 2032 if ( rc == 0 && *lcp != NULL ) { 2033 /* freeit, because lc_refcnt == 1 */ 2034 (*lcp)->lc_refcnt = 0; 2035 (void)ldap_back_freeconn( li, *lcp, 0 ); 2036 *lcp = NULL; 2037 } 2038 } 2039 2040 } else { 2041 Debug( LDAP_DEBUG_TRACE, 2042 "ldap_back_retry: conn %p refcnt=%u unable to retry.\n", 2043 (void *)(*lcp), (*lcp)->lc_refcnt ); 2044 2045 LDAP_BACK_CONN_TAINTED_SET( *lcp ); 2046 ldap_back_release_conn_lock( li, lcp, 0 ); 2047 assert( *lcp == NULL ); 2048 2049 if ( sendok & LDAP_BACK_SENDERR ) { 2050 rs->sr_err = LDAP_UNAVAILABLE; 2051 rs->sr_text = "Unable to retry"; 2052 send_ldap_result( op, rs ); 2053 } 2054 } 2055 2056 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); 2057 2058 return rc; 2059} 2060 2061static int 2062ldap_back_is_proxy_authz( Operation *op, SlapReply *rs, ldap_back_send_t sendok, 2063 struct berval *binddn, struct berval *bindcred ) 2064{ 2065 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; 2066 struct berval ndn; 2067 int dobind = 0; 2068 2069 if ( op->o_conn == NULL || op->o_do_not_cache ) { 2070 goto done; 2071 } 2072 2073 /* don't proxyAuthz if protocol is not LDAPv3 */ 2074 switch ( li->li_version ) { 2075 case LDAP_VERSION3: 2076 break; 2077 2078 case 0: 2079 if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) { 2080 break; 2081 } 2082 /* fall thru */ 2083 2084 default: 2085 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 2086 if ( sendok & LDAP_BACK_SENDERR ) { 2087 send_ldap_result( op, rs ); 2088 dobind = -1; 2089 } 2090 goto done; 2091 } 2092 2093 /* safe default */ 2094 *binddn = slap_empty_bv; 2095 *bindcred = slap_empty_bv; 2096 2097 if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) { 2098 ndn = op->o_conn->c_ndn; 2099 2100 } else { 2101 ndn = op->o_ndn; 2102 } 2103 2104 if ( !( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE )) { 2105 if ( op->o_tag == LDAP_REQ_BIND && ( sendok & LDAP_BACK_SENDERR )) { 2106 if ( !BER_BVISEMPTY( &ndn )) { 2107 dobind = 0; 2108 goto done; 2109 } 2110 } else if ( SLAP_IS_AUTHZ_BACKEND( op )) { 2111 dobind = 0; 2112 goto done; 2113 } 2114 } 2115 2116 switch ( li->li_idassert_mode ) { 2117 case LDAP_BACK_IDASSERT_LEGACY: 2118 if ( !BER_BVISNULL( &ndn ) && !BER_BVISEMPTY( &ndn ) ) { 2119 if ( !BER_BVISNULL( &li->li_idassert_authcDN ) && !BER_BVISEMPTY( &li->li_idassert_authcDN ) ) 2120 { 2121 *binddn = li->li_idassert_authcDN; 2122 *bindcred = li->li_idassert_passwd; 2123 dobind = 1; 2124 } 2125 } 2126 break; 2127 2128 default: 2129 /* NOTE: rootdn can always idassert */ 2130 if ( BER_BVISNULL( &ndn ) 2131 && li->li_idassert_authz == NULL 2132 && !( li->li_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) ) 2133 { 2134 if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) { 2135 rs->sr_err = LDAP_INAPPROPRIATE_AUTH; 2136 if ( sendok & LDAP_BACK_SENDERR ) { 2137 send_ldap_result( op, rs ); 2138 dobind = -1; 2139 } 2140 2141 } else { 2142 rs->sr_err = LDAP_SUCCESS; 2143 *binddn = slap_empty_bv; 2144 *bindcred = slap_empty_bv; 2145 break; 2146 } 2147 2148 goto done; 2149 2150 } else if ( !be_isroot( op ) ) { 2151 if ( li->li_idassert_passthru ) { 2152 struct berval authcDN; 2153 2154 if ( BER_BVISNULL( &ndn ) ) { 2155 authcDN = slap_empty_bv; 2156 2157 } else { 2158 authcDN = ndn; 2159 } 2160 rs->sr_err = slap_sasl_matches( op, li->li_idassert_passthru, 2161 &authcDN, &authcDN ); 2162 if ( rs->sr_err == LDAP_SUCCESS ) { 2163 dobind = 0; 2164 break; 2165 } 2166 } 2167 2168 if ( li->li_idassert_authz ) { 2169 struct berval authcDN; 2170 2171 if ( BER_BVISNULL( &ndn ) ) { 2172 authcDN = slap_empty_bv; 2173 2174 } else { 2175 authcDN = ndn; 2176 } 2177 rs->sr_err = slap_sasl_matches( op, li->li_idassert_authz, 2178 &authcDN, &authcDN ); 2179 if ( rs->sr_err != LDAP_SUCCESS ) { 2180 if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) { 2181 if ( sendok & LDAP_BACK_SENDERR ) { 2182 send_ldap_result( op, rs ); 2183 dobind = -1; 2184 } 2185 2186 } else { 2187 rs->sr_err = LDAP_SUCCESS; 2188 *binddn = slap_empty_bv; 2189 *bindcred = slap_empty_bv; 2190 break; 2191 } 2192 2193 goto done; 2194 } 2195 } 2196 } 2197 2198 *binddn = li->li_idassert_authcDN; 2199 *bindcred = li->li_idassert_passwd; 2200 dobind = 1; 2201 break; 2202 } 2203 2204done:; 2205 return dobind; 2206} 2207 2208static int 2209ldap_back_proxy_authz_bind( 2210 ldapconn_t *lc, 2211 Operation *op, 2212 SlapReply *rs, 2213 ldap_back_send_t sendok, 2214 struct berval *binddn, 2215 struct berval *bindcred ) 2216{ 2217 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; 2218 struct berval ndn; 2219 int msgid; 2220 int rc; 2221 2222 if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) { 2223 ndn = op->o_conn->c_ndn; 2224 2225 } else { 2226 ndn = op->o_ndn; 2227 } 2228 2229 if ( li->li_idassert_authmethod == LDAP_AUTH_SASL ) { 2230#ifdef HAVE_CYRUS_SASL 2231 void *defaults = NULL; 2232 struct berval authzID = BER_BVNULL; 2233 int freeauthz = 0; 2234 LDAPControl **ctrlsp = NULL; 2235 LDAPMessage *result = NULL; 2236 const char *rmech = NULL; 2237 const char *save_text = rs->sr_text; 2238 2239#ifdef SLAP_AUTH_DN 2240 LDAPControl ctrl, *ctrls[2]; 2241 int msgid; 2242#endif /* SLAP_AUTH_DN */ 2243 2244 /* if SASL supports native authz, prepare for it */ 2245 if ( ( !op->o_do_not_cache || !op->o_is_auth_check ) && 2246 ( li->li_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) ) 2247 { 2248 switch ( li->li_idassert_mode ) { 2249 case LDAP_BACK_IDASSERT_OTHERID: 2250 case LDAP_BACK_IDASSERT_OTHERDN: 2251 authzID = li->li_idassert_authzID; 2252 break; 2253 2254 case LDAP_BACK_IDASSERT_ANONYMOUS: 2255 BER_BVSTR( &authzID, "dn:" ); 2256 break; 2257 2258 case LDAP_BACK_IDASSERT_SELF: 2259 if ( BER_BVISNULL( &ndn ) ) { 2260 /* connection is not authc'd, so don't idassert */ 2261 BER_BVSTR( &authzID, "dn:" ); 2262 break; 2263 } 2264 authzID.bv_len = STRLENOF( "dn:" ) + ndn.bv_len; 2265 authzID.bv_val = slap_sl_malloc( authzID.bv_len + 1, op->o_tmpmemctx ); 2266 AC_MEMCPY( authzID.bv_val, "dn:", STRLENOF( "dn:" ) ); 2267 AC_MEMCPY( authzID.bv_val + STRLENOF( "dn:" ), 2268 ndn.bv_val, ndn.bv_len + 1 ); 2269 freeauthz = 1; 2270 break; 2271 2272 default: 2273 break; 2274 } 2275 } 2276 2277 if ( li->li_idassert_secprops != NULL ) { 2278 rs->sr_err = ldap_set_option( lc->lc_ld, 2279 LDAP_OPT_X_SASL_SECPROPS, 2280 (void *)li->li_idassert_secprops ); 2281 2282 if ( rs->sr_err != LDAP_OPT_SUCCESS ) { 2283 rs->sr_err = LDAP_OTHER; 2284 if ( sendok & LDAP_BACK_SENDERR ) { 2285 send_ldap_result( op, rs ); 2286 } 2287 LDAP_BACK_CONN_ISBOUND_CLEAR( lc ); 2288 goto done; 2289 } 2290 } 2291 2292 defaults = lutil_sasl_defaults( lc->lc_ld, 2293 li->li_idassert_sasl_mech.bv_val, 2294 li->li_idassert_sasl_realm.bv_val, 2295 li->li_idassert_authcID.bv_val, 2296 li->li_idassert_passwd.bv_val, 2297 authzID.bv_val ); 2298 if ( defaults == NULL ) { 2299 rs->sr_err = LDAP_OTHER; 2300 LDAP_BACK_CONN_ISBOUND_CLEAR( lc ); 2301 if ( sendok & LDAP_BACK_SENDERR ) { 2302 send_ldap_result( op, rs ); 2303 } 2304 goto done; 2305 } 2306 2307#ifdef SLAP_AUTH_DN 2308 if ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_AUTHZID ) { 2309 assert( BER_BVISNULL( binddn ) ); 2310 2311 ctrl.ldctl_oid = LDAP_CONTROL_AUTHZID_REQUEST; 2312 ctrl.ldctl_iscritical = 0; 2313 BER_BVZERO( &ctrl.ldctl_value ); 2314 ctrls[0] = &ctrl; 2315 ctrls[1] = NULL; 2316 ctrlsp = ctrls; 2317 } 2318#endif /* SLAP_AUTH_DN */ 2319 2320 do { 2321 rs->sr_err = ldap_sasl_interactive_bind( lc->lc_ld, binddn->bv_val, 2322 li->li_idassert_sasl_mech.bv_val, 2323 ctrlsp, NULL, LDAP_SASL_QUIET, lutil_sasl_interact, defaults, 2324 result, &rmech, &msgid ); 2325 2326 if ( rs->sr_err != LDAP_SASL_BIND_IN_PROGRESS ) 2327 break; 2328 2329 ldap_msgfree( result ); 2330 2331 if ( ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) { 2332 ldap_get_option( lc->lc_ld, LDAP_OPT_RESULT_CODE, (void*)&rs->sr_err ); 2333 ldap_get_option( lc->lc_ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*)&rs->sr_text ); 2334 break; 2335 } 2336 } while ( rs->sr_err == LDAP_SASL_BIND_IN_PROGRESS ); 2337 2338 ldap_pvt_thread_mutex_lock( &li->li_counter_mutex ); 2339 ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_BIND ], 1 ); 2340 ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex ); 2341 2342 switch ( rs->sr_err ) { 2343 case LDAP_SUCCESS: 2344#ifdef SLAP_AUTH_DN 2345 /* FIXME: right now, the only reason to check 2346 * response controls is RFC 3829 authzid */ 2347 if ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_AUTHZID ) { 2348 ctrlsp = NULL; 2349 rc = ldap_parse_result( lc->lc_ld, result, NULL, NULL, NULL, NULL, 2350 &ctrlsp, 0 ); 2351 if ( rc == LDAP_SUCCESS && ctrlsp ) { 2352 LDAPControl *ctrl; 2353 2354 ctrl = ldap_control_find( LDAP_CONTROL_AUTHZID_RESPONSE, 2355 ctrlsp, NULL ); 2356 if ( ctrl ) { 2357 Debug( LDAP_DEBUG_TRACE, "%s: ldap_back_proxy_authz_bind: authzID=\"%s\" (authzid)\n", 2358 op->o_log_prefix, ctrl->ldctl_value.bv_val ); 2359 if ( ctrl->ldctl_value.bv_len > STRLENOF("dn:") && 2360 strncasecmp( ctrl->ldctl_value.bv_val, "dn:", STRLENOF("dn:") ) == 0 ) 2361 { 2362 struct berval bv; 2363 bv.bv_val = &ctrl->ldctl_value.bv_val[STRLENOF("dn:")]; 2364 bv.bv_len = ctrl->ldctl_value.bv_len - STRLENOF("dn:"); 2365 ber_bvreplace( &lc->lc_bound_ndn, &bv ); 2366 } 2367 } 2368 } 2369 2370 ldap_controls_free( ctrlsp ); 2371 2372 } else if ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_WHOAMI ) { 2373 struct berval *val = NULL; 2374 rc = ldap_whoami_s( lc->lc_ld, &val, NULL, NULL ); 2375 if ( rc == LDAP_SUCCESS && val != NULL ) { 2376 Debug( LDAP_DEBUG_TRACE, "%s: ldap_back_proxy_authz_bind: authzID=\"%s\" (whoami)\n", 2377 op->o_log_prefix, val->bv_val ); 2378 if ( val->bv_len > STRLENOF("dn:") && 2379 strncasecmp( val->bv_val, "dn:", STRLENOF("dn:") ) == 0 ) 2380 { 2381 struct berval bv; 2382 bv.bv_val = &val->bv_val[STRLENOF("dn:")]; 2383 bv.bv_len = val->bv_len - STRLENOF("dn:"); 2384 ber_bvreplace( &lc->lc_bound_ndn, &bv ); 2385 } 2386 ber_bvfree( val ); 2387 } 2388 } 2389 2390 if ( ( li->li_idassert_flags & LDAP_BACK_AUTH_DN_MASK ) && 2391 BER_BVISNULL( &lc->lc_bound_ndn ) ) 2392 { 2393 /* all in all, we only need it to be non-null */ 2394 /* FIXME: should this be configurable? */ 2395 static struct berval bv = BER_BVC("cn=authzdn"); 2396 ber_bvreplace( &lc->lc_bound_ndn, &bv ); 2397 } 2398#endif /* SLAP_AUTH_DN */ 2399 LDAP_BACK_CONN_ISBOUND_SET( lc ); 2400 break; 2401 2402 case LDAP_LOCAL_ERROR: 2403 /* list client API error codes that require 2404 * to taint the connection */ 2405 /* FIXME: should actually retry? */ 2406 LDAP_BACK_CONN_TAINTED_SET( lc ); 2407 2408 /* fallthru */ 2409 2410 default: 2411 LDAP_BACK_CONN_ISBOUND_CLEAR( lc ); 2412 rs->sr_err = slap_map_api2result( rs ); 2413 if ( sendok & LDAP_BACK_SENDERR ) { 2414 send_ldap_result( op, rs ); 2415 } 2416 break; 2417 } 2418 2419 if ( save_text != rs->sr_text ) { 2420 ldap_memfree( (char *)rs->sr_text ); 2421 rs->sr_text = save_text; 2422 } 2423 2424 ldap_msgfree( result ); 2425 2426 lutil_sasl_freedefs( defaults ); 2427 if ( freeauthz ) { 2428 slap_sl_free( authzID.bv_val, op->o_tmpmemctx ); 2429 } 2430 2431 goto done; 2432#endif /* HAVE_CYRUS_SASL */ 2433 } 2434 2435 switch ( li->li_idassert_authmethod ) { 2436 case LDAP_AUTH_NONE: 2437 /* FIXME: do we really need this? */ 2438 BER_BVSTR( binddn, "" ); 2439 BER_BVSTR( bindcred, "" ); 2440 /* fallthru */ 2441 2442 case LDAP_AUTH_SIMPLE: 2443 rs->sr_err = ldap_sasl_bind( lc->lc_ld, 2444 binddn->bv_val, LDAP_SASL_SIMPLE, 2445 bindcred, NULL, NULL, &msgid ); 2446 rc = ldap_back_op_result( lc, op, rs, msgid, 2447 -1, ( sendok | LDAP_BACK_BINDING ) ); 2448 2449 ldap_pvt_thread_mutex_lock( &li->li_counter_mutex ); 2450 ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_BIND ], 1 ); 2451 ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex ); 2452 break; 2453 2454 default: 2455 /* unsupported! */ 2456 LDAP_BACK_CONN_ISBOUND_CLEAR( lc ); 2457 rs->sr_err = LDAP_AUTH_METHOD_NOT_SUPPORTED; 2458 if ( sendok & LDAP_BACK_SENDERR ) { 2459 send_ldap_result( op, rs ); 2460 } 2461 goto done; 2462 } 2463 2464 if ( rc == LDAP_SUCCESS ) { 2465 /* set rebind stuff in case of successful proxyAuthz bind, 2466 * so that referral chasing is attempted using the right 2467 * identity */ 2468 LDAP_BACK_CONN_ISBOUND_SET( lc ); 2469 if ( !BER_BVISNULL( binddn ) ) { 2470 ber_bvreplace( &lc->lc_bound_ndn, binddn ); 2471 } 2472 2473 if ( !BER_BVISNULL( &lc->lc_cred ) ) { 2474 memset( lc->lc_cred.bv_val, 0, 2475 lc->lc_cred.bv_len ); 2476 } 2477 2478 if ( LDAP_BACK_SAVECRED( li ) ) { 2479 if ( !BER_BVISNULL( bindcred ) ) { 2480 ber_bvreplace( &lc->lc_cred, bindcred ); 2481 ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc ); 2482 } 2483 2484 } else { 2485 lc->lc_cred.bv_len = 0; 2486 } 2487 } 2488 2489done:; 2490 return LDAP_BACK_CONN_ISBOUND( lc ); 2491} 2492 2493/* 2494 * ldap_back_proxy_authz_ctrl() prepends a proxyAuthz control 2495 * to existing server-side controls if required; if not, 2496 * the existing server-side controls are placed in *pctrls. 2497 * The caller, after using the controls in client API 2498 * operations, if ( *pctrls != op->o_ctrls ), should 2499 * free( (*pctrls)[ 0 ] ) and free( *pctrls ). 2500 * The function returns success if the control could 2501 * be added if required, or if it did nothing; in the future, 2502 * it might return some error if it failed. 2503 * 2504 * if no bind took place yet, but the connection is bound 2505 * and the "proxyauthzdn" is set, then bind as "proxyauthzdn" 2506 * and explicitly add proxyAuthz the control to every operation 2507 * with the dn bound to the connection as control value. 2508 * 2509 * If no server-side controls are defined for the operation, 2510 * simply add the proxyAuthz control; otherwise, if the 2511 * proxyAuthz control is not already set, add it as 2512 * the first one 2513 * 2514 * FIXME: is controls order significant for security? 2515 * ANSWER: controls ordering and interoperability 2516 * must be indicated by the specs of each control; if none 2517 * is specified, the order is irrelevant. 2518 */ 2519int 2520ldap_back_proxy_authz_ctrl( 2521 Operation *op, 2522 SlapReply *rs, 2523 struct berval *bound_ndn, 2524 int version, 2525 slap_idassert_t *si, 2526 LDAPControl *ctrl ) 2527{ 2528 slap_idassert_mode_t mode; 2529 struct berval assertedID, 2530 ndn; 2531 int isroot = 0; 2532 2533 rs->sr_err = SLAP_CB_CONTINUE; 2534 2535 /* FIXME: SASL/EXTERNAL over ldapi:// doesn't honor the authcID, 2536 * but if it is not set this test fails. We need a different 2537 * means to detect if idassert is enabled */ 2538 if ( ( BER_BVISNULL( &si->si_bc.sb_authcId ) || BER_BVISEMPTY( &si->si_bc.sb_authcId ) ) 2539 && ( BER_BVISNULL( &si->si_bc.sb_binddn ) || BER_BVISEMPTY( &si->si_bc.sb_binddn ) ) 2540 && BER_BVISNULL( &si->si_bc.sb_saslmech ) ) 2541 { 2542 goto done; 2543 } 2544 2545 if ( !op->o_conn || op->o_do_not_cache || ( isroot = be_isroot( op ) ) ) { 2546 goto done; 2547 } 2548 2549 if ( op->o_tag == LDAP_REQ_BIND ) { 2550 ndn = op->o_req_ndn; 2551 } else { 2552 ndn = op->o_ndn; 2553 } 2554 2555 if ( si->si_mode == LDAP_BACK_IDASSERT_LEGACY ) { 2556 if ( op->o_proxy_authz ) { 2557 /* 2558 * FIXME: we do not want to perform proxyAuthz 2559 * on behalf of the client, because this would 2560 * be performed with "proxyauthzdn" privileges. 2561 * 2562 * This might actually be too strict, since 2563 * the "proxyauthzdn" authzTo, and each entry's 2564 * authzFrom attributes may be crafted 2565 * to avoid unwanted proxyAuthz to take place. 2566 */ 2567#if 0 2568 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 2569 rs->sr_text = "proxyAuthz not allowed within namingContext"; 2570#endif 2571 goto done; 2572 } 2573 2574 if ( !BER_BVISNULL( bound_ndn ) ) { 2575 goto done; 2576 } 2577 2578 if ( BER_BVISNULL( &ndn ) ) { 2579 goto done; 2580 } 2581 2582 if ( BER_BVISNULL( &si->si_bc.sb_binddn ) ) { 2583 goto done; 2584 } 2585 2586 } else if ( si->si_bc.sb_method == LDAP_AUTH_SASL ) { 2587 if ( ( si->si_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) ) 2588 { 2589 /* already asserted in SASL via native authz */ 2590 goto done; 2591 } 2592 2593 } else if ( si->si_authz && !isroot ) { 2594 int rc; 2595 struct berval authcDN; 2596 2597 if ( BER_BVISNULL( &ndn ) ) { 2598 authcDN = slap_empty_bv; 2599 } else { 2600 authcDN = ndn; 2601 } 2602 rc = slap_sasl_matches( op, si->si_authz, 2603 &authcDN, &authcDN ); 2604 if ( rc != LDAP_SUCCESS ) { 2605 if ( si->si_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) { 2606 /* ndn is not authorized 2607 * to use idassert */ 2608 rs->sr_err = rc; 2609 } 2610 goto done; 2611 } 2612 } 2613 2614 if ( op->o_proxy_authz ) { 2615 /* 2616 * FIXME: we can: 2617 * 1) ignore the already set proxyAuthz control 2618 * 2) leave it in place, and don't set ours 2619 * 3) add both 2620 * 4) reject the operation 2621 * 2622 * option (4) is very drastic 2623 * option (3) will make the remote server reject 2624 * the operation, thus being equivalent to (4) 2625 * option (2) will likely break the idassert 2626 * assumptions, so we cannot accept it; 2627 * option (1) means that we are contradicting 2628 * the client's request. 2629 * 2630 * I think (4) is the only correct choice. 2631 */ 2632 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 2633 rs->sr_text = "proxyAuthz not allowed within namingContext"; 2634 } 2635 2636 if ( op->o_is_auth_check ) { 2637 mode = LDAP_BACK_IDASSERT_NOASSERT; 2638 2639 } else { 2640 mode = si->si_mode; 2641 } 2642 2643 switch ( mode ) { 2644 case LDAP_BACK_IDASSERT_LEGACY: 2645 /* original behavior: 2646 * assert the client's identity */ 2647 case LDAP_BACK_IDASSERT_SELF: 2648 assertedID = ndn; 2649 break; 2650 2651 case LDAP_BACK_IDASSERT_ANONYMOUS: 2652 /* assert "anonymous" */ 2653 assertedID = slap_empty_bv; 2654 break; 2655 2656 case LDAP_BACK_IDASSERT_NOASSERT: 2657 /* don't assert; bind as proxyauthzdn */ 2658 goto done; 2659 2660 case LDAP_BACK_IDASSERT_OTHERID: 2661 case LDAP_BACK_IDASSERT_OTHERDN: 2662 /* assert idassert DN */ 2663 assertedID = si->si_bc.sb_authzId; 2664 break; 2665 2666 default: 2667 assert( 0 ); 2668 } 2669 2670 /* if we got here, "" is allowed to proxyAuthz */ 2671 if ( BER_BVISNULL( &assertedID ) ) { 2672 assertedID = slap_empty_bv; 2673 } 2674 2675 /* don't idassert the bound DN (ITS#4497) */ 2676 if ( dn_match( &assertedID, bound_ndn ) ) { 2677 goto done; 2678 } 2679 2680 ctrl->ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ; 2681 ctrl->ldctl_iscritical = ( ( si->si_flags & LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL ) == LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL ); 2682 2683 switch ( si->si_mode ) { 2684 /* already in u:ID or dn:DN form */ 2685 case LDAP_BACK_IDASSERT_OTHERID: 2686 case LDAP_BACK_IDASSERT_OTHERDN: 2687 ber_dupbv_x( &ctrl->ldctl_value, &assertedID, op->o_tmpmemctx ); 2688 rs->sr_err = LDAP_SUCCESS; 2689 break; 2690 2691 /* needs the dn: prefix */ 2692 default: 2693 ctrl->ldctl_value.bv_len = assertedID.bv_len + STRLENOF( "dn:" ); 2694 ctrl->ldctl_value.bv_val = op->o_tmpalloc( ctrl->ldctl_value.bv_len + 1, 2695 op->o_tmpmemctx ); 2696 AC_MEMCPY( ctrl->ldctl_value.bv_val, "dn:", STRLENOF( "dn:" ) ); 2697 AC_MEMCPY( &ctrl->ldctl_value.bv_val[ STRLENOF( "dn:" ) ], 2698 assertedID.bv_val, assertedID.bv_len + 1 ); 2699 rs->sr_err = LDAP_SUCCESS; 2700 break; 2701 } 2702 2703 /* Older versions of <draft-weltman-ldapv3-proxy> required 2704 * to encode the value of the authzID (and called it proxyDN); 2705 * this hack provides compatibility with those DSAs that 2706 * implement it this way */ 2707 if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) { 2708 struct berval authzID = ctrl->ldctl_value; 2709 BerElementBuffer berbuf; 2710 BerElement *ber = (BerElement *)&berbuf; 2711 ber_tag_t tag; 2712 2713 ber_init2( ber, 0, LBER_USE_DER ); 2714 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); 2715 2716 tag = ber_printf( ber, "O", &authzID ); 2717 if ( tag == LBER_ERROR ) { 2718 rs->sr_err = LDAP_OTHER; 2719 goto free_ber; 2720 } 2721 2722 if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) { 2723 rs->sr_err = LDAP_OTHER; 2724 goto free_ber; 2725 } 2726 2727 rs->sr_err = LDAP_SUCCESS; 2728 2729free_ber:; 2730 op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx ); 2731 ber_free_buf( ber ); 2732 2733 if ( rs->sr_err != LDAP_SUCCESS ) { 2734 goto done; 2735 } 2736 2737 } else if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) { 2738 struct berval authzID = ctrl->ldctl_value, 2739 tmp; 2740 BerElementBuffer berbuf; 2741 BerElement *ber = (BerElement *)&berbuf; 2742 ber_tag_t tag; 2743 2744 if ( strncasecmp( authzID.bv_val, "dn:", STRLENOF( "dn:" ) ) != 0 ) { 2745 rs->sr_err = LDAP_PROTOCOL_ERROR; 2746 goto done; 2747 } 2748 2749 tmp = authzID; 2750 tmp.bv_val += STRLENOF( "dn:" ); 2751 tmp.bv_len -= STRLENOF( "dn:" ); 2752 2753 ber_init2( ber, 0, LBER_USE_DER ); 2754 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx ); 2755 2756 /* apparently, Mozilla API encodes this 2757 * as "SEQUENCE { LDAPDN }" */ 2758 tag = ber_printf( ber, "{O}", &tmp ); 2759 if ( tag == LBER_ERROR ) { 2760 rs->sr_err = LDAP_OTHER; 2761 goto free_ber2; 2762 } 2763 2764 if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) { 2765 rs->sr_err = LDAP_OTHER; 2766 goto free_ber2; 2767 } 2768 2769 ctrl->ldctl_oid = LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ; 2770 rs->sr_err = LDAP_SUCCESS; 2771 2772free_ber2:; 2773 op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx ); 2774 ber_free_buf( ber ); 2775 2776 if ( rs->sr_err != LDAP_SUCCESS ) { 2777 goto done; 2778 } 2779 } 2780 2781done:; 2782 2783 return rs->sr_err; 2784} 2785 2786/* 2787 * Add controls; 2788 * 2789 * if any needs to be added, it is prepended to existing ones, 2790 * in a newly allocated array. The companion function 2791 * ldap_back_controls_free() must be used to restore the original 2792 * status of op->o_ctrls. 2793 */ 2794int 2795ldap_back_controls_add( 2796 Operation *op, 2797 SlapReply *rs, 2798 ldapconn_t *lc, 2799 LDAPControl ***pctrls ) 2800{ 2801 ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; 2802 2803 LDAPControl **ctrls = NULL; 2804 /* set to the maximum number of controls this backend can add */ 2805 LDAPControl c[ 2 ] = { { 0 } }; 2806 int n = 0, i, j1 = 0, j2 = 0, skipped = 0; 2807 2808 *pctrls = NULL; 2809 2810 rs->sr_err = LDAP_SUCCESS; 2811 2812 /* don't add controls if protocol is not LDAPv3 */ 2813 switch ( li->li_version ) { 2814 case LDAP_VERSION3: 2815 break; 2816 2817 case 0: 2818 if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) { 2819 break; 2820 } 2821 /* fall thru */ 2822 2823 default: 2824 goto done; 2825 } 2826 2827 /* put controls that go __before__ existing ones here */ 2828 2829 /* proxyAuthz for identity assertion */ 2830 switch ( ldap_back_proxy_authz_ctrl( op, rs, &lc->lc_bound_ndn, 2831 li->li_version, &li->li_idassert, &c[ j1 ] ) ) 2832 { 2833 case SLAP_CB_CONTINUE: 2834 break; 2835 2836 case LDAP_SUCCESS: 2837 j1++; 2838 break; 2839 2840 default: 2841 goto done; 2842 } 2843 2844 /* put controls that go __after__ existing ones here */ 2845 2846#ifdef SLAP_CONTROL_X_SESSION_TRACKING 2847 /* FIXME: according to <draft-wahl-ldap-session>, 2848 * the server should check if the control can be added 2849 * based on the identity of the client and so */ 2850 2851 /* session tracking */ 2852 if ( LDAP_BACK_ST_REQUEST( li ) ) { 2853 switch ( slap_ctrl_session_tracking_request_add( op, rs, &c[ j1 + j2 ] ) ) { 2854 case SLAP_CB_CONTINUE: 2855 break; 2856 2857 case LDAP_SUCCESS: 2858 j2++; 2859 break; 2860 2861 default: 2862 goto done; 2863 } 2864 } 2865#endif /* SLAP_CONTROL_X_SESSION_TRACKING */ 2866 2867 if ( rs->sr_err == SLAP_CB_CONTINUE ) { 2868 rs->sr_err = LDAP_SUCCESS; 2869 } 2870 2871 /* if nothing to do, just bail out */ 2872 if ( j1 == 0 && j2 == 0 ) { 2873 goto done; 2874 } 2875 2876 assert( j1 + j2 <= (int) (sizeof( c )/sizeof( c[0] )) ); 2877 2878 if ( op->o_ctrls ) { 2879 for ( n = 0; op->o_ctrls[ n ]; n++ ) 2880 /* just count ctrls */ ; 2881 } 2882 2883 ctrls = op->o_tmpalloc( (n + j1 + j2 + 1) * sizeof( LDAPControl * ) + ( j1 + j2 ) * sizeof( LDAPControl ), 2884 op->o_tmpmemctx ); 2885 if ( j1 ) { 2886 ctrls[ 0 ] = (LDAPControl *)&ctrls[ n + j1 + j2 + 1 ]; 2887 *ctrls[ 0 ] = c[ 0 ]; 2888 for ( i = 1; i < j1; i++ ) { 2889 ctrls[ i ] = &ctrls[ 0 ][ i ]; 2890 *ctrls[ i ] = c[ i ]; 2891 } 2892 } 2893 2894 i = 0; 2895 if ( op->o_ctrls ) { 2896 LDAPControl *proxyauthz = ldap_control_find( 2897 LDAP_CONTROL_PROXY_AUTHZ, op->o_ctrls, NULL ); 2898 2899 for ( i = 0; op->o_ctrls[ i ]; i++ ) { 2900 /* Only replace it if we generated one */ 2901 if ( j1 && proxyauthz && proxyauthz == op->o_ctrls[ i ] ) { 2902 /* Frontend has already checked only one is present */ 2903 assert( skipped == 0 ); 2904 skipped++; 2905 continue; 2906 } 2907 ctrls[ i + j1 - skipped ] = op->o_ctrls[ i ]; 2908 } 2909 } 2910 2911 n += j1 - skipped; 2912 if ( j2 ) { 2913 ctrls[ n ] = (LDAPControl *)&ctrls[ n + j2 + 1 ] + j1; 2914 *ctrls[ n ] = c[ j1 ]; 2915 for ( i = 1; i < j2; i++ ) { 2916 ctrls[ n + i ] = &ctrls[ n ][ i ]; 2917 *ctrls[ n + i ] = c[ i ]; 2918 } 2919 } 2920 2921 ctrls[ n + j2 ] = NULL; 2922 2923done:; 2924 if ( ctrls == NULL ) { 2925 ctrls = op->o_ctrls; 2926 } 2927 2928 *pctrls = ctrls; 2929 2930 return rs->sr_err; 2931} 2932 2933int 2934ldap_back_controls_free( Operation *op, SlapReply *rs, LDAPControl ***pctrls ) 2935{ 2936 LDAPControl **ctrls = *pctrls; 2937 2938 /* we assume that the controls added by the proxy come first, 2939 * so as soon as we find op->o_ctrls[ 0 ] we can stop */ 2940 if ( ctrls && ctrls != op->o_ctrls ) { 2941 int i = 0, n = 0, n_added; 2942 LDAPControl *lower, *upper; 2943 2944 assert( ctrls[ 0 ] != NULL ); 2945 2946 for ( n = 0; ctrls[ n ] != NULL; n++ ) 2947 /* count 'em */ ; 2948 2949 if ( op->o_ctrls ) { 2950 for ( i = 0; op->o_ctrls[ i ] != NULL; i++ ) 2951 /* count 'em */ ; 2952 } 2953 2954 n_added = n - i; 2955 lower = (LDAPControl *)&ctrls[ n ]; 2956 upper = &lower[ n_added ]; 2957 2958 for ( i = 0; ctrls[ i ] != NULL; i++ ) { 2959 if ( ctrls[ i ] < lower || ctrls[ i ] >= upper ) { 2960 /* original; don't touch */ 2961 continue; 2962 } 2963 2964 if ( !BER_BVISNULL( &ctrls[ i ]->ldctl_value ) ) { 2965 op->o_tmpfree( ctrls[ i ]->ldctl_value.bv_val, op->o_tmpmemctx ); 2966 } 2967 } 2968 2969 op->o_tmpfree( ctrls, op->o_tmpmemctx ); 2970 } 2971 2972 *pctrls = NULL; 2973 2974 return 0; 2975} 2976 2977int 2978ldap_back_conn2str( const ldapconn_base_t *lc, char *buf, ber_len_t buflen ) 2979{ 2980 char tbuf[ SLAP_TEXT_BUFLEN ]; 2981 char *ptr = buf, *end = buf + buflen; 2982 int len; 2983 2984 if ( ptr + sizeof("conn=") > end ) return -1; 2985 ptr = lutil_strcopy( ptr, "conn=" ); 2986 2987 len = ldap_back_connid2str( lc, ptr, (ber_len_t)(end - ptr) ); 2988 ptr += len; 2989 if ( ptr >= end ) return -1; 2990 2991 if ( !BER_BVISNULL( &lc->lcb_local_ndn ) ) { 2992 if ( ptr + sizeof(" DN=\"\"") + lc->lcb_local_ndn.bv_len > end ) return -1; 2993 ptr = lutil_strcopy( ptr, " DN=\"" ); 2994 ptr = lutil_strncopy( ptr, lc->lcb_local_ndn.bv_val, lc->lcb_local_ndn.bv_len ); 2995 *ptr++ = '"'; 2996 } 2997 2998 if ( lc->lcb_create_time != 0 ) { 2999 len = snprintf( tbuf, sizeof(tbuf), "%ld", lc->lcb_create_time ); 3000 if ( ptr + sizeof(" created=") + len >= end ) return -1; 3001 ptr = lutil_strcopy( ptr, " created=" ); 3002 ptr = lutil_strcopy( ptr, tbuf ); 3003 } 3004 3005 if ( lc->lcb_time != 0 ) { 3006 len = snprintf( tbuf, sizeof(tbuf), "%ld", lc->lcb_time ); 3007 if ( ptr + sizeof(" modified=") + len >= end ) return -1; 3008 ptr = lutil_strcopy( ptr, " modified=" ); 3009 ptr = lutil_strcopy( ptr, tbuf ); 3010 } 3011 3012 len = snprintf( tbuf, sizeof(tbuf), "%u", lc->lcb_refcnt ); 3013 if ( ptr + sizeof(" refcnt=") + len >= end ) return -1; 3014 ptr = lutil_strcopy( ptr, " refcnt=" ); 3015 ptr = lutil_strcopy( ptr, tbuf ); 3016 3017 return ptr - buf; 3018} 3019 3020int 3021ldap_back_connid2str( const ldapconn_base_t *lc, char *buf, ber_len_t buflen ) 3022{ 3023 static struct berval conns[] = { 3024 BER_BVC("ROOTDN"), 3025 BER_BVC("ROOTDN-TLS"), 3026 BER_BVC("ANON"), 3027 BER_BVC("ANON-TLS"), 3028 BER_BVC("BIND"), 3029 BER_BVC("BIND-TLS"), 3030 BER_BVNULL 3031 }; 3032 3033 int len = 0; 3034 3035 if ( LDAP_BACK_PCONN_ISPRIV( (const ldapconn_t *)lc ) ) { 3036 long cid; 3037 struct berval *bv; 3038 3039 cid = (long)lc->lcb_conn; 3040 assert( cid >= LDAP_BACK_PCONN_FIRST && cid < LDAP_BACK_PCONN_LAST ); 3041 3042 bv = &conns[ cid ]; 3043 3044 if ( bv->bv_len >= buflen ) { 3045 return bv->bv_len + 1; 3046 } 3047 3048 len = bv->bv_len; 3049 lutil_strncopy( buf, bv->bv_val, bv->bv_len + 1 ); 3050 3051 } else { 3052 len = snprintf( buf, buflen, "%lu", lc->lcb_conn->c_connid ); 3053 } 3054 3055 return len; 3056} 3057 3058void * 3059ldap_back_conn_expire_fn( void *ctx, void *arg ) 3060{ 3061 struct re_s *rtask = arg; 3062 ldapinfo_t *li = (ldapinfo_t *)rtask->arg; 3063 ldap_back_conn_prune( li ); 3064 3065 return NULL; 3066} 3067 3068/* Pick which expires first: connection TTL or idle timeout */ 3069static time_t 3070ldap_back_conn_expire_time( ldapinfo_t *li, ldapconn_t *lc) { 3071 if ( li->li_conn_ttl != 0 && li->li_idle_timeout != 0 ) { 3072 return ( lc->lc_create_time + li->li_conn_ttl ) < ( lc->lc_time + li->li_idle_timeout ) ? 3073 ( lc->lc_create_time + li->li_conn_ttl ) : ( lc->lc_time + li->li_idle_timeout ); 3074 } else if ( li->li_conn_ttl != 0 ) { 3075 return lc->lc_create_time + li->li_conn_ttl; 3076 } else if ( li->li_idle_timeout != 0 ) { 3077 return lc->lc_time + li->li_idle_timeout; 3078 } 3079 return -1; 3080} 3081 3082static void 3083ldap_back_conn_prune( ldapinfo_t *li ) 3084{ 3085 time_t now = slap_get_time(); 3086 time_t next_timeout = -1; /* -1 means uninitialized */ 3087 TAvlnode *edge; 3088 int c; 3089 3090 /* 3091 * Iterate though connections and close those that are pass the expiry time. 3092 * Also calculate the time for next connection to to expire. 3093 */ 3094 ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); 3095 3096 for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) { 3097 ldapconn_t *lc = LDAP_TAILQ_FIRST( &li->li_conn_priv[ c ].lic_priv ); 3098 3099 while ( lc ) { 3100 ldapconn_t *next = LDAP_TAILQ_NEXT( lc, lc_q ); 3101 time_t conn_expires = ldap_back_conn_expire_time( li, lc ); 3102 3103 if ( now >= conn_expires ) { 3104 if ( lc->lc_refcnt == 0 ) { 3105 Debug( LDAP_DEBUG_TRACE, 3106 "ldap_back_conn_prune: closing expired connection lc=%p\n", 3107 lc ); 3108 ldap_back_freeconn( li, lc, 0 ); 3109 } else { 3110 Debug( LDAP_DEBUG_TRACE, 3111 "ldap_back_conn_prune: tainting expired connection lc=%p\n", 3112 lc ); 3113 LDAP_BACK_CONN_TAINTED_SET( lc ); 3114 } 3115 } else if ( next_timeout == -1 || conn_expires < next_timeout ) { 3116 /* next_timeout was not yet initialized or current connection expires sooner */ 3117 next_timeout = conn_expires; 3118 } 3119 3120 lc = next; 3121 } 3122 } 3123 3124 edge = ldap_tavl_end( li->li_conninfo.lai_tree, TAVL_DIR_LEFT ); 3125 while ( edge ) { 3126 TAvlnode *next = ldap_tavl_next( edge, TAVL_DIR_RIGHT ); 3127 ldapconn_t *lc = (ldapconn_t *)edge->avl_data; 3128 time_t conn_expires = ldap_back_conn_expire_time( li, lc ); 3129 3130 if ( now >= conn_expires ) { 3131 if ( lc->lc_refcnt == 0 ) { 3132 Debug( LDAP_DEBUG_TRACE, 3133 "ldap_back_conn_prune: closing expired connection lc=%p\n", 3134 lc ); 3135 ldap_back_freeconn( li, lc, 0 ); 3136 } else { 3137 Debug( LDAP_DEBUG_TRACE, 3138 "ldap_back_conn_prune: tainting expired connection lc=%p\n", 3139 lc ); 3140 LDAP_BACK_CONN_TAINTED_SET( lc ); 3141 } 3142 } else if ( next_timeout == -1 || conn_expires < next_timeout ) { 3143 next_timeout = conn_expires; 3144 } 3145 3146 edge = next; 3147 } 3148 3149 ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); 3150 3151 /* Reschedule for next timeout or cancel the task */ 3152 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 3153 if ( next_timeout > 0 ) { 3154 if ( ldap_pvt_runqueue_isrunning( &slapd_rq, li->li_conn_expire_task ) ) { 3155 ldap_pvt_runqueue_stoptask( &slapd_rq, li->li_conn_expire_task ); 3156 } 3157 li->li_conn_expire_task->interval.tv_sec = next_timeout - now; 3158 ldap_pvt_runqueue_resched( &slapd_rq, li->li_conn_expire_task, 0 ); 3159 3160 /* 3161 * The thread that handles runqueue might have already processed all tasks 3162 * before we insertered new task or rescheduled the existing task with new 3163 * timeout period. Wake it up to ensure that the task will be picked up. 3164 */ 3165 slap_wake_listener(); 3166 Debug( LDAP_DEBUG_TRACE, 3167 "ldap_back_conn_prune: scheduled connection expiry timer to %ld sec\n", 3168 li->li_conn_expire_task->interval.tv_sec ); 3169 } else if ( next_timeout == -1 && li->li_conn_expire_task != NULL ) { 3170 if ( ldap_pvt_runqueue_isrunning( &slapd_rq, li->li_conn_expire_task ) ) { 3171 ldap_pvt_runqueue_stoptask( &slapd_rq, li->li_conn_expire_task ); 3172 } 3173 ldap_pvt_runqueue_remove( &slapd_rq, li->li_conn_expire_task ); 3174 li->li_conn_expire_task = NULL; 3175 } 3176 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 3177 3178 return; 3179} 3180 3181static void 3182ldap_back_schedule_conn_expiry( ldapinfo_t *li, ldapconn_t *lc ) { 3183 /* Do nothing if timeouts are not set. */ 3184 if ( li->li_conn_ttl == 0 && li->li_idle_timeout == 0 ) { 3185 return; 3186 } 3187 3188 /* 3189 * If connection expire task is not running, create it and schedule for 3190 * timeout of this connection. 3191 * 3192 * If the task is already running, this connection cannot be next one 3193 * to expire and therefore timeout does not need to be re-calculated. 3194 */ 3195 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); 3196 if ( li->li_conn_expire_task == NULL ) { 3197 li->li_conn_expire_task = ldap_pvt_runqueue_insert( &slapd_rq, 3198 ldap_back_conn_expire_time( li, lc ) - slap_get_time(), 3199 ldap_back_conn_expire_fn, li, "ldap_back_conn_expire_fn", 3200 "ldap_back_conn_expire_timer" ); 3201 slap_wake_listener(); 3202 Debug( LDAP_DEBUG_TRACE, 3203 "ldap_back_conn_prune: scheduled connection expiry timer to %ld sec\n", 3204 li->li_conn_expire_task->interval.tv_sec ); 3205 } 3206 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); 3207 3208 return; 3209}