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