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