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