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