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