1/* $OpenLDAP$ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 1998-2011 The OpenLDAP Foundation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted only as authorized by the OpenLDAP 9 * Public License. 10 * 11 * A copy of this license is available in the file LICENSE in the 12 * top-level directory of the distribution or, alternatively, at 13 * <http://www.OpenLDAP.org/license.html>. 14 */ 15/* Portions Copyright (c) 1995 Regents of the University of Michigan. 16 * All rights reserved. 17 */ 18/* This notice applies to changes, created by or for Novell, Inc., 19 * to preexisting works for which notices appear elsewhere in this file. 20 * 21 * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved. 22 * 23 * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES. 24 * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION 25 * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT 26 * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE 27 * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS 28 * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC 29 * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE 30 * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. 31 *--- 32 * Modification to OpenLDAP source by Novell, Inc. 33 * April 2000 sfs Added code to chase V3 referrals 34 * request.c - sending of ldap requests; handling of referrals 35 *--- 36 * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License 37 * can be found in the file "build/LICENSE-2.0.1" in this distribution 38 * of OpenLDAP Software. 39 */ 40 41#include "portable.h" 42 43#include <stdio.h> 44 45#include <ac/stdlib.h> 46 47#include <ac/errno.h> 48#include <ac/socket.h> 49#include <ac/string.h> 50#include <ac/time.h> 51#include <ac/unistd.h> 52 53#include "ldap-int.h" 54#include "lber.h" 55 56/* used by ldap_send_server_request and ldap_new_connection */ 57#ifdef LDAP_R_COMPILE 58#define LDAP_CONN_LOCK_IF(nolock) \ 59 { if (nolock) LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); } 60#define LDAP_CONN_UNLOCK_IF(nolock) \ 61 { if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); } 62#define LDAP_REQ_LOCK_IF(nolock) \ 63 { if (nolock) LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); } 64#define LDAP_REQ_UNLOCK_IF(nolock) \ 65 { if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); } 66#define LDAP_RES_LOCK_IF(nolock) \ 67 { if (nolock) LDAP_MUTEX_LOCK( &ld->ld_res_mutex ); } 68#define LDAP_RES_UNLOCK_IF(nolock) \ 69 { if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex ); } 70#else 71#define LDAP_CONN_LOCK_IF(nolock) 72#define LDAP_CONN_UNLOCK_IF(nolock) 73#define LDAP_REQ_LOCK_IF(nolock) 74#define LDAP_REQ_UNLOCK_IF(nolock) 75#define LDAP_RES_LOCK_IF(nolock) 76#define LDAP_RES_UNLOCK_IF(nolock) 77#endif 78 79#ifdef LDAP_RESPONSE_RB_TREE 80#include "rb_response.h" 81#endif 82 83static LDAPConn *find_connection LDAP_P(( LDAP *ld, LDAPURLDesc *srv, int any )); 84static void use_connection LDAP_P(( LDAP *ld, LDAPConn *lc )); 85static void ldap_free_request_int LDAP_P(( LDAP *ld, LDAPRequest *lr )); 86 87static BerElement * 88re_encode_request( LDAP *ld, 89 BerElement *origber, 90 ber_int_t msgid, 91 int sref, 92 LDAPURLDesc *srv, 93 int *type ); 94 95BerElement * 96ldap_alloc_ber_with_options( LDAP *ld ) 97{ 98 BerElement *ber; 99 100 ber = ber_alloc_t( ld->ld_lberoptions ); 101 if ( ber == NULL ) { 102 ld->ld_errno = LDAP_NO_MEMORY; 103 } 104 105 return( ber ); 106} 107 108 109void 110ldap_set_ber_options( LDAP *ld, BerElement *ber ) 111{ 112 /* ld_lberoptions is constant, hence no lock */ 113 ber->ber_options = ld->ld_lberoptions; 114} 115 116 117/* sets needed mutexes - no mutexes set to this point */ 118ber_int_t 119ldap_send_initial_request( 120 LDAP *ld, 121 ber_tag_t msgtype, 122 const char *dn, 123 BerElement *ber, 124 ber_int_t msgid) 125{ 126 int rc = 1; 127 ber_socket_t sd = AC_SOCKET_INVALID; 128 129 Debug( LDAP_DEBUG_TRACE, "ldap_send_initial_request\n", 0, 0, 0 ); 130 131 LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); 132 if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd ) == -1 ) { 133 /* not connected yet */ 134 rc = ldap_open_defconn( ld ); 135 136 } 137 if ( ld->ld_defconn && ld->ld_defconn->lconn_status == LDAP_CONNST_CONNECTING ) 138 rc = ldap_int_check_async_open( ld, sd ); 139 if( rc < 0 ) { 140 ber_free( ber, 1 ); 141 LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 142 return( -1 ); 143 } else if ( rc == 0 ) { 144 Debug( LDAP_DEBUG_TRACE, 145 "ldap_open_defconn: successful\n", 146 0, 0, 0 ); 147 } 148 149#ifdef LDAP_CONNECTIONLESS 150 if (LDAP_IS_UDP(ld)) { 151 if (msgtype == LDAP_REQ_BIND) { 152 LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex ); 153 if (ld->ld_options.ldo_cldapdn) 154 ldap_memfree(ld->ld_options.ldo_cldapdn); 155 ld->ld_options.ldo_cldapdn = ldap_strdup(dn); 156 ber_free( ber, 1 ); 157 LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex ); 158 LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 159 return 0; 160 } 161 if (msgtype != LDAP_REQ_ABANDON && msgtype != LDAP_REQ_SEARCH) 162 { 163 ber_free( ber, 1 ); 164 LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 165 return LDAP_PARAM_ERROR; 166 } 167 } 168#endif 169 LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); 170 rc = ldap_send_server_request( ld, ber, msgid, NULL, 171 NULL, NULL, NULL, 0, 0 ); 172 LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); 173 LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 174 return(rc); 175} 176 177 178/* protected by conn_mutex */ 179int 180ldap_int_flush_request( 181 LDAP *ld, 182 LDAPRequest *lr ) 183{ 184 LDAPConn *lc = lr->lr_conn; 185 186 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); 187 if ( ber_flush2( lc->lconn_sb, lr->lr_ber, LBER_FLUSH_FREE_NEVER ) != 0 ) { 188 if ( sock_errno() == EAGAIN ) { 189 /* need to continue write later */ 190 lr->lr_status = LDAP_REQST_WRITING; 191 ldap_mark_select_write( ld, lc->lconn_sb ); 192 ld->ld_errno = LDAP_BUSY; 193 return -2; 194 } else { 195 ld->ld_errno = LDAP_SERVER_DOWN; 196 ldap_free_request( ld, lr ); 197 ldap_free_connection( ld, lc, 0, 0 ); 198 return( -1 ); 199 } 200 } else { 201 if ( lr->lr_parent == NULL ) { 202 lr->lr_ber->ber_end = lr->lr_ber->ber_ptr; 203 lr->lr_ber->ber_ptr = lr->lr_ber->ber_buf; 204 } 205 lr->lr_status = LDAP_REQST_INPROGRESS; 206 207 /* sent -- waiting for a response */ 208 ldap_mark_select_read( ld, lc->lconn_sb ); 209 } 210 return 0; 211} 212 213/* 214 * protected by req_mutex 215 * if m_noconn then protect using conn_lock 216 * else already protected with conn_lock 217 * if m_res then also protected by res_mutex 218 */ 219 220int 221ldap_send_server_request( 222 LDAP *ld, 223 BerElement *ber, 224 ber_int_t msgid, 225 LDAPRequest *parentreq, 226 LDAPURLDesc **srvlist, 227 LDAPConn *lc, 228 LDAPreqinfo *bind, 229 int m_noconn, 230 int m_res ) 231{ 232 LDAPRequest *lr; 233 int incparent, rc; 234 235 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); 236 Debug( LDAP_DEBUG_TRACE, "ldap_send_server_request\n", 0, 0, 0 ); 237 238 incparent = 0; 239 ld->ld_errno = LDAP_SUCCESS; /* optimistic */ 240 241 LDAP_CONN_LOCK_IF(m_noconn); 242 if ( lc == NULL ) { 243 if ( srvlist == NULL ) { 244 lc = ld->ld_defconn; 245 } else { 246 lc = find_connection( ld, *srvlist, 1 ); 247 if ( lc == NULL ) { 248 if ( (bind != NULL) && (parentreq != NULL) ) { 249 /* Remember the bind in the parent */ 250 incparent = 1; 251 ++parentreq->lr_outrefcnt; 252 } 253 lc = ldap_new_connection( ld, srvlist, 0, 254 1, bind, 1, m_res ); 255 } 256 } 257 } 258 259 /* async connect... */ 260 if ( lc != NULL && lc->lconn_status == LDAP_CONNST_CONNECTING ) { 261 ber_socket_t sd = AC_SOCKET_ERROR; 262 struct timeval tv = { 0 }; 263 264 ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_GET_FD, &sd ); 265 266 /* poll ... */ 267 switch ( ldap_int_poll( ld, sd, &tv ) ) { 268 case 0: 269 /* go on! */ 270 lc->lconn_status = LDAP_CONNST_CONNECTED; 271 break; 272 273 case -2: 274 /* async only occurs if a network timeout is set */ 275 276 /* honor network timeout */ 277 LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex ); 278 if ( time( NULL ) - lc->lconn_created <= ld->ld_options.ldo_tm_net.tv_sec ) 279 { 280 /* caller will have to call again */ 281 ld->ld_errno = LDAP_X_CONNECTING; 282 } 283 LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex ); 284 /* fallthru */ 285 286 default: 287 /* error */ 288 break; 289 } 290 } 291 292 if ( lc == NULL || lc->lconn_status != LDAP_CONNST_CONNECTED ) { 293 if ( ld->ld_errno == LDAP_SUCCESS ) { 294 ld->ld_errno = LDAP_SERVER_DOWN; 295 } 296 297 ber_free( ber, 1 ); 298 if ( incparent ) { 299 /* Forget about the bind */ 300 --parentreq->lr_outrefcnt; 301 } 302 LDAP_CONN_UNLOCK_IF(m_noconn); 303 return( -1 ); 304 } 305 306 use_connection( ld, lc ); 307 308#ifdef LDAP_CONNECTIONLESS 309 if ( LDAP_IS_UDP( ld )) { 310 BerElement tmpber = *ber; 311 ber_rewind( &tmpber ); 312 LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex ); 313 rc = ber_write( &tmpber, ld->ld_options.ldo_peer, 314 sizeof( struct sockaddr ), 0 ); 315 LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex ); 316 if ( rc == -1 ) { 317 ld->ld_errno = LDAP_ENCODING_ERROR; 318 LDAP_CONN_UNLOCK_IF(m_noconn); 319 return rc; 320 } 321 } 322#endif 323 324 /* If we still have an incomplete write, try to finish it before 325 * dealing with the new request. If we don't finish here, return 326 * LDAP_BUSY and let the caller retry later. We only allow a single 327 * request to be in WRITING state. 328 */ 329 rc = 0; 330 if ( ld->ld_requests && 331 ld->ld_requests->lr_status == LDAP_REQST_WRITING && 332 ldap_int_flush_request( ld, ld->ld_requests ) < 0 ) 333 { 334 rc = -1; 335 } 336 if ( rc ) { 337 LDAP_CONN_UNLOCK_IF(m_noconn); 338 return rc; 339 } 340 341 lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ) ); 342 if ( lr == NULL ) { 343 ld->ld_errno = LDAP_NO_MEMORY; 344 ldap_free_connection( ld, lc, 0, 0 ); 345 ber_free( ber, 1 ); 346 if ( incparent ) { 347 /* Forget about the bind */ 348 --parentreq->lr_outrefcnt; 349 } 350 LDAP_CONN_UNLOCK_IF(m_noconn); 351 return( -1 ); 352 } 353 lr->lr_msgid = msgid; 354 lr->lr_status = LDAP_REQST_INPROGRESS; 355 lr->lr_res_errno = LDAP_SUCCESS; /* optimistic */ 356 lr->lr_ber = ber; 357 lr->lr_conn = lc; 358 if ( parentreq != NULL ) { /* sub-request */ 359 if ( !incparent ) { 360 /* Increment if we didn't do it before the bind */ 361 ++parentreq->lr_outrefcnt; 362 } 363 lr->lr_origid = parentreq->lr_origid; 364 lr->lr_parentcnt = ++parentreq->lr_parentcnt; 365 lr->lr_parent = parentreq; 366 lr->lr_refnext = parentreq->lr_child; 367 parentreq->lr_child = lr; 368 } else { /* original request */ 369 lr->lr_origid = lr->lr_msgid; 370 } 371 372 /* Extract requestDN for future reference */ 373 { 374 BerElement tmpber = *ber; 375 ber_int_t bint; 376 ber_tag_t tag, rtag; 377 378 ber_reset( &tmpber, 1 ); 379 rtag = ber_scanf( &tmpber, "{it", /*}*/ &bint, &tag ); 380 switch ( tag ) { 381 case LDAP_REQ_BIND: 382 rtag = ber_scanf( &tmpber, "{i" /*}*/, &bint ); 383 break; 384 case LDAP_REQ_DELETE: 385 break; 386 default: 387 rtag = ber_scanf( &tmpber, "{" /*}*/ ); 388 case LDAP_REQ_ABANDON: 389 break; 390 } 391 if ( tag != LDAP_REQ_ABANDON ) { 392 ber_skip_tag( &tmpber, &lr->lr_dn.bv_len ); 393 lr->lr_dn.bv_val = tmpber.ber_ptr; 394 } 395 } 396 397 lr->lr_prev = NULL; 398 lr->lr_next = ld->ld_requests; 399 if ( lr->lr_next != NULL ) { 400 lr->lr_next->lr_prev = lr; 401 } 402 ld->ld_requests = lr; 403 404 ld->ld_errno = LDAP_SUCCESS; 405 if ( ldap_int_flush_request( ld, lr ) == -1 ) { 406 msgid = -1; 407 } 408 409 LDAP_CONN_UNLOCK_IF(m_noconn); 410 return( msgid ); 411} 412 413/* return 0 if no StartTLS ext, 1 if present, 2 if critical */ 414static int 415find_tls_ext( LDAPURLDesc *srv ) 416{ 417 int i, crit; 418 char *ext; 419 420 if ( !srv->lud_exts ) 421 return 0; 422 423 for (i=0; srv->lud_exts[i]; i++) { 424 crit = 0; 425 ext = srv->lud_exts[i]; 426 if ( ext[0] == '!') { 427 ext++; 428 crit = 1; 429 } 430 if ( !strcasecmp( ext, "StartTLS" ) || 431 !strcasecmp( ext, "X-StartTLS" ) || 432 !strcmp( ext, LDAP_EXOP_START_TLS )) { 433 return crit + 1; 434 } 435 } 436 return 0; 437} 438 439/* 440 * always protected by conn_mutex 441 * optionally protected by req_mutex and res_mutex 442 */ 443LDAPConn * 444ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb, 445 int connect, LDAPreqinfo *bind, int m_req, int m_res ) 446{ 447 LDAPConn *lc; 448 int async = 0; 449 450 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); 451 Debug( LDAP_DEBUG_TRACE, "ldap_new_connection %d %d %d\n", 452 use_ldsb, connect, (bind != NULL) ); 453 /* 454 * make a new LDAP server connection 455 * XXX open connection synchronously for now 456 */ 457 lc = (LDAPConn *)LDAP_CALLOC( 1, sizeof( LDAPConn ) ); 458 if ( lc == NULL ) { 459 ld->ld_errno = LDAP_NO_MEMORY; 460 return( NULL ); 461 } 462 463 if ( use_ldsb ) { 464 assert( ld->ld_sb != NULL ); 465 lc->lconn_sb = ld->ld_sb; 466 467 } else { 468 lc->lconn_sb = ber_sockbuf_alloc(); 469 if ( lc->lconn_sb == NULL ) { 470 LDAP_FREE( (char *)lc ); 471 ld->ld_errno = LDAP_NO_MEMORY; 472 return( NULL ); 473 } 474 } 475 476 if ( connect ) { 477 LDAPURLDesc **srvp, *srv = NULL; 478 479 async = LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_CONNECT_ASYNC ); 480 481 for ( srvp = srvlist; *srvp != NULL; srvp = &(*srvp)->lud_next ) { 482 int rc; 483 484 rc = ldap_int_open_connection( ld, lc, *srvp, async ); 485 if ( rc != -1 ) { 486 srv = *srvp; 487 488 if ( ld->ld_urllist_proc && ( !async || rc != -2 ) ) { 489 ld->ld_urllist_proc( ld, srvlist, srvp, ld->ld_urllist_params ); 490 } 491 492 break; 493 } 494 } 495 496 if ( srv == NULL ) { 497 if ( !use_ldsb ) { 498 ber_sockbuf_free( lc->lconn_sb ); 499 } 500 LDAP_FREE( (char *)lc ); 501 ld->ld_errno = LDAP_SERVER_DOWN; 502 return( NULL ); 503 } 504 505 lc->lconn_server = ldap_url_dup( srv ); 506 } 507 508 lc->lconn_status = async ? LDAP_CONNST_CONNECTING : LDAP_CONNST_CONNECTED; 509 lc->lconn_next = ld->ld_conns; 510 ld->ld_conns = lc; 511 512 if ( connect ) { 513#ifdef HAVE_TLS 514 if ( lc->lconn_server->lud_exts ) { 515 int rc, ext = find_tls_ext( lc->lconn_server ); 516 if ( ext ) { 517 LDAPConn *savedefconn; 518 519 savedefconn = ld->ld_defconn; 520 ++lc->lconn_refcnt; /* avoid premature free */ 521 ld->ld_defconn = lc; 522 523 LDAP_REQ_UNLOCK_IF(m_req); 524 LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 525 LDAP_RES_UNLOCK_IF(m_res); 526 rc = ldap_start_tls_s( ld, NULL, NULL ); 527 LDAP_RES_LOCK_IF(m_res); 528 LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); 529 LDAP_REQ_LOCK_IF(m_req); 530 ld->ld_defconn = savedefconn; 531 --lc->lconn_refcnt; 532 533 if ( rc != LDAP_SUCCESS && ext == 2 ) { 534 ldap_free_connection( ld, lc, 1, 0 ); 535 return NULL; 536 } 537 } 538 } 539#endif 540 } 541 542 if ( bind != NULL ) { 543 int err = 0; 544 LDAPConn *savedefconn; 545 546 /* Set flag to prevent additional referrals 547 * from being processed on this 548 * connection until the bind has completed 549 */ 550 lc->lconn_rebind_inprogress = 1; 551 /* V3 rebind function */ 552 if ( ld->ld_rebind_proc != NULL) { 553 LDAPURLDesc *srvfunc; 554 555 srvfunc = ldap_url_dup( *srvlist ); 556 if ( srvfunc == NULL ) { 557 ld->ld_errno = LDAP_NO_MEMORY; 558 err = -1; 559 } else { 560 savedefconn = ld->ld_defconn; 561 ++lc->lconn_refcnt; /* avoid premature free */ 562 ld->ld_defconn = lc; 563 564 Debug( LDAP_DEBUG_TRACE, "Call application rebind_proc\n", 0, 0, 0); 565 LDAP_REQ_UNLOCK_IF(m_req); 566 LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 567 LDAP_RES_UNLOCK_IF(m_res); 568 err = (*ld->ld_rebind_proc)( ld, 569 bind->ri_url, bind->ri_request, bind->ri_msgid, 570 ld->ld_rebind_params ); 571 LDAP_RES_LOCK_IF(m_res); 572 LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); 573 LDAP_REQ_LOCK_IF(m_req); 574 575 ld->ld_defconn = savedefconn; 576 --lc->lconn_refcnt; 577 578 if ( err != 0 ) { 579 err = -1; 580 ldap_free_connection( ld, lc, 1, 0 ); 581 lc = NULL; 582 } 583 ldap_free_urldesc( srvfunc ); 584 } 585 586 } else { 587 int msgid, rc; 588 struct berval passwd = BER_BVNULL; 589 590 savedefconn = ld->ld_defconn; 591 ++lc->lconn_refcnt; /* avoid premature free */ 592 ld->ld_defconn = lc; 593 594 Debug( LDAP_DEBUG_TRACE, 595 "anonymous rebind via ldap_sasl_bind(\"\")\n", 596 0, 0, 0); 597 598 LDAP_REQ_UNLOCK_IF(m_req); 599 LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 600 LDAP_RES_UNLOCK_IF(m_res); 601 rc = ldap_sasl_bind( ld, "", LDAP_SASL_SIMPLE, &passwd, 602 NULL, NULL, &msgid ); 603 if ( rc != LDAP_SUCCESS ) { 604 err = -1; 605 606 } else { 607 for ( err = 1; err > 0; ) { 608 struct timeval tv = { 0, 100000 }; 609 LDAPMessage *res = NULL; 610 611 switch ( ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res ) ) { 612 case -1: 613 err = -1; 614 break; 615 616 case 0: 617#ifdef LDAP_R_COMPILE 618 ldap_pvt_thread_yield(); 619#endif 620 break; 621 622 case LDAP_RES_BIND: 623 rc = ldap_parse_result( ld, res, &err, NULL, NULL, NULL, NULL, 1 ); 624 if ( rc != LDAP_SUCCESS ) { 625 err = -1; 626 627 } else if ( err != LDAP_SUCCESS ) { 628 err = -1; 629 } 630 /* else err == LDAP_SUCCESS == 0 */ 631 break; 632 633 default: 634 Debug( LDAP_DEBUG_TRACE, 635 "ldap_new_connection %p: " 636 "unexpected response %d " 637 "from BIND request id=%d\n", 638 (void *) ld, ldap_msgtype( res ), msgid ); 639 err = -1; 640 break; 641 } 642 } 643 } 644 LDAP_RES_LOCK_IF(m_res); 645 LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); 646 LDAP_REQ_LOCK_IF(m_req); 647 ld->ld_defconn = savedefconn; 648 --lc->lconn_refcnt; 649 650 if ( err != 0 ) { 651 ldap_free_connection( ld, lc, 1, 0 ); 652 lc = NULL; 653 } 654 } 655 if ( lc != NULL ) 656 lc->lconn_rebind_inprogress = 0; 657 } 658 return( lc ); 659} 660 661 662/* protected by ld_conn_mutex */ 663static LDAPConn * 664find_connection( LDAP *ld, LDAPURLDesc *srv, int any ) 665/* 666 * return an existing connection (if any) to the server srv 667 * if "any" is non-zero, check for any server in the "srv" chain 668 */ 669{ 670 LDAPConn *lc; 671 LDAPURLDesc *lcu, *lsu; 672 int lcu_port, lsu_port; 673 int found = 0; 674 675 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); 676 for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) { 677 lcu = lc->lconn_server; 678 lcu_port = ldap_pvt_url_scheme_port( lcu->lud_scheme, 679 lcu->lud_port ); 680 681 for ( lsu = srv; lsu != NULL; lsu = lsu->lud_next ) { 682 lsu_port = ldap_pvt_url_scheme_port( lsu->lud_scheme, 683 lsu->lud_port ); 684 685 if ( lsu_port == lcu_port 686 && strcmp( lcu->lud_scheme, lsu->lud_scheme ) == 0 687 && lcu->lud_host != NULL && lsu->lud_host != NULL 688 && strcasecmp( lsu->lud_host, lcu->lud_host ) == 0 ) 689 { 690 found = 1; 691 break; 692 } 693 694 if ( !any ) break; 695 } 696 if ( found ) 697 break; 698 } 699 return lc; 700} 701 702 703 704/* protected by ld_conn_mutex */ 705static void 706use_connection( LDAP *ld, LDAPConn *lc ) 707{ 708 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); 709 ++lc->lconn_refcnt; 710 lc->lconn_lastused = time( NULL ); 711} 712 713 714/* protected by ld_conn_mutex */ 715void 716ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind ) 717{ 718 LDAPConn *tmplc, *prevlc; 719 720 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); 721 Debug( LDAP_DEBUG_TRACE, 722 "ldap_free_connection %d %d\n", 723 force, unbind, 0 ); 724 725 if ( force || --lc->lconn_refcnt <= 0 ) { 726 /* remove from connections list first */ 727 728 for ( prevlc = NULL, tmplc = ld->ld_conns; 729 tmplc != NULL; 730 tmplc = tmplc->lconn_next ) 731 { 732 if ( tmplc == lc ) { 733 if ( prevlc == NULL ) { 734 ld->ld_conns = tmplc->lconn_next; 735 } else { 736 prevlc->lconn_next = tmplc->lconn_next; 737 } 738 if ( ld->ld_defconn == lc ) { 739 ld->ld_defconn = NULL; 740 } 741 break; 742 } 743 prevlc = tmplc; 744 } 745 746 /* process connection callbacks */ 747 { 748 struct ldapoptions *lo; 749 ldaplist *ll; 750 ldap_conncb *cb; 751 752 lo = &ld->ld_options; 753 LDAP_MUTEX_LOCK( &lo->ldo_mutex ); 754 if ( lo->ldo_conn_cbs ) { 755 for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) { 756 cb = ll->ll_data; 757 cb->lc_del( ld, lc->lconn_sb, cb ); 758 } 759 } 760 LDAP_MUTEX_UNLOCK( &lo->ldo_mutex ); 761 lo = LDAP_INT_GLOBAL_OPT(); 762 LDAP_MUTEX_LOCK( &lo->ldo_mutex ); 763 if ( lo->ldo_conn_cbs ) { 764 for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) { 765 cb = ll->ll_data; 766 cb->lc_del( ld, lc->lconn_sb, cb ); 767 } 768 } 769 LDAP_MUTEX_UNLOCK( &lo->ldo_mutex ); 770 } 771 772 if ( lc->lconn_status == LDAP_CONNST_CONNECTED ) { 773 ldap_mark_select_clear( ld, lc->lconn_sb ); 774 if ( unbind ) { 775 ldap_send_unbind( ld, lc->lconn_sb, 776 NULL, NULL ); 777 } 778 } 779 780 if ( lc->lconn_ber != NULL ) { 781 ber_free( lc->lconn_ber, 1 ); 782 } 783 784 ldap_int_sasl_close( ld, lc ); 785#ifdef HAVE_GSSAPI 786 ldap_int_gssapi_close( ld, lc ); 787#endif 788 789 ldap_free_urllist( lc->lconn_server ); 790 791 /* FIXME: is this at all possible? 792 * ldap_ld_free() in unbind.c calls ldap_free_connection() 793 * with force == 1 __after__ explicitly calling 794 * ldap_free_request() on all requests */ 795 if ( force ) { 796 LDAPRequest *lr; 797 798 for ( lr = ld->ld_requests; lr; ) { 799 LDAPRequest *lr_next = lr->lr_next; 800 801 if ( lr->lr_conn == lc ) { 802 ldap_free_request_int( ld, lr ); 803 } 804 805 lr = lr_next; 806 } 807 } 808 809 if ( lc->lconn_sb != ld->ld_sb ) { 810 ber_sockbuf_free( lc->lconn_sb ); 811 } else { 812 ber_int_sb_close( lc->lconn_sb ); 813 } 814 815 if ( lc->lconn_rebind_queue != NULL) { 816 int i; 817 for( i = 0; lc->lconn_rebind_queue[i] != NULL; i++ ) { 818 LDAP_VFREE( lc->lconn_rebind_queue[i] ); 819 } 820 LDAP_FREE( lc->lconn_rebind_queue ); 821 } 822 823 LDAP_FREE( lc ); 824 825 Debug( LDAP_DEBUG_TRACE, 826 "ldap_free_connection: actually freed\n", 827 0, 0, 0 ); 828 829 } else { 830 lc->lconn_lastused = time( NULL ); 831 Debug( LDAP_DEBUG_TRACE, "ldap_free_connection: refcnt %d\n", 832 lc->lconn_refcnt, 0, 0 ); 833 } 834} 835 836 837/* Protects self with ld_conn_mutex */ 838#ifdef LDAP_DEBUG 839void 840ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all ) 841{ 842 LDAPConn *lc; 843 char timebuf[32]; 844 845 Debug( LDAP_DEBUG_TRACE, "** ld %p Connection%s:\n", (void *)ld, all ? "s" : "", 0 ); 846 LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); 847 for ( lc = lconns; lc != NULL; lc = lc->lconn_next ) { 848 if ( lc->lconn_server != NULL ) { 849 Debug( LDAP_DEBUG_TRACE, "* host: %s port: %d%s\n", 850 ( lc->lconn_server->lud_host == NULL ) ? "(null)" 851 : lc->lconn_server->lud_host, 852 lc->lconn_server->lud_port, ( lc->lconn_sb == 853 ld->ld_sb ) ? " (default)" : "" ); 854 } 855 Debug( LDAP_DEBUG_TRACE, " refcnt: %d status: %s\n", lc->lconn_refcnt, 856 ( lc->lconn_status == LDAP_CONNST_NEEDSOCKET ) 857 ? "NeedSocket" : 858 ( lc->lconn_status == LDAP_CONNST_CONNECTING ) 859 ? "Connecting" : "Connected", 0 ); 860 Debug( LDAP_DEBUG_TRACE, " last used: %s%s\n", 861 ldap_pvt_ctime( &lc->lconn_lastused, timebuf ), 862 lc->lconn_rebind_inprogress ? " rebind in progress" : "", 0 ); 863 if ( lc->lconn_rebind_inprogress ) { 864 if ( lc->lconn_rebind_queue != NULL) { 865 int i; 866 867 for ( i = 0; lc->lconn_rebind_queue[i] != NULL; i++ ) { 868 int j; 869 for( j = 0; lc->lconn_rebind_queue[i][j] != 0; j++ ) { 870 Debug( LDAP_DEBUG_TRACE, " queue %d entry %d - %s\n", 871 i, j, lc->lconn_rebind_queue[i][j] ); 872 } 873 } 874 } else { 875 Debug( LDAP_DEBUG_TRACE, " queue is empty\n", 0, 0, 0 ); 876 } 877 } 878 Debug( LDAP_DEBUG_TRACE, "\n", 0, 0, 0 ); 879 if ( !all ) { 880 break; 881 } 882 } 883 LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 884} 885 886 887/* protected by req_mutex and res_mutex */ 888void 889ldap_dump_requests_and_responses( LDAP *ld ) 890{ 891 LDAPRequest *lr; 892 LDAPMessage *lm, *l; 893 int i; 894 struct rb_node *rbn; 895 896 Debug( LDAP_DEBUG_TRACE, "** ld %p Outstanding Requests:\n", 897 (void *)ld, 0, 0 ); 898 lr = ld->ld_requests; 899 if ( lr == NULL ) { 900 Debug( LDAP_DEBUG_TRACE, " Empty\n", 0, 0, 0 ); 901 } 902 for ( i = 0; lr != NULL; lr = lr->lr_next, i++ ) { 903 Debug( LDAP_DEBUG_TRACE, " * msgid %d, origid %d, status %s\n", 904 lr->lr_msgid, lr->lr_origid, 905 ( lr->lr_status == LDAP_REQST_INPROGRESS ) ? "InProgress" : 906 ( lr->lr_status == LDAP_REQST_CHASINGREFS ) ? "ChasingRefs" : 907 ( lr->lr_status == LDAP_REQST_NOTCONNECTED ) ? "NotConnected" : 908 ( lr->lr_status == LDAP_REQST_WRITING ) ? "Writing" : 909 ( lr->lr_status == LDAP_REQST_COMPLETED ) ? "RequestCompleted" 910 : "InvalidStatus" ); 911 Debug( LDAP_DEBUG_TRACE, " outstanding referrals %d, parent count %d\n", 912 lr->lr_outrefcnt, lr->lr_parentcnt, 0 ); 913 } 914 Debug( LDAP_DEBUG_TRACE, " ld %p request count %d (abandoned %lu)\n", 915 (void *)ld, i, ld->ld_nabandoned ); 916#ifdef LDAP_RESPONSE_RB_TREE 917 ldap_resp_rbt_dump( ld ); 918#else 919 Debug( LDAP_DEBUG_TRACE, "** ld %p Response Queue:\n", (void *)ld, 0, 0 ); 920 if ( ( lm = ld->ld_responses ) == NULL ) { 921 Debug( LDAP_DEBUG_TRACE, " Empty\n", 0, 0, 0 ); 922 } 923 for ( i = 0; lm != NULL; lm = lm->lm_next, i++ ) { 924 Debug( LDAP_DEBUG_TRACE, " * msgid %d, type %lu\n", 925 lm->lm_msgid, (unsigned long)lm->lm_msgtype, 0 ); 926 if ( lm->lm_chain != NULL ) { 927 Debug( LDAP_DEBUG_TRACE, " chained responses:\n", 0, 0, 0 ); 928 for ( l = lm->lm_chain; l != NULL; l = l->lm_chain ) { 929 Debug( LDAP_DEBUG_TRACE, 930 " * msgid %d, type %lu\n", 931 l->lm_msgid, 932 (unsigned long)l->lm_msgtype, 0 ); 933 } 934 } 935 } 936#endif /* LDAP_RESPONSE_RB_TREE */ 937 Debug( LDAP_DEBUG_TRACE, " ld %p response count %d\n", (void *)ld, i, 0 ); 938} 939#endif /* LDAP_DEBUG */ 940 941/* protected by req_mutex */ 942static void 943ldap_free_request_int( LDAP *ld, LDAPRequest *lr ) 944{ 945 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); 946 /* if lr_refcnt > 0, the request has been looked up 947 * by ldap_find_request_by_msgid(); if in the meanwhile 948 * the request is free()'d by someone else, just decrease 949 * the reference count and extract it from the request 950 * list; later on, it will be freed. */ 951 if ( lr->lr_prev == NULL ) { 952 if ( lr->lr_refcnt == 0 ) { 953 /* free'ing the first request? */ 954 assert( ld->ld_requests == lr ); 955 } 956 957 if ( ld->ld_requests == lr ) { 958 ld->ld_requests = lr->lr_next; 959 } 960 961 } else { 962 lr->lr_prev->lr_next = lr->lr_next; 963 } 964 965 if ( lr->lr_next != NULL ) { 966 lr->lr_next->lr_prev = lr->lr_prev; 967 } 968 969 if ( lr->lr_refcnt > 0 ) { 970 lr->lr_refcnt = -lr->lr_refcnt; 971 972 lr->lr_prev = NULL; 973 lr->lr_next = NULL; 974 975 return; 976 } 977 978 if ( lr->lr_ber != NULL ) { 979 ber_free( lr->lr_ber, 1 ); 980 lr->lr_ber = NULL; 981 } 982 983 if ( lr->lr_res_error != NULL ) { 984 LDAP_FREE( lr->lr_res_error ); 985 lr->lr_res_error = NULL; 986 } 987 988 if ( lr->lr_res_matched != NULL ) { 989 LDAP_FREE( lr->lr_res_matched ); 990 lr->lr_res_matched = NULL; 991 } 992 993 LDAP_FREE( lr ); 994} 995 996/* protected by req_mutex */ 997void 998ldap_free_request( LDAP *ld, LDAPRequest *lr ) 999{ 1000 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); 1001 Debug( LDAP_DEBUG_TRACE, "ldap_free_request (origid %d, msgid %d)\n", 1002 lr->lr_origid, lr->lr_msgid, 0 ); 1003 1004 /* free all referrals (child requests) */ 1005 while ( lr->lr_child ) { 1006 ldap_free_request( ld, lr->lr_child ); 1007 } 1008 1009 if ( lr->lr_parent != NULL ) { 1010 LDAPRequest **lrp; 1011 1012 --lr->lr_parent->lr_outrefcnt; 1013 for ( lrp = &lr->lr_parent->lr_child; 1014 *lrp && *lrp != lr; 1015 lrp = &(*lrp)->lr_refnext ); 1016 1017 if ( *lrp == lr ) { 1018 *lrp = lr->lr_refnext; 1019 } 1020 } 1021 ldap_free_request_int( ld, lr ); 1022} 1023 1024/* 1025 * call first time with *cntp = -1 1026 * when returns *cntp == -1, no referrals are left 1027 * 1028 * NOTE: may replace *refsp, or shuffle the contents 1029 * of the original array. 1030 */ 1031static int ldap_int_nextref( 1032 LDAP *ld, 1033 char ***refsp, 1034 int *cntp, 1035 void *params ) 1036{ 1037 assert( refsp != NULL ); 1038 assert( *refsp != NULL ); 1039 assert( cntp != NULL ); 1040 1041 if ( *cntp < -1 ) { 1042 *cntp = -1; 1043 return -1; 1044 } 1045 1046 (*cntp)++; 1047 1048 if ( (*refsp)[ *cntp ] == NULL ) { 1049 *cntp = -1; 1050 } 1051 1052 return 0; 1053} 1054 1055/* 1056 * Chase v3 referrals 1057 * 1058 * Parameters: 1059 * (IN) ld = LDAP connection handle 1060 * (IN) lr = LDAP Request structure 1061 * (IN) refs = array of pointers to referral strings that we will chase 1062 * The array will be free'd by this function when no longer needed 1063 * (IN) sref != 0 if following search reference 1064 * (OUT) errstrp = Place to return a string of referrals which could not be followed 1065 * (OUT) hadrefp = 1 if sucessfully followed referral 1066 * 1067 * Return value - number of referrals followed 1068 * 1069 * Protected by res_mutex, conn_mutex and req_mutex (try_read1msg) 1070 */ 1071int 1072ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char **errstrp, int *hadrefp ) 1073{ 1074 char *unfollowed; 1075 int unfollowedcnt = 0; 1076 LDAPRequest *origreq; 1077 LDAPURLDesc *srv = NULL; 1078 BerElement *ber; 1079 char **refarray = NULL; 1080 LDAPConn *lc; 1081 int rc, count, i, j, id; 1082 LDAPreqinfo rinfo; 1083 LDAP_NEXTREF_PROC *nextref_proc = ld->ld_nextref_proc ? ld->ld_nextref_proc : ldap_int_nextref; 1084 1085 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); 1086 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); 1087 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); 1088 Debug( LDAP_DEBUG_TRACE, "ldap_chase_v3referrals\n", 0, 0, 0 ); 1089 1090 ld->ld_errno = LDAP_SUCCESS; /* optimistic */ 1091 *hadrefp = 0; 1092 1093 unfollowed = NULL; 1094 rc = count = 0; 1095 1096 /* If no referrals in array, return */ 1097 if ( (refs == NULL) || ( (refs)[0] == NULL) ) { 1098 rc = 0; 1099 goto done; 1100 } 1101 1102 /* Check for hop limit exceeded */ 1103 if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) { 1104 Debug( LDAP_DEBUG_ANY, 1105 "more than %d referral hops (dropping)\n", ld->ld_refhoplimit, 0, 0 ); 1106 ld->ld_errno = LDAP_REFERRAL_LIMIT_EXCEEDED; 1107 rc = -1; 1108 goto done; 1109 } 1110 1111 /* find original request */ 1112 for ( origreq = lr; 1113 origreq->lr_parent != NULL; 1114 origreq = origreq->lr_parent ) 1115 { 1116 /* empty */ ; 1117 } 1118 1119 refarray = refs; 1120 refs = NULL; 1121 1122 /* parse out & follow referrals */ 1123 /* NOTE: if nextref_proc == ldap_int_nextref, params is ignored */ 1124 i = -1; 1125 for ( nextref_proc( ld, &refarray, &i, ld->ld_nextref_params ); 1126 i != -1; 1127 nextref_proc( ld, &refarray, &i, ld->ld_nextref_params ) ) 1128 { 1129 1130 /* Parse the referral URL */ 1131 rc = ldap_url_parse_ext( refarray[i], &srv, LDAP_PVT_URL_PARSE_NOEMPTY_DN ); 1132 if ( rc != LDAP_URL_SUCCESS ) { 1133 /* ldap_url_parse_ext() returns LDAP_URL_* errors 1134 * which do not map on API errors */ 1135 ld->ld_errno = LDAP_PARAM_ERROR; 1136 rc = -1; 1137 goto done; 1138 } 1139 1140 if( srv->lud_crit_exts ) { 1141 int ok = 0; 1142#ifdef HAVE_TLS 1143 /* If StartTLS is the only critical ext, OK. */ 1144 if ( find_tls_ext( srv ) == 2 && srv->lud_crit_exts == 1 ) 1145 ok = 1; 1146#endif 1147 if ( !ok ) { 1148 /* we do not support any other extensions */ 1149 ld->ld_errno = LDAP_NOT_SUPPORTED; 1150 rc = -1; 1151 goto done; 1152 } 1153 } 1154 1155 /* check connection for re-bind in progress */ 1156 if (( lc = find_connection( ld, srv, 1 )) != NULL ) { 1157 /* See if we've already requested this DN with this conn */ 1158 LDAPRequest *lp; 1159 int looped = 0; 1160 ber_len_t len = srv->lud_dn ? strlen( srv->lud_dn ) : 0; 1161 for ( lp = origreq; lp; ) { 1162 if ( lp->lr_conn == lc 1163 && len == lp->lr_dn.bv_len 1164 && len 1165 && strncmp( srv->lud_dn, lp->lr_dn.bv_val, len ) == 0 ) 1166 { 1167 looped = 1; 1168 break; 1169 } 1170 if ( lp == origreq ) { 1171 lp = lp->lr_child; 1172 } else { 1173 lp = lp->lr_refnext; 1174 } 1175 } 1176 if ( looped ) { 1177 ldap_free_urllist( srv ); 1178 srv = NULL; 1179 ld->ld_errno = LDAP_CLIENT_LOOP; 1180 rc = -1; 1181 continue; 1182 } 1183 1184 if ( lc->lconn_rebind_inprogress ) { 1185 /* We are already chasing a referral or search reference and a 1186 * bind on that connection is in progress. We must queue 1187 * referrals on that connection, so we don't get a request 1188 * going out before the bind operation completes. This happens 1189 * if two search references come in one behind the other 1190 * for the same server with different contexts. 1191 */ 1192 Debug( LDAP_DEBUG_TRACE, 1193 "ldap_chase_v3referrals: queue referral \"%s\"\n", 1194 refarray[i], 0, 0); 1195 if( lc->lconn_rebind_queue == NULL ) { 1196 /* Create a referral list */ 1197 lc->lconn_rebind_queue = 1198 (char ***) LDAP_MALLOC( sizeof(void *) * 2); 1199 1200 if( lc->lconn_rebind_queue == NULL) { 1201 ld->ld_errno = LDAP_NO_MEMORY; 1202 rc = -1; 1203 goto done; 1204 } 1205 1206 lc->lconn_rebind_queue[0] = refarray; 1207 lc->lconn_rebind_queue[1] = NULL; 1208 refarray = NULL; 1209 1210 } else { 1211 /* Count how many referral arrays we already have */ 1212 for( j = 0; lc->lconn_rebind_queue[j] != NULL; j++) { 1213 /* empty */; 1214 } 1215 1216 /* Add the new referral to the list */ 1217 lc->lconn_rebind_queue = (char ***) LDAP_REALLOC( 1218 lc->lconn_rebind_queue, sizeof(void *) * (j + 2)); 1219 1220 if( lc->lconn_rebind_queue == NULL ) { 1221 ld->ld_errno = LDAP_NO_MEMORY; 1222 rc = -1; 1223 goto done; 1224 } 1225 lc->lconn_rebind_queue[j] = refarray; 1226 lc->lconn_rebind_queue[j+1] = NULL; 1227 refarray = NULL; 1228 } 1229 1230 /* We have queued the referral/reference, now just return */ 1231 rc = 0; 1232 *hadrefp = 1; 1233 count = 1; /* Pretend we already followed referral */ 1234 goto done; 1235 } 1236 } 1237 /* Re-encode the request with the new starting point of the search. 1238 * Note: In the future we also need to replace the filter if one 1239 * was provided with the search reference 1240 */ 1241 1242 /* For references we don't want old dn if new dn empty */ 1243 if ( sref && srv->lud_dn == NULL ) { 1244 srv->lud_dn = LDAP_STRDUP( "" ); 1245 } 1246 1247 LDAP_NEXT_MSGID( ld, id ); 1248 ber = re_encode_request( ld, origreq->lr_ber, id, 1249 sref, srv, &rinfo.ri_request ); 1250 1251 if( ber == NULL ) { 1252 ld->ld_errno = LDAP_ENCODING_ERROR; 1253 rc = -1; 1254 goto done; 1255 } 1256 1257 Debug( LDAP_DEBUG_TRACE, 1258 "ldap_chase_v3referral: msgid %d, url \"%s\"\n", 1259 lr->lr_msgid, refarray[i], 0); 1260 1261 /* Send the new request to the server - may require a bind */ 1262 rinfo.ri_msgid = origreq->lr_origid; 1263 rinfo.ri_url = refarray[i]; 1264 rc = ldap_send_server_request( ld, ber, id, 1265 origreq, &srv, NULL, &rinfo, 0, 1 ); 1266 if ( rc < 0 ) { 1267 /* Failure, try next referral in the list */ 1268 Debug( LDAP_DEBUG_ANY, "Unable to chase referral \"%s\" (%d: %s)\n", 1269 refarray[i], ld->ld_errno, ldap_err2string( ld->ld_errno ) ); 1270 unfollowedcnt += ldap_append_referral( ld, &unfollowed, refarray[i] ); 1271 ldap_free_urllist( srv ); 1272 srv = NULL; 1273 ld->ld_errno = LDAP_REFERRAL; 1274 } else { 1275 /* Success, no need to try this referral list further */ 1276 rc = 0; 1277 ++count; 1278 *hadrefp = 1; 1279 1280 /* check if there is a queue of referrals that came in during bind */ 1281 if ( lc == NULL) { 1282 lc = find_connection( ld, srv, 1 ); 1283 if ( lc == NULL ) { 1284 ld->ld_errno = LDAP_OPERATIONS_ERROR; 1285 rc = -1; 1286 LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 1287 goto done; 1288 } 1289 } 1290 1291 if ( lc->lconn_rebind_queue != NULL ) { 1292 /* Release resources of previous list */ 1293 LDAP_VFREE( refarray ); 1294 refarray = NULL; 1295 ldap_free_urllist( srv ); 1296 srv = NULL; 1297 1298 /* Pull entries off end of queue so list always null terminated */ 1299 for( j = 0; lc->lconn_rebind_queue[j] != NULL; j++ ) 1300 ; 1301 refarray = lc->lconn_rebind_queue[j - 1]; 1302 lc->lconn_rebind_queue[j-1] = NULL; 1303 /* we pulled off last entry from queue, free queue */ 1304 if ( j == 1 ) { 1305 LDAP_FREE( lc->lconn_rebind_queue ); 1306 lc->lconn_rebind_queue = NULL; 1307 } 1308 /* restart the loop the with new referral list */ 1309 i = -1; 1310 continue; 1311 } 1312 break; /* referral followed, break out of for loop */ 1313 } 1314 } /* end for loop */ 1315done: 1316 LDAP_VFREE( refarray ); 1317 ldap_free_urllist( srv ); 1318 LDAP_FREE( *errstrp ); 1319 1320 if( rc == 0 ) { 1321 *errstrp = NULL; 1322 LDAP_FREE( unfollowed ); 1323 return count; 1324 } else { 1325 *errstrp = unfollowed; 1326 return rc; 1327 } 1328} 1329 1330/* 1331 * XXX merging of errors in this routine needs to be improved 1332 * Protected by res_mutex, conn_mutex and req_mutex (try_read1msg) 1333 */ 1334int 1335ldap_chase_referrals( LDAP *ld, 1336 LDAPRequest *lr, 1337 char **errstrp, 1338 int sref, 1339 int *hadrefp ) 1340{ 1341 int rc, count, id; 1342 unsigned len; 1343 char *p, *ref, *unfollowed; 1344 LDAPRequest *origreq; 1345 LDAPURLDesc *srv; 1346 BerElement *ber; 1347 LDAPreqinfo rinfo; 1348 LDAPConn *lc; 1349 1350 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); 1351 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); 1352 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); 1353 Debug( LDAP_DEBUG_TRACE, "ldap_chase_referrals\n", 0, 0, 0 ); 1354 1355 ld->ld_errno = LDAP_SUCCESS; /* optimistic */ 1356 *hadrefp = 0; 1357 1358 if ( *errstrp == NULL ) { 1359 return( 0 ); 1360 } 1361 1362 len = strlen( *errstrp ); 1363 for ( p = *errstrp; len >= LDAP_REF_STR_LEN; ++p, --len ) { 1364 if ( strncasecmp( p, LDAP_REF_STR, LDAP_REF_STR_LEN ) == 0 ) { 1365 *p = '\0'; 1366 p += LDAP_REF_STR_LEN; 1367 break; 1368 } 1369 } 1370 1371 if ( len < LDAP_REF_STR_LEN ) { 1372 return( 0 ); 1373 } 1374 1375 if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) { 1376 Debug( LDAP_DEBUG_ANY, 1377 "more than %d referral hops (dropping)\n", 1378 ld->ld_refhoplimit, 0, 0 ); 1379 /* XXX report as error in ld->ld_errno? */ 1380 return( 0 ); 1381 } 1382 1383 /* find original request */ 1384 for ( origreq = lr; origreq->lr_parent != NULL; 1385 origreq = origreq->lr_parent ) { 1386 /* empty */; 1387 } 1388 1389 unfollowed = NULL; 1390 rc = count = 0; 1391 1392 /* parse out & follow referrals */ 1393 for ( ref = p; rc == 0 && ref != NULL; ref = p ) { 1394 p = strchr( ref, '\n' ); 1395 if ( p != NULL ) { 1396 *p++ = '\0'; 1397 } 1398 1399 rc = ldap_url_parse_ext( ref, &srv, LDAP_PVT_URL_PARSE_NOEMPTY_DN ); 1400 if ( rc != LDAP_URL_SUCCESS ) { 1401 Debug( LDAP_DEBUG_TRACE, 1402 "ignoring %s referral <%s>\n", 1403 ref, rc == LDAP_URL_ERR_BADSCHEME ? "unknown" : "incorrect", 0 ); 1404 rc = ldap_append_referral( ld, &unfollowed, ref ); 1405 *hadrefp = 1; 1406 continue; 1407 } 1408 1409 Debug( LDAP_DEBUG_TRACE, 1410 "chasing LDAP referral: <%s>\n", ref, 0, 0 ); 1411 1412 *hadrefp = 1; 1413 1414 /* See if we've already been here */ 1415 if (( lc = find_connection( ld, srv, 1 )) != NULL ) { 1416 LDAPRequest *lp; 1417 int looped = 0; 1418 ber_len_t len = srv->lud_dn ? strlen( srv->lud_dn ) : 0; 1419 for ( lp = lr; lp; lp = lp->lr_parent ) { 1420 if ( lp->lr_conn == lc 1421 && len == lp->lr_dn.bv_len ) 1422 { 1423 if ( len && strncmp( srv->lud_dn, lp->lr_dn.bv_val, len ) ) 1424 continue; 1425 looped = 1; 1426 break; 1427 } 1428 } 1429 if ( looped ) { 1430 ldap_free_urllist( srv ); 1431 ld->ld_errno = LDAP_CLIENT_LOOP; 1432 rc = -1; 1433 continue; 1434 } 1435 } 1436 1437 LDAP_NEXT_MSGID( ld, id ); 1438 ber = re_encode_request( ld, origreq->lr_ber, 1439 id, sref, srv, &rinfo.ri_request ); 1440 1441 if ( ber == NULL ) { 1442 return -1 ; 1443 } 1444 1445 /* copy the complete referral for rebind process */ 1446 rinfo.ri_url = LDAP_STRDUP( ref ); 1447 1448 rinfo.ri_msgid = origreq->lr_origid; 1449 1450 rc = ldap_send_server_request( ld, ber, id, 1451 lr, &srv, NULL, &rinfo, 0, 1 ); 1452 LDAP_FREE( rinfo.ri_url ); 1453 1454 if( rc >= 0 ) { 1455 ++count; 1456 } else { 1457 Debug( LDAP_DEBUG_ANY, 1458 "Unable to chase referral \"%s\" (%d: %s)\n", 1459 ref, ld->ld_errno, ldap_err2string( ld->ld_errno ) ); 1460 rc = ldap_append_referral( ld, &unfollowed, ref ); 1461 } 1462 1463 ldap_free_urllist(srv); 1464 } 1465 1466 LDAP_FREE( *errstrp ); 1467 *errstrp = unfollowed; 1468 1469 return(( rc == 0 ) ? count : rc ); 1470} 1471 1472 1473int 1474ldap_append_referral( LDAP *ld, char **referralsp, char *s ) 1475{ 1476 int first; 1477 1478 if ( *referralsp == NULL ) { 1479 first = 1; 1480 *referralsp = (char *)LDAP_MALLOC( strlen( s ) + LDAP_REF_STR_LEN 1481 + 1 ); 1482 } else { 1483 first = 0; 1484 *referralsp = (char *)LDAP_REALLOC( *referralsp, 1485 strlen( *referralsp ) + strlen( s ) + 2 ); 1486 } 1487 1488 if ( *referralsp == NULL ) { 1489 ld->ld_errno = LDAP_NO_MEMORY; 1490 return( -1 ); 1491 } 1492 1493 if ( first ) { 1494 strcpy( *referralsp, LDAP_REF_STR ); 1495 } else { 1496 strcat( *referralsp, "\n" ); 1497 } 1498 strcat( *referralsp, s ); 1499 1500 return( 0 ); 1501} 1502 1503 1504 1505static BerElement * 1506re_encode_request( LDAP *ld, 1507 BerElement *origber, 1508 ber_int_t msgid, 1509 int sref, 1510 LDAPURLDesc *srv, 1511 int *type ) 1512{ 1513 /* 1514 * XXX this routine knows way too much about how the lber library works! 1515 */ 1516 ber_int_t along; 1517 ber_tag_t tag; 1518 ber_tag_t rtag; 1519 ber_int_t ver; 1520 ber_int_t scope; 1521 int rc; 1522 BerElement tmpber, *ber; 1523 struct berval dn; 1524 1525 Debug( LDAP_DEBUG_TRACE, 1526 "re_encode_request: new msgid %ld, new dn <%s>\n", 1527 (long) msgid, 1528 ( srv == NULL || srv->lud_dn == NULL) ? "NONE" : srv->lud_dn, 0 ); 1529 1530 tmpber = *origber; 1531 1532 /* 1533 * all LDAP requests are sequences that start with a message id. 1534 * For all except delete, this is followed by a sequence that is 1535 * tagged with the operation code. For delete, the provided DN 1536 * is not wrapped by a sequence. 1537 */ 1538 rtag = ber_scanf( &tmpber, "{it", /*}*/ &along, &tag ); 1539 1540 if ( rtag == LBER_ERROR ) { 1541 ld->ld_errno = LDAP_DECODING_ERROR; 1542 return( NULL ); 1543 } 1544 1545 assert( tag != 0); 1546 if ( tag == LDAP_REQ_BIND ) { 1547 /* bind requests have a version number before the DN & other stuff */ 1548 rtag = ber_scanf( &tmpber, "{im" /*}*/, &ver, &dn ); 1549 1550 } else if ( tag == LDAP_REQ_DELETE ) { 1551 /* delete requests don't have a DN wrapping sequence */ 1552 rtag = ber_scanf( &tmpber, "m", &dn ); 1553 1554 } else if ( tag == LDAP_REQ_SEARCH ) { 1555 /* search requests need to be re-scope-ed */ 1556 rtag = ber_scanf( &tmpber, "{me" /*"}"*/, &dn, &scope ); 1557 1558 if( srv->lud_scope != LDAP_SCOPE_DEFAULT ) { 1559 /* use the scope provided in reference */ 1560 scope = srv->lud_scope; 1561 1562 } else if ( sref ) { 1563 /* use scope implied by previous operation 1564 * base -> base 1565 * one -> base 1566 * subtree -> subtree 1567 * subordinate -> subtree 1568 */ 1569 switch( scope ) { 1570 default: 1571 case LDAP_SCOPE_BASE: 1572 case LDAP_SCOPE_ONELEVEL: 1573 scope = LDAP_SCOPE_BASE; 1574 break; 1575 case LDAP_SCOPE_SUBTREE: 1576 case LDAP_SCOPE_SUBORDINATE: 1577 scope = LDAP_SCOPE_SUBTREE; 1578 break; 1579 } 1580 } 1581 1582 } else { 1583 rtag = ber_scanf( &tmpber, "{m" /*}*/, &dn ); 1584 } 1585 1586 if( rtag == LBER_ERROR ) { 1587 ld->ld_errno = LDAP_DECODING_ERROR; 1588 return NULL; 1589 } 1590 1591 /* restore character zero'd out by ber_scanf*/ 1592 dn.bv_val[dn.bv_len] = tmpber.ber_tag; 1593 1594 if (( ber = ldap_alloc_ber_with_options( ld )) == NULL ) { 1595 return NULL; 1596 } 1597 1598 if ( srv->lud_dn ) { 1599 ber_str2bv( srv->lud_dn, 0, 0, &dn ); 1600 } 1601 1602 if ( tag == LDAP_REQ_BIND ) { 1603 rc = ber_printf( ber, "{it{iO" /*}}*/, msgid, tag, ver, &dn ); 1604 } else if ( tag == LDAP_REQ_DELETE ) { 1605 rc = ber_printf( ber, "{itON}", msgid, tag, &dn ); 1606 } else if ( tag == LDAP_REQ_SEARCH ) { 1607 rc = ber_printf( ber, "{it{Oe" /*}}*/, msgid, tag, &dn, scope ); 1608 } else { 1609 rc = ber_printf( ber, "{it{O" /*}}*/, msgid, tag, &dn ); 1610 } 1611 1612 if ( rc == -1 ) { 1613 ld->ld_errno = LDAP_ENCODING_ERROR; 1614 ber_free( ber, 1 ); 1615 return NULL; 1616 } 1617 1618 if ( tag != LDAP_REQ_DELETE && ( 1619 ber_write(ber, tmpber.ber_ptr, ( tmpber.ber_end - tmpber.ber_ptr ), 0) 1620 != ( tmpber.ber_end - tmpber.ber_ptr ) || 1621 ber_printf( ber, /*{{*/ "N}N}" ) == -1 ) ) 1622 { 1623 ld->ld_errno = LDAP_ENCODING_ERROR; 1624 ber_free( ber, 1 ); 1625 return NULL; 1626 } 1627 1628#ifdef LDAP_DEBUG 1629 if ( ldap_debug & LDAP_DEBUG_PACKETS ) { 1630 Debug( LDAP_DEBUG_ANY, "re_encode_request new request is:\n", 1631 0, 0, 0 ); 1632 ber_log_dump( LDAP_DEBUG_BER, ldap_debug, ber, 0 ); 1633 } 1634#endif /* LDAP_DEBUG */ 1635 1636 *type = tag; /* return request type */ 1637 return ber; 1638} 1639 1640 1641/* protected by req_mutex */ 1642LDAPRequest * 1643ldap_find_request_by_msgid( LDAP *ld, ber_int_t msgid ) 1644{ 1645 LDAPRequest *lr; 1646 1647 for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) { 1648 if ( lr->lr_status == LDAP_REQST_COMPLETED ) { 1649 continue; /* Skip completed requests */ 1650 } 1651 if ( msgid == lr->lr_msgid ) { 1652 lr->lr_refcnt++; 1653 break; 1654 } 1655 } 1656 1657 return( lr ); 1658} 1659 1660/* protected by req_mutex */ 1661void 1662ldap_return_request( LDAP *ld, LDAPRequest *lrx, int freeit ) 1663{ 1664 LDAPRequest *lr; 1665 1666 for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) { 1667 if ( lr == lrx ) { 1668 if ( lr->lr_refcnt > 0 ) { 1669 lr->lr_refcnt--; 1670 1671 } else if ( lr->lr_refcnt < 0 ) { 1672 lr->lr_refcnt++; 1673 if ( lr->lr_refcnt == 0 ) { 1674 lr = NULL; 1675 } 1676 } 1677 break; 1678 } 1679 } 1680 if ( lr == NULL ) { 1681 ldap_free_request_int( ld, lrx ); 1682 1683 } else if ( freeit ) { 1684 ldap_free_request( ld, lrx ); 1685 } 1686} 1687