1 /* $OpenLDAP: pkg/ldap/libraries/libldap/request.c,v 1.125.2.8 2008/05/27 20:08:37 quanah Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2008 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
15 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
16 * All rights reserved.
18 /* This notice applies to changes, created by or for Novell, Inc.,
19 * to preexisting works for which notices appear elsewhere in this file.
21 * Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
23 * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
24 * USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO VERSION
25 * 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS AVAILABLE AT
26 * HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" IN THE
27 * TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION OF THIS
28 * WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP PUBLIC
29 * LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT THE
30 * PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
32 * Modification to OpenLDAP source by Novell, Inc.
33 * April 2000 sfs Added code to chase V3 referrals
34 * request.c - sending of ldap requests; handling of referrals
36 * Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License
37 * can be found in the file "build/LICENSE-2.0.1" in this distribution
38 * of OpenLDAP Software.
45 #include <ac/stdlib.h>
48 #include <ac/socket.h>
49 #include <ac/string.h>
51 #include <ac/unistd.h>
56 static LDAPConn
*find_connection
LDAP_P(( LDAP
*ld
, LDAPURLDesc
*srv
, int any
));
57 static void use_connection
LDAP_P(( LDAP
*ld
, LDAPConn
*lc
));
58 static void ldap_free_request_int
LDAP_P(( LDAP
*ld
, LDAPRequest
*lr
));
61 re_encode_request( LDAP
*ld
,
69 ldap_alloc_ber_with_options( LDAP
*ld
)
73 ber
= ber_alloc_t( ld
->ld_lberoptions
);
75 ld
->ld_errno
= LDAP_NO_MEMORY
;
83 ldap_set_ber_options( LDAP
*ld
, BerElement
*ber
)
85 ber
->ber_options
= ld
->ld_lberoptions
;
90 ldap_send_initial_request(
99 Debug( LDAP_DEBUG_TRACE
, "ldap_send_initial_request\n", 0, 0, 0 );
101 #ifdef LDAP_R_COMPILE
102 ldap_pvt_thread_mutex_lock( &ld
->ld_req_mutex
);
104 if ( ber_sockbuf_ctrl( ld
->ld_sb
, LBER_SB_OPT_GET_FD
, NULL
) == -1 ) {
105 /* not connected yet */
106 rc
= ldap_open_defconn( ld
);
109 #ifdef LDAP_R_COMPILE
110 ldap_pvt_thread_mutex_unlock( &ld
->ld_req_mutex
);
115 } else if ( rc
== 0 ) {
116 Debug( LDAP_DEBUG_TRACE
,
117 "ldap_open_defconn: successful\n",
121 #ifdef LDAP_CONNECTIONLESS
122 if (LDAP_IS_UDP(ld
)) {
123 if (msgtype
== LDAP_REQ_BIND
) {
124 if (ld
->ld_options
.ldo_cldapdn
)
125 ldap_memfree(ld
->ld_options
.ldo_cldapdn
);
126 ld
->ld_options
.ldo_cldapdn
= ldap_strdup(dn
);
129 if (msgtype
!= LDAP_REQ_ABANDON
&& msgtype
!= LDAP_REQ_SEARCH
)
130 return LDAP_PARAM_ERROR
;
133 #ifdef LDAP_R_COMPILE
134 ldap_pvt_thread_mutex_lock( &ld
->ld_req_mutex
);
136 rc
= ldap_send_server_request( ld
, ber
, msgid
, NULL
,
138 #ifdef LDAP_R_COMPILE
139 ldap_pvt_thread_mutex_unlock( &ld
->ld_req_mutex
);
146 ldap_int_flush_request(
150 LDAPConn
*lc
= lr
->lr_conn
;
152 if ( ber_flush2( lc
->lconn_sb
, lr
->lr_ber
, LBER_FLUSH_FREE_NEVER
) != 0 ) {
153 if ( sock_errno() == EAGAIN
) {
154 /* need to continue write later */
155 lr
->lr_status
= LDAP_REQST_WRITING
;
156 ldap_mark_select_write( ld
, lc
->lconn_sb
);
157 ld
->ld_errno
= LDAP_BUSY
;
160 ld
->ld_errno
= LDAP_SERVER_DOWN
;
161 ldap_free_request( ld
, lr
);
162 ldap_free_connection( ld
, lc
, 0, 0 );
166 if ( lr
->lr_parent
== NULL
) {
167 lr
->lr_ber
->ber_end
= lr
->lr_ber
->ber_ptr
;
168 lr
->lr_ber
->ber_ptr
= lr
->lr_ber
->ber_buf
;
170 lr
->lr_status
= LDAP_REQST_INPROGRESS
;
172 /* sent -- waiting for a response */
173 ldap_mark_select_read( ld
, lc
->lconn_sb
);
179 ldap_send_server_request(
183 LDAPRequest
*parentreq
,
184 LDAPURLDesc
**srvlist
,
191 Debug( LDAP_DEBUG_TRACE
, "ldap_send_server_request\n", 0, 0, 0 );
194 ld
->ld_errno
= LDAP_SUCCESS
; /* optimistic */
197 if ( srvlist
== NULL
) {
200 lc
= find_connection( ld
, *srvlist
, 1 );
202 if ( (bind
!= NULL
) && (parentreq
!= NULL
) ) {
203 /* Remember the bind in the parent */
205 ++parentreq
->lr_outrefcnt
;
207 lc
= ldap_new_connection( ld
, srvlist
, 0, 1, bind
);
212 /* async connect... */
213 if ( lc
!= NULL
&& lc
->lconn_status
== LDAP_CONNST_CONNECTING
) {
214 ber_socket_t sd
= AC_SOCKET_ERROR
;
215 struct timeval tv
= { 0 };
217 ber_sockbuf_ctrl( lc
->lconn_sb
, LBER_SB_OPT_GET_FD
, &sd
);
220 switch ( ldap_int_poll( ld
, sd
, &tv
) ) {
223 lc
->lconn_status
= LDAP_CONNST_CONNECTED
;
227 /* async only occurs if a network timeout is set */
229 /* honor network timeout */
230 if ( time( NULL
) - lc
->lconn_created
<= ld
->ld_options
.ldo_tm_net
.tv_sec
)
232 /* caller will have to call again */
233 ld
->ld_errno
= LDAP_X_CONNECTING
;
243 if ( lc
== NULL
|| lc
->lconn_status
!= LDAP_CONNST_CONNECTED
) {
244 if ( ld
->ld_errno
== LDAP_SUCCESS
) {
245 ld
->ld_errno
= LDAP_SERVER_DOWN
;
250 /* Forget about the bind */
251 --parentreq
->lr_outrefcnt
;
256 use_connection( ld
, lc
);
258 #ifdef LDAP_CONNECTIONLESS
259 if ( LDAP_IS_UDP( ld
)) {
260 BerElement tmpber
= *ber
;
261 ber_rewind( &tmpber
);
262 rc
= ber_write( &tmpber
, ld
->ld_options
.ldo_peer
,
263 sizeof( struct sockaddr
), 0 );
265 ld
->ld_errno
= LDAP_ENCODING_ERROR
;
271 /* If we still have an incomplete write, try to finish it before
272 * dealing with the new request. If we don't finish here, return
273 * LDAP_BUSY and let the caller retry later. We only allow a single
274 * request to be in WRITING state.
277 if ( ld
->ld_requests
&&
278 ld
->ld_requests
->lr_status
== LDAP_REQST_WRITING
&&
279 ldap_int_flush_request( ld
, ld
->ld_requests
) < 0 )
285 lr
= (LDAPRequest
*)LDAP_CALLOC( 1, sizeof( LDAPRequest
) );
287 ld
->ld_errno
= LDAP_NO_MEMORY
;
288 ldap_free_connection( ld
, lc
, 0, 0 );
291 /* Forget about the bind */
292 --parentreq
->lr_outrefcnt
;
296 lr
->lr_msgid
= msgid
;
297 lr
->lr_status
= LDAP_REQST_INPROGRESS
;
298 lr
->lr_res_errno
= LDAP_SUCCESS
; /* optimistic */
301 if ( parentreq
!= NULL
) { /* sub-request */
303 /* Increment if we didn't do it before the bind */
304 ++parentreq
->lr_outrefcnt
;
306 lr
->lr_origid
= parentreq
->lr_origid
;
307 lr
->lr_parentcnt
= ++parentreq
->lr_parentcnt
;
308 lr
->lr_parent
= parentreq
;
309 lr
->lr_refnext
= parentreq
->lr_child
;
310 parentreq
->lr_child
= lr
;
311 } else { /* original request */
312 lr
->lr_origid
= lr
->lr_msgid
;
315 /* Extract requestDN for future reference */
317 BerElement tmpber
= *ber
;
321 ber_reset( &tmpber
, 1 );
322 rtag
= ber_scanf( &tmpber
, "{it", /*}*/ &bint
, &tag
);
325 rtag
= ber_scanf( &tmpber
, "{i" /*}*/, &bint
);
327 case LDAP_REQ_DELETE
:
330 rtag
= ber_scanf( &tmpber
, "{" /*}*/ );
331 case LDAP_REQ_ABANDON
:
334 if ( tag
!= LDAP_REQ_ABANDON
) {
335 ber_skip_tag( &tmpber
, &lr
->lr_dn
.bv_len
);
336 lr
->lr_dn
.bv_val
= tmpber
.ber_ptr
;
341 lr
->lr_next
= ld
->ld_requests
;
342 if ( lr
->lr_next
!= NULL
) {
343 lr
->lr_next
->lr_prev
= lr
;
345 ld
->ld_requests
= lr
;
347 ld
->ld_errno
= LDAP_SUCCESS
;
348 if ( ldap_int_flush_request( ld
, lr
) == -1 ) {
356 ldap_new_connection( LDAP
*ld
, LDAPURLDesc
**srvlist
, int use_ldsb
,
357 int connect
, LDAPreqinfo
*bind
)
362 Debug( LDAP_DEBUG_TRACE
, "ldap_new_connection %d %d %d\n",
363 use_ldsb
, connect
, (bind
!= NULL
) );
365 * make a new LDAP server connection
366 * XXX open connection synchronously for now
368 lc
= (LDAPConn
*)LDAP_CALLOC( 1, sizeof( LDAPConn
) );
370 ld
->ld_errno
= LDAP_NO_MEMORY
;
375 assert( ld
->ld_sb
!= NULL
);
376 lc
->lconn_sb
= ld
->ld_sb
;
379 lc
->lconn_sb
= ber_sockbuf_alloc();
380 if ( lc
->lconn_sb
== NULL
) {
381 LDAP_FREE( (char *)lc
);
382 ld
->ld_errno
= LDAP_NO_MEMORY
;
388 LDAPURLDesc
**srvp
, *srv
= NULL
;
390 async
= LDAP_BOOL_GET( &ld
->ld_options
, LDAP_BOOL_CONNECT_ASYNC
);
392 for ( srvp
= srvlist
; *srvp
!= NULL
; srvp
= &(*srvp
)->lud_next
) {
395 rc
= ldap_int_open_connection( ld
, lc
, *srvp
, async
);
399 if ( ld
->ld_urllist_proc
&& ( !async
|| rc
!= -2 ) ) {
400 ld
->ld_urllist_proc( ld
, srvlist
, srvp
, ld
->ld_urllist_params
);
409 ber_sockbuf_free( lc
->lconn_sb
);
411 LDAP_FREE( (char *)lc
);
412 ld
->ld_errno
= LDAP_SERVER_DOWN
;
416 lc
->lconn_server
= ldap_url_dup( srv
);
419 lc
->lconn_status
= async
? LDAP_CONNST_CONNECTING
: LDAP_CONNST_CONNECTED
;
420 #ifdef LDAP_R_COMPILE
421 ldap_pvt_thread_mutex_lock( &ld
->ld_conn_mutex
);
423 lc
->lconn_next
= ld
->ld_conns
;
425 #ifdef LDAP_R_COMPILE
426 ldap_pvt_thread_mutex_unlock( &ld
->ld_conn_mutex
);
429 if ( bind
!= NULL
) {
431 LDAPConn
*savedefconn
;
433 /* Set flag to prevent additional referrals
434 * from being processed on this
435 * connection until the bind has completed
437 lc
->lconn_rebind_inprogress
= 1;
438 /* V3 rebind function */
439 if ( ld
->ld_rebind_proc
!= NULL
) {
440 LDAPURLDesc
*srvfunc
;
442 srvfunc
= ldap_url_dup( *srvlist
);
443 if ( srvfunc
== NULL
) {
444 ld
->ld_errno
= LDAP_NO_MEMORY
;
447 savedefconn
= ld
->ld_defconn
;
448 ++lc
->lconn_refcnt
; /* avoid premature free */
451 Debug( LDAP_DEBUG_TRACE
, "Call application rebind_proc\n", 0, 0, 0);
452 #ifdef LDAP_R_COMPILE
453 ldap_pvt_thread_mutex_unlock( &ld
->ld_req_mutex
);
454 ldap_pvt_thread_mutex_unlock( &ld
->ld_res_mutex
);
456 err
= (*ld
->ld_rebind_proc
)( ld
,
457 bind
->ri_url
, bind
->ri_request
, bind
->ri_msgid
,
458 ld
->ld_rebind_params
);
459 #ifdef LDAP_R_COMPILE
460 ldap_pvt_thread_mutex_lock( &ld
->ld_res_mutex
);
461 ldap_pvt_thread_mutex_lock( &ld
->ld_req_mutex
);
464 ld
->ld_defconn
= savedefconn
;
469 ldap_free_connection( ld
, lc
, 1, 0 );
472 ldap_free_urldesc( srvfunc
);
477 struct berval passwd
= BER_BVNULL
;
479 savedefconn
= ld
->ld_defconn
;
480 ++lc
->lconn_refcnt
; /* avoid premature free */
483 Debug( LDAP_DEBUG_TRACE
,
484 "anonymous rebind via ldap_sasl_bind(\"\")\n",
487 #ifdef LDAP_R_COMPILE
488 ldap_pvt_thread_mutex_unlock( &ld
->ld_req_mutex
);
489 ldap_pvt_thread_mutex_unlock( &ld
->ld_res_mutex
);
491 rc
= ldap_sasl_bind( ld
, "", LDAP_SASL_SIMPLE
, &passwd
,
492 NULL
, NULL
, &msgid
);
493 if ( rc
!= LDAP_SUCCESS
) {
497 for ( err
= 1; err
> 0; ) {
498 struct timeval tv
= { 0, 100000 };
499 LDAPMessage
*res
= NULL
;
501 switch ( ldap_result( ld
, msgid
, LDAP_MSG_ALL
, &tv
, &res
) ) {
507 #ifdef LDAP_R_COMPILE
508 ldap_pvt_thread_yield();
513 rc
= ldap_parse_result( ld
, res
, &err
, NULL
, NULL
, NULL
, NULL
, 1 );
514 if ( rc
!= LDAP_SUCCESS
) {
517 } else if ( err
!= LDAP_SUCCESS
) {
520 /* else err == LDAP_SUCCESS == 0 */
524 Debug( LDAP_DEBUG_TRACE
,
525 "ldap_new_connection %p: "
526 "unexpected response %d "
527 "from BIND request id=%d\n",
528 (void *) ld
, ldap_msgtype( res
), msgid
);
534 #ifdef LDAP_R_COMPILE
535 ldap_pvt_thread_mutex_lock( &ld
->ld_res_mutex
);
536 ldap_pvt_thread_mutex_lock( &ld
->ld_req_mutex
);
538 ld
->ld_defconn
= savedefconn
;
542 ldap_free_connection( ld
, lc
, 1, 0 );
547 lc
->lconn_rebind_inprogress
= 0;
555 find_connection( LDAP
*ld
, LDAPURLDesc
*srv
, int any
)
557 * return an existing connection (if any) to the server srv
558 * if "any" is non-zero, check for any server in the "srv" chain
562 LDAPURLDesc
*lcu
, *lsu
;
563 int lcu_port
, lsu_port
;
566 #ifdef LDAP_R_COMPILE
567 ldap_pvt_thread_mutex_lock( &ld
->ld_conn_mutex
);
569 for ( lc
= ld
->ld_conns
; lc
!= NULL
; lc
= lc
->lconn_next
) {
570 lcu
= lc
->lconn_server
;
571 lcu_port
= ldap_pvt_url_scheme_port( lcu
->lud_scheme
,
574 for ( lsu
= srv
; lsu
!= NULL
; lsu
= lsu
->lud_next
) {
575 lsu_port
= ldap_pvt_url_scheme_port( lsu
->lud_scheme
,
578 if ( lsu_port
== lcu_port
579 && strcmp( lcu
->lud_scheme
, lsu
->lud_scheme
) == 0
580 && lcu
->lud_host
!= NULL
&& *lcu
->lud_host
!= '\0'
581 && lsu
->lud_host
!= NULL
&& *lsu
->lud_host
!= '\0'
582 && strcasecmp( lsu
->lud_host
, lcu
->lud_host
) == 0 )
593 #ifdef LDAP_R_COMPILE
594 ldap_pvt_thread_mutex_unlock( &ld
->ld_conn_mutex
);
602 use_connection( LDAP
*ld
, LDAPConn
*lc
)
605 lc
->lconn_lastused
= time( NULL
);
610 ldap_free_connection( LDAP
*ld
, LDAPConn
*lc
, int force
, int unbind
)
612 LDAPConn
*tmplc
, *prevlc
;
614 Debug( LDAP_DEBUG_TRACE
,
615 "ldap_free_connection %d %d\n",
618 if ( force
|| --lc
->lconn_refcnt
<= 0 ) {
619 /* remove from connections list first */
620 #ifdef LDAP_R_COMPILE
621 ldap_pvt_thread_mutex_lock( &ld
->ld_conn_mutex
);
624 for ( prevlc
= NULL
, tmplc
= ld
->ld_conns
;
626 tmplc
= tmplc
->lconn_next
)
629 if ( prevlc
== NULL
) {
630 ld
->ld_conns
= tmplc
->lconn_next
;
632 prevlc
->lconn_next
= tmplc
->lconn_next
;
634 if ( ld
->ld_defconn
== lc
) {
635 ld
->ld_defconn
= NULL
;
641 #ifdef LDAP_R_COMPILE
642 ldap_pvt_thread_mutex_unlock( &ld
->ld_conn_mutex
);
645 if ( lc
->lconn_status
== LDAP_CONNST_CONNECTED
) {
646 ldap_mark_select_clear( ld
, lc
->lconn_sb
);
648 ldap_send_unbind( ld
, lc
->lconn_sb
,
653 if ( lc
->lconn_ber
!= NULL
) {
654 ber_free( lc
->lconn_ber
, 1 );
657 ldap_int_sasl_close( ld
, lc
);
659 ldap_free_urllist( lc
->lconn_server
);
661 /* FIXME: is this at all possible?
662 * ldap_ld_free() in unbind.c calls ldap_free_connection()
663 * with force == 1 __after__ explicitly calling
664 * ldap_free_request() on all requests */
668 for ( lr
= ld
->ld_requests
; lr
; ) {
669 LDAPRequest
*lr_next
= lr
->lr_next
;
671 if ( lr
->lr_conn
== lc
) {
672 ldap_free_request_int( ld
, lr
);
679 if ( lc
->lconn_sb
!= ld
->ld_sb
) {
680 ber_sockbuf_free( lc
->lconn_sb
);
682 ber_int_sb_close( lc
->lconn_sb
);
685 if ( lc
->lconn_rebind_queue
!= NULL
) {
687 for( i
= 0; lc
->lconn_rebind_queue
[i
] != NULL
; i
++ ) {
688 LDAP_VFREE( lc
->lconn_rebind_queue
[i
] );
690 LDAP_FREE( lc
->lconn_rebind_queue
);
695 Debug( LDAP_DEBUG_TRACE
,
696 "ldap_free_connection: actually freed\n",
700 lc
->lconn_lastused
= time( NULL
);
701 Debug( LDAP_DEBUG_TRACE
, "ldap_free_connection: refcnt %d\n",
702 lc
->lconn_refcnt
, 0, 0 );
709 ldap_dump_connection( LDAP
*ld
, LDAPConn
*lconns
, int all
)
714 Debug( LDAP_DEBUG_TRACE
, "** ld %p Connection%s:\n", (void *)ld
, all
? "s" : "", 0 );
715 for ( lc
= lconns
; lc
!= NULL
; lc
= lc
->lconn_next
) {
716 if ( lc
->lconn_server
!= NULL
) {
717 Debug( LDAP_DEBUG_TRACE
, "* host: %s port: %d%s\n",
718 ( lc
->lconn_server
->lud_host
== NULL
) ? "(null)"
719 : lc
->lconn_server
->lud_host
,
720 lc
->lconn_server
->lud_port
, ( lc
->lconn_sb
==
721 ld
->ld_sb
) ? " (default)" : "" );
723 Debug( LDAP_DEBUG_TRACE
, " refcnt: %d status: %s\n", lc
->lconn_refcnt
,
724 ( lc
->lconn_status
== LDAP_CONNST_NEEDSOCKET
)
726 ( lc
->lconn_status
== LDAP_CONNST_CONNECTING
)
727 ? "Connecting" : "Connected", 0 );
728 Debug( LDAP_DEBUG_TRACE
, " last used: %s%s\n",
729 ldap_pvt_ctime( &lc
->lconn_lastused
, timebuf
),
730 lc
->lconn_rebind_inprogress
? " rebind in progress" : "", 0 );
731 if ( lc
->lconn_rebind_inprogress
) {
732 if ( lc
->lconn_rebind_queue
!= NULL
) {
735 for ( i
= 0; lc
->lconn_rebind_queue
[i
] != NULL
; i
++ ) {
737 for( j
= 0; lc
->lconn_rebind_queue
[i
][j
] != 0; j
++ ) {
738 Debug( LDAP_DEBUG_TRACE
, " queue %d entry %d - %s\n",
739 i
, j
, lc
->lconn_rebind_queue
[i
][j
] );
743 Debug( LDAP_DEBUG_TRACE
, " queue is empty\n", 0, 0, 0 );
746 Debug( LDAP_DEBUG_TRACE
, "\n", 0, 0, 0 );
755 ldap_dump_requests_and_responses( LDAP
*ld
)
761 Debug( LDAP_DEBUG_TRACE
, "** ld %p Outstanding Requests:\n",
763 lr
= ld
->ld_requests
;
765 Debug( LDAP_DEBUG_TRACE
, " Empty\n", 0, 0, 0 );
767 for ( i
= 0; lr
!= NULL
; lr
= lr
->lr_next
, i
++ ) {
768 Debug( LDAP_DEBUG_TRACE
, " * msgid %d, origid %d, status %s\n",
769 lr
->lr_msgid
, lr
->lr_origid
,
770 ( lr
->lr_status
== LDAP_REQST_INPROGRESS
) ? "InProgress" :
771 ( lr
->lr_status
== LDAP_REQST_CHASINGREFS
) ? "ChasingRefs" :
772 ( lr
->lr_status
== LDAP_REQST_NOTCONNECTED
) ? "NotConnected" :
773 ( lr
->lr_status
== LDAP_REQST_WRITING
) ? "Writing" :
774 ( lr
->lr_status
== LDAP_REQST_COMPLETED
) ? "RequestCompleted"
776 Debug( LDAP_DEBUG_TRACE
, " outstanding referrals %d, parent count %d\n",
777 lr
->lr_outrefcnt
, lr
->lr_parentcnt
, 0 );
779 Debug( LDAP_DEBUG_TRACE
, " ld %p request count %d (abandoned %lu)\n",
780 (void *)ld
, i
, ld
->ld_nabandoned
);
781 Debug( LDAP_DEBUG_TRACE
, "** ld %p Response Queue:\n", (void *)ld
, 0, 0 );
782 if ( ( lm
= ld
->ld_responses
) == NULL
) {
783 Debug( LDAP_DEBUG_TRACE
, " Empty\n", 0, 0, 0 );
785 for ( i
= 0; lm
!= NULL
; lm
= lm
->lm_next
, i
++ ) {
786 Debug( LDAP_DEBUG_TRACE
, " * msgid %d, type %lu\n",
787 lm
->lm_msgid
, (unsigned long)lm
->lm_msgtype
, 0 );
788 if ( lm
->lm_chain
!= NULL
) {
789 Debug( LDAP_DEBUG_TRACE
, " chained responses:\n", 0, 0, 0 );
790 for ( l
= lm
->lm_chain
; l
!= NULL
; l
= l
->lm_chain
) {
791 Debug( LDAP_DEBUG_TRACE
,
792 " * msgid %d, type %lu\n",
794 (unsigned long)l
->lm_msgtype
, 0 );
798 Debug( LDAP_DEBUG_TRACE
, " ld %p response count %d\n", (void *)ld
, i
, 0 );
800 #endif /* LDAP_DEBUG */
803 ldap_free_request_int( LDAP
*ld
, LDAPRequest
*lr
)
805 /* if lr_refcnt > 0, the request has been looked up
806 * by ldap_find_request_by_msgid(); if in the meanwhile
807 * the request is free()'d by someone else, just decrease
808 * the reference count and extract it from the request
809 * list; later on, it will be freed. */
810 if ( lr
->lr_prev
== NULL
) {
811 if ( lr
->lr_refcnt
== 0 ) {
812 /* free'ing the first request? */
813 assert( ld
->ld_requests
== lr
);
816 if ( ld
->ld_requests
== lr
) {
817 ld
->ld_requests
= lr
->lr_next
;
821 lr
->lr_prev
->lr_next
= lr
->lr_next
;
824 if ( lr
->lr_next
!= NULL
) {
825 lr
->lr_next
->lr_prev
= lr
->lr_prev
;
828 if ( lr
->lr_refcnt
> 0 ) {
829 lr
->lr_refcnt
= -lr
->lr_refcnt
;
837 if ( lr
->lr_ber
!= NULL
) {
838 ber_free( lr
->lr_ber
, 1 );
842 if ( lr
->lr_res_error
!= NULL
) {
843 LDAP_FREE( lr
->lr_res_error
);
844 lr
->lr_res_error
= NULL
;
847 if ( lr
->lr_res_matched
!= NULL
) {
848 LDAP_FREE( lr
->lr_res_matched
);
849 lr
->lr_res_matched
= NULL
;
856 ldap_free_request( LDAP
*ld
, LDAPRequest
*lr
)
858 #ifdef LDAP_R_COMPILE
859 LDAP_PVT_THREAD_ASSERT_MUTEX_OWNER( &ld
->ld_req_mutex
);
862 Debug( LDAP_DEBUG_TRACE
, "ldap_free_request (origid %d, msgid %d)\n",
863 lr
->lr_origid
, lr
->lr_msgid
, 0 );
865 /* free all referrals (child requests) */
866 while ( lr
->lr_child
) {
867 ldap_free_request( ld
, lr
->lr_child
);
870 if ( lr
->lr_parent
!= NULL
) {
873 --lr
->lr_parent
->lr_outrefcnt
;
874 for ( lrp
= &lr
->lr_parent
->lr_child
;
876 lrp
= &(*lrp
)->lr_refnext
);
879 *lrp
= lr
->lr_refnext
;
882 ldap_free_request_int( ld
, lr
);
886 * call first time with *cntp = -1
887 * when returns *cntp == -1, no referrals are left
889 * NOTE: may replace *refsp, or shuffle the contents
890 * of the original array.
892 static int ldap_int_nextref(
898 assert( refsp
!= NULL
);
899 assert( *refsp
!= NULL
);
900 assert( cntp
!= NULL
);
909 if ( (*refsp
)[ *cntp
] == NULL
) {
920 * (IN) ld = LDAP connection handle
921 * (IN) lr = LDAP Request structure
922 * (IN) refs = array of pointers to referral strings that we will chase
923 * The array will be free'd by this function when no longer needed
924 * (IN) sref != 0 if following search reference
925 * (OUT) errstrp = Place to return a string of referrals which could not be followed
926 * (OUT) hadrefp = 1 if sucessfully followed referral
928 * Return value - number of referrals followed
931 ldap_chase_v3referrals( LDAP
*ld
, LDAPRequest
*lr
, char **refs
, int sref
, char **errstrp
, int *hadrefp
)
934 int unfollowedcnt
= 0;
935 LDAPRequest
*origreq
;
936 LDAPURLDesc
*srv
= NULL
;
938 char **refarray
= NULL
;
940 int rc
, count
, i
, j
, id
;
943 ld
->ld_errno
= LDAP_SUCCESS
; /* optimistic */
946 Debug( LDAP_DEBUG_TRACE
, "ldap_chase_v3referrals\n", 0, 0, 0 );
951 /* If no referrals in array, return */
952 if ( (refs
== NULL
) || ( (refs
)[0] == NULL
) ) {
957 /* Check for hop limit exceeded */
958 if ( lr
->lr_parentcnt
>= ld
->ld_refhoplimit
) {
959 Debug( LDAP_DEBUG_ANY
,
960 "more than %d referral hops (dropping)\n", ld
->ld_refhoplimit
, 0, 0 );
961 ld
->ld_errno
= LDAP_REFERRAL_LIMIT_EXCEEDED
;
966 /* find original request */
968 origreq
->lr_parent
!= NULL
;
969 origreq
= origreq
->lr_parent
)
977 if ( ld
->ld_nextref_proc
== NULL
) {
978 ld
->ld_nextref_proc
= ldap_int_nextref
;
981 /* parse out & follow referrals */
983 for ( ld
->ld_nextref_proc( ld
, &refarray
, &i
, ld
->ld_nextref_params
);
985 ld
->ld_nextref_proc( ld
, &refarray
, &i
, ld
->ld_nextref_params
) )
988 /* Parse the referral URL */
989 rc
= ldap_url_parse_ext( refarray
[i
], &srv
, LDAP_PVT_URL_PARSE_NOEMPTY_DN
);
990 if ( rc
!= LDAP_URL_SUCCESS
) {
991 /* ldap_url_parse_ext() returns LDAP_URL_* errors
992 * which do not map on API errors */
993 ld
->ld_errno
= LDAP_PARAM_ERROR
;
998 if( srv
->lud_crit_exts
) {
999 /* we do not support any extensions */
1000 ld
->ld_errno
= LDAP_NOT_SUPPORTED
;
1005 /* check connection for re-bind in progress */
1006 if (( lc
= find_connection( ld
, srv
, 1 )) != NULL
) {
1007 /* See if we've already requested this DN with this conn */
1010 int len
= srv
->lud_dn
? strlen( srv
->lud_dn
) : 0;
1011 for ( lp
= origreq
; lp
; ) {
1012 if ( lp
->lr_conn
== lc
1013 && len
== lp
->lr_dn
.bv_len
1015 && strncmp( srv
->lud_dn
, lp
->lr_dn
.bv_val
, len
) == 0 )
1020 if ( lp
== origreq
) {
1023 lp
= lp
->lr_refnext
;
1027 ldap_free_urllist( srv
);
1029 ld
->ld_errno
= LDAP_CLIENT_LOOP
;
1034 if ( lc
->lconn_rebind_inprogress
) {
1035 /* We are already chasing a referral or search reference and a
1036 * bind on that connection is in progress. We must queue
1037 * referrals on that connection, so we don't get a request
1038 * going out before the bind operation completes. This happens
1039 * if two search references come in one behind the other
1040 * for the same server with different contexts.
1042 Debug( LDAP_DEBUG_TRACE
,
1043 "ldap_chase_v3referrals: queue referral \"%s\"\n",
1045 if( lc
->lconn_rebind_queue
== NULL
) {
1046 /* Create a referral list */
1047 lc
->lconn_rebind_queue
=
1048 (char ***) LDAP_MALLOC( sizeof(void *) * 2);
1050 if( lc
->lconn_rebind_queue
== NULL
) {
1051 ld
->ld_errno
= LDAP_NO_MEMORY
;
1056 lc
->lconn_rebind_queue
[0] = refarray
;
1057 lc
->lconn_rebind_queue
[1] = NULL
;
1061 /* Count how many referral arrays we already have */
1062 for( j
= 0; lc
->lconn_rebind_queue
[j
] != NULL
; j
++) {
1066 /* Add the new referral to the list */
1067 lc
->lconn_rebind_queue
= (char ***) LDAP_REALLOC(
1068 lc
->lconn_rebind_queue
, sizeof(void *) * (j
+ 2));
1070 if( lc
->lconn_rebind_queue
== NULL
) {
1071 ld
->ld_errno
= LDAP_NO_MEMORY
;
1075 lc
->lconn_rebind_queue
[j
] = refarray
;
1076 lc
->lconn_rebind_queue
[j
+1] = NULL
;
1080 /* We have queued the referral/reference, now just return */
1083 count
= 1; /* Pretend we already followed referral */
1087 /* Re-encode the request with the new starting point of the search.
1088 * Note: In the future we also need to replace the filter if one
1089 * was provided with the search reference
1092 /* For references we don't want old dn if new dn empty */
1093 if ( sref
&& srv
->lud_dn
== NULL
) {
1094 srv
->lud_dn
= LDAP_STRDUP( "" );
1097 LDAP_NEXT_MSGID( ld
, id
);
1098 ber
= re_encode_request( ld
, origreq
->lr_ber
, id
,
1099 sref
, srv
, &rinfo
.ri_request
);
1102 ld
->ld_errno
= LDAP_ENCODING_ERROR
;
1107 Debug( LDAP_DEBUG_TRACE
,
1108 "ldap_chase_v3referral: msgid %d, url \"%s\"\n",
1109 lr
->lr_msgid
, refarray
[i
], 0);
1111 /* Send the new request to the server - may require a bind */
1112 rinfo
.ri_msgid
= origreq
->lr_origid
;
1113 rinfo
.ri_url
= refarray
[i
];
1114 #ifdef LDAP_R_COMPILE
1115 ldap_pvt_thread_mutex_lock( &ld
->ld_req_mutex
);
1117 rc
= ldap_send_server_request( ld
, ber
, id
,
1118 origreq
, &srv
, NULL
, &rinfo
);
1119 #ifdef LDAP_R_COMPILE
1120 ldap_pvt_thread_mutex_unlock( &ld
->ld_req_mutex
);
1123 /* Failure, try next referral in the list */
1124 Debug( LDAP_DEBUG_ANY
, "Unable to chase referral \"%s\" (%d: %s)\n",
1125 refarray
[i
], ld
->ld_errno
, ldap_err2string( ld
->ld_errno
) );
1126 unfollowedcnt
+= ldap_append_referral( ld
, &unfollowed
, refarray
[i
] );
1127 ldap_free_urllist( srv
);
1129 ld
->ld_errno
= LDAP_REFERRAL
;
1131 /* Success, no need to try this referral list further */
1136 /* check if there is a queue of referrals that came in during bind */
1138 lc
= find_connection( ld
, srv
, 1 );
1140 ld
->ld_errno
= LDAP_OPERATIONS_ERROR
;
1146 if ( lc
->lconn_rebind_queue
!= NULL
) {
1147 /* Release resources of previous list */
1148 LDAP_VFREE( refarray
);
1150 ldap_free_urllist( srv
);
1153 /* Pull entries off end of queue so list always null terminated */
1154 for( j
= 0; lc
->lconn_rebind_queue
[j
] != NULL
; j
++ )
1156 refarray
= lc
->lconn_rebind_queue
[j
- 1];
1157 lc
->lconn_rebind_queue
[j
-1] = NULL
;
1158 /* we pulled off last entry from queue, free queue */
1160 LDAP_FREE( lc
->lconn_rebind_queue
);
1161 lc
->lconn_rebind_queue
= NULL
;
1163 /* restart the loop the with new referral list */
1167 break; /* referral followed, break out of for loop */
1169 } /* end for loop */
1171 LDAP_VFREE( refarray
);
1172 ldap_free_urllist( srv
);
1173 LDAP_FREE( *errstrp
);
1177 LDAP_FREE( unfollowed
);
1180 *errstrp
= unfollowed
;
1186 * XXX merging of errors in this routine needs to be improved
1189 ldap_chase_referrals( LDAP
*ld
,
1197 char *p
, *ref
, *unfollowed
;
1198 LDAPRequest
*origreq
;
1204 Debug( LDAP_DEBUG_TRACE
, "ldap_chase_referrals\n", 0, 0, 0 );
1206 ld
->ld_errno
= LDAP_SUCCESS
; /* optimistic */
1209 if ( *errstrp
== NULL
) {
1213 len
= strlen( *errstrp
);
1214 for ( p
= *errstrp
; len
>= LDAP_REF_STR_LEN
; ++p
, --len
) {
1215 if ( strncasecmp( p
, LDAP_REF_STR
, LDAP_REF_STR_LEN
) == 0 ) {
1217 p
+= LDAP_REF_STR_LEN
;
1222 if ( len
< LDAP_REF_STR_LEN
) {
1226 if ( lr
->lr_parentcnt
>= ld
->ld_refhoplimit
) {
1227 Debug( LDAP_DEBUG_ANY
,
1228 "more than %d referral hops (dropping)\n",
1229 ld
->ld_refhoplimit
, 0, 0 );
1230 /* XXX report as error in ld->ld_errno? */
1234 /* find original request */
1235 for ( origreq
= lr
; origreq
->lr_parent
!= NULL
;
1236 origreq
= origreq
->lr_parent
) {
1243 /* parse out & follow referrals */
1244 for ( ref
= p
; rc
== 0 && ref
!= NULL
; ref
= p
) {
1245 p
= strchr( ref
, '\n' );
1250 rc
= ldap_url_parse_ext( ref
, &srv
, LDAP_PVT_URL_PARSE_NOEMPTY_DN
);
1251 if ( rc
!= LDAP_URL_SUCCESS
) {
1252 Debug( LDAP_DEBUG_TRACE
,
1253 "ignoring %s referral <%s>\n",
1254 ref
, rc
== LDAP_URL_ERR_BADSCHEME
? "unknown" : "incorrect", 0 );
1255 rc
= ldap_append_referral( ld
, &unfollowed
, ref
);
1260 Debug( LDAP_DEBUG_TRACE
,
1261 "chasing LDAP referral: <%s>\n", ref
, 0, 0 );
1265 /* See if we've already been here */
1266 if (( lc
= find_connection( ld
, srv
, 1 )) != NULL
) {
1269 int len
= srv
->lud_dn
? strlen( srv
->lud_dn
) : 0;
1270 for ( lp
= lr
; lp
; lp
= lp
->lr_parent
) {
1271 if ( lp
->lr_conn
== lc
1272 && len
== lp
->lr_dn
.bv_len
)
1274 if ( len
&& strncmp( srv
->lud_dn
, lp
->lr_dn
.bv_val
, len
) )
1281 ldap_free_urllist( srv
);
1282 ld
->ld_errno
= LDAP_CLIENT_LOOP
;
1288 LDAP_NEXT_MSGID( ld
, id
);
1289 ber
= re_encode_request( ld
, origreq
->lr_ber
,
1290 id
, sref
, srv
, &rinfo
.ri_request
);
1292 if ( ber
== NULL
) {
1296 /* copy the complete referral for rebind process */
1297 rinfo
.ri_url
= LDAP_STRDUP( ref
);
1299 rinfo
.ri_msgid
= origreq
->lr_origid
;
1301 #ifdef LDAP_R_COMPILE
1302 ldap_pvt_thread_mutex_lock( &ld
->ld_req_mutex
);
1304 rc
= ldap_send_server_request( ld
, ber
, id
,
1305 lr
, &srv
, NULL
, &rinfo
);
1306 #ifdef LDAP_R_COMPILE
1307 ldap_pvt_thread_mutex_unlock( &ld
->ld_req_mutex
);
1310 LDAP_FREE( rinfo
.ri_url
);
1315 Debug( LDAP_DEBUG_ANY
,
1316 "Unable to chase referral \"%s\" (%d: %s)\n",
1317 ref
, ld
->ld_errno
, ldap_err2string( ld
->ld_errno
) );
1318 rc
= ldap_append_referral( ld
, &unfollowed
, ref
);
1321 ldap_free_urllist(srv
);
1324 LDAP_FREE( *errstrp
);
1325 *errstrp
= unfollowed
;
1327 return(( rc
== 0 ) ? count
: rc
);
1332 ldap_append_referral( LDAP
*ld
, char **referralsp
, char *s
)
1336 if ( *referralsp
== NULL
) {
1338 *referralsp
= (char *)LDAP_MALLOC( strlen( s
) + LDAP_REF_STR_LEN
1342 *referralsp
= (char *)LDAP_REALLOC( *referralsp
,
1343 strlen( *referralsp
) + strlen( s
) + 2 );
1346 if ( *referralsp
== NULL
) {
1347 ld
->ld_errno
= LDAP_NO_MEMORY
;
1352 strcpy( *referralsp
, LDAP_REF_STR
);
1354 strcat( *referralsp
, "\n" );
1356 strcat( *referralsp
, s
);
1364 re_encode_request( LDAP
*ld
,
1365 BerElement
*origber
,
1372 * XXX this routine knows way too much about how the lber library works!
1380 BerElement tmpber
, *ber
;
1383 Debug( LDAP_DEBUG_TRACE
,
1384 "re_encode_request: new msgid %ld, new dn <%s>\n",
1386 ( srv
== NULL
|| srv
->lud_dn
== NULL
) ? "NONE" : srv
->lud_dn
, 0 );
1391 * all LDAP requests are sequences that start with a message id.
1392 * For all except delete, this is followed by a sequence that is
1393 * tagged with the operation code. For delete, the provided DN
1394 * is not wrapped by a sequence.
1396 rtag
= ber_scanf( &tmpber
, "{it", /*}*/ &along
, &tag
);
1398 if ( rtag
== LBER_ERROR
) {
1399 ld
->ld_errno
= LDAP_DECODING_ERROR
;
1404 if ( tag
== LDAP_REQ_BIND
) {
1405 /* bind requests have a version number before the DN & other stuff */
1406 rtag
= ber_scanf( &tmpber
, "{im" /*}*/, &ver
, &dn
);
1408 } else if ( tag
== LDAP_REQ_DELETE
) {
1409 /* delete requests don't have a DN wrapping sequence */
1410 rtag
= ber_scanf( &tmpber
, "m", &dn
);
1412 } else if ( tag
== LDAP_REQ_SEARCH
) {
1413 /* search requests need to be re-scope-ed */
1414 rtag
= ber_scanf( &tmpber
, "{me" /*"}"*/, &dn
, &scope
);
1416 if( srv
->lud_scope
!= LDAP_SCOPE_DEFAULT
) {
1417 /* use the scope provided in reference */
1418 scope
= srv
->lud_scope
;
1420 } else if ( sref
) {
1421 /* use scope implied by previous operation
1424 * subtree -> subtree
1425 * subordinate -> subtree
1429 case LDAP_SCOPE_BASE
:
1430 case LDAP_SCOPE_ONELEVEL
:
1431 scope
= LDAP_SCOPE_BASE
;
1433 case LDAP_SCOPE_SUBTREE
:
1434 case LDAP_SCOPE_SUBORDINATE
:
1435 scope
= LDAP_SCOPE_SUBTREE
;
1441 rtag
= ber_scanf( &tmpber
, "{m" /*}*/, &dn
);
1444 if( rtag
== LBER_ERROR
) {
1445 ld
->ld_errno
= LDAP_DECODING_ERROR
;
1449 /* restore character zero'd out by ber_scanf*/
1450 dn
.bv_val
[dn
.bv_len
] = tmpber
.ber_tag
;
1452 if (( ber
= ldap_alloc_ber_with_options( ld
)) == NULL
) {
1456 if ( srv
->lud_dn
) {
1457 ber_str2bv( srv
->lud_dn
, 0, 0, &dn
);
1460 if ( tag
== LDAP_REQ_BIND
) {
1461 rc
= ber_printf( ber
, "{it{iO" /*}}*/, msgid
, tag
, ver
, &dn
);
1462 } else if ( tag
== LDAP_REQ_DELETE
) {
1463 rc
= ber_printf( ber
, "{itON}", msgid
, tag
, &dn
);
1464 } else if ( tag
== LDAP_REQ_SEARCH
) {
1465 rc
= ber_printf( ber
, "{it{Oe" /*}}*/, msgid
, tag
, &dn
, scope
);
1467 rc
= ber_printf( ber
, "{it{O" /*}}*/, msgid
, tag
, &dn
);
1471 ld
->ld_errno
= LDAP_ENCODING_ERROR
;
1476 if ( tag
!= LDAP_REQ_DELETE
&& (
1477 ber_write(ber
, tmpber
.ber_ptr
, ( tmpber
.ber_end
- tmpber
.ber_ptr
), 0)
1478 != ( tmpber
.ber_end
- tmpber
.ber_ptr
) ||
1479 ber_printf( ber
, /*{{*/ "N}N}" ) == -1 ) )
1481 ld
->ld_errno
= LDAP_ENCODING_ERROR
;
1487 if ( ldap_debug
& LDAP_DEBUG_PACKETS
) {
1488 Debug( LDAP_DEBUG_ANY
, "re_encode_request new request is:\n",
1490 ber_log_dump( LDAP_DEBUG_BER
, ldap_debug
, ber
, 0 );
1492 #endif /* LDAP_DEBUG */
1494 *type
= tag
; /* return request type */
1500 ldap_find_request_by_msgid( LDAP
*ld
, ber_int_t msgid
)
1504 #ifdef LDAP_R_COMPILE
1505 ldap_pvt_thread_mutex_lock( &ld
->ld_req_mutex
);
1507 for ( lr
= ld
->ld_requests
; lr
!= NULL
; lr
= lr
->lr_next
) {
1508 if ( lr
->lr_status
== LDAP_REQST_COMPLETED
) {
1509 continue; /* Skip completed requests */
1511 if ( msgid
== lr
->lr_msgid
) {
1516 #ifdef LDAP_R_COMPILE
1517 ldap_pvt_thread_mutex_unlock( &ld
->ld_req_mutex
);
1524 ldap_return_request( LDAP
*ld
, LDAPRequest
*lrx
, int freeit
)
1528 #ifdef LDAP_R_COMPILE
1529 ldap_pvt_thread_mutex_lock( &ld
->ld_req_mutex
);
1531 for ( lr
= ld
->ld_requests
; lr
!= NULL
; lr
= lr
->lr_next
) {
1533 if ( lr
->lr_refcnt
> 0 ) {
1536 } else if ( lr
->lr_refcnt
< 0 ) {
1538 if ( lr
->lr_refcnt
== 0 ) {
1546 ldap_free_request_int( ld
, lrx
);
1548 } else if ( freeit
) {
1549 ldap_free_request( ld
, lrx
);
1551 #ifdef LDAP_R_COMPILE
1552 ldap_pvt_thread_mutex_unlock( &ld
->ld_req_mutex
);