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