1*549b59edSchristos /* $NetBSD: request.c,v 1.3 2021/08/14 16:14:56 christos Exp $ */
24e6df137Slukem
3d11b170bStron /* $OpenLDAP$ */
42de962bdSlukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
52de962bdSlukem *
6*549b59edSchristos * Copyright 1998-2021 The OpenLDAP Foundation.
72de962bdSlukem * All rights reserved.
82de962bdSlukem *
92de962bdSlukem * Redistribution and use in source and binary forms, with or without
102de962bdSlukem * modification, are permitted only as authorized by the OpenLDAP
112de962bdSlukem * Public License.
122de962bdSlukem *
132de962bdSlukem * A copy of this license is available in the file LICENSE in the
142de962bdSlukem * top-level directory of the distribution or, alternatively, at
152de962bdSlukem * <http://www.OpenLDAP.org/license.html>.
162de962bdSlukem */
172de962bdSlukem /* Portions Copyright (c) 1995 Regents of the University of Michigan.
182de962bdSlukem * All rights reserved.
192de962bdSlukem */
202de962bdSlukem /* This notice applies to changes, created by or for Novell, Inc.,
212de962bdSlukem * to preexisting works for which notices appear elsewhere in this file.
222de962bdSlukem *
232de962bdSlukem * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
242de962bdSlukem *
252de962bdSlukem * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
262de962bdSlukem * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION
272de962bdSlukem * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT
282de962bdSlukem * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE
292de962bdSlukem * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS
302de962bdSlukem * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC
312de962bdSlukem * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE
322de962bdSlukem * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
332de962bdSlukem *---
342de962bdSlukem * Modification to OpenLDAP source by Novell, Inc.
352de962bdSlukem * April 2000 sfs Added code to chase V3 referrals
362de962bdSlukem * request.c - sending of ldap requests; handling of referrals
372de962bdSlukem *---
382de962bdSlukem * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License
392de962bdSlukem * can be found in the file "build/LICENSE-2.0.1" in this distribution
402de962bdSlukem * of OpenLDAP Software.
412de962bdSlukem */
422de962bdSlukem
43376af7d7Schristos #include <sys/cdefs.h>
44*549b59edSchristos __RCSID("$NetBSD: request.c,v 1.3 2021/08/14 16:14:56 christos Exp $");
45376af7d7Schristos
462de962bdSlukem #include "portable.h"
472de962bdSlukem
482de962bdSlukem #include <stdio.h>
492de962bdSlukem
502de962bdSlukem #include <ac/stdlib.h>
512de962bdSlukem
522de962bdSlukem #include <ac/errno.h>
532de962bdSlukem #include <ac/socket.h>
542de962bdSlukem #include <ac/string.h>
552de962bdSlukem #include <ac/time.h>
562de962bdSlukem #include <ac/unistd.h>
572de962bdSlukem
582de962bdSlukem #include "ldap-int.h"
592de962bdSlukem #include "lber.h"
602de962bdSlukem
61d11b170bStron /* used by ldap_send_server_request and ldap_new_connection */
62d11b170bStron #ifdef LDAP_R_COMPILE
63d11b170bStron #define LDAP_CONN_LOCK_IF(nolock) \
64d11b170bStron { if (nolock) LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); }
65d11b170bStron #define LDAP_CONN_UNLOCK_IF(nolock) \
66d11b170bStron { if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); }
67d11b170bStron #define LDAP_REQ_LOCK_IF(nolock) \
68d11b170bStron { if (nolock) LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); }
69d11b170bStron #define LDAP_REQ_UNLOCK_IF(nolock) \
70d11b170bStron { if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); }
71d11b170bStron #define LDAP_RES_LOCK_IF(nolock) \
72d11b170bStron { if (nolock) LDAP_MUTEX_LOCK( &ld->ld_res_mutex ); }
73d11b170bStron #define LDAP_RES_UNLOCK_IF(nolock) \
74d11b170bStron { if (nolock) LDAP_MUTEX_UNLOCK( &ld->ld_res_mutex ); }
75d11b170bStron #else
76d11b170bStron #define LDAP_CONN_LOCK_IF(nolock)
77d11b170bStron #define LDAP_CONN_UNLOCK_IF(nolock)
78d11b170bStron #define LDAP_REQ_LOCK_IF(nolock)
79d11b170bStron #define LDAP_REQ_UNLOCK_IF(nolock)
80d11b170bStron #define LDAP_RES_LOCK_IF(nolock)
81d11b170bStron #define LDAP_RES_UNLOCK_IF(nolock)
82d11b170bStron #endif
83d11b170bStron
842de962bdSlukem static LDAPConn *find_connection LDAP_P(( LDAP *ld, LDAPURLDesc *srv, int any ));
852de962bdSlukem static void use_connection LDAP_P(( LDAP *ld, LDAPConn *lc ));
862de962bdSlukem static void ldap_free_request_int LDAP_P(( LDAP *ld, LDAPRequest *lr ));
872de962bdSlukem
882de962bdSlukem static BerElement *
892de962bdSlukem re_encode_request( LDAP *ld,
902de962bdSlukem BerElement *origber,
912de962bdSlukem ber_int_t msgid,
922de962bdSlukem int sref,
932de962bdSlukem LDAPURLDesc *srv,
942de962bdSlukem int *type );
952de962bdSlukem
962de962bdSlukem BerElement *
ldap_alloc_ber_with_options(LDAP * ld)972de962bdSlukem ldap_alloc_ber_with_options( LDAP *ld )
982de962bdSlukem {
992de962bdSlukem BerElement *ber;
1002de962bdSlukem
1012de962bdSlukem ber = ber_alloc_t( ld->ld_lberoptions );
1022de962bdSlukem if ( ber == NULL ) {
1032de962bdSlukem ld->ld_errno = LDAP_NO_MEMORY;
1042de962bdSlukem }
1052de962bdSlukem
1062de962bdSlukem return( ber );
1072de962bdSlukem }
1082de962bdSlukem
1092de962bdSlukem
1102de962bdSlukem void
ldap_set_ber_options(LDAP * ld,BerElement * ber)1112de962bdSlukem ldap_set_ber_options( LDAP *ld, BerElement *ber )
1122de962bdSlukem {
113d11b170bStron /* ld_lberoptions is constant, hence no lock */
1142de962bdSlukem ber->ber_options = ld->ld_lberoptions;
1152de962bdSlukem }
1162de962bdSlukem
1172de962bdSlukem
118d11b170bStron /* sets needed mutexes - no mutexes set to this point */
1192de962bdSlukem ber_int_t
ldap_send_initial_request(LDAP * ld,ber_tag_t msgtype,const char * dn,BerElement * ber,ber_int_t msgid)1202de962bdSlukem ldap_send_initial_request(
1212de962bdSlukem LDAP *ld,
1222de962bdSlukem ber_tag_t msgtype,
1232de962bdSlukem const char *dn,
1242de962bdSlukem BerElement *ber,
1252de962bdSlukem ber_int_t msgid)
1262de962bdSlukem {
1272de962bdSlukem int rc = 1;
128d11b170bStron ber_socket_t sd = AC_SOCKET_INVALID;
1292de962bdSlukem
130*549b59edSchristos Debug0( LDAP_DEBUG_TRACE, "ldap_send_initial_request\n" );
1312de962bdSlukem
132d11b170bStron LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
133d11b170bStron if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd ) == -1 ) {
1342de962bdSlukem /* not connected yet */
1352de962bdSlukem rc = ldap_open_defconn( ld );
136376af7d7Schristos if ( rc == 0 ) {
137376af7d7Schristos ber_sockbuf_ctrl( ld->ld_defconn->lconn_sb,
138376af7d7Schristos LBER_SB_OPT_GET_FD, &sd );
139376af7d7Schristos }
1402de962bdSlukem }
141d11b170bStron if ( ld->ld_defconn && ld->ld_defconn->lconn_status == LDAP_CONNST_CONNECTING )
142d11b170bStron rc = ldap_int_check_async_open( ld, sd );
1432de962bdSlukem if( rc < 0 ) {
1442de962bdSlukem ber_free( ber, 1 );
145d11b170bStron LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
1462de962bdSlukem return( -1 );
1472de962bdSlukem } else if ( rc == 0 ) {
148*549b59edSchristos Debug0( LDAP_DEBUG_TRACE,
149*549b59edSchristos "ldap_open_defconn: successful\n" );
1502de962bdSlukem }
1512de962bdSlukem
1522de962bdSlukem #ifdef LDAP_CONNECTIONLESS
1532de962bdSlukem if (LDAP_IS_UDP(ld)) {
1542de962bdSlukem if (msgtype == LDAP_REQ_BIND) {
155d11b170bStron LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
1562de962bdSlukem if (ld->ld_options.ldo_cldapdn)
1572de962bdSlukem ldap_memfree(ld->ld_options.ldo_cldapdn);
1582de962bdSlukem ld->ld_options.ldo_cldapdn = ldap_strdup(dn);
159ef2f90d3Sadam ber_free( ber, 1 );
160d11b170bStron LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
161d11b170bStron LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
1622de962bdSlukem return 0;
1632de962bdSlukem }
1642de962bdSlukem if (msgtype != LDAP_REQ_ABANDON && msgtype != LDAP_REQ_SEARCH)
165ef2f90d3Sadam {
166ef2f90d3Sadam ber_free( ber, 1 );
167d11b170bStron LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
1682de962bdSlukem return LDAP_PARAM_ERROR;
1692de962bdSlukem }
170ef2f90d3Sadam }
1712de962bdSlukem #endif
172d11b170bStron LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
1732de962bdSlukem rc = ldap_send_server_request( ld, ber, msgid, NULL,
174d11b170bStron NULL, NULL, NULL, 0, 0 );
175d11b170bStron LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
176d11b170bStron LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
1772de962bdSlukem return(rc);
1782de962bdSlukem }
1792de962bdSlukem
1802de962bdSlukem
181d11b170bStron /* protected by conn_mutex */
1822de962bdSlukem int
ldap_int_flush_request(LDAP * ld,LDAPRequest * lr)1832de962bdSlukem ldap_int_flush_request(
1842de962bdSlukem LDAP *ld,
1852de962bdSlukem LDAPRequest *lr )
1862de962bdSlukem {
1872de962bdSlukem LDAPConn *lc = lr->lr_conn;
1882de962bdSlukem
189d11b170bStron LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
1902de962bdSlukem if ( ber_flush2( lc->lconn_sb, lr->lr_ber, LBER_FLUSH_FREE_NEVER ) != 0 ) {
1914e27b3e8Schristos if (( sock_errno() == EAGAIN ) || ( sock_errno() == ENOTCONN )) {
1924e27b3e8Schristos /* ENOTCONN is returned in Solaris 10 */
1932de962bdSlukem /* need to continue write later */
1942de962bdSlukem lr->lr_status = LDAP_REQST_WRITING;
1952de962bdSlukem ldap_mark_select_write( ld, lc->lconn_sb );
1962de962bdSlukem ld->ld_errno = LDAP_BUSY;
1972de962bdSlukem return -2;
1982de962bdSlukem } else {
1992de962bdSlukem ld->ld_errno = LDAP_SERVER_DOWN;
2002de962bdSlukem ldap_free_request( ld, lr );
2012de962bdSlukem ldap_free_connection( ld, lc, 0, 0 );
2022de962bdSlukem return( -1 );
2032de962bdSlukem }
2042de962bdSlukem } else {
2052de962bdSlukem if ( lr->lr_parent == NULL ) {
2062de962bdSlukem lr->lr_ber->ber_end = lr->lr_ber->ber_ptr;
2072de962bdSlukem lr->lr_ber->ber_ptr = lr->lr_ber->ber_buf;
2082de962bdSlukem }
2092de962bdSlukem lr->lr_status = LDAP_REQST_INPROGRESS;
2102de962bdSlukem
2112de962bdSlukem /* sent -- waiting for a response */
2122de962bdSlukem ldap_mark_select_read( ld, lc->lconn_sb );
213d11b170bStron ldap_clear_select_write( ld, lc->lconn_sb );
2142de962bdSlukem }
2152de962bdSlukem return 0;
2162de962bdSlukem }
2172de962bdSlukem
218d11b170bStron /*
219d11b170bStron * protected by req_mutex
220d11b170bStron * if m_noconn then protect using conn_lock
221d11b170bStron * else already protected with conn_lock
222d11b170bStron * if m_res then also protected by res_mutex
223d11b170bStron */
224d11b170bStron
2252de962bdSlukem int
ldap_send_server_request(LDAP * ld,BerElement * ber,ber_int_t msgid,LDAPRequest * parentreq,LDAPURLDesc ** srvlist,LDAPConn * lc,LDAPreqinfo * bind,int m_noconn,int m_res)2262de962bdSlukem ldap_send_server_request(
2272de962bdSlukem LDAP *ld,
2282de962bdSlukem BerElement *ber,
2292de962bdSlukem ber_int_t msgid,
2302de962bdSlukem LDAPRequest *parentreq,
2312de962bdSlukem LDAPURLDesc **srvlist,
2322de962bdSlukem LDAPConn *lc,
233d11b170bStron LDAPreqinfo *bind,
234d11b170bStron int m_noconn,
235d11b170bStron int m_res )
2362de962bdSlukem {
2372de962bdSlukem LDAPRequest *lr;
2382de962bdSlukem int incparent, rc;
2392de962bdSlukem
240d11b170bStron LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
241*549b59edSchristos Debug0( LDAP_DEBUG_TRACE, "ldap_send_server_request\n" );
2422de962bdSlukem
2432de962bdSlukem incparent = 0;
2442de962bdSlukem ld->ld_errno = LDAP_SUCCESS; /* optimistic */
2452de962bdSlukem
246d11b170bStron LDAP_CONN_LOCK_IF(m_noconn);
2472de962bdSlukem if ( lc == NULL ) {
2482de962bdSlukem if ( srvlist == NULL ) {
2492de962bdSlukem lc = ld->ld_defconn;
2502de962bdSlukem } else {
2512de962bdSlukem lc = find_connection( ld, *srvlist, 1 );
2522de962bdSlukem if ( lc == NULL ) {
2532de962bdSlukem if ( (bind != NULL) && (parentreq != NULL) ) {
2542de962bdSlukem /* Remember the bind in the parent */
2552de962bdSlukem incparent = 1;
2562de962bdSlukem ++parentreq->lr_outrefcnt;
2572de962bdSlukem }
258d11b170bStron lc = ldap_new_connection( ld, srvlist, 0,
259d11b170bStron 1, bind, 1, m_res );
2602de962bdSlukem }
2612de962bdSlukem }
2622de962bdSlukem }
2632de962bdSlukem
2642de962bdSlukem /* async connect... */
2652de962bdSlukem if ( lc != NULL && lc->lconn_status == LDAP_CONNST_CONNECTING ) {
2662de962bdSlukem ber_socket_t sd = AC_SOCKET_ERROR;
2672de962bdSlukem struct timeval tv = { 0 };
2682de962bdSlukem
2692de962bdSlukem ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_GET_FD, &sd );
2702de962bdSlukem
2712de962bdSlukem /* poll ... */
272d11b170bStron switch ( ldap_int_poll( ld, sd, &tv, 1 ) ) {
2732de962bdSlukem case 0:
2742de962bdSlukem /* go on! */
2752de962bdSlukem lc->lconn_status = LDAP_CONNST_CONNECTED;
2762de962bdSlukem break;
2772de962bdSlukem
2782de962bdSlukem case -2:
2792de962bdSlukem /* async only occurs if a network timeout is set */
2802de962bdSlukem
2812de962bdSlukem /* honor network timeout */
282d11b170bStron LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
2832de962bdSlukem if ( time( NULL ) - lc->lconn_created <= ld->ld_options.ldo_tm_net.tv_sec )
2842de962bdSlukem {
2852de962bdSlukem /* caller will have to call again */
2862de962bdSlukem ld->ld_errno = LDAP_X_CONNECTING;
2872de962bdSlukem }
288d11b170bStron LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
2892de962bdSlukem /* fallthru */
2902de962bdSlukem
2912de962bdSlukem default:
2922de962bdSlukem /* error */
2932de962bdSlukem break;
2942de962bdSlukem }
2952de962bdSlukem }
2962de962bdSlukem
2972de962bdSlukem if ( lc == NULL || lc->lconn_status != LDAP_CONNST_CONNECTED ) {
2982de962bdSlukem if ( ld->ld_errno == LDAP_SUCCESS ) {
2992de962bdSlukem ld->ld_errno = LDAP_SERVER_DOWN;
3002de962bdSlukem }
3012de962bdSlukem
3022de962bdSlukem ber_free( ber, 1 );
3032de962bdSlukem if ( incparent ) {
3042de962bdSlukem /* Forget about the bind */
3052de962bdSlukem --parentreq->lr_outrefcnt;
3062de962bdSlukem }
307d11b170bStron LDAP_CONN_UNLOCK_IF(m_noconn);
3082de962bdSlukem return( -1 );
3092de962bdSlukem }
3102de962bdSlukem
3112de962bdSlukem use_connection( ld, lc );
3122de962bdSlukem
3132de962bdSlukem #ifdef LDAP_CONNECTIONLESS
3142de962bdSlukem if ( LDAP_IS_UDP( ld )) {
3152de962bdSlukem BerElement tmpber = *ber;
3162de962bdSlukem ber_rewind( &tmpber );
317d11b170bStron LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
3182de962bdSlukem rc = ber_write( &tmpber, ld->ld_options.ldo_peer,
319d11b170bStron sizeof( struct sockaddr_storage ), 0 );
320d11b170bStron LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
3212de962bdSlukem if ( rc == -1 ) {
3222de962bdSlukem ld->ld_errno = LDAP_ENCODING_ERROR;
3234e27b3e8Schristos ber_free( ber, 1 );
324d11b170bStron LDAP_CONN_UNLOCK_IF(m_noconn);
3252de962bdSlukem return rc;
3262de962bdSlukem }
3272de962bdSlukem }
3282de962bdSlukem #endif
3292de962bdSlukem
3302de962bdSlukem /* If we still have an incomplete write, try to finish it before
3312de962bdSlukem * dealing with the new request. If we don't finish here, return
3322de962bdSlukem * LDAP_BUSY and let the caller retry later. We only allow a single
3332de962bdSlukem * request to be in WRITING state.
3342de962bdSlukem */
3352de962bdSlukem rc = 0;
336*549b59edSchristos if ( ld->ld_requests != NULL ) {
337*549b59edSchristos TAvlnode *node = ldap_tavl_end( ld->ld_requests, TAVL_DIR_RIGHT );
338*549b59edSchristos LDAPRequest *lr;
339*549b59edSchristos
340*549b59edSchristos assert( node != NULL );
341*549b59edSchristos lr = node->avl_data;
342*549b59edSchristos if ( lr->lr_status == LDAP_REQST_WRITING &&
343*549b59edSchristos ldap_int_flush_request( ld, lr ) < 0 ) {
3442de962bdSlukem rc = -1;
3452de962bdSlukem }
346*549b59edSchristos }
347d11b170bStron if ( rc ) {
3484e27b3e8Schristos ber_free( ber, 1 );
349d11b170bStron LDAP_CONN_UNLOCK_IF(m_noconn);
350d11b170bStron return rc;
351d11b170bStron }
3522de962bdSlukem
3532de962bdSlukem lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ) );
3542de962bdSlukem if ( lr == NULL ) {
3552de962bdSlukem ld->ld_errno = LDAP_NO_MEMORY;
3562de962bdSlukem ldap_free_connection( ld, lc, 0, 0 );
3572de962bdSlukem ber_free( ber, 1 );
3582de962bdSlukem if ( incparent ) {
3592de962bdSlukem /* Forget about the bind */
3602de962bdSlukem --parentreq->lr_outrefcnt;
3612de962bdSlukem }
362d11b170bStron LDAP_CONN_UNLOCK_IF(m_noconn);
3632de962bdSlukem return( -1 );
3642de962bdSlukem }
3652de962bdSlukem lr->lr_msgid = msgid;
3662de962bdSlukem lr->lr_status = LDAP_REQST_INPROGRESS;
3672de962bdSlukem lr->lr_res_errno = LDAP_SUCCESS; /* optimistic */
3682de962bdSlukem lr->lr_ber = ber;
3692de962bdSlukem lr->lr_conn = lc;
3702de962bdSlukem if ( parentreq != NULL ) { /* sub-request */
3712de962bdSlukem if ( !incparent ) {
3722de962bdSlukem /* Increment if we didn't do it before the bind */
3732de962bdSlukem ++parentreq->lr_outrefcnt;
3742de962bdSlukem }
3752de962bdSlukem lr->lr_origid = parentreq->lr_origid;
3762de962bdSlukem lr->lr_parentcnt = ++parentreq->lr_parentcnt;
3772de962bdSlukem lr->lr_parent = parentreq;
3782de962bdSlukem lr->lr_refnext = parentreq->lr_child;
3792de962bdSlukem parentreq->lr_child = lr;
3802de962bdSlukem } else { /* original request */
3812de962bdSlukem lr->lr_origid = lr->lr_msgid;
3822de962bdSlukem }
3832de962bdSlukem
3842de962bdSlukem /* Extract requestDN for future reference */
385d11b170bStron #ifdef LDAP_CONNECTIONLESS
386d11b170bStron if ( !LDAP_IS_UDP(ld) )
387d11b170bStron #endif
3882de962bdSlukem {
3892de962bdSlukem BerElement tmpber = *ber;
3902de962bdSlukem ber_int_t bint;
3912de962bdSlukem ber_tag_t tag, rtag;
3922de962bdSlukem
3932de962bdSlukem ber_reset( &tmpber, 1 );
3942de962bdSlukem rtag = ber_scanf( &tmpber, "{it", /*}*/ &bint, &tag );
3952de962bdSlukem switch ( tag ) {
3962de962bdSlukem case LDAP_REQ_BIND:
3972de962bdSlukem rtag = ber_scanf( &tmpber, "{i" /*}*/, &bint );
3982de962bdSlukem break;
3992de962bdSlukem case LDAP_REQ_DELETE:
4002de962bdSlukem break;
4012de962bdSlukem default:
4022de962bdSlukem rtag = ber_scanf( &tmpber, "{" /*}*/ );
4032de962bdSlukem case LDAP_REQ_ABANDON:
4042de962bdSlukem break;
4052de962bdSlukem }
4062de962bdSlukem if ( tag != LDAP_REQ_ABANDON ) {
4072de962bdSlukem ber_skip_tag( &tmpber, &lr->lr_dn.bv_len );
4082de962bdSlukem lr->lr_dn.bv_val = tmpber.ber_ptr;
4092de962bdSlukem }
4102de962bdSlukem }
4112de962bdSlukem
412*549b59edSchristos rc = ldap_tavl_insert( &ld->ld_requests, lr, ldap_req_cmp, ldap_avl_dup_error );
413*549b59edSchristos assert( rc == LDAP_SUCCESS );
4142de962bdSlukem
4152de962bdSlukem ld->ld_errno = LDAP_SUCCESS;
4162de962bdSlukem if ( ldap_int_flush_request( ld, lr ) == -1 ) {
4172de962bdSlukem msgid = -1;
4182de962bdSlukem }
4192de962bdSlukem
420d11b170bStron LDAP_CONN_UNLOCK_IF(m_noconn);
4212de962bdSlukem return( msgid );
4222de962bdSlukem }
4232de962bdSlukem
4244e6df137Slukem /* return 0 if no StartTLS ext, 1 if present, 2 if critical */
4254e6df137Slukem static int
find_tls_ext(LDAPURLDesc * srv)4264e6df137Slukem find_tls_ext( LDAPURLDesc *srv )
4274e6df137Slukem {
4284e6df137Slukem int i, crit;
4294e6df137Slukem char *ext;
4304e6df137Slukem
4314e6df137Slukem if ( !srv->lud_exts )
4324e6df137Slukem return 0;
4334e6df137Slukem
4344e6df137Slukem for (i=0; srv->lud_exts[i]; i++) {
4354e6df137Slukem crit = 0;
4364e6df137Slukem ext = srv->lud_exts[i];
4374e6df137Slukem if ( ext[0] == '!') {
4384e6df137Slukem ext++;
4394e6df137Slukem crit = 1;
4404e6df137Slukem }
4414e6df137Slukem if ( !strcasecmp( ext, "StartTLS" ) ||
4424e6df137Slukem !strcasecmp( ext, "X-StartTLS" ) ||
4434e6df137Slukem !strcmp( ext, LDAP_EXOP_START_TLS )) {
4444e6df137Slukem return crit + 1;
4454e6df137Slukem }
4464e6df137Slukem }
4474e6df137Slukem return 0;
4484e6df137Slukem }
4494e6df137Slukem
450d11b170bStron /*
451d11b170bStron * always protected by conn_mutex
452d11b170bStron * optionally protected by req_mutex and res_mutex
453d11b170bStron */
4542de962bdSlukem LDAPConn *
ldap_new_connection(LDAP * ld,LDAPURLDesc ** srvlist,int use_ldsb,int connect,LDAPreqinfo * bind,int m_req,int m_res)4552de962bdSlukem ldap_new_connection( LDAP *ld, LDAPURLDesc **srvlist, int use_ldsb,
456d11b170bStron int connect, LDAPreqinfo *bind, int m_req, int m_res )
4572de962bdSlukem {
4582de962bdSlukem LDAPConn *lc;
4592de962bdSlukem int async = 0;
4602de962bdSlukem
461d11b170bStron LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
462*549b59edSchristos Debug3( LDAP_DEBUG_TRACE, "ldap_new_connection %d %d %d\n",
4632de962bdSlukem use_ldsb, connect, (bind != NULL) );
4642de962bdSlukem /*
4652de962bdSlukem * make a new LDAP server connection
4662de962bdSlukem * XXX open connection synchronously for now
4672de962bdSlukem */
4682de962bdSlukem lc = (LDAPConn *)LDAP_CALLOC( 1, sizeof( LDAPConn ) );
4692de962bdSlukem if ( lc == NULL ) {
4702de962bdSlukem ld->ld_errno = LDAP_NO_MEMORY;
4712de962bdSlukem return( NULL );
4722de962bdSlukem }
4732de962bdSlukem
4742de962bdSlukem if ( use_ldsb ) {
4752de962bdSlukem assert( ld->ld_sb != NULL );
4762de962bdSlukem lc->lconn_sb = ld->ld_sb;
4772de962bdSlukem
4782de962bdSlukem } else {
4792de962bdSlukem lc->lconn_sb = ber_sockbuf_alloc();
4802de962bdSlukem if ( lc->lconn_sb == NULL ) {
4812de962bdSlukem LDAP_FREE( (char *)lc );
4822de962bdSlukem ld->ld_errno = LDAP_NO_MEMORY;
4832de962bdSlukem return( NULL );
4842de962bdSlukem }
4852de962bdSlukem }
4862de962bdSlukem
4872de962bdSlukem if ( connect ) {
4882de962bdSlukem LDAPURLDesc **srvp, *srv = NULL;
4892de962bdSlukem
4902de962bdSlukem async = LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_CONNECT_ASYNC );
4912de962bdSlukem
4922de962bdSlukem for ( srvp = srvlist; *srvp != NULL; srvp = &(*srvp)->lud_next ) {
4932de962bdSlukem int rc;
4942de962bdSlukem
4952de962bdSlukem rc = ldap_int_open_connection( ld, lc, *srvp, async );
4962de962bdSlukem if ( rc != -1 ) {
4972de962bdSlukem srv = *srvp;
4982de962bdSlukem
499376af7d7Schristos /* If we fully connected, async is moot */
500376af7d7Schristos if ( rc == 0 )
501376af7d7Schristos async = 0;
502376af7d7Schristos
5032de962bdSlukem if ( ld->ld_urllist_proc && ( !async || rc != -2 ) ) {
5042de962bdSlukem ld->ld_urllist_proc( ld, srvlist, srvp, ld->ld_urllist_params );
5052de962bdSlukem }
5062de962bdSlukem
5072de962bdSlukem break;
5082de962bdSlukem }
5092de962bdSlukem }
5102de962bdSlukem
5112de962bdSlukem if ( srv == NULL ) {
5122de962bdSlukem if ( !use_ldsb ) {
5132de962bdSlukem ber_sockbuf_free( lc->lconn_sb );
5142de962bdSlukem }
5152de962bdSlukem LDAP_FREE( (char *)lc );
5162de962bdSlukem ld->ld_errno = LDAP_SERVER_DOWN;
5172de962bdSlukem return( NULL );
5182de962bdSlukem }
5192de962bdSlukem
5202de962bdSlukem lc->lconn_server = ldap_url_dup( srv );
521376af7d7Schristos if ( !lc->lconn_server ) {
522376af7d7Schristos if ( !use_ldsb )
523376af7d7Schristos ber_sockbuf_free( lc->lconn_sb );
524376af7d7Schristos LDAP_FREE( (char *)lc );
525376af7d7Schristos ld->ld_errno = LDAP_NO_MEMORY;
526376af7d7Schristos return( NULL );
527376af7d7Schristos }
5282de962bdSlukem }
5292de962bdSlukem
5302de962bdSlukem lc->lconn_status = async ? LDAP_CONNST_CONNECTING : LDAP_CONNST_CONNECTED;
5312de962bdSlukem lc->lconn_next = ld->ld_conns;
5322de962bdSlukem ld->ld_conns = lc;
5332de962bdSlukem
5344e6df137Slukem if ( connect ) {
5354e6df137Slukem #ifdef HAVE_TLS
5364e6df137Slukem if ( lc->lconn_server->lud_exts ) {
5374e6df137Slukem int rc, ext = find_tls_ext( lc->lconn_server );
5384e6df137Slukem if ( ext ) {
5394e6df137Slukem LDAPConn *savedefconn;
5404e6df137Slukem
5414e6df137Slukem savedefconn = ld->ld_defconn;
5424e6df137Slukem ++lc->lconn_refcnt; /* avoid premature free */
5434e6df137Slukem ld->ld_defconn = lc;
5444e6df137Slukem
545d11b170bStron LDAP_REQ_UNLOCK_IF(m_req);
546d11b170bStron LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
547d11b170bStron LDAP_RES_UNLOCK_IF(m_res);
5484e6df137Slukem rc = ldap_start_tls_s( ld, NULL, NULL );
549d11b170bStron LDAP_RES_LOCK_IF(m_res);
550d11b170bStron LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
551d11b170bStron LDAP_REQ_LOCK_IF(m_req);
5524e6df137Slukem ld->ld_defconn = savedefconn;
5534e6df137Slukem --lc->lconn_refcnt;
5544e6df137Slukem
5554e6df137Slukem if ( rc != LDAP_SUCCESS && ext == 2 ) {
5564e6df137Slukem ldap_free_connection( ld, lc, 1, 0 );
5574e6df137Slukem return NULL;
5584e6df137Slukem }
5594e6df137Slukem }
5604e6df137Slukem }
5614e6df137Slukem #endif
5624e6df137Slukem }
5634e6df137Slukem
5642de962bdSlukem if ( bind != NULL ) {
5652de962bdSlukem int err = 0;
5662de962bdSlukem LDAPConn *savedefconn;
5672de962bdSlukem
5682de962bdSlukem /* Set flag to prevent additional referrals
5692de962bdSlukem * from being processed on this
5702de962bdSlukem * connection until the bind has completed
5712de962bdSlukem */
5722de962bdSlukem lc->lconn_rebind_inprogress = 1;
5732de962bdSlukem /* V3 rebind function */
5742de962bdSlukem if ( ld->ld_rebind_proc != NULL) {
5752de962bdSlukem LDAPURLDesc *srvfunc;
5762de962bdSlukem
5772de962bdSlukem srvfunc = ldap_url_dup( *srvlist );
5782de962bdSlukem if ( srvfunc == NULL ) {
5792de962bdSlukem ld->ld_errno = LDAP_NO_MEMORY;
5802de962bdSlukem err = -1;
5812de962bdSlukem } else {
5822de962bdSlukem savedefconn = ld->ld_defconn;
5832de962bdSlukem ++lc->lconn_refcnt; /* avoid premature free */
5842de962bdSlukem ld->ld_defconn = lc;
5852de962bdSlukem
586*549b59edSchristos Debug0( LDAP_DEBUG_TRACE, "Call application rebind_proc\n" );
587d11b170bStron LDAP_REQ_UNLOCK_IF(m_req);
588d11b170bStron LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
589d11b170bStron LDAP_RES_UNLOCK_IF(m_res);
5902de962bdSlukem err = (*ld->ld_rebind_proc)( ld,
5912de962bdSlukem bind->ri_url, bind->ri_request, bind->ri_msgid,
5922de962bdSlukem ld->ld_rebind_params );
593d11b170bStron LDAP_RES_LOCK_IF(m_res);
594d11b170bStron LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
595d11b170bStron LDAP_REQ_LOCK_IF(m_req);
5962de962bdSlukem
5972de962bdSlukem ld->ld_defconn = savedefconn;
5982de962bdSlukem --lc->lconn_refcnt;
5992de962bdSlukem
6002de962bdSlukem if ( err != 0 ) {
6012de962bdSlukem err = -1;
6022de962bdSlukem ldap_free_connection( ld, lc, 1, 0 );
6032de962bdSlukem lc = NULL;
6042de962bdSlukem }
6052de962bdSlukem ldap_free_urldesc( srvfunc );
6062de962bdSlukem }
6072de962bdSlukem
6082de962bdSlukem } else {
6092de962bdSlukem int msgid, rc;
6102de962bdSlukem struct berval passwd = BER_BVNULL;
6112de962bdSlukem
6122de962bdSlukem savedefconn = ld->ld_defconn;
6132de962bdSlukem ++lc->lconn_refcnt; /* avoid premature free */
6142de962bdSlukem ld->ld_defconn = lc;
6152de962bdSlukem
616*549b59edSchristos Debug0( LDAP_DEBUG_TRACE,
617*549b59edSchristos "anonymous rebind via ldap_sasl_bind(\"\")\n" );
6182de962bdSlukem
619d11b170bStron LDAP_REQ_UNLOCK_IF(m_req);
620d11b170bStron LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
621d11b170bStron LDAP_RES_UNLOCK_IF(m_res);
6222de962bdSlukem rc = ldap_sasl_bind( ld, "", LDAP_SASL_SIMPLE, &passwd,
6232de962bdSlukem NULL, NULL, &msgid );
6242de962bdSlukem if ( rc != LDAP_SUCCESS ) {
6252de962bdSlukem err = -1;
6262de962bdSlukem
6272de962bdSlukem } else {
6282de962bdSlukem for ( err = 1; err > 0; ) {
6292de962bdSlukem struct timeval tv = { 0, 100000 };
6302de962bdSlukem LDAPMessage *res = NULL;
6312de962bdSlukem
6322de962bdSlukem switch ( ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res ) ) {
6332de962bdSlukem case -1:
6342de962bdSlukem err = -1;
6352de962bdSlukem break;
6362de962bdSlukem
6372de962bdSlukem case 0:
6382de962bdSlukem #ifdef LDAP_R_COMPILE
6392de962bdSlukem ldap_pvt_thread_yield();
6402de962bdSlukem #endif
6412de962bdSlukem break;
6422de962bdSlukem
6432de962bdSlukem case LDAP_RES_BIND:
6442de962bdSlukem rc = ldap_parse_result( ld, res, &err, NULL, NULL, NULL, NULL, 1 );
6452de962bdSlukem if ( rc != LDAP_SUCCESS ) {
6462de962bdSlukem err = -1;
6472de962bdSlukem
6482de962bdSlukem } else if ( err != LDAP_SUCCESS ) {
6492de962bdSlukem err = -1;
6502de962bdSlukem }
6512de962bdSlukem /* else err == LDAP_SUCCESS == 0 */
6522de962bdSlukem break;
6532de962bdSlukem
6542de962bdSlukem default:
655*549b59edSchristos Debug3( LDAP_DEBUG_TRACE,
6562de962bdSlukem "ldap_new_connection %p: "
6572de962bdSlukem "unexpected response %d "
6582de962bdSlukem "from BIND request id=%d\n",
6592de962bdSlukem (void *) ld, ldap_msgtype( res ), msgid );
6602de962bdSlukem err = -1;
6612de962bdSlukem break;
6622de962bdSlukem }
6632de962bdSlukem }
6642de962bdSlukem }
665d11b170bStron LDAP_RES_LOCK_IF(m_res);
666d11b170bStron LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
667d11b170bStron LDAP_REQ_LOCK_IF(m_req);
6682de962bdSlukem ld->ld_defconn = savedefconn;
6692de962bdSlukem --lc->lconn_refcnt;
6702de962bdSlukem
6712de962bdSlukem if ( err != 0 ) {
6722de962bdSlukem ldap_free_connection( ld, lc, 1, 0 );
6732de962bdSlukem lc = NULL;
6742de962bdSlukem }
6752de962bdSlukem }
6762de962bdSlukem if ( lc != NULL )
6772de962bdSlukem lc->lconn_rebind_inprogress = 0;
6782de962bdSlukem }
6792de962bdSlukem return( lc );
6802de962bdSlukem }
6812de962bdSlukem
6822de962bdSlukem
683d11b170bStron /* protected by ld_conn_mutex */
6842de962bdSlukem static LDAPConn *
find_connection(LDAP * ld,LDAPURLDesc * srv,int any)6852de962bdSlukem find_connection( LDAP *ld, LDAPURLDesc *srv, int any )
6862de962bdSlukem /*
6872de962bdSlukem * return an existing connection (if any) to the server srv
6882de962bdSlukem * if "any" is non-zero, check for any server in the "srv" chain
6892de962bdSlukem */
6902de962bdSlukem {
6912de962bdSlukem LDAPConn *lc;
6922de962bdSlukem LDAPURLDesc *lcu, *lsu;
6932de962bdSlukem int lcu_port, lsu_port;
6942de962bdSlukem int found = 0;
6952de962bdSlukem
696d11b170bStron LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
6972de962bdSlukem for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
6982de962bdSlukem lcu = lc->lconn_server;
6992de962bdSlukem lcu_port = ldap_pvt_url_scheme_port( lcu->lud_scheme,
7002de962bdSlukem lcu->lud_port );
7012de962bdSlukem
7022de962bdSlukem for ( lsu = srv; lsu != NULL; lsu = lsu->lud_next ) {
7032de962bdSlukem lsu_port = ldap_pvt_url_scheme_port( lsu->lud_scheme,
7042de962bdSlukem lsu->lud_port );
7052de962bdSlukem
7062de962bdSlukem if ( lsu_port == lcu_port
7072de962bdSlukem && strcmp( lcu->lud_scheme, lsu->lud_scheme ) == 0
7084e6df137Slukem && lcu->lud_host != NULL && lsu->lud_host != NULL
7092de962bdSlukem && strcasecmp( lsu->lud_host, lcu->lud_host ) == 0 )
7102de962bdSlukem {
7112de962bdSlukem found = 1;
7122de962bdSlukem break;
7132de962bdSlukem }
7142de962bdSlukem
7152de962bdSlukem if ( !any ) break;
7162de962bdSlukem }
7172de962bdSlukem if ( found )
7182de962bdSlukem break;
7192de962bdSlukem }
7202de962bdSlukem return lc;
7212de962bdSlukem }
7222de962bdSlukem
7232de962bdSlukem
7242de962bdSlukem
725d11b170bStron /* protected by ld_conn_mutex */
7262de962bdSlukem static void
use_connection(LDAP * ld,LDAPConn * lc)7272de962bdSlukem use_connection( LDAP *ld, LDAPConn *lc )
7282de962bdSlukem {
729d11b170bStron LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
7302de962bdSlukem ++lc->lconn_refcnt;
7312de962bdSlukem lc->lconn_lastused = time( NULL );
7322de962bdSlukem }
7332de962bdSlukem
7342de962bdSlukem
735d11b170bStron /* protected by ld_conn_mutex */
7362de962bdSlukem void
ldap_free_connection(LDAP * ld,LDAPConn * lc,int force,int unbind)7372de962bdSlukem ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind )
7382de962bdSlukem {
7392de962bdSlukem LDAPConn *tmplc, *prevlc;
7402de962bdSlukem
741d11b170bStron LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
742*549b59edSchristos Debug2( LDAP_DEBUG_TRACE,
7432de962bdSlukem "ldap_free_connection %d %d\n",
744*549b59edSchristos force, unbind );
7452de962bdSlukem
7462de962bdSlukem if ( force || --lc->lconn_refcnt <= 0 ) {
7472de962bdSlukem /* remove from connections list first */
7482de962bdSlukem
7492de962bdSlukem for ( prevlc = NULL, tmplc = ld->ld_conns;
7502de962bdSlukem tmplc != NULL;
7512de962bdSlukem tmplc = tmplc->lconn_next )
7522de962bdSlukem {
7532de962bdSlukem if ( tmplc == lc ) {
7542de962bdSlukem if ( prevlc == NULL ) {
7552de962bdSlukem ld->ld_conns = tmplc->lconn_next;
7562de962bdSlukem } else {
7572de962bdSlukem prevlc->lconn_next = tmplc->lconn_next;
7582de962bdSlukem }
759bb30016cSlukem if ( ld->ld_defconn == lc ) {
760bb30016cSlukem ld->ld_defconn = NULL;
761bb30016cSlukem }
7622de962bdSlukem break;
7632de962bdSlukem }
7642de962bdSlukem prevlc = tmplc;
7652de962bdSlukem }
7662de962bdSlukem
7674e6df137Slukem /* process connection callbacks */
7684e6df137Slukem {
7694e6df137Slukem struct ldapoptions *lo;
7704e6df137Slukem ldaplist *ll;
7714e6df137Slukem ldap_conncb *cb;
7724e6df137Slukem
7734e6df137Slukem lo = &ld->ld_options;
774d11b170bStron LDAP_MUTEX_LOCK( &lo->ldo_mutex );
7754e6df137Slukem if ( lo->ldo_conn_cbs ) {
7764e6df137Slukem for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) {
7774e6df137Slukem cb = ll->ll_data;
7784e6df137Slukem cb->lc_del( ld, lc->lconn_sb, cb );
7794e6df137Slukem }
7804e6df137Slukem }
781d11b170bStron LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
7824e6df137Slukem lo = LDAP_INT_GLOBAL_OPT();
783d11b170bStron LDAP_MUTEX_LOCK( &lo->ldo_mutex );
7844e6df137Slukem if ( lo->ldo_conn_cbs ) {
7854e6df137Slukem for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) {
7864e6df137Slukem cb = ll->ll_data;
7874e6df137Slukem cb->lc_del( ld, lc->lconn_sb, cb );
7884e6df137Slukem }
7894e6df137Slukem }
790d11b170bStron LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
7914e6df137Slukem }
7924e6df137Slukem
7932de962bdSlukem if ( lc->lconn_status == LDAP_CONNST_CONNECTED ) {
7942de962bdSlukem ldap_mark_select_clear( ld, lc->lconn_sb );
7952de962bdSlukem if ( unbind ) {
7962de962bdSlukem ldap_send_unbind( ld, lc->lconn_sb,
7972de962bdSlukem NULL, NULL );
7982de962bdSlukem }
7992de962bdSlukem }
8002de962bdSlukem
8012de962bdSlukem if ( lc->lconn_ber != NULL ) {
8022de962bdSlukem ber_free( lc->lconn_ber, 1 );
8032de962bdSlukem }
8042de962bdSlukem
8052de962bdSlukem ldap_int_sasl_close( ld, lc );
8064e6df137Slukem #ifdef HAVE_GSSAPI
8074e6df137Slukem ldap_int_gssapi_close( ld, lc );
8084e6df137Slukem #endif
8092de962bdSlukem
8102de962bdSlukem ldap_free_urllist( lc->lconn_server );
8112de962bdSlukem
8122de962bdSlukem /* FIXME: is this at all possible?
8132de962bdSlukem * ldap_ld_free() in unbind.c calls ldap_free_connection()
8142de962bdSlukem * with force == 1 __after__ explicitly calling
815*549b59edSchristos * ldap_tavl_free on ld->ld_requests */
8162de962bdSlukem if ( force ) {
817*549b59edSchristos ldap_tavl_free( ld->ld_requests, ldap_do_free_request );
818*549b59edSchristos ld->ld_requests = NULL;
8192de962bdSlukem }
8202de962bdSlukem
8212de962bdSlukem if ( lc->lconn_sb != ld->ld_sb ) {
8222de962bdSlukem ber_sockbuf_free( lc->lconn_sb );
823bb30016cSlukem } else {
824bb30016cSlukem ber_int_sb_close( lc->lconn_sb );
8252de962bdSlukem }
8262de962bdSlukem
8272de962bdSlukem if ( lc->lconn_rebind_queue != NULL) {
8282de962bdSlukem int i;
8292de962bdSlukem for( i = 0; lc->lconn_rebind_queue[i] != NULL; i++ ) {
8302de962bdSlukem LDAP_VFREE( lc->lconn_rebind_queue[i] );
8312de962bdSlukem }
8322de962bdSlukem LDAP_FREE( lc->lconn_rebind_queue );
8332de962bdSlukem }
8342de962bdSlukem
8352de962bdSlukem LDAP_FREE( lc );
8362de962bdSlukem
837*549b59edSchristos Debug0( LDAP_DEBUG_TRACE,
838*549b59edSchristos "ldap_free_connection: actually freed\n" );
8392de962bdSlukem
8402de962bdSlukem } else {
8412de962bdSlukem lc->lconn_lastused = time( NULL );
842*549b59edSchristos Debug1( LDAP_DEBUG_TRACE, "ldap_free_connection: refcnt %d\n",
843*549b59edSchristos lc->lconn_refcnt );
8442de962bdSlukem }
8452de962bdSlukem }
8462de962bdSlukem
8472de962bdSlukem
848d11b170bStron /* Protects self with ld_conn_mutex */
8492de962bdSlukem #ifdef LDAP_DEBUG
8502de962bdSlukem void
ldap_dump_connection(LDAP * ld,LDAPConn * lconns,int all)8512de962bdSlukem ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all )
8522de962bdSlukem {
8532de962bdSlukem LDAPConn *lc;
8542de962bdSlukem char timebuf[32];
8552de962bdSlukem
856*549b59edSchristos Debug2( LDAP_DEBUG_TRACE, "** ld %p Connection%s:\n", (void *)ld, all ? "s" : "" );
857d11b170bStron LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
8582de962bdSlukem for ( lc = lconns; lc != NULL; lc = lc->lconn_next ) {
8592de962bdSlukem if ( lc->lconn_server != NULL ) {
860*549b59edSchristos Debug3( LDAP_DEBUG_TRACE, "* host: %s port: %d%s\n",
8612de962bdSlukem ( lc->lconn_server->lud_host == NULL ) ? "(null)"
8622de962bdSlukem : lc->lconn_server->lud_host,
8632de962bdSlukem lc->lconn_server->lud_port, ( lc->lconn_sb ==
8642de962bdSlukem ld->ld_sb ) ? " (default)" : "" );
8652de962bdSlukem }
866*549b59edSchristos if ( lc->lconn_sb != NULL ) {
867*549b59edSchristos char from[LDAP_IPADDRLEN];
868*549b59edSchristos struct berval frombv = BER_BVC(from);
869*549b59edSchristos ber_socket_t sb;
870*549b59edSchristos if ( ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_GET_FD, &sb ) == 1 ) {
871*549b59edSchristos Sockaddr sin;
872*549b59edSchristos socklen_t len = sizeof( sin );
873*549b59edSchristos if ( getsockname( sb, (struct sockaddr *)&sin, &len ) == 0 ) {
874*549b59edSchristos ldap_pvt_sockaddrstr( &sin, &frombv );
875*549b59edSchristos Debug1( LDAP_DEBUG_TRACE, "* from: %s\n",
876*549b59edSchristos ( from == NULL ) ? "(null)" : from );
877*549b59edSchristos }
878*549b59edSchristos }
879*549b59edSchristos }
880*549b59edSchristos Debug2( LDAP_DEBUG_TRACE, " refcnt: %d status: %s\n", lc->lconn_refcnt,
8812de962bdSlukem ( lc->lconn_status == LDAP_CONNST_NEEDSOCKET )
8822de962bdSlukem ? "NeedSocket" :
8832de962bdSlukem ( lc->lconn_status == LDAP_CONNST_CONNECTING )
884*549b59edSchristos ? "Connecting" : "Connected" );
885*549b59edSchristos Debug2( LDAP_DEBUG_TRACE, " last used: %s%s\n",
8862de962bdSlukem ldap_pvt_ctime( &lc->lconn_lastused, timebuf ),
887*549b59edSchristos lc->lconn_rebind_inprogress ? " rebind in progress" : "" );
8882de962bdSlukem if ( lc->lconn_rebind_inprogress ) {
8892de962bdSlukem if ( lc->lconn_rebind_queue != NULL) {
8902de962bdSlukem int i;
8912de962bdSlukem
8922de962bdSlukem for ( i = 0; lc->lconn_rebind_queue[i] != NULL; i++ ) {
8932de962bdSlukem int j;
8942de962bdSlukem for( j = 0; lc->lconn_rebind_queue[i][j] != 0; j++ ) {
895*549b59edSchristos Debug3( LDAP_DEBUG_TRACE, " queue %d entry %d - %s\n",
8962de962bdSlukem i, j, lc->lconn_rebind_queue[i][j] );
8972de962bdSlukem }
8982de962bdSlukem }
8992de962bdSlukem } else {
900*549b59edSchristos Debug0( LDAP_DEBUG_TRACE, " queue is empty\n" );
9012de962bdSlukem }
9022de962bdSlukem }
903*549b59edSchristos Debug0( LDAP_DEBUG_TRACE, "\n" );
9042de962bdSlukem if ( !all ) {
9052de962bdSlukem break;
9062de962bdSlukem }
9072de962bdSlukem }
908d11b170bStron LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
9092de962bdSlukem }
9102de962bdSlukem
9112de962bdSlukem
912d11b170bStron /* protected by req_mutex and res_mutex */
9132de962bdSlukem void
ldap_dump_requests_and_responses(LDAP * ld)9142de962bdSlukem ldap_dump_requests_and_responses( LDAP *ld )
9152de962bdSlukem {
9162de962bdSlukem LDAPMessage *lm, *l;
917*549b59edSchristos TAvlnode *node;
9182de962bdSlukem int i;
9192de962bdSlukem
920*549b59edSchristos Debug1( LDAP_DEBUG_TRACE, "** ld %p Outstanding Requests:\n",
921*549b59edSchristos (void *)ld );
922*549b59edSchristos node = ldap_tavl_end( ld->ld_requests, TAVL_DIR_LEFT );
923*549b59edSchristos if ( node == NULL ) {
924*549b59edSchristos Debug0( LDAP_DEBUG_TRACE, " Empty\n" );
9252de962bdSlukem }
926*549b59edSchristos for ( i = 0 ; node != NULL; i++, node = ldap_tavl_next( node, TAVL_DIR_RIGHT ) ) {
927*549b59edSchristos LDAPRequest *lr = node->avl_data;
928*549b59edSchristos
929*549b59edSchristos Debug3( LDAP_DEBUG_TRACE, " * msgid %d, origid %d, status %s\n",
9302de962bdSlukem lr->lr_msgid, lr->lr_origid,
9312de962bdSlukem ( lr->lr_status == LDAP_REQST_INPROGRESS ) ? "InProgress" :
9322de962bdSlukem ( lr->lr_status == LDAP_REQST_CHASINGREFS ) ? "ChasingRefs" :
9332de962bdSlukem ( lr->lr_status == LDAP_REQST_NOTCONNECTED ) ? "NotConnected" :
9342de962bdSlukem ( lr->lr_status == LDAP_REQST_WRITING ) ? "Writing" :
9352de962bdSlukem ( lr->lr_status == LDAP_REQST_COMPLETED ) ? "RequestCompleted"
9362de962bdSlukem : "InvalidStatus" );
937*549b59edSchristos Debug2( LDAP_DEBUG_TRACE, " outstanding referrals %d, parent count %d\n",
938*549b59edSchristos lr->lr_outrefcnt, lr->lr_parentcnt );
9392de962bdSlukem }
940*549b59edSchristos Debug3( LDAP_DEBUG_TRACE, " ld %p request count %d (abandoned %lu)\n",
9412de962bdSlukem (void *)ld, i, ld->ld_nabandoned );
942*549b59edSchristos Debug1( LDAP_DEBUG_TRACE, "** ld %p Response Queue:\n", (void *)ld );
9432de962bdSlukem if ( ( lm = ld->ld_responses ) == NULL ) {
944*549b59edSchristos Debug0( LDAP_DEBUG_TRACE, " Empty\n" );
9452de962bdSlukem }
9462de962bdSlukem for ( i = 0; lm != NULL; lm = lm->lm_next, i++ ) {
947*549b59edSchristos Debug2( LDAP_DEBUG_TRACE, " * msgid %d, type %lu\n",
948*549b59edSchristos lm->lm_msgid, (unsigned long)lm->lm_msgtype );
9492de962bdSlukem if ( lm->lm_chain != NULL ) {
950*549b59edSchristos Debug0( LDAP_DEBUG_TRACE, " chained responses:\n" );
9512de962bdSlukem for ( l = lm->lm_chain; l != NULL; l = l->lm_chain ) {
952*549b59edSchristos Debug2( LDAP_DEBUG_TRACE,
9532de962bdSlukem " * msgid %d, type %lu\n",
9542de962bdSlukem l->lm_msgid,
955*549b59edSchristos (unsigned long)l->lm_msgtype );
9562de962bdSlukem }
9572de962bdSlukem }
9582de962bdSlukem }
959*549b59edSchristos Debug2( LDAP_DEBUG_TRACE, " ld %p response count %d\n", (void *)ld, i );
9602de962bdSlukem }
9612de962bdSlukem #endif /* LDAP_DEBUG */
9622de962bdSlukem
963d11b170bStron /* protected by req_mutex */
964*549b59edSchristos void
ldap_do_free_request(void * arg)965*549b59edSchristos ldap_do_free_request( void *arg )
9662de962bdSlukem {
967*549b59edSchristos LDAPRequest *lr = arg;
968*549b59edSchristos
969*549b59edSchristos Debug3( LDAP_DEBUG_TRACE, "ldap_do_free_request: "
970*549b59edSchristos "asked to free lr %p msgid %d refcnt %d\n",
971*549b59edSchristos lr, lr->lr_msgid, lr->lr_refcnt );
9722de962bdSlukem /* if lr_refcnt > 0, the request has been looked up
9732de962bdSlukem * by ldap_find_request_by_msgid(); if in the meanwhile
9742de962bdSlukem * the request is free()'d by someone else, just decrease
975*549b59edSchristos * the reference count; later on, it will be freed. */
9762de962bdSlukem if ( lr->lr_refcnt > 0 ) {
977*549b59edSchristos assert( lr->lr_refcnt == 1 );
9782de962bdSlukem lr->lr_refcnt = -lr->lr_refcnt;
9792de962bdSlukem return;
9802de962bdSlukem }
9812de962bdSlukem
9822de962bdSlukem if ( lr->lr_ber != NULL ) {
9832de962bdSlukem ber_free( lr->lr_ber, 1 );
9842de962bdSlukem lr->lr_ber = NULL;
9852de962bdSlukem }
9862de962bdSlukem
9872de962bdSlukem if ( lr->lr_res_error != NULL ) {
9882de962bdSlukem LDAP_FREE( lr->lr_res_error );
9892de962bdSlukem lr->lr_res_error = NULL;
9902de962bdSlukem }
9912de962bdSlukem
9922de962bdSlukem if ( lr->lr_res_matched != NULL ) {
9932de962bdSlukem LDAP_FREE( lr->lr_res_matched );
9942de962bdSlukem lr->lr_res_matched = NULL;
9952de962bdSlukem }
9962de962bdSlukem
9972de962bdSlukem LDAP_FREE( lr );
9982de962bdSlukem }
9992de962bdSlukem
1000*549b59edSchristos int
ldap_req_cmp(const void * l,const void * r)1001*549b59edSchristos ldap_req_cmp( const void *l, const void *r )
1002*549b59edSchristos {
1003*549b59edSchristos const LDAPRequest *left = l, *right = r;
1004*549b59edSchristos return left->lr_msgid - right->lr_msgid;
1005*549b59edSchristos }
1006*549b59edSchristos
1007*549b59edSchristos /* protected by req_mutex */
1008*549b59edSchristos static void
ldap_free_request_int(LDAP * ld,LDAPRequest * lr)1009*549b59edSchristos ldap_free_request_int( LDAP *ld, LDAPRequest *lr )
1010*549b59edSchristos {
1011*549b59edSchristos LDAPRequest *removed;
1012*549b59edSchristos
1013*549b59edSchristos LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
1014*549b59edSchristos removed = ldap_tavl_delete( &ld->ld_requests, lr, ldap_req_cmp );
1015*549b59edSchristos assert( !removed || removed == lr );
1016*549b59edSchristos Debug3( LDAP_DEBUG_TRACE, "ldap_free_request_int: "
1017*549b59edSchristos "lr %p msgid %d%s removed\n",
1018*549b59edSchristos lr, lr->lr_msgid, removed ? "" : " not" );
1019*549b59edSchristos
1020*549b59edSchristos ldap_do_free_request( lr );
1021*549b59edSchristos }
1022*549b59edSchristos
1023d11b170bStron /* protected by req_mutex */
10242de962bdSlukem void
ldap_free_request(LDAP * ld,LDAPRequest * lr)10252de962bdSlukem ldap_free_request( LDAP *ld, LDAPRequest *lr )
10262de962bdSlukem {
1027d11b170bStron LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
1028*549b59edSchristos Debug2( LDAP_DEBUG_TRACE, "ldap_free_request (origid %d, msgid %d)\n",
1029*549b59edSchristos lr->lr_origid, lr->lr_msgid );
10302de962bdSlukem
10312de962bdSlukem /* free all referrals (child requests) */
10322de962bdSlukem while ( lr->lr_child ) {
10332de962bdSlukem ldap_free_request( ld, lr->lr_child );
10342de962bdSlukem }
10352de962bdSlukem
10362de962bdSlukem if ( lr->lr_parent != NULL ) {
10372de962bdSlukem LDAPRequest **lrp;
10382de962bdSlukem
10392de962bdSlukem --lr->lr_parent->lr_outrefcnt;
10402de962bdSlukem for ( lrp = &lr->lr_parent->lr_child;
10412de962bdSlukem *lrp && *lrp != lr;
10422de962bdSlukem lrp = &(*lrp)->lr_refnext );
10432de962bdSlukem
10442de962bdSlukem if ( *lrp == lr ) {
10452de962bdSlukem *lrp = lr->lr_refnext;
10462de962bdSlukem }
10472de962bdSlukem }
10482de962bdSlukem ldap_free_request_int( ld, lr );
10492de962bdSlukem }
10502de962bdSlukem
10512de962bdSlukem /*
10522de962bdSlukem * call first time with *cntp = -1
10532de962bdSlukem * when returns *cntp == -1, no referrals are left
10542de962bdSlukem *
10552de962bdSlukem * NOTE: may replace *refsp, or shuffle the contents
10562de962bdSlukem * of the original array.
10572de962bdSlukem */
ldap_int_nextref(LDAP * ld,char *** refsp,int * cntp,void * params)10582de962bdSlukem static int ldap_int_nextref(
10592de962bdSlukem LDAP *ld,
10602de962bdSlukem char ***refsp,
10612de962bdSlukem int *cntp,
10622de962bdSlukem void *params )
10632de962bdSlukem {
10642de962bdSlukem assert( refsp != NULL );
10652de962bdSlukem assert( *refsp != NULL );
10662de962bdSlukem assert( cntp != NULL );
10672de962bdSlukem
10682de962bdSlukem if ( *cntp < -1 ) {
10692de962bdSlukem *cntp = -1;
10702de962bdSlukem return -1;
10712de962bdSlukem }
10722de962bdSlukem
10732de962bdSlukem (*cntp)++;
10742de962bdSlukem
10752de962bdSlukem if ( (*refsp)[ *cntp ] == NULL ) {
10762de962bdSlukem *cntp = -1;
10772de962bdSlukem }
10782de962bdSlukem
10792de962bdSlukem return 0;
10802de962bdSlukem }
10812de962bdSlukem
10822de962bdSlukem /*
10832de962bdSlukem * Chase v3 referrals
10842de962bdSlukem *
10852de962bdSlukem * Parameters:
10862de962bdSlukem * (IN) ld = LDAP connection handle
10872de962bdSlukem * (IN) lr = LDAP Request structure
10882de962bdSlukem * (IN) refs = array of pointers to referral strings that we will chase
10892de962bdSlukem * The array will be free'd by this function when no longer needed
10902de962bdSlukem * (IN) sref != 0 if following search reference
10912de962bdSlukem * (OUT) errstrp = Place to return a string of referrals which could not be followed
1092*549b59edSchristos * (OUT) hadrefp = 1 if successfully followed referral
10932de962bdSlukem *
10942de962bdSlukem * Return value - number of referrals followed
1095d11b170bStron *
1096d11b170bStron * Protected by res_mutex, conn_mutex and req_mutex (try_read1msg)
10972de962bdSlukem */
10982de962bdSlukem int
ldap_chase_v3referrals(LDAP * ld,LDAPRequest * lr,char ** refs,int sref,char ** errstrp,int * hadrefp)10992de962bdSlukem ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char **errstrp, int *hadrefp )
11002de962bdSlukem {
11012de962bdSlukem char *unfollowed;
11022de962bdSlukem int unfollowedcnt = 0;
11032de962bdSlukem LDAPRequest *origreq;
11042de962bdSlukem LDAPURLDesc *srv = NULL;
11052de962bdSlukem BerElement *ber;
11062de962bdSlukem char **refarray = NULL;
11072de962bdSlukem LDAPConn *lc;
11082de962bdSlukem int rc, count, i, j, id;
11092de962bdSlukem LDAPreqinfo rinfo;
1110d11b170bStron LDAP_NEXTREF_PROC *nextref_proc = ld->ld_nextref_proc ? ld->ld_nextref_proc : ldap_int_nextref;
1111d11b170bStron
1112d11b170bStron LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
1113d11b170bStron LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
1114d11b170bStron LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
1115*549b59edSchristos Debug0( LDAP_DEBUG_TRACE, "ldap_chase_v3referrals\n" );
11162de962bdSlukem
11172de962bdSlukem ld->ld_errno = LDAP_SUCCESS; /* optimistic */
11182de962bdSlukem *hadrefp = 0;
11192de962bdSlukem
11202de962bdSlukem unfollowed = NULL;
11212de962bdSlukem rc = count = 0;
11222de962bdSlukem
11232de962bdSlukem /* If no referrals in array, return */
11242de962bdSlukem if ( (refs == NULL) || ( (refs)[0] == NULL) ) {
11252de962bdSlukem rc = 0;
11262de962bdSlukem goto done;
11272de962bdSlukem }
11282de962bdSlukem
11292de962bdSlukem /* Check for hop limit exceeded */
11302de962bdSlukem if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) {
1131*549b59edSchristos Debug1( LDAP_DEBUG_ANY,
1132*549b59edSchristos "more than %d referral hops (dropping)\n", ld->ld_refhoplimit );
11332de962bdSlukem ld->ld_errno = LDAP_REFERRAL_LIMIT_EXCEEDED;
11342de962bdSlukem rc = -1;
11352de962bdSlukem goto done;
11362de962bdSlukem }
11372de962bdSlukem
11382de962bdSlukem /* find original request */
11392de962bdSlukem for ( origreq = lr;
11402de962bdSlukem origreq->lr_parent != NULL;
11412de962bdSlukem origreq = origreq->lr_parent )
11422de962bdSlukem {
11432de962bdSlukem /* empty */ ;
11442de962bdSlukem }
11452de962bdSlukem
11462de962bdSlukem refarray = refs;
11472de962bdSlukem refs = NULL;
11482de962bdSlukem
11492de962bdSlukem /* parse out & follow referrals */
1150d11b170bStron /* NOTE: if nextref_proc == ldap_int_nextref, params is ignored */
11512de962bdSlukem i = -1;
1152d11b170bStron for ( nextref_proc( ld, &refarray, &i, ld->ld_nextref_params );
11532de962bdSlukem i != -1;
1154d11b170bStron nextref_proc( ld, &refarray, &i, ld->ld_nextref_params ) )
11552de962bdSlukem {
11562de962bdSlukem
11572de962bdSlukem /* Parse the referral URL */
11582de962bdSlukem rc = ldap_url_parse_ext( refarray[i], &srv, LDAP_PVT_URL_PARSE_NOEMPTY_DN );
11592de962bdSlukem if ( rc != LDAP_URL_SUCCESS ) {
11602de962bdSlukem /* ldap_url_parse_ext() returns LDAP_URL_* errors
11612de962bdSlukem * which do not map on API errors */
11622de962bdSlukem ld->ld_errno = LDAP_PARAM_ERROR;
11632de962bdSlukem rc = -1;
11642de962bdSlukem goto done;
11652de962bdSlukem }
11662de962bdSlukem
11672de962bdSlukem if( srv->lud_crit_exts ) {
11684e6df137Slukem int ok = 0;
11694e6df137Slukem #ifdef HAVE_TLS
11704e6df137Slukem /* If StartTLS is the only critical ext, OK. */
11714e6df137Slukem if ( find_tls_ext( srv ) == 2 && srv->lud_crit_exts == 1 )
11724e6df137Slukem ok = 1;
11734e6df137Slukem #endif
11744e6df137Slukem if ( !ok ) {
11754e6df137Slukem /* we do not support any other extensions */
11762de962bdSlukem ld->ld_errno = LDAP_NOT_SUPPORTED;
11772de962bdSlukem rc = -1;
11782de962bdSlukem goto done;
11792de962bdSlukem }
11804e6df137Slukem }
11812de962bdSlukem
11822de962bdSlukem /* check connection for re-bind in progress */
11832de962bdSlukem if (( lc = find_connection( ld, srv, 1 )) != NULL ) {
11842de962bdSlukem /* See if we've already requested this DN with this conn */
11852de962bdSlukem LDAPRequest *lp;
11862de962bdSlukem int looped = 0;
11874e6df137Slukem ber_len_t len = srv->lud_dn ? strlen( srv->lud_dn ) : 0;
11882de962bdSlukem for ( lp = origreq; lp; ) {
11892de962bdSlukem if ( lp->lr_conn == lc
11902de962bdSlukem && len == lp->lr_dn.bv_len
11912de962bdSlukem && len
11922de962bdSlukem && strncmp( srv->lud_dn, lp->lr_dn.bv_val, len ) == 0 )
11932de962bdSlukem {
11942de962bdSlukem looped = 1;
11952de962bdSlukem break;
11962de962bdSlukem }
11972de962bdSlukem if ( lp == origreq ) {
11982de962bdSlukem lp = lp->lr_child;
11992de962bdSlukem } else {
12002de962bdSlukem lp = lp->lr_refnext;
12012de962bdSlukem }
12022de962bdSlukem }
12032de962bdSlukem if ( looped ) {
12042de962bdSlukem ldap_free_urllist( srv );
12052de962bdSlukem srv = NULL;
12062de962bdSlukem ld->ld_errno = LDAP_CLIENT_LOOP;
12072de962bdSlukem rc = -1;
12082de962bdSlukem continue;
12092de962bdSlukem }
12102de962bdSlukem
12112de962bdSlukem if ( lc->lconn_rebind_inprogress ) {
12122de962bdSlukem /* We are already chasing a referral or search reference and a
12132de962bdSlukem * bind on that connection is in progress. We must queue
12142de962bdSlukem * referrals on that connection, so we don't get a request
12152de962bdSlukem * going out before the bind operation completes. This happens
12162de962bdSlukem * if two search references come in one behind the other
12172de962bdSlukem * for the same server with different contexts.
12182de962bdSlukem */
1219*549b59edSchristos Debug1( LDAP_DEBUG_TRACE,
12202de962bdSlukem "ldap_chase_v3referrals: queue referral \"%s\"\n",
1221*549b59edSchristos refarray[i] );
12222de962bdSlukem if( lc->lconn_rebind_queue == NULL ) {
12232de962bdSlukem /* Create a referral list */
12242de962bdSlukem lc->lconn_rebind_queue =
12252de962bdSlukem (char ***) LDAP_MALLOC( sizeof(void *) * 2);
12262de962bdSlukem
12272de962bdSlukem if( lc->lconn_rebind_queue == NULL) {
12282de962bdSlukem ld->ld_errno = LDAP_NO_MEMORY;
12292de962bdSlukem rc = -1;
12302de962bdSlukem goto done;
12312de962bdSlukem }
12322de962bdSlukem
12332de962bdSlukem lc->lconn_rebind_queue[0] = refarray;
12342de962bdSlukem lc->lconn_rebind_queue[1] = NULL;
12352de962bdSlukem refarray = NULL;
12362de962bdSlukem
12372de962bdSlukem } else {
12382de962bdSlukem /* Count how many referral arrays we already have */
12392de962bdSlukem for( j = 0; lc->lconn_rebind_queue[j] != NULL; j++) {
12402de962bdSlukem /* empty */;
12412de962bdSlukem }
12422de962bdSlukem
12432de962bdSlukem /* Add the new referral to the list */
12442de962bdSlukem lc->lconn_rebind_queue = (char ***) LDAP_REALLOC(
12452de962bdSlukem lc->lconn_rebind_queue, sizeof(void *) * (j + 2));
12462de962bdSlukem
12472de962bdSlukem if( lc->lconn_rebind_queue == NULL ) {
12482de962bdSlukem ld->ld_errno = LDAP_NO_MEMORY;
12492de962bdSlukem rc = -1;
12502de962bdSlukem goto done;
12512de962bdSlukem }
12522de962bdSlukem lc->lconn_rebind_queue[j] = refarray;
12532de962bdSlukem lc->lconn_rebind_queue[j+1] = NULL;
12542de962bdSlukem refarray = NULL;
12552de962bdSlukem }
12562de962bdSlukem
12572de962bdSlukem /* We have queued the referral/reference, now just return */
12582de962bdSlukem rc = 0;
12592de962bdSlukem *hadrefp = 1;
12602de962bdSlukem count = 1; /* Pretend we already followed referral */
12612de962bdSlukem goto done;
12622de962bdSlukem }
12632de962bdSlukem }
12642de962bdSlukem /* Re-encode the request with the new starting point of the search.
12652de962bdSlukem * Note: In the future we also need to replace the filter if one
12662de962bdSlukem * was provided with the search reference
12672de962bdSlukem */
12682de962bdSlukem
12692de962bdSlukem /* For references we don't want old dn if new dn empty */
12702de962bdSlukem if ( sref && srv->lud_dn == NULL ) {
12712de962bdSlukem srv->lud_dn = LDAP_STRDUP( "" );
12722de962bdSlukem }
12732de962bdSlukem
12742de962bdSlukem LDAP_NEXT_MSGID( ld, id );
12752de962bdSlukem ber = re_encode_request( ld, origreq->lr_ber, id,
12762de962bdSlukem sref, srv, &rinfo.ri_request );
12772de962bdSlukem
12782de962bdSlukem if( ber == NULL ) {
12792de962bdSlukem ld->ld_errno = LDAP_ENCODING_ERROR;
12802de962bdSlukem rc = -1;
12812de962bdSlukem goto done;
12822de962bdSlukem }
12832de962bdSlukem
1284*549b59edSchristos Debug2( LDAP_DEBUG_TRACE,
12852de962bdSlukem "ldap_chase_v3referral: msgid %d, url \"%s\"\n",
1286*549b59edSchristos lr->lr_msgid, refarray[i] );
12872de962bdSlukem
12882de962bdSlukem /* Send the new request to the server - may require a bind */
12892de962bdSlukem rinfo.ri_msgid = origreq->lr_origid;
12902de962bdSlukem rinfo.ri_url = refarray[i];
12912de962bdSlukem rc = ldap_send_server_request( ld, ber, id,
1292d11b170bStron origreq, &srv, NULL, &rinfo, 0, 1 );
12932de962bdSlukem if ( rc < 0 ) {
12942de962bdSlukem /* Failure, try next referral in the list */
1295*549b59edSchristos Debug3( LDAP_DEBUG_ANY, "Unable to chase referral \"%s\" (%d: %s)\n",
12962de962bdSlukem refarray[i], ld->ld_errno, ldap_err2string( ld->ld_errno ) );
12972de962bdSlukem unfollowedcnt += ldap_append_referral( ld, &unfollowed, refarray[i] );
12982de962bdSlukem ldap_free_urllist( srv );
12992de962bdSlukem srv = NULL;
13002de962bdSlukem ld->ld_errno = LDAP_REFERRAL;
13012de962bdSlukem } else {
13022de962bdSlukem /* Success, no need to try this referral list further */
13032de962bdSlukem rc = 0;
13042de962bdSlukem ++count;
13052de962bdSlukem *hadrefp = 1;
13062de962bdSlukem
13072de962bdSlukem /* check if there is a queue of referrals that came in during bind */
13082de962bdSlukem if ( lc == NULL) {
13092de962bdSlukem lc = find_connection( ld, srv, 1 );
13102de962bdSlukem if ( lc == NULL ) {
13112de962bdSlukem ld->ld_errno = LDAP_OPERATIONS_ERROR;
13122de962bdSlukem rc = -1;
1313d11b170bStron LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
13142de962bdSlukem goto done;
13152de962bdSlukem }
13162de962bdSlukem }
13172de962bdSlukem
13182de962bdSlukem if ( lc->lconn_rebind_queue != NULL ) {
13192de962bdSlukem /* Release resources of previous list */
13202de962bdSlukem LDAP_VFREE( refarray );
13212de962bdSlukem refarray = NULL;
13222de962bdSlukem ldap_free_urllist( srv );
13232de962bdSlukem srv = NULL;
13242de962bdSlukem
13252de962bdSlukem /* Pull entries off end of queue so list always null terminated */
13262de962bdSlukem for( j = 0; lc->lconn_rebind_queue[j] != NULL; j++ )
13272de962bdSlukem ;
13282de962bdSlukem refarray = lc->lconn_rebind_queue[j - 1];
13292de962bdSlukem lc->lconn_rebind_queue[j-1] = NULL;
13302de962bdSlukem /* we pulled off last entry from queue, free queue */
13312de962bdSlukem if ( j == 1 ) {
13322de962bdSlukem LDAP_FREE( lc->lconn_rebind_queue );
13332de962bdSlukem lc->lconn_rebind_queue = NULL;
13342de962bdSlukem }
13352de962bdSlukem /* restart the loop the with new referral list */
13362de962bdSlukem i = -1;
13372de962bdSlukem continue;
13382de962bdSlukem }
13392de962bdSlukem break; /* referral followed, break out of for loop */
13402de962bdSlukem }
13412de962bdSlukem } /* end for loop */
13422de962bdSlukem done:
13432de962bdSlukem LDAP_VFREE( refarray );
13442de962bdSlukem ldap_free_urllist( srv );
13452de962bdSlukem LDAP_FREE( *errstrp );
13462de962bdSlukem
13472de962bdSlukem if( rc == 0 ) {
13482de962bdSlukem *errstrp = NULL;
13492de962bdSlukem LDAP_FREE( unfollowed );
13502de962bdSlukem return count;
13512de962bdSlukem } else {
13522de962bdSlukem *errstrp = unfollowed;
13532de962bdSlukem return rc;
13542de962bdSlukem }
13552de962bdSlukem }
13562de962bdSlukem
13572de962bdSlukem /*
13582de962bdSlukem * XXX merging of errors in this routine needs to be improved
1359d11b170bStron * Protected by res_mutex, conn_mutex and req_mutex (try_read1msg)
13602de962bdSlukem */
13612de962bdSlukem int
ldap_chase_referrals(LDAP * ld,LDAPRequest * lr,char ** errstrp,int sref,int * hadrefp)13622de962bdSlukem ldap_chase_referrals( LDAP *ld,
13632de962bdSlukem LDAPRequest *lr,
13642de962bdSlukem char **errstrp,
13652de962bdSlukem int sref,
13662de962bdSlukem int *hadrefp )
13672de962bdSlukem {
13682de962bdSlukem int rc, count, id;
13692de962bdSlukem unsigned len;
13702de962bdSlukem char *p, *ref, *unfollowed;
13712de962bdSlukem LDAPRequest *origreq;
13722de962bdSlukem LDAPURLDesc *srv;
13732de962bdSlukem BerElement *ber;
13742de962bdSlukem LDAPreqinfo rinfo;
13752de962bdSlukem LDAPConn *lc;
13762de962bdSlukem
1377d11b170bStron LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );
1378d11b170bStron LDAP_ASSERT_MUTEX_OWNER( &ld->ld_conn_mutex );
1379d11b170bStron LDAP_ASSERT_MUTEX_OWNER( &ld->ld_req_mutex );
1380*549b59edSchristos Debug0( LDAP_DEBUG_TRACE, "ldap_chase_referrals\n" );
13812de962bdSlukem
13822de962bdSlukem ld->ld_errno = LDAP_SUCCESS; /* optimistic */
13832de962bdSlukem *hadrefp = 0;
13842de962bdSlukem
13852de962bdSlukem if ( *errstrp == NULL ) {
13862de962bdSlukem return( 0 );
13872de962bdSlukem }
13882de962bdSlukem
13892de962bdSlukem len = strlen( *errstrp );
13902de962bdSlukem for ( p = *errstrp; len >= LDAP_REF_STR_LEN; ++p, --len ) {
13912de962bdSlukem if ( strncasecmp( p, LDAP_REF_STR, LDAP_REF_STR_LEN ) == 0 ) {
13922de962bdSlukem *p = '\0';
13932de962bdSlukem p += LDAP_REF_STR_LEN;
13942de962bdSlukem break;
13952de962bdSlukem }
13962de962bdSlukem }
13972de962bdSlukem
13982de962bdSlukem if ( len < LDAP_REF_STR_LEN ) {
13992de962bdSlukem return( 0 );
14002de962bdSlukem }
14012de962bdSlukem
14022de962bdSlukem if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) {
1403*549b59edSchristos Debug1( LDAP_DEBUG_ANY,
14042de962bdSlukem "more than %d referral hops (dropping)\n",
1405*549b59edSchristos ld->ld_refhoplimit );
14062de962bdSlukem /* XXX report as error in ld->ld_errno? */
14072de962bdSlukem return( 0 );
14082de962bdSlukem }
14092de962bdSlukem
14102de962bdSlukem /* find original request */
14112de962bdSlukem for ( origreq = lr; origreq->lr_parent != NULL;
14122de962bdSlukem origreq = origreq->lr_parent ) {
14132de962bdSlukem /* empty */;
14142de962bdSlukem }
14152de962bdSlukem
14162de962bdSlukem unfollowed = NULL;
14172de962bdSlukem rc = count = 0;
14182de962bdSlukem
14192de962bdSlukem /* parse out & follow referrals */
14202de962bdSlukem for ( ref = p; rc == 0 && ref != NULL; ref = p ) {
14212de962bdSlukem p = strchr( ref, '\n' );
14222de962bdSlukem if ( p != NULL ) {
14232de962bdSlukem *p++ = '\0';
14242de962bdSlukem }
14252de962bdSlukem
14262de962bdSlukem rc = ldap_url_parse_ext( ref, &srv, LDAP_PVT_URL_PARSE_NOEMPTY_DN );
14272de962bdSlukem if ( rc != LDAP_URL_SUCCESS ) {
1428*549b59edSchristos Debug2( LDAP_DEBUG_TRACE,
14292de962bdSlukem "ignoring %s referral <%s>\n",
1430*549b59edSchristos ref, rc == LDAP_URL_ERR_BADSCHEME ? "unknown" : "incorrect" );
14312de962bdSlukem rc = ldap_append_referral( ld, &unfollowed, ref );
14322de962bdSlukem *hadrefp = 1;
14332de962bdSlukem continue;
14342de962bdSlukem }
14352de962bdSlukem
1436*549b59edSchristos Debug1( LDAP_DEBUG_TRACE,
1437*549b59edSchristos "chasing LDAP referral: <%s>\n", ref );
14382de962bdSlukem
14392de962bdSlukem *hadrefp = 1;
14402de962bdSlukem
14412de962bdSlukem /* See if we've already been here */
14422de962bdSlukem if (( lc = find_connection( ld, srv, 1 )) != NULL ) {
14432de962bdSlukem LDAPRequest *lp;
14442de962bdSlukem int looped = 0;
14454e6df137Slukem ber_len_t len = srv->lud_dn ? strlen( srv->lud_dn ) : 0;
14462de962bdSlukem for ( lp = lr; lp; lp = lp->lr_parent ) {
14472de962bdSlukem if ( lp->lr_conn == lc
14482de962bdSlukem && len == lp->lr_dn.bv_len )
14492de962bdSlukem {
14502de962bdSlukem if ( len && strncmp( srv->lud_dn, lp->lr_dn.bv_val, len ) )
14512de962bdSlukem continue;
14522de962bdSlukem looped = 1;
14532de962bdSlukem break;
14542de962bdSlukem }
14552de962bdSlukem }
14562de962bdSlukem if ( looped ) {
14572de962bdSlukem ldap_free_urllist( srv );
14582de962bdSlukem ld->ld_errno = LDAP_CLIENT_LOOP;
14592de962bdSlukem rc = -1;
14602de962bdSlukem continue;
14612de962bdSlukem }
14622de962bdSlukem }
14632de962bdSlukem
14642de962bdSlukem LDAP_NEXT_MSGID( ld, id );
14652de962bdSlukem ber = re_encode_request( ld, origreq->lr_ber,
14662de962bdSlukem id, sref, srv, &rinfo.ri_request );
14672de962bdSlukem
14682de962bdSlukem if ( ber == NULL ) {
1469376af7d7Schristos ldap_free_urllist( srv );
14702de962bdSlukem return -1 ;
14712de962bdSlukem }
14722de962bdSlukem
14732de962bdSlukem /* copy the complete referral for rebind process */
14742de962bdSlukem rinfo.ri_url = LDAP_STRDUP( ref );
14752de962bdSlukem
14762de962bdSlukem rinfo.ri_msgid = origreq->lr_origid;
14772de962bdSlukem
14782de962bdSlukem rc = ldap_send_server_request( ld, ber, id,
1479d11b170bStron lr, &srv, NULL, &rinfo, 0, 1 );
14802de962bdSlukem LDAP_FREE( rinfo.ri_url );
14812de962bdSlukem
14822de962bdSlukem if( rc >= 0 ) {
14832de962bdSlukem ++count;
14842de962bdSlukem } else {
1485*549b59edSchristos Debug3( LDAP_DEBUG_ANY,
14862de962bdSlukem "Unable to chase referral \"%s\" (%d: %s)\n",
14872de962bdSlukem ref, ld->ld_errno, ldap_err2string( ld->ld_errno ) );
14882de962bdSlukem rc = ldap_append_referral( ld, &unfollowed, ref );
14892de962bdSlukem }
14902de962bdSlukem
14912de962bdSlukem ldap_free_urllist(srv);
14922de962bdSlukem }
14932de962bdSlukem
14942de962bdSlukem LDAP_FREE( *errstrp );
14952de962bdSlukem *errstrp = unfollowed;
14962de962bdSlukem
14972de962bdSlukem return(( rc == 0 ) ? count : rc );
14982de962bdSlukem }
14992de962bdSlukem
15002de962bdSlukem
15012de962bdSlukem int
ldap_append_referral(LDAP * ld,char ** referralsp,char * s)15022de962bdSlukem ldap_append_referral( LDAP *ld, char **referralsp, char *s )
15032de962bdSlukem {
15042de962bdSlukem int first;
15052de962bdSlukem
15062de962bdSlukem if ( *referralsp == NULL ) {
15072de962bdSlukem first = 1;
15082de962bdSlukem *referralsp = (char *)LDAP_MALLOC( strlen( s ) + LDAP_REF_STR_LEN
15092de962bdSlukem + 1 );
15102de962bdSlukem } else {
15112de962bdSlukem first = 0;
15122de962bdSlukem *referralsp = (char *)LDAP_REALLOC( *referralsp,
15132de962bdSlukem strlen( *referralsp ) + strlen( s ) + 2 );
15142de962bdSlukem }
15152de962bdSlukem
15162de962bdSlukem if ( *referralsp == NULL ) {
15172de962bdSlukem ld->ld_errno = LDAP_NO_MEMORY;
15182de962bdSlukem return( -1 );
15192de962bdSlukem }
15202de962bdSlukem
15212de962bdSlukem if ( first ) {
15222de962bdSlukem strcpy( *referralsp, LDAP_REF_STR );
15232de962bdSlukem } else {
15242de962bdSlukem strcat( *referralsp, "\n" );
15252de962bdSlukem }
15262de962bdSlukem strcat( *referralsp, s );
15272de962bdSlukem
15282de962bdSlukem return( 0 );
15292de962bdSlukem }
15302de962bdSlukem
15312de962bdSlukem
15322de962bdSlukem
15332de962bdSlukem static BerElement *
re_encode_request(LDAP * ld,BerElement * origber,ber_int_t msgid,int sref,LDAPURLDesc * srv,int * type)15342de962bdSlukem re_encode_request( LDAP *ld,
15352de962bdSlukem BerElement *origber,
15362de962bdSlukem ber_int_t msgid,
15372de962bdSlukem int sref,
15382de962bdSlukem LDAPURLDesc *srv,
15392de962bdSlukem int *type )
15402de962bdSlukem {
15412de962bdSlukem /*
15422de962bdSlukem * XXX this routine knows way too much about how the lber library works!
15432de962bdSlukem */
15442de962bdSlukem ber_int_t along;
15452de962bdSlukem ber_tag_t tag;
15462de962bdSlukem ber_tag_t rtag;
15472de962bdSlukem ber_int_t ver;
15482de962bdSlukem ber_int_t scope;
15492de962bdSlukem int rc;
15502de962bdSlukem BerElement tmpber, *ber;
15512de962bdSlukem struct berval dn;
15522de962bdSlukem
1553*549b59edSchristos Debug2( LDAP_DEBUG_TRACE,
15542de962bdSlukem "re_encode_request: new msgid %ld, new dn <%s>\n",
15552de962bdSlukem (long) msgid,
1556*549b59edSchristos ( srv == NULL || srv->lud_dn == NULL) ? "NONE" : srv->lud_dn );
15572de962bdSlukem
15582de962bdSlukem tmpber = *origber;
15592de962bdSlukem
15602de962bdSlukem /*
15612de962bdSlukem * all LDAP requests are sequences that start with a message id.
15622de962bdSlukem * For all except delete, this is followed by a sequence that is
15632de962bdSlukem * tagged with the operation code. For delete, the provided DN
15642de962bdSlukem * is not wrapped by a sequence.
15652de962bdSlukem */
15662de962bdSlukem rtag = ber_scanf( &tmpber, "{it", /*}*/ &along, &tag );
15672de962bdSlukem
15682de962bdSlukem if ( rtag == LBER_ERROR ) {
15692de962bdSlukem ld->ld_errno = LDAP_DECODING_ERROR;
15702de962bdSlukem return( NULL );
15712de962bdSlukem }
15722de962bdSlukem
15732de962bdSlukem assert( tag != 0);
15742de962bdSlukem if ( tag == LDAP_REQ_BIND ) {
15752de962bdSlukem /* bind requests have a version number before the DN & other stuff */
15762de962bdSlukem rtag = ber_scanf( &tmpber, "{im" /*}*/, &ver, &dn );
15772de962bdSlukem
15782de962bdSlukem } else if ( tag == LDAP_REQ_DELETE ) {
15792de962bdSlukem /* delete requests don't have a DN wrapping sequence */
15802de962bdSlukem rtag = ber_scanf( &tmpber, "m", &dn );
15812de962bdSlukem
15822de962bdSlukem } else if ( tag == LDAP_REQ_SEARCH ) {
15832de962bdSlukem /* search requests need to be re-scope-ed */
15842de962bdSlukem rtag = ber_scanf( &tmpber, "{me" /*"}"*/, &dn, &scope );
15852de962bdSlukem
15862de962bdSlukem if( srv->lud_scope != LDAP_SCOPE_DEFAULT ) {
15872de962bdSlukem /* use the scope provided in reference */
15882de962bdSlukem scope = srv->lud_scope;
15892de962bdSlukem
15902de962bdSlukem } else if ( sref ) {
15912de962bdSlukem /* use scope implied by previous operation
15922de962bdSlukem * base -> base
15932de962bdSlukem * one -> base
15942de962bdSlukem * subtree -> subtree
15952de962bdSlukem * subordinate -> subtree
15962de962bdSlukem */
15972de962bdSlukem switch( scope ) {
15982de962bdSlukem default:
15992de962bdSlukem case LDAP_SCOPE_BASE:
16002de962bdSlukem case LDAP_SCOPE_ONELEVEL:
16012de962bdSlukem scope = LDAP_SCOPE_BASE;
16022de962bdSlukem break;
16032de962bdSlukem case LDAP_SCOPE_SUBTREE:
16042de962bdSlukem case LDAP_SCOPE_SUBORDINATE:
16052de962bdSlukem scope = LDAP_SCOPE_SUBTREE;
16062de962bdSlukem break;
16072de962bdSlukem }
16082de962bdSlukem }
16092de962bdSlukem
16102de962bdSlukem } else {
16112de962bdSlukem rtag = ber_scanf( &tmpber, "{m" /*}*/, &dn );
16122de962bdSlukem }
16132de962bdSlukem
16142de962bdSlukem if( rtag == LBER_ERROR ) {
16152de962bdSlukem ld->ld_errno = LDAP_DECODING_ERROR;
16162de962bdSlukem return NULL;
16172de962bdSlukem }
16182de962bdSlukem
16192de962bdSlukem /* restore character zero'd out by ber_scanf*/
16202de962bdSlukem dn.bv_val[dn.bv_len] = tmpber.ber_tag;
16212de962bdSlukem
16222de962bdSlukem if (( ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
16232de962bdSlukem return NULL;
16242de962bdSlukem }
16252de962bdSlukem
16262de962bdSlukem if ( srv->lud_dn ) {
16272de962bdSlukem ber_str2bv( srv->lud_dn, 0, 0, &dn );
16282de962bdSlukem }
16292de962bdSlukem
16302de962bdSlukem if ( tag == LDAP_REQ_BIND ) {
16312de962bdSlukem rc = ber_printf( ber, "{it{iO" /*}}*/, msgid, tag, ver, &dn );
16322de962bdSlukem } else if ( tag == LDAP_REQ_DELETE ) {
16332de962bdSlukem rc = ber_printf( ber, "{itON}", msgid, tag, &dn );
16342de962bdSlukem } else if ( tag == LDAP_REQ_SEARCH ) {
16352de962bdSlukem rc = ber_printf( ber, "{it{Oe" /*}}*/, msgid, tag, &dn, scope );
16362de962bdSlukem } else {
16372de962bdSlukem rc = ber_printf( ber, "{it{O" /*}}*/, msgid, tag, &dn );
16382de962bdSlukem }
16392de962bdSlukem
16402de962bdSlukem if ( rc == -1 ) {
16412de962bdSlukem ld->ld_errno = LDAP_ENCODING_ERROR;
16422de962bdSlukem ber_free( ber, 1 );
16432de962bdSlukem return NULL;
16442de962bdSlukem }
16452de962bdSlukem
16462de962bdSlukem if ( tag != LDAP_REQ_DELETE && (
16472de962bdSlukem ber_write(ber, tmpber.ber_ptr, ( tmpber.ber_end - tmpber.ber_ptr ), 0)
16482de962bdSlukem != ( tmpber.ber_end - tmpber.ber_ptr ) ||
16492de962bdSlukem ber_printf( ber, /*{{*/ "N}N}" ) == -1 ) )
16502de962bdSlukem {
16512de962bdSlukem ld->ld_errno = LDAP_ENCODING_ERROR;
16522de962bdSlukem ber_free( ber, 1 );
16532de962bdSlukem return NULL;
16542de962bdSlukem }
16552de962bdSlukem
16562de962bdSlukem #ifdef LDAP_DEBUG
16572de962bdSlukem if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
1658*549b59edSchristos Debug0( LDAP_DEBUG_ANY, "re_encode_request new request is:\n" );
16592de962bdSlukem ber_log_dump( LDAP_DEBUG_BER, ldap_debug, ber, 0 );
16602de962bdSlukem }
16612de962bdSlukem #endif /* LDAP_DEBUG */
16622de962bdSlukem
16632de962bdSlukem *type = tag; /* return request type */
16642de962bdSlukem return ber;
16652de962bdSlukem }
16662de962bdSlukem
16672de962bdSlukem
1668d11b170bStron /* protected by req_mutex */
16692de962bdSlukem LDAPRequest *
ldap_find_request_by_msgid(LDAP * ld,ber_int_t msgid)16702de962bdSlukem ldap_find_request_by_msgid( LDAP *ld, ber_int_t msgid )
16712de962bdSlukem {
1672*549b59edSchristos LDAPRequest *lr, needle = {0};
1673*549b59edSchristos needle.lr_msgid = msgid;
16742de962bdSlukem
1675*549b59edSchristos lr = ldap_tavl_find( ld->ld_requests, &needle, ldap_req_cmp );
1676*549b59edSchristos if ( lr != NULL && lr->lr_status != LDAP_REQST_COMPLETED ) {
1677*549b59edSchristos /* try_read1msg is the only user at the moment and we would free it
1678*549b59edSchristos * multiple times if retrieving the request again */
1679*549b59edSchristos assert( lr->lr_refcnt == 0 );
16802de962bdSlukem lr->lr_refcnt++;
1681*549b59edSchristos Debug3( LDAP_DEBUG_TRACE, "ldap_find_request_by_msgid: "
1682*549b59edSchristos "msgid %d, lr %p lr->lr_refcnt = %d\n",
1683*549b59edSchristos msgid, lr, lr->lr_refcnt );
1684*549b59edSchristos return lr;
16852de962bdSlukem }
16862de962bdSlukem
1687*549b59edSchristos Debug2( LDAP_DEBUG_TRACE, "ldap_find_request_by_msgid: "
1688*549b59edSchristos "msgid %d, lr %p\n", msgid, lr );
1689*549b59edSchristos return NULL;
16902de962bdSlukem }
16912de962bdSlukem
1692d11b170bStron /* protected by req_mutex */
16932de962bdSlukem void
ldap_return_request(LDAP * ld,LDAPRequest * lrx,int freeit)16942de962bdSlukem ldap_return_request( LDAP *ld, LDAPRequest *lrx, int freeit )
16952de962bdSlukem {
16962de962bdSlukem LDAPRequest *lr;
16972de962bdSlukem
1698*549b59edSchristos lr = ldap_tavl_find( ld->ld_requests, lrx, ldap_req_cmp );
1699*549b59edSchristos Debug2( LDAP_DEBUG_TRACE, "ldap_return_request: "
1700*549b59edSchristos "lrx %p, lr %p\n", lrx, lr );
1701*549b59edSchristos if ( lr ) {
1702*549b59edSchristos assert( lr == lrx );
17032de962bdSlukem if ( lr->lr_refcnt > 0 ) {
17042de962bdSlukem lr->lr_refcnt--;
17052de962bdSlukem } else if ( lr->lr_refcnt < 0 ) {
17062de962bdSlukem lr->lr_refcnt++;
17072de962bdSlukem if ( lr->lr_refcnt == 0 ) {
17082de962bdSlukem lr = NULL;
17092de962bdSlukem }
17102de962bdSlukem }
17112de962bdSlukem }
1712*549b59edSchristos Debug3( LDAP_DEBUG_TRACE, "ldap_return_request: "
1713*549b59edSchristos "lrx->lr_msgid %d, lrx->lr_refcnt is now %d, lr is %s present\n",
1714*549b59edSchristos lrx->lr_msgid, lrx->lr_refcnt, lr ? "still" : "not" );
1715*549b59edSchristos /* The request is not tracked anymore */
17162de962bdSlukem if ( lr == NULL ) {
17172de962bdSlukem ldap_free_request_int( ld, lrx );
17182de962bdSlukem } else if ( freeit ) {
17192de962bdSlukem ldap_free_request( ld, lrx );
17202de962bdSlukem }
17212de962bdSlukem }
1722