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