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