1 /* $NetBSD: request.c,v 1.2 2020/08/11 13:15:37 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2020 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.2 2020/08/11 13:15:37 christos Exp $"); 45 46 #include "portable.h" 47 48 #include <stdio.h> 49 50 #include <ac/stdlib.h> 51 52 #include <ac/errno.h> 53 #include <ac/socket.h> 54 #include <ac/string.h> 55 #include <ac/time.h> 56 #include <ac/unistd.h> 57 58 #include "ldap-int.h" 59 #include "lber.h" 60 61 /* used by ldap_send_server_request and ldap_new_connection */ 62 #ifdef LDAP_R_COMPILE 63 #define LDAP_CONN_LOCK_IF(nolock) \ 64 { if (nolock) LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); } 65 #define LDAP_CONN_UNLOCK_IF(nolock) \ 66 { if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); } 67 #define LDAP_REQ_LOCK_IF(nolock) \ 68 { if (nolock) LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); } 69 #define LDAP_REQ_UNLOCK_IF(nolock) \ 70 { if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); } 71 #define LDAP_RES_LOCK_IF(nolock) \ 72 { if (nolock) LDAP_MUTEX_LOCK( &ld->ld_res_mutex ); } 73 #define LDAP_RES_UNLOCK_IF(nolock) \ 74 { if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex ); } 75 #else 76 #define LDAP_CONN_LOCK_IF(nolock) 77 #define LDAP_CONN_UNLOCK_IF(nolock) 78 #define LDAP_REQ_LOCK_IF(nolock) 79 #define LDAP_REQ_UNLOCK_IF(nolock) 80 #define LDAP_RES_LOCK_IF(nolock) 81 #define LDAP_RES_UNLOCK_IF(nolock) 82 #endif 83 84 static LDAPConn *find_connection LDAP_P(( LDAP *ld, LDAPURLDesc *srv, int any )); 85 static void use_connection LDAP_P(( LDAP *ld, LDAPConn *lc )); 86 static void ldap_free_request_int LDAP_P(( LDAP *ld, LDAPRequest *lr )); 87 88 static BerElement * 89 re_encode_request( LDAP *ld, 90 BerElement *origber, 91 ber_int_t msgid, 92 int sref, 93 LDAPURLDesc *srv, 94 int *type ); 95 96 BerElement * 97 ldap_alloc_ber_with_options( LDAP *ld ) 98 { 99 BerElement *ber; 100 101 ber = ber_alloc_t( ld->ld_lberoptions ); 102 if ( ber == NULL ) { 103 ld->ld_errno = LDAP_NO_MEMORY; 104 } 105 106 return( ber ); 107 } 108 109 110 void 111 ldap_set_ber_options( LDAP *ld, BerElement *ber ) 112 { 113 /* ld_lberoptions is constant, hence no lock */ 114 ber->ber_options = ld->ld_lberoptions; 115 } 116 117 118 /* sets needed mutexes - no mutexes set to this point */ 119 ber_int_t 120 ldap_send_initial_request( 121 LDAP *ld, 122 ber_tag_t msgtype, 123 const char *dn, 124 BerElement *ber, 125 ber_int_t msgid) 126 { 127 int rc = 1; 128 ber_socket_t sd = AC_SOCKET_INVALID; 129 130 Debug( LDAP_DEBUG_TRACE, "ldap_send_initial_request\n", 0, 0, 0 ); 131 132 LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); 133 if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd ) == -1 ) { 134 /* not connected yet */ 135 rc = ldap_open_defconn( ld ); 136 if ( rc == 0 ) { 137 ber_sockbuf_ctrl( ld->ld_defconn->lconn_sb, 138 LBER_SB_OPT_GET_FD, &sd ); 139 } 140 } 141 if ( ld->ld_defconn && ld->ld_defconn->lconn_status == LDAP_CONNST_CONNECTING ) 142 rc = ldap_int_check_async_open( ld, sd ); 143 if( rc < 0 ) { 144 ber_free( ber, 1 ); 145 LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 146 return( -1 ); 147 } else if ( rc == 0 ) { 148 Debug( LDAP_DEBUG_TRACE, 149 "ldap_open_defconn: successful\n", 150 0, 0, 0 ); 151 } 152 153 #ifdef LDAP_CONNECTIONLESS 154 if (LDAP_IS_UDP(ld)) { 155 if (msgtype == LDAP_REQ_BIND) { 156 LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex ); 157 if (ld->ld_options.ldo_cldapdn) 158 ldap_memfree(ld->ld_options.ldo_cldapdn); 159 ld->ld_options.ldo_cldapdn = ldap_strdup(dn); 160 ber_free( ber, 1 ); 161 LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex ); 162 LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 163 return 0; 164 } 165 if (msgtype != LDAP_REQ_ABANDON && msgtype != LDAP_REQ_SEARCH) 166 { 167 ber_free( ber, 1 ); 168 LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 169 return LDAP_PARAM_ERROR; 170 } 171 } 172 #endif 173 LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); 174 rc = ldap_send_server_request( ld, ber, msgid, NULL, 175 NULL, NULL, NULL, 0, 0 ); 176 LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); 177 LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 178 return(rc); 179 } 180 181 182 /* protected by conn_mutex */ 183 int 184 ldap_int_flush_request( 185 LDAP *ld, 186 LDAPRequest *lr ) 187 { 188 LDAPConn *lc = lr->lr_conn; 189 190 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); 191 if ( ber_flush2( lc->lconn_sb, lr->lr_ber, LBER_FLUSH_FREE_NEVER ) != 0 ) { 192 if (( sock_errno() == EAGAIN ) || ( 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 Debug( LDAP_DEBUG_TRACE, "ldap_send_server_request\n", 0, 0, 0 ); 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 && 338 ld->ld_requests->lr_status == LDAP_REQST_WRITING && 339 ldap_int_flush_request( ld, ld->ld_requests ) < 0 ) 340 { 341 rc = -1; 342 } 343 if ( rc ) { 344 ber_free( ber, 1 ); 345 LDAP_CONN_UNLOCK_IF(m_noconn); 346 return rc; 347 } 348 349 lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ) ); 350 if ( lr == NULL ) { 351 ld->ld_errno = LDAP_NO_MEMORY; 352 ldap_free_connection( ld, lc, 0, 0 ); 353 ber_free( ber, 1 ); 354 if ( incparent ) { 355 /* Forget about the bind */ 356 --parentreq->lr_outrefcnt; 357 } 358 LDAP_CONN_UNLOCK_IF(m_noconn); 359 return( -1 ); 360 } 361 lr->lr_msgid = msgid; 362 lr->lr_status = LDAP_REQST_INPROGRESS; 363 lr->lr_res_errno = LDAP_SUCCESS; /* optimistic */ 364 lr->lr_ber = ber; 365 lr->lr_conn = lc; 366 if ( parentreq != NULL ) { /* sub-request */ 367 if ( !incparent ) { 368 /* Increment if we didn't do it before the bind */ 369 ++parentreq->lr_outrefcnt; 370 } 371 lr->lr_origid = parentreq->lr_origid; 372 lr->lr_parentcnt = ++parentreq->lr_parentcnt; 373 lr->lr_parent = parentreq; 374 lr->lr_refnext = parentreq->lr_child; 375 parentreq->lr_child = lr; 376 } else { /* original request */ 377 lr->lr_origid = lr->lr_msgid; 378 } 379 380 /* Extract requestDN for future reference */ 381 #ifdef LDAP_CONNECTIONLESS 382 if ( !LDAP_IS_UDP(ld) ) 383 #endif 384 { 385 BerElement tmpber = *ber; 386 ber_int_t bint; 387 ber_tag_t tag, rtag; 388 389 ber_reset( &tmpber, 1 ); 390 rtag = ber_scanf( &tmpber, "{it", /*}*/ &bint, &tag ); 391 switch ( tag ) { 392 case LDAP_REQ_BIND: 393 rtag = ber_scanf( &tmpber, "{i" /*}*/, &bint ); 394 break; 395 case LDAP_REQ_DELETE: 396 break; 397 default: 398 rtag = ber_scanf( &tmpber, "{" /*}*/ ); 399 case LDAP_REQ_ABANDON: 400 break; 401 } 402 if ( tag != LDAP_REQ_ABANDON ) { 403 ber_skip_tag( &tmpber, &lr->lr_dn.bv_len ); 404 lr->lr_dn.bv_val = tmpber.ber_ptr; 405 } 406 } 407 408 lr->lr_prev = NULL; 409 lr->lr_next = ld->ld_requests; 410 if ( lr->lr_next != NULL ) { 411 lr->lr_next->lr_prev = lr; 412 } 413 ld->ld_requests = lr; 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 Debug( 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 Debug( LDAP_DEBUG_TRACE, "Call application rebind_proc\n", 0, 0, 0); 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 Debug( LDAP_DEBUG_TRACE, 617 "anonymous rebind via ldap_sasl_bind(\"\")\n", 618 0, 0, 0); 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 Debug( 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 Debug( LDAP_DEBUG_TRACE, 744 "ldap_free_connection %d %d\n", 745 force, unbind, 0 ); 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_free_request() on all requests */ 817 if ( force ) { 818 LDAPRequest *lr; 819 820 for ( lr = ld->ld_requests; lr; ) { 821 LDAPRequest *lr_next = lr->lr_next; 822 823 if ( lr->lr_conn == lc ) { 824 ldap_free_request_int( ld, lr ); 825 } 826 827 lr = lr_next; 828 } 829 } 830 831 if ( lc->lconn_sb != ld->ld_sb ) { 832 ber_sockbuf_free( lc->lconn_sb ); 833 } else { 834 ber_int_sb_close( lc->lconn_sb ); 835 } 836 837 if ( lc->lconn_rebind_queue != NULL) { 838 int i; 839 for( i = 0; lc->lconn_rebind_queue[i] != NULL; i++ ) { 840 LDAP_VFREE( lc->lconn_rebind_queue[i] ); 841 } 842 LDAP_FREE( lc->lconn_rebind_queue ); 843 } 844 845 LDAP_FREE( lc ); 846 847 Debug( LDAP_DEBUG_TRACE, 848 "ldap_free_connection: actually freed\n", 849 0, 0, 0 ); 850 851 } else { 852 lc->lconn_lastused = time( NULL ); 853 Debug( LDAP_DEBUG_TRACE, "ldap_free_connection: refcnt %d\n", 854 lc->lconn_refcnt, 0, 0 ); 855 } 856 } 857 858 859 /* Protects self with ld_conn_mutex */ 860 #ifdef LDAP_DEBUG 861 void 862 ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all ) 863 { 864 LDAPConn *lc; 865 char timebuf[32]; 866 867 Debug( LDAP_DEBUG_TRACE, "** ld %p Connection%s:\n", (void *)ld, all ? "s" : "", 0 ); 868 LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); 869 for ( lc = lconns; lc != NULL; lc = lc->lconn_next ) { 870 if ( lc->lconn_server != NULL ) { 871 Debug( LDAP_DEBUG_TRACE, "* host: %s port: %d%s\n", 872 ( lc->lconn_server->lud_host == NULL ) ? "(null)" 873 : lc->lconn_server->lud_host, 874 lc->lconn_server->lud_port, ( lc->lconn_sb == 875 ld->ld_sb ) ? " (default)" : "" ); 876 } 877 Debug( LDAP_DEBUG_TRACE, " refcnt: %d status: %s\n", lc->lconn_refcnt, 878 ( lc->lconn_status == LDAP_CONNST_NEEDSOCKET ) 879 ? "NeedSocket" : 880 ( lc->lconn_status == LDAP_CONNST_CONNECTING ) 881 ? "Connecting" : "Connected", 0 ); 882 Debug( LDAP_DEBUG_TRACE, " last used: %s%s\n", 883 ldap_pvt_ctime( &lc->lconn_lastused, timebuf ), 884 lc->lconn_rebind_inprogress ? " rebind in progress" : "", 0 ); 885 if ( lc->lconn_rebind_inprogress ) { 886 if ( lc->lconn_rebind_queue != NULL) { 887 int i; 888 889 for ( i = 0; lc->lconn_rebind_queue[i] != NULL; i++ ) { 890 int j; 891 for( j = 0; lc->lconn_rebind_queue[i][j] != 0; j++ ) { 892 Debug( LDAP_DEBUG_TRACE, " queue %d entry %d - %s\n", 893 i, j, lc->lconn_rebind_queue[i][j] ); 894 } 895 } 896 } else { 897 Debug( LDAP_DEBUG_TRACE, " queue is empty\n", 0, 0, 0 ); 898 } 899 } 900 Debug( LDAP_DEBUG_TRACE, "\n", 0, 0, 0 ); 901 if ( !all ) { 902 break; 903 } 904 } 905 LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 906 } 907 908 909 /* protected by req_mutex and res_mutex */ 910 void 911 ldap_dump_requests_and_responses( LDAP *ld ) 912 { 913 LDAPRequest *lr; 914 LDAPMessage *lm, *l; 915 int i; 916 917 Debug( LDAP_DEBUG_TRACE, "** ld %p Outstanding Requests:\n", 918 (void *)ld, 0, 0 ); 919 lr = ld->ld_requests; 920 if ( lr == NULL ) { 921 Debug( LDAP_DEBUG_TRACE, " Empty\n", 0, 0, 0 ); 922 } 923 for ( i = 0; lr != NULL; lr = lr->lr_next, i++ ) { 924 Debug( LDAP_DEBUG_TRACE, " * msgid %d, origid %d, status %s\n", 925 lr->lr_msgid, lr->lr_origid, 926 ( lr->lr_status == LDAP_REQST_INPROGRESS ) ? "InProgress" : 927 ( lr->lr_status == LDAP_REQST_CHASINGREFS ) ? "ChasingRefs" : 928 ( lr->lr_status == LDAP_REQST_NOTCONNECTED ) ? "NotConnected" : 929 ( lr->lr_status == LDAP_REQST_WRITING ) ? "Writing" : 930 ( lr->lr_status == LDAP_REQST_COMPLETED ) ? "RequestCompleted" 931 : "InvalidStatus" ); 932 Debug( LDAP_DEBUG_TRACE, " outstanding referrals %d, parent count %d\n", 933 lr->lr_outrefcnt, lr->lr_parentcnt, 0 ); 934 } 935 Debug( LDAP_DEBUG_TRACE, " ld %p request count %d (abandoned %lu)\n", 936 (void *)ld, i, ld->ld_nabandoned ); 937 Debug( LDAP_DEBUG_TRACE, "** ld %p Response Queue:\n", (void *)ld, 0, 0 ); 938 if ( ( lm = ld->ld_responses ) == NULL ) { 939 Debug( LDAP_DEBUG_TRACE, " Empty\n", 0, 0, 0 ); 940 } 941 for ( i = 0; lm != NULL; lm = lm->lm_next, i++ ) { 942 Debug( LDAP_DEBUG_TRACE, " * msgid %d, type %lu\n", 943 lm->lm_msgid, (unsigned long)lm->lm_msgtype, 0 ); 944 if ( lm->lm_chain != NULL ) { 945 Debug( LDAP_DEBUG_TRACE, " chained responses:\n", 0, 0, 0 ); 946 for ( l = lm->lm_chain; l != NULL; l = l->lm_chain ) { 947 Debug( LDAP_DEBUG_TRACE, 948 " * msgid %d, type %lu\n", 949 l->lm_msgid, 950 (unsigned long)l->lm_msgtype, 0 ); 951 } 952 } 953 } 954 Debug( LDAP_DEBUG_TRACE, " ld %p response count %d\n", (void *)ld, i, 0 ); 955 } 956 #endif /* LDAP_DEBUG */ 957 958 /* protected by req_mutex */ 959 static void 960 ldap_free_request_int( LDAP *ld, LDAPRequest *lr ) 961 { 962 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); 963 /* if lr_refcnt > 0, the request has been looked up 964 * by ldap_find_request_by_msgid(); if in the meanwhile 965 * the request is free()'d by someone else, just decrease 966 * the reference count and extract it from the request 967 * list; later on, it will be freed. */ 968 if ( lr->lr_prev == NULL ) { 969 if ( lr->lr_refcnt == 0 ) { 970 /* free'ing the first request? */ 971 assert( ld->ld_requests == lr ); 972 } 973 974 if ( ld->ld_requests == lr ) { 975 ld->ld_requests = lr->lr_next; 976 } 977 978 } else { 979 lr->lr_prev->lr_next = lr->lr_next; 980 } 981 982 if ( lr->lr_next != NULL ) { 983 lr->lr_next->lr_prev = lr->lr_prev; 984 } 985 986 if ( lr->lr_refcnt > 0 ) { 987 lr->lr_refcnt = -lr->lr_refcnt; 988 989 lr->lr_prev = NULL; 990 lr->lr_next = NULL; 991 992 return; 993 } 994 995 if ( lr->lr_ber != NULL ) { 996 ber_free( lr->lr_ber, 1 ); 997 lr->lr_ber = NULL; 998 } 999 1000 if ( lr->lr_res_error != NULL ) { 1001 LDAP_FREE( lr->lr_res_error ); 1002 lr->lr_res_error = NULL; 1003 } 1004 1005 if ( lr->lr_res_matched != NULL ) { 1006 LDAP_FREE( lr->lr_res_matched ); 1007 lr->lr_res_matched = NULL; 1008 } 1009 1010 LDAP_FREE( lr ); 1011 } 1012 1013 /* protected by req_mutex */ 1014 void 1015 ldap_free_request( LDAP *ld, LDAPRequest *lr ) 1016 { 1017 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); 1018 Debug( LDAP_DEBUG_TRACE, "ldap_free_request (origid %d, msgid %d)\n", 1019 lr->lr_origid, lr->lr_msgid, 0 ); 1020 1021 /* free all referrals (child requests) */ 1022 while ( lr->lr_child ) { 1023 ldap_free_request( ld, lr->lr_child ); 1024 } 1025 1026 if ( lr->lr_parent != NULL ) { 1027 LDAPRequest **lrp; 1028 1029 --lr->lr_parent->lr_outrefcnt; 1030 for ( lrp = &lr->lr_parent->lr_child; 1031 *lrp && *lrp != lr; 1032 lrp = &(*lrp)->lr_refnext ); 1033 1034 if ( *lrp == lr ) { 1035 *lrp = lr->lr_refnext; 1036 } 1037 } 1038 ldap_free_request_int( ld, lr ); 1039 } 1040 1041 /* 1042 * call first time with *cntp = -1 1043 * when returns *cntp == -1, no referrals are left 1044 * 1045 * NOTE: may replace *refsp, or shuffle the contents 1046 * of the original array. 1047 */ 1048 static int ldap_int_nextref( 1049 LDAP *ld, 1050 char ***refsp, 1051 int *cntp, 1052 void *params ) 1053 { 1054 assert( refsp != NULL ); 1055 assert( *refsp != NULL ); 1056 assert( cntp != NULL ); 1057 1058 if ( *cntp < -1 ) { 1059 *cntp = -1; 1060 return -1; 1061 } 1062 1063 (*cntp)++; 1064 1065 if ( (*refsp)[ *cntp ] == NULL ) { 1066 *cntp = -1; 1067 } 1068 1069 return 0; 1070 } 1071 1072 /* 1073 * Chase v3 referrals 1074 * 1075 * Parameters: 1076 * (IN) ld = LDAP connection handle 1077 * (IN) lr = LDAP Request structure 1078 * (IN) refs = array of pointers to referral strings that we will chase 1079 * The array will be free'd by this function when no longer needed 1080 * (IN) sref != 0 if following search reference 1081 * (OUT) errstrp = Place to return a string of referrals which could not be followed 1082 * (OUT) hadrefp = 1 if sucessfully followed referral 1083 * 1084 * Return value - number of referrals followed 1085 * 1086 * Protected by res_mutex, conn_mutex and req_mutex (try_read1msg) 1087 */ 1088 int 1089 ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char **errstrp, int *hadrefp ) 1090 { 1091 char *unfollowed; 1092 int unfollowedcnt = 0; 1093 LDAPRequest *origreq; 1094 LDAPURLDesc *srv = NULL; 1095 BerElement *ber; 1096 char **refarray = NULL; 1097 LDAPConn *lc; 1098 int rc, count, i, j, id; 1099 LDAPreqinfo rinfo; 1100 LDAP_NEXTREF_PROC *nextref_proc = ld->ld_nextref_proc ? ld->ld_nextref_proc : ldap_int_nextref; 1101 1102 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); 1103 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); 1104 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); 1105 Debug( LDAP_DEBUG_TRACE, "ldap_chase_v3referrals\n", 0, 0, 0 ); 1106 1107 ld->ld_errno = LDAP_SUCCESS; /* optimistic */ 1108 *hadrefp = 0; 1109 1110 unfollowed = NULL; 1111 rc = count = 0; 1112 1113 /* If no referrals in array, return */ 1114 if ( (refs == NULL) || ( (refs)[0] == NULL) ) { 1115 rc = 0; 1116 goto done; 1117 } 1118 1119 /* Check for hop limit exceeded */ 1120 if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) { 1121 Debug( LDAP_DEBUG_ANY, 1122 "more than %d referral hops (dropping)\n", ld->ld_refhoplimit, 0, 0 ); 1123 ld->ld_errno = LDAP_REFERRAL_LIMIT_EXCEEDED; 1124 rc = -1; 1125 goto done; 1126 } 1127 1128 /* find original request */ 1129 for ( origreq = lr; 1130 origreq->lr_parent != NULL; 1131 origreq = origreq->lr_parent ) 1132 { 1133 /* empty */ ; 1134 } 1135 1136 refarray = refs; 1137 refs = NULL; 1138 1139 /* parse out & follow referrals */ 1140 /* NOTE: if nextref_proc == ldap_int_nextref, params is ignored */ 1141 i = -1; 1142 for ( nextref_proc( ld, &refarray, &i, ld->ld_nextref_params ); 1143 i != -1; 1144 nextref_proc( ld, &refarray, &i, ld->ld_nextref_params ) ) 1145 { 1146 1147 /* Parse the referral URL */ 1148 rc = ldap_url_parse_ext( refarray[i], &srv, LDAP_PVT_URL_PARSE_NOEMPTY_DN ); 1149 if ( rc != LDAP_URL_SUCCESS ) { 1150 /* ldap_url_parse_ext() returns LDAP_URL_* errors 1151 * which do not map on API errors */ 1152 ld->ld_errno = LDAP_PARAM_ERROR; 1153 rc = -1; 1154 goto done; 1155 } 1156 1157 if( srv->lud_crit_exts ) { 1158 int ok = 0; 1159 #ifdef HAVE_TLS 1160 /* If StartTLS is the only critical ext, OK. */ 1161 if ( find_tls_ext( srv ) == 2 && srv->lud_crit_exts == 1 ) 1162 ok = 1; 1163 #endif 1164 if ( !ok ) { 1165 /* we do not support any other extensions */ 1166 ld->ld_errno = LDAP_NOT_SUPPORTED; 1167 rc = -1; 1168 goto done; 1169 } 1170 } 1171 1172 /* check connection for re-bind in progress */ 1173 if (( lc = find_connection( ld, srv, 1 )) != NULL ) { 1174 /* See if we've already requested this DN with this conn */ 1175 LDAPRequest *lp; 1176 int looped = 0; 1177 ber_len_t len = srv->lud_dn ? strlen( srv->lud_dn ) : 0; 1178 for ( lp = origreq; lp; ) { 1179 if ( lp->lr_conn == lc 1180 && len == lp->lr_dn.bv_len 1181 && len 1182 && strncmp( srv->lud_dn, lp->lr_dn.bv_val, len ) == 0 ) 1183 { 1184 looped = 1; 1185 break; 1186 } 1187 if ( lp == origreq ) { 1188 lp = lp->lr_child; 1189 } else { 1190 lp = lp->lr_refnext; 1191 } 1192 } 1193 if ( looped ) { 1194 ldap_free_urllist( srv ); 1195 srv = NULL; 1196 ld->ld_errno = LDAP_CLIENT_LOOP; 1197 rc = -1; 1198 continue; 1199 } 1200 1201 if ( lc->lconn_rebind_inprogress ) { 1202 /* We are already chasing a referral or search reference and a 1203 * bind on that connection is in progress. We must queue 1204 * referrals on that connection, so we don't get a request 1205 * going out before the bind operation completes. This happens 1206 * if two search references come in one behind the other 1207 * for the same server with different contexts. 1208 */ 1209 Debug( LDAP_DEBUG_TRACE, 1210 "ldap_chase_v3referrals: queue referral \"%s\"\n", 1211 refarray[i], 0, 0); 1212 if( lc->lconn_rebind_queue == NULL ) { 1213 /* Create a referral list */ 1214 lc->lconn_rebind_queue = 1215 (char ***) LDAP_MALLOC( sizeof(void *) * 2); 1216 1217 if( lc->lconn_rebind_queue == NULL) { 1218 ld->ld_errno = LDAP_NO_MEMORY; 1219 rc = -1; 1220 goto done; 1221 } 1222 1223 lc->lconn_rebind_queue[0] = refarray; 1224 lc->lconn_rebind_queue[1] = NULL; 1225 refarray = NULL; 1226 1227 } else { 1228 /* Count how many referral arrays we already have */ 1229 for( j = 0; lc->lconn_rebind_queue[j] != NULL; j++) { 1230 /* empty */; 1231 } 1232 1233 /* Add the new referral to the list */ 1234 lc->lconn_rebind_queue = (char ***) LDAP_REALLOC( 1235 lc->lconn_rebind_queue, sizeof(void *) * (j + 2)); 1236 1237 if( lc->lconn_rebind_queue == NULL ) { 1238 ld->ld_errno = LDAP_NO_MEMORY; 1239 rc = -1; 1240 goto done; 1241 } 1242 lc->lconn_rebind_queue[j] = refarray; 1243 lc->lconn_rebind_queue[j+1] = NULL; 1244 refarray = NULL; 1245 } 1246 1247 /* We have queued the referral/reference, now just return */ 1248 rc = 0; 1249 *hadrefp = 1; 1250 count = 1; /* Pretend we already followed referral */ 1251 goto done; 1252 } 1253 } 1254 /* Re-encode the request with the new starting point of the search. 1255 * Note: In the future we also need to replace the filter if one 1256 * was provided with the search reference 1257 */ 1258 1259 /* For references we don't want old dn if new dn empty */ 1260 if ( sref && srv->lud_dn == NULL ) { 1261 srv->lud_dn = LDAP_STRDUP( "" ); 1262 } 1263 1264 LDAP_NEXT_MSGID( ld, id ); 1265 ber = re_encode_request( ld, origreq->lr_ber, id, 1266 sref, srv, &rinfo.ri_request ); 1267 1268 if( ber == NULL ) { 1269 ld->ld_errno = LDAP_ENCODING_ERROR; 1270 rc = -1; 1271 goto done; 1272 } 1273 1274 Debug( LDAP_DEBUG_TRACE, 1275 "ldap_chase_v3referral: msgid %d, url \"%s\"\n", 1276 lr->lr_msgid, refarray[i], 0); 1277 1278 /* Send the new request to the server - may require a bind */ 1279 rinfo.ri_msgid = origreq->lr_origid; 1280 rinfo.ri_url = refarray[i]; 1281 rc = ldap_send_server_request( ld, ber, id, 1282 origreq, &srv, NULL, &rinfo, 0, 1 ); 1283 if ( rc < 0 ) { 1284 /* Failure, try next referral in the list */ 1285 Debug( LDAP_DEBUG_ANY, "Unable to chase referral \"%s\" (%d: %s)\n", 1286 refarray[i], ld->ld_errno, ldap_err2string( ld->ld_errno ) ); 1287 unfollowedcnt += ldap_append_referral( ld, &unfollowed, refarray[i] ); 1288 ldap_free_urllist( srv ); 1289 srv = NULL; 1290 ld->ld_errno = LDAP_REFERRAL; 1291 } else { 1292 /* Success, no need to try this referral list further */ 1293 rc = 0; 1294 ++count; 1295 *hadrefp = 1; 1296 1297 /* check if there is a queue of referrals that came in during bind */ 1298 if ( lc == NULL) { 1299 lc = find_connection( ld, srv, 1 ); 1300 if ( lc == NULL ) { 1301 ld->ld_errno = LDAP_OPERATIONS_ERROR; 1302 rc = -1; 1303 LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 1304 goto done; 1305 } 1306 } 1307 1308 if ( lc->lconn_rebind_queue != NULL ) { 1309 /* Release resources of previous list */ 1310 LDAP_VFREE( refarray ); 1311 refarray = NULL; 1312 ldap_free_urllist( srv ); 1313 srv = NULL; 1314 1315 /* Pull entries off end of queue so list always null terminated */ 1316 for( j = 0; lc->lconn_rebind_queue[j] != NULL; j++ ) 1317 ; 1318 refarray = lc->lconn_rebind_queue[j - 1]; 1319 lc->lconn_rebind_queue[j-1] = NULL; 1320 /* we pulled off last entry from queue, free queue */ 1321 if ( j == 1 ) { 1322 LDAP_FREE( lc->lconn_rebind_queue ); 1323 lc->lconn_rebind_queue = NULL; 1324 } 1325 /* restart the loop the with new referral list */ 1326 i = -1; 1327 continue; 1328 } 1329 break; /* referral followed, break out of for loop */ 1330 } 1331 } /* end for loop */ 1332 done: 1333 LDAP_VFREE( refarray ); 1334 ldap_free_urllist( srv ); 1335 LDAP_FREE( *errstrp ); 1336 1337 if( rc == 0 ) { 1338 *errstrp = NULL; 1339 LDAP_FREE( unfollowed ); 1340 return count; 1341 } else { 1342 *errstrp = unfollowed; 1343 return rc; 1344 } 1345 } 1346 1347 /* 1348 * XXX merging of errors in this routine needs to be improved 1349 * Protected by res_mutex, conn_mutex and req_mutex (try_read1msg) 1350 */ 1351 int 1352 ldap_chase_referrals( LDAP *ld, 1353 LDAPRequest *lr, 1354 char **errstrp, 1355 int sref, 1356 int *hadrefp ) 1357 { 1358 int rc, count, id; 1359 unsigned len; 1360 char *p, *ref, *unfollowed; 1361 LDAPRequest *origreq; 1362 LDAPURLDesc *srv; 1363 BerElement *ber; 1364 LDAPreqinfo rinfo; 1365 LDAPConn *lc; 1366 1367 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex ); 1368 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex ); 1369 LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex ); 1370 Debug( LDAP_DEBUG_TRACE, "ldap_chase_referrals\n", 0, 0, 0 ); 1371 1372 ld->ld_errno = LDAP_SUCCESS; /* optimistic */ 1373 *hadrefp = 0; 1374 1375 if ( *errstrp == NULL ) { 1376 return( 0 ); 1377 } 1378 1379 len = strlen( *errstrp ); 1380 for ( p = *errstrp; len >= LDAP_REF_STR_LEN; ++p, --len ) { 1381 if ( strncasecmp( p, LDAP_REF_STR, LDAP_REF_STR_LEN ) == 0 ) { 1382 *p = '\0'; 1383 p += LDAP_REF_STR_LEN; 1384 break; 1385 } 1386 } 1387 1388 if ( len < LDAP_REF_STR_LEN ) { 1389 return( 0 ); 1390 } 1391 1392 if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) { 1393 Debug( LDAP_DEBUG_ANY, 1394 "more than %d referral hops (dropping)\n", 1395 ld->ld_refhoplimit, 0, 0 ); 1396 /* XXX report as error in ld->ld_errno? */ 1397 return( 0 ); 1398 } 1399 1400 /* find original request */ 1401 for ( origreq = lr; origreq->lr_parent != NULL; 1402 origreq = origreq->lr_parent ) { 1403 /* empty */; 1404 } 1405 1406 unfollowed = NULL; 1407 rc = count = 0; 1408 1409 /* parse out & follow referrals */ 1410 for ( ref = p; rc == 0 && ref != NULL; ref = p ) { 1411 p = strchr( ref, '\n' ); 1412 if ( p != NULL ) { 1413 *p++ = '\0'; 1414 } 1415 1416 rc = ldap_url_parse_ext( ref, &srv, LDAP_PVT_URL_PARSE_NOEMPTY_DN ); 1417 if ( rc != LDAP_URL_SUCCESS ) { 1418 Debug( LDAP_DEBUG_TRACE, 1419 "ignoring %s referral <%s>\n", 1420 ref, rc == LDAP_URL_ERR_BADSCHEME ? "unknown" : "incorrect", 0 ); 1421 rc = ldap_append_referral( ld, &unfollowed, ref ); 1422 *hadrefp = 1; 1423 continue; 1424 } 1425 1426 Debug( LDAP_DEBUG_TRACE, 1427 "chasing LDAP referral: <%s>\n", ref, 0, 0 ); 1428 1429 *hadrefp = 1; 1430 1431 /* See if we've already been here */ 1432 if (( lc = find_connection( ld, srv, 1 )) != NULL ) { 1433 LDAPRequest *lp; 1434 int looped = 0; 1435 ber_len_t len = srv->lud_dn ? strlen( srv->lud_dn ) : 0; 1436 for ( lp = lr; lp; lp = lp->lr_parent ) { 1437 if ( lp->lr_conn == lc 1438 && len == lp->lr_dn.bv_len ) 1439 { 1440 if ( len && strncmp( srv->lud_dn, lp->lr_dn.bv_val, len ) ) 1441 continue; 1442 looped = 1; 1443 break; 1444 } 1445 } 1446 if ( looped ) { 1447 ldap_free_urllist( srv ); 1448 ld->ld_errno = LDAP_CLIENT_LOOP; 1449 rc = -1; 1450 continue; 1451 } 1452 } 1453 1454 LDAP_NEXT_MSGID( ld, id ); 1455 ber = re_encode_request( ld, origreq->lr_ber, 1456 id, sref, srv, &rinfo.ri_request ); 1457 1458 if ( ber == NULL ) { 1459 ldap_free_urllist( srv ); 1460 return -1 ; 1461 } 1462 1463 /* copy the complete referral for rebind process */ 1464 rinfo.ri_url = LDAP_STRDUP( ref ); 1465 1466 rinfo.ri_msgid = origreq->lr_origid; 1467 1468 rc = ldap_send_server_request( ld, ber, id, 1469 lr, &srv, NULL, &rinfo, 0, 1 ); 1470 LDAP_FREE( rinfo.ri_url ); 1471 1472 if( rc >= 0 ) { 1473 ++count; 1474 } else { 1475 Debug( LDAP_DEBUG_ANY, 1476 "Unable to chase referral \"%s\" (%d: %s)\n", 1477 ref, ld->ld_errno, ldap_err2string( ld->ld_errno ) ); 1478 rc = ldap_append_referral( ld, &unfollowed, ref ); 1479 } 1480 1481 ldap_free_urllist(srv); 1482 } 1483 1484 LDAP_FREE( *errstrp ); 1485 *errstrp = unfollowed; 1486 1487 return(( rc == 0 ) ? count : rc ); 1488 } 1489 1490 1491 int 1492 ldap_append_referral( LDAP *ld, char **referralsp, char *s ) 1493 { 1494 int first; 1495 1496 if ( *referralsp == NULL ) { 1497 first = 1; 1498 *referralsp = (char *)LDAP_MALLOC( strlen( s ) + LDAP_REF_STR_LEN 1499 + 1 ); 1500 } else { 1501 first = 0; 1502 *referralsp = (char *)LDAP_REALLOC( *referralsp, 1503 strlen( *referralsp ) + strlen( s ) + 2 ); 1504 } 1505 1506 if ( *referralsp == NULL ) { 1507 ld->ld_errno = LDAP_NO_MEMORY; 1508 return( -1 ); 1509 } 1510 1511 if ( first ) { 1512 strcpy( *referralsp, LDAP_REF_STR ); 1513 } else { 1514 strcat( *referralsp, "\n" ); 1515 } 1516 strcat( *referralsp, s ); 1517 1518 return( 0 ); 1519 } 1520 1521 1522 1523 static BerElement * 1524 re_encode_request( LDAP *ld, 1525 BerElement *origber, 1526 ber_int_t msgid, 1527 int sref, 1528 LDAPURLDesc *srv, 1529 int *type ) 1530 { 1531 /* 1532 * XXX this routine knows way too much about how the lber library works! 1533 */ 1534 ber_int_t along; 1535 ber_tag_t tag; 1536 ber_tag_t rtag; 1537 ber_int_t ver; 1538 ber_int_t scope; 1539 int rc; 1540 BerElement tmpber, *ber; 1541 struct berval dn; 1542 1543 Debug( LDAP_DEBUG_TRACE, 1544 "re_encode_request: new msgid %ld, new dn <%s>\n", 1545 (long) msgid, 1546 ( srv == NULL || srv->lud_dn == NULL) ? "NONE" : srv->lud_dn, 0 ); 1547 1548 tmpber = *origber; 1549 1550 /* 1551 * all LDAP requests are sequences that start with a message id. 1552 * For all except delete, this is followed by a sequence that is 1553 * tagged with the operation code. For delete, the provided DN 1554 * is not wrapped by a sequence. 1555 */ 1556 rtag = ber_scanf( &tmpber, "{it", /*}*/ &along, &tag ); 1557 1558 if ( rtag == LBER_ERROR ) { 1559 ld->ld_errno = LDAP_DECODING_ERROR; 1560 return( NULL ); 1561 } 1562 1563 assert( tag != 0); 1564 if ( tag == LDAP_REQ_BIND ) { 1565 /* bind requests have a version number before the DN & other stuff */ 1566 rtag = ber_scanf( &tmpber, "{im" /*}*/, &ver, &dn ); 1567 1568 } else if ( tag == LDAP_REQ_DELETE ) { 1569 /* delete requests don't have a DN wrapping sequence */ 1570 rtag = ber_scanf( &tmpber, "m", &dn ); 1571 1572 } else if ( tag == LDAP_REQ_SEARCH ) { 1573 /* search requests need to be re-scope-ed */ 1574 rtag = ber_scanf( &tmpber, "{me" /*"}"*/, &dn, &scope ); 1575 1576 if( srv->lud_scope != LDAP_SCOPE_DEFAULT ) { 1577 /* use the scope provided in reference */ 1578 scope = srv->lud_scope; 1579 1580 } else if ( sref ) { 1581 /* use scope implied by previous operation 1582 * base -> base 1583 * one -> base 1584 * subtree -> subtree 1585 * subordinate -> subtree 1586 */ 1587 switch( scope ) { 1588 default: 1589 case LDAP_SCOPE_BASE: 1590 case LDAP_SCOPE_ONELEVEL: 1591 scope = LDAP_SCOPE_BASE; 1592 break; 1593 case LDAP_SCOPE_SUBTREE: 1594 case LDAP_SCOPE_SUBORDINATE: 1595 scope = LDAP_SCOPE_SUBTREE; 1596 break; 1597 } 1598 } 1599 1600 } else { 1601 rtag = ber_scanf( &tmpber, "{m" /*}*/, &dn ); 1602 } 1603 1604 if( rtag == LBER_ERROR ) { 1605 ld->ld_errno = LDAP_DECODING_ERROR; 1606 return NULL; 1607 } 1608 1609 /* restore character zero'd out by ber_scanf*/ 1610 dn.bv_val[dn.bv_len] = tmpber.ber_tag; 1611 1612 if (( ber = ldap_alloc_ber_with_options( ld )) == NULL ) { 1613 return NULL; 1614 } 1615 1616 if ( srv->lud_dn ) { 1617 ber_str2bv( srv->lud_dn, 0, 0, &dn ); 1618 } 1619 1620 if ( tag == LDAP_REQ_BIND ) { 1621 rc = ber_printf( ber, "{it{iO" /*}}*/, msgid, tag, ver, &dn ); 1622 } else if ( tag == LDAP_REQ_DELETE ) { 1623 rc = ber_printf( ber, "{itON}", msgid, tag, &dn ); 1624 } else if ( tag == LDAP_REQ_SEARCH ) { 1625 rc = ber_printf( ber, "{it{Oe" /*}}*/, msgid, tag, &dn, scope ); 1626 } else { 1627 rc = ber_printf( ber, "{it{O" /*}}*/, msgid, tag, &dn ); 1628 } 1629 1630 if ( rc == -1 ) { 1631 ld->ld_errno = LDAP_ENCODING_ERROR; 1632 ber_free( ber, 1 ); 1633 return NULL; 1634 } 1635 1636 if ( tag != LDAP_REQ_DELETE && ( 1637 ber_write(ber, tmpber.ber_ptr, ( tmpber.ber_end - tmpber.ber_ptr ), 0) 1638 != ( tmpber.ber_end - tmpber.ber_ptr ) || 1639 ber_printf( ber, /*{{*/ "N}N}" ) == -1 ) ) 1640 { 1641 ld->ld_errno = LDAP_ENCODING_ERROR; 1642 ber_free( ber, 1 ); 1643 return NULL; 1644 } 1645 1646 #ifdef LDAP_DEBUG 1647 if ( ldap_debug & LDAP_DEBUG_PACKETS ) { 1648 Debug( LDAP_DEBUG_ANY, "re_encode_request new request is:\n", 1649 0, 0, 0 ); 1650 ber_log_dump( LDAP_DEBUG_BER, ldap_debug, ber, 0 ); 1651 } 1652 #endif /* LDAP_DEBUG */ 1653 1654 *type = tag; /* return request type */ 1655 return ber; 1656 } 1657 1658 1659 /* protected by req_mutex */ 1660 LDAPRequest * 1661 ldap_find_request_by_msgid( LDAP *ld, ber_int_t msgid ) 1662 { 1663 LDAPRequest *lr; 1664 1665 for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) { 1666 if ( lr->lr_status == LDAP_REQST_COMPLETED ) { 1667 continue; /* Skip completed requests */ 1668 } 1669 if ( msgid == lr->lr_msgid ) { 1670 lr->lr_refcnt++; 1671 break; 1672 } 1673 } 1674 1675 return( lr ); 1676 } 1677 1678 /* protected by req_mutex */ 1679 void 1680 ldap_return_request( LDAP *ld, LDAPRequest *lrx, int freeit ) 1681 { 1682 LDAPRequest *lr; 1683 1684 for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) { 1685 if ( lr == lrx ) { 1686 if ( lr->lr_refcnt > 0 ) { 1687 lr->lr_refcnt--; 1688 1689 } else if ( lr->lr_refcnt < 0 ) { 1690 lr->lr_refcnt++; 1691 if ( lr->lr_refcnt == 0 ) { 1692 lr = NULL; 1693 } 1694 } 1695 break; 1696 } 1697 } 1698 if ( lr == NULL ) { 1699 ldap_free_request_int( ld, lrx ); 1700 1701 } else if ( freeit ) { 1702 ldap_free_request( ld, lrx ); 1703 } 1704 } 1705