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