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