]> git.sur5r.net Git - openldap/blob - libraries/libldap/request.c
Sync with HEAD
[openldap] / libraries / libldap / request.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2005 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 static LDAPConn *find_connection LDAP_P(( LDAP *ld, LDAPURLDesc *srv, int any ));
57 static void use_connection LDAP_P(( LDAP *ld, LDAPConn *lc ));
58
59 static BerElement *
60 re_encode_request( LDAP *ld,
61         BerElement *origber,
62         ber_int_t msgid,
63         int sref,
64         LDAPURLDesc *srv,
65         int *type );
66
67 BerElement *
68 ldap_alloc_ber_with_options( LDAP *ld )
69 {
70         BerElement      *ber;
71
72     if (( ber = ber_alloc_t( ld->ld_lberoptions )) == NULL ) {
73                 ld->ld_errno = LDAP_NO_MEMORY;
74         }
75
76         return( ber );
77 }
78
79
80 void
81 ldap_set_ber_options( LDAP *ld, BerElement *ber )
82 {
83         ber->ber_options = ld->ld_lberoptions;
84 }
85
86
87 ber_int_t
88 ldap_send_initial_request(
89         LDAP *ld,
90         ber_tag_t msgtype,
91         const char *dn,
92         BerElement *ber,
93         ber_int_t msgid)
94 {
95         LDAPURLDesc     *servers;
96         int rc;
97
98         Debug( LDAP_DEBUG_TRACE, "ldap_send_initial_request\n", 0, 0, 0 );
99
100         if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) {
101                 /* not connected yet */
102                 int rc = ldap_open_defconn( ld );
103
104                 if( rc < 0 ) {
105                         ber_free( ber, 1 );
106                         return( -1 );
107                 }
108
109                 Debug( LDAP_DEBUG_TRACE,
110                         "ldap_open_defconn: successful\n",
111                         0, 0, 0 );
112         }
113
114         {
115                 /*
116                  * use of DNS is turned off or this is an X.500 DN...
117                  * use our default connection
118                  */
119                 servers = NULL;
120         }       
121
122 #ifdef LDAP_CONNECTIONLESS
123         if (LDAP_IS_UDP(ld)) {
124                 if (msgtype == LDAP_REQ_BIND) {
125                         if (ld->ld_options.ldo_cldapdn)
126                                 ldap_memfree(ld->ld_options.ldo_cldapdn);
127                         ld->ld_options.ldo_cldapdn = ldap_strdup(dn);
128                         return 0;
129                 }
130                 if (msgtype != LDAP_REQ_ABANDON && msgtype != LDAP_REQ_SEARCH)
131                         return LDAP_PARAM_ERROR;
132         }
133 #endif
134 #ifdef LDAP_R_COMPILE
135         ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
136 #endif
137         rc = ldap_send_server_request( ld, ber, msgid, NULL,
138                                                                         servers, NULL, NULL );
139 #ifdef LDAP_R_COMPILE
140         ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
141 #endif
142         if (servers)
143                 ldap_free_urllist(servers);
144         return(rc);
145 }
146
147
148 int
149 ldap_int_flush_request(
150         LDAP *ld,
151         LDAPRequest *lr )
152 {
153         LDAPConn *lc = lr->lr_conn;
154
155         if ( ber_flush( lc->lconn_sb, lr->lr_ber, 0 ) != 0 ) {
156                 if ( errno == EAGAIN ) {
157                         /* need to continue write later */
158                         lr->lr_status = LDAP_REQST_WRITING;
159                         ldap_mark_select_write( ld, lc->lconn_sb );
160                         ld->ld_errno = LDAP_BUSY;
161                         return -2;
162                 } else {
163                         ld->ld_errno = LDAP_SERVER_DOWN;
164                         ldap_free_request( ld, lr );
165                         ldap_free_connection( ld, lc, 0, 0 );
166                         return( -1 );
167                 }
168         } else {
169                 if ( lr->lr_parent == NULL ) {
170                         lr->lr_ber->ber_end = lr->lr_ber->ber_ptr;
171                         lr->lr_ber->ber_ptr = lr->lr_ber->ber_buf;
172                 }
173                 lr->lr_status = LDAP_REQST_INPROGRESS;
174
175                 /* sent -- waiting for a response */
176                 ldap_mark_select_read( ld, lc->lconn_sb );
177         }
178         return 0;
179 }
180
181 int
182 ldap_send_server_request(
183         LDAP *ld,
184         BerElement *ber,
185         ber_int_t msgid,
186         LDAPRequest *parentreq,
187         LDAPURLDesc *srvlist,
188         LDAPConn *lc,
189         LDAPreqinfo *bind )
190 {
191         LDAPRequest     *lr;
192         int incparent, rc;
193
194         Debug( LDAP_DEBUG_TRACE, "ldap_send_server_request\n", 0, 0, 0 );
195
196         incparent = 0;
197         ld->ld_errno = LDAP_SUCCESS;    /* optimistic */
198
199         if ( lc == NULL ) {
200                 if ( srvlist == NULL ) {
201                         lc = ld->ld_defconn;
202                 } else {
203                         if (( lc = find_connection( ld, srvlist, 1 )) ==
204                             NULL ) {
205                                 if ( (bind != NULL) && (parentreq != NULL) ) {
206                                         /* Remember the bind in the parent */
207                                         incparent = 1;
208                                         ++parentreq->lr_outrefcnt;
209                                 }
210                                 lc = ldap_new_connection( ld, srvlist, 0, 1, bind );
211                         }
212                 }
213         }
214
215         if ( lc == NULL || lc->lconn_status != LDAP_CONNST_CONNECTED ) {
216                 ber_free( ber, 1 );
217                 if ( ld->ld_errno == LDAP_SUCCESS ) {
218                         ld->ld_errno = LDAP_SERVER_DOWN;
219                 }
220                 if ( incparent ) {
221                         /* Forget about the bind */
222                         --parentreq->lr_outrefcnt; 
223                 }
224                 return( -1 );
225         }
226
227         use_connection( ld, lc );
228
229         /* If we still have an incomplete write, try to finish it before
230          * dealing with the new request. If we don't finish here, return
231          * LDAP_BUSY and let the caller retry later. We only allow a single
232          * request to be in WRITING state.
233          */
234         rc = 0;
235         if ( ld->ld_requests &&
236                 ld->ld_requests->lr_status == LDAP_REQST_WRITING &&
237                 ldap_int_flush_request( ld, ld->ld_requests ) < 0 ) {
238                 rc = -1;
239         }
240         if ( rc ) return rc;
241
242         if (( lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ))) ==
243             NULL ) {
244                 ld->ld_errno = LDAP_NO_MEMORY;
245                 ldap_free_connection( ld, lc, 0, 0 );
246                 ber_free( ber, 1 );
247                 if ( incparent ) {
248                         /* Forget about the bind */
249                         --parentreq->lr_outrefcnt; 
250                 }
251                 return( -1 );
252         } 
253         lr->lr_msgid = msgid;
254         lr->lr_status = LDAP_REQST_INPROGRESS;
255         lr->lr_res_errno = LDAP_SUCCESS;        /* optimistic */
256         lr->lr_ber = ber;
257         lr->lr_conn = lc;
258         if ( parentreq != NULL ) {      /* sub-request */
259                 if ( !incparent ) { 
260                         /* Increment if we didn't do it before the bind */
261                         ++parentreq->lr_outrefcnt;
262                 }
263                 lr->lr_origid = parentreq->lr_origid;
264                 lr->lr_parentcnt = parentreq->lr_parentcnt + 1;
265                 lr->lr_parent = parentreq;
266                 lr->lr_refnext = parentreq->lr_child;
267                 parentreq->lr_child = lr;
268         } else {                        /* original request */
269                 lr->lr_origid = lr->lr_msgid;
270         }
271
272         if (( lr->lr_next = ld->ld_requests ) != NULL ) {
273                 lr->lr_next->lr_prev = lr;
274         }
275         ld->ld_requests = lr;
276         lr->lr_prev = NULL;
277
278         ld->ld_errno = LDAP_SUCCESS;
279         if ( ldap_int_flush_request( ld, lr ) == -1 ) {
280                 msgid = -1;
281         }
282
283         return( msgid );
284 }
285
286 LDAPConn *
287 ldap_new_connection( LDAP *ld, LDAPURLDesc *srvlist, int use_ldsb,
288         int connect, LDAPreqinfo *bind )
289 {
290         LDAPConn        *lc;
291         LDAPURLDesc     *srv;
292         Sockbuf         *sb = NULL;
293
294         Debug( LDAP_DEBUG_TRACE, "ldap_new_connection\n", 0, 0, 0 );
295         /*
296          * make a new LDAP server connection
297          * XXX open connection synchronously for now
298          */
299         if (( lc = (LDAPConn *)LDAP_CALLOC( 1, sizeof( LDAPConn ))) == NULL ||
300             ( !use_ldsb && ( (sb = ber_sockbuf_alloc()) == NULL ))) {
301                 if ( lc != NULL ) {
302                         LDAP_FREE( (char *)lc );
303                 }
304                 ld->ld_errno = LDAP_NO_MEMORY;
305                 return( NULL );
306         }
307
308         lc->lconn_sb = ( use_ldsb ) ? ld->ld_sb : sb;
309
310         if ( connect ) {
311                 for ( srv = srvlist; srv != NULL; srv = srv->lud_next ) {
312                         if ( ldap_int_open_connection( ld, lc, srv, 0 ) != -1 ) {
313                                 break;
314                         }
315                 }
316
317                 if ( srv == NULL ) {
318                         if ( !use_ldsb ) {
319                                 ber_sockbuf_free( lc->lconn_sb );
320                         }
321                     LDAP_FREE( (char *)lc );
322                     ld->ld_errno = LDAP_SERVER_DOWN;
323                     return( NULL );
324                 }
325
326                 lc->lconn_server = ldap_url_dup(srv);
327         }
328
329         lc->lconn_status = LDAP_CONNST_CONNECTED;
330         lc->lconn_next = ld->ld_conns;
331         ld->ld_conns = lc;
332
333         /*
334          * XXX for now, we always do a synchronous bind.  This will have
335          * to change in the long run...
336          */
337         if ( bind != NULL) {
338                 int             err = 0;
339                 LDAPConn        *savedefconn;
340
341                 /* Set flag to prevent additional referrals from being processed on this
342                  * connection until the bind has completed
343                  */
344                 lc->lconn_rebind_inprogress = 1;
345                 /* V3 rebind function */
346                 if ( ld->ld_rebind_proc != NULL) {
347                         LDAPURLDesc     *srvfunc;
348                         if( ( srvfunc = ldap_url_dup( srvlist)) == NULL) {
349                                 ld->ld_errno = LDAP_NO_MEMORY;
350                                 err = -1;
351                         } else {
352                                 savedefconn = ld->ld_defconn;
353                                 ++lc->lconn_refcnt;     /* avoid premature free */
354                                 ld->ld_defconn = lc;
355
356                                 Debug( LDAP_DEBUG_TRACE, "Call application rebind_proc\n", 0, 0, 0);
357 #ifdef LDAP_R_COMPILE
358                 ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
359                 ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex );
360 #endif
361                                 err = (*ld->ld_rebind_proc)( ld,
362                                         bind->ri_url, bind->ri_request, bind->ri_msgid,
363                                         ld->ld_rebind_params );
364 #ifdef LDAP_R_COMPILE
365                 ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
366                 ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
367 #endif
368
369                                 ld->ld_defconn = savedefconn;
370                                 --lc->lconn_refcnt;
371
372                                 if( err != 0) {
373                                 err = -1;
374                                         ldap_free_connection( ld, lc, 1, 0 );
375                                         lc = NULL;
376                         }
377                                 ldap_free_urldesc( srvfunc);
378                 }
379                 } else {
380                         savedefconn = ld->ld_defconn;
381                         ++lc->lconn_refcnt;     /* avoid premature free */
382                         ld->ld_defconn = lc;
383
384                         Debug( LDAP_DEBUG_TRACE, "anonymous rebind via ldap_bind_s\n", 0, 0, 0);
385 #ifdef LDAP_R_COMPILE
386                         ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
387                         ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex );
388 #endif
389                         if ( ldap_bind_s( ld, "", "", LDAP_AUTH_SIMPLE ) != LDAP_SUCCESS ) {
390                                 err = -1;
391                         }
392 #ifdef LDAP_R_COMPILE
393                         ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
394                         ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
395 #endif
396                         ld->ld_defconn = savedefconn;
397                         --lc->lconn_refcnt;
398
399                 if ( err != 0 ) {
400                         ldap_free_connection( ld, lc, 1, 0 );
401                         lc = NULL;
402                 }
403         }
404                 if( lc != NULL)
405                         lc->lconn_rebind_inprogress = 0;
406         }
407
408         return( lc );
409 }
410
411
412 static LDAPConn *
413 find_connection( LDAP *ld, LDAPURLDesc *srv, int any )
414 /*
415  * return an existing connection (if any) to the server srv
416  * if "any" is non-zero, check for any server in the "srv" chain
417  */
418 {
419         LDAPConn        *lc;
420         LDAPURLDesc     *lcu, *lsu;
421         int lcu_port, lsu_port;
422
423         for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
424                 lcu = lc->lconn_server;
425                 lcu_port = ldap_pvt_url_scheme_port( lcu->lud_scheme,
426                         lcu->lud_port );
427
428                 for ( lsu = srv; lsu != NULL; lsu = lsu->lud_next ) {
429                         lsu_port = ldap_pvt_url_scheme_port( lsu->lud_scheme,
430                                 lsu->lud_port );
431
432                         if ( strcmp( lcu->lud_scheme, lsu->lud_scheme ) == 0
433                                 && lcu->lud_host != NULL && *lcu->lud_host != '\0'
434                             && lsu->lud_host != NULL && *lsu->lud_host != '\0'
435                                 && strcasecmp( lsu->lud_host, lcu->lud_host ) == 0
436                             && lsu_port == lcu_port )
437                         {
438                                 return lc;
439                         }
440
441                         if ( !any ) break;
442                 }
443         }
444
445         return NULL;
446 }
447
448
449
450 static void
451 use_connection( LDAP *ld, LDAPConn *lc )
452 {
453         ++lc->lconn_refcnt;
454         lc->lconn_lastused = time( NULL );
455 }
456
457
458 void
459 ldap_free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind )
460 {
461         LDAPConn        *tmplc, *prevlc;
462
463         Debug( LDAP_DEBUG_TRACE, "ldap_free_connection\n", 0, 0, 0 );
464
465         if ( force || --lc->lconn_refcnt <= 0 ) {
466                 if ( lc->lconn_status == LDAP_CONNST_CONNECTED ) {
467                         ldap_mark_select_clear( ld, lc->lconn_sb );
468                         if ( unbind ) {
469                                 ldap_send_unbind( ld, lc->lconn_sb, NULL, NULL );
470                         }
471                 }
472
473                 if( lc->lconn_ber != NULL ) {
474                         ber_free( lc->lconn_ber, 1 );
475                 }
476
477                 ldap_int_sasl_close( ld, lc );
478
479                 prevlc = NULL;
480                 for ( tmplc = ld->ld_conns; tmplc != NULL;
481                     tmplc = tmplc->lconn_next ) {
482                         if ( tmplc == lc ) {
483                                 if ( prevlc == NULL ) {
484                                     ld->ld_conns = tmplc->lconn_next;
485                                 } else {
486                                     prevlc->lconn_next = tmplc->lconn_next;
487                                 }
488                                 break;
489                         }
490                         prevlc = tmplc;
491                 }
492                 ldap_free_urllist( lc->lconn_server );
493 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
494                 if ( lc->lconn_krbinstance != NULL ) {
495                         LDAP_FREE( lc->lconn_krbinstance );
496                 }
497 #endif
498                 if ( lc->lconn_sb != ld->ld_sb ) {
499                         ber_sockbuf_free( lc->lconn_sb );
500                 }
501                 if( lc->lconn_rebind_queue != NULL) {
502                         int i;
503                         for( i = 0; lc->lconn_rebind_queue[i] != NULL; i++) {
504                                 LDAP_VFREE(lc->lconn_rebind_queue[i]);
505                         }
506                         LDAP_FREE( lc->lconn_rebind_queue);
507                 }
508                 LDAP_FREE( lc );
509                 Debug( LDAP_DEBUG_TRACE, "ldap_free_connection: actually freed\n",
510                     0, 0, 0 );
511         } else {
512                 lc->lconn_lastused = time( NULL );
513                 Debug( LDAP_DEBUG_TRACE, "ldap_free_connection: refcnt %d\n",
514                     lc->lconn_refcnt, 0, 0 );
515         }
516 }
517
518
519 #ifdef LDAP_DEBUG
520 void
521 ldap_dump_connection( LDAP *ld, LDAPConn *lconns, int all )
522 {
523         LDAPConn        *lc;
524         char            timebuf[32];
525
526         fprintf( stderr, "** Connection%s:\n", all ? "s" : "" );
527         for ( lc = lconns; lc != NULL; lc = lc->lconn_next ) {
528                 if ( lc->lconn_server != NULL ) {
529                         fprintf( stderr, "* host: %s  port: %d%s\n",
530                             ( lc->lconn_server->lud_host == NULL ) ? "(null)"
531                             : lc->lconn_server->lud_host,
532                             lc->lconn_server->lud_port, ( lc->lconn_sb ==
533                             ld->ld_sb ) ? "  (default)" : "" );
534                 }
535                 fprintf( stderr, "  refcnt: %d  status: %s\n", lc->lconn_refcnt,
536                     ( lc->lconn_status == LDAP_CONNST_NEEDSOCKET ) ?
537                     "NeedSocket" : ( lc->lconn_status ==
538                     LDAP_CONNST_CONNECTING ) ? "Connecting" : "Connected" );
539                 fprintf( stderr, "  last used: %s",
540                     ldap_pvt_ctime( &lc->lconn_lastused, timebuf ));
541                 if( lc->lconn_rebind_inprogress ) {
542                         fprintf( stderr, "  rebind in progress\n");
543                         if( lc->lconn_rebind_queue != NULL) {
544                                 int i = 0;
545                                 for( ;lc->lconn_rebind_queue[i] != NULL; i++) {
546                                         int j = 0;
547                                         for( ;lc->lconn_rebind_queue[i][j] != 0; j++) {
548                                                 fprintf( stderr, "    queue %d entry %d - %s\n",
549                                                         i, j, lc->lconn_rebind_queue[i][j]);
550                                         }
551                                 }
552                         } else {
553                                 fprintf( stderr, "    queue is empty\n");
554                         }
555                 }
556                 fprintf(stderr, "\n");
557                 if ( !all ) {
558                         break;
559                 }
560         }
561 }
562
563
564 void
565 ldap_dump_requests_and_responses( LDAP *ld )
566 {
567         LDAPRequest     *lr;
568         LDAPMessage     *lm, *l;
569
570 #ifdef LDAP_R_COMPILE
571         ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
572 #endif
573         fprintf( stderr, "** Outstanding Requests:\n" );
574         if (( lr = ld->ld_requests ) == NULL ) {
575                 fprintf( stderr, "   Empty\n" );
576         }
577         for ( ; lr != NULL; lr = lr->lr_next ) {
578             fprintf( stderr, " * msgid %d,  origid %d, status %s\n",
579                 lr->lr_msgid, lr->lr_origid,
580                 ( lr->lr_status == LDAP_REQST_INPROGRESS ) ? "InProgress" :
581                 ( lr->lr_status == LDAP_REQST_CHASINGREFS ) ? "ChasingRefs" :
582                 ( lr->lr_status == LDAP_REQST_NOTCONNECTED ) ? "NotConnected" :
583                 ( lr->lr_status == LDAP_REQST_WRITING) ? "Writing" :
584                 ( lr->lr_status == LDAP_REQST_COMPLETED ? "Request Completed" : "Invalid Status"));
585             fprintf( stderr, "   outstanding referrals %d, parent count %d\n",
586                     lr->lr_outrefcnt, lr->lr_parentcnt );
587         }
588 #ifdef LDAP_R_COMPILE
589         ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
590 #endif
591         fprintf( stderr, "** Response Queue:\n" );
592         if (( lm = ld->ld_responses ) == NULL ) {
593                 fprintf( stderr, "   Empty\n" );
594         }
595         for ( ; lm != NULL; lm = lm->lm_next ) {
596                 fprintf( stderr, " * msgid %d,  type %lu\n",
597                     lm->lm_msgid, (unsigned long) lm->lm_msgtype );
598                 if (( l = lm->lm_chain ) != NULL ) {
599                         fprintf( stderr, "   chained responses:\n" );
600                         for ( ; l != NULL; l = l->lm_chain ) {
601                                 fprintf( stderr,
602                                     "  * msgid %d,  type %lu\n",
603                                     l->lm_msgid,
604                                     (unsigned long) l->lm_msgtype );
605                         }
606                 }
607         }
608 }
609 #endif /* LDAP_DEBUG */
610
611 void
612 ldap_free_request_int( LDAP *ld, LDAPRequest *lr )
613 {
614         if ( lr->lr_prev == NULL ) {
615                 ld->ld_requests = lr->lr_next;
616         } else {
617                 lr->lr_prev->lr_next = lr->lr_next;
618         }
619
620         if ( lr->lr_next != NULL ) {
621                 lr->lr_next->lr_prev = lr->lr_prev;
622         }
623
624         if ( lr->lr_ber != NULL ) {
625                 ber_free( lr->lr_ber, 1 );
626         }
627
628         if ( lr->lr_res_error != NULL ) {
629                 LDAP_FREE( lr->lr_res_error );
630         }
631
632         if ( lr->lr_res_matched != NULL ) {
633                 LDAP_FREE( lr->lr_res_matched );
634         }
635
636         LDAP_FREE( lr );
637 }
638
639 void
640 ldap_free_request( LDAP *ld, LDAPRequest *lr )
641 {
642         LDAPRequest     **ttmplr;
643
644         Debug( LDAP_DEBUG_TRACE, "ldap_free_request (origid %d, msgid %d)\n",
645                 lr->lr_origid, lr->lr_msgid, 0 );
646
647         /* free all referrals (child requests) */
648         while ( lr->lr_child )
649                 ldap_free_request( ld, lr->lr_child );
650
651         if ( lr->lr_parent != NULL ) {
652                 --lr->lr_parent->lr_outrefcnt;
653                 for ( ttmplr = &lr->lr_parent->lr_child; *ttmplr && *ttmplr != lr; ttmplr = &(*ttmplr)->lr_refnext ); 
654                 if ( *ttmplr == lr )  
655                         *ttmplr = lr->lr_refnext;
656         }
657         ldap_free_request_int( ld, lr );
658 }
659
660 /*
661  * call first time with *cntp = -1
662  * when returns *cntp == -1, no referrals are left
663  *
664  * NOTE: may replace *refsp, or shuffle the contents
665  * of the original array.
666  */
667 static int ldap_int_nextref(
668         LDAP                    *ld,
669         char                    ***refsp,
670         int                     *cntp,
671         void                    *params )
672 {
673         assert( refsp != NULL );
674         assert( *refsp != NULL );
675         assert( cntp != NULL );
676
677         if ( *cntp < -1 ) {
678                 *cntp = -1;
679                 return -1;
680         }
681
682         (*cntp)++;
683
684         if ( (*refsp)[ *cntp ] == NULL ) {
685                 *cntp = -1;
686         }
687
688         return 0;
689 }
690
691 /*
692  * Chase v3 referrals
693  *
694  * Parameters:
695  *  (IN) ld = LDAP connection handle
696  *  (IN) lr = LDAP Request structure
697  *  (IN) refs = array of pointers to referral strings that we will chase
698  *              The array will be free'd by this function when no longer needed
699  *  (IN) sref != 0 if following search reference
700  *  (OUT) errstrp = Place to return a string of referrals which could not be followed
701  *  (OUT) hadrefp = 1 if sucessfully followed referral
702  *
703  * Return value - number of referrals followed
704  */
705 int
706 ldap_chase_v3referrals( LDAP *ld, LDAPRequest *lr, char **refs, int sref, char **errstrp, int *hadrefp )
707 {
708         char            *unfollowed;
709         int                      unfollowedcnt = 0;
710         LDAPRequest     *origreq;
711         LDAPURLDesc     *srv = NULL;
712         BerElement      *ber;
713         char            **refarray = NULL;
714         LDAPConn        *lc;
715         int                      rc, count, i, j, id;
716         LDAPreqinfo  rinfo;
717
718         ld->ld_errno = LDAP_SUCCESS;    /* optimistic */
719         *hadrefp = 0;
720
721         Debug( LDAP_DEBUG_TRACE, "ldap_chase_v3referrals\n", 0, 0, 0 );
722
723         unfollowed = NULL;
724         rc = count = 0;
725
726         /* If no referrals in array, return */
727         if ( (refs == NULL) || ( (refs)[0] == NULL) ) {
728                 rc = 0;
729                 goto done;
730         }
731
732         /* Check for hop limit exceeded */
733         if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) {
734                 Debug( LDAP_DEBUG_ANY,
735                     "more than %d referral hops (dropping)\n", ld->ld_refhoplimit, 0, 0 );
736                 ld->ld_errno = LDAP_REFERRAL_LIMIT_EXCEEDED;
737             rc = -1;
738                 goto done;
739         }
740
741         /* find original request */
742         for ( origreq = lr;
743                 origreq->lr_parent != NULL;
744                 origreq = origreq->lr_parent )
745         {
746                 /* empty */ ;
747         }
748
749         refarray = refs;
750         refs = NULL;
751
752         if ( ld->ld_nextref_proc == NULL ) {
753                 ld->ld_nextref_proc = ldap_int_nextref;
754         }
755
756         /* parse out & follow referrals */
757         i = -1;
758         for ( ld->ld_nextref_proc( ld, &refarray, &i, ld->ld_nextref_params );
759                         i != -1;
760                         ld->ld_nextref_proc( ld, &refarray, &i, ld->ld_nextref_params ) )
761         {
762
763                 /* Parse the referral URL */
764                 if (( rc = ldap_url_parse_ext( refarray[i], &srv)) != LDAP_SUCCESS) {
765                         ld->ld_errno = rc;
766                         rc = -1;
767                         goto done;
768                 }
769
770                 if( srv->lud_crit_exts ) {
771                         /* we do not support any extensions */
772                         ld->ld_errno = LDAP_NOT_SUPPORTED;
773                         rc = -1;
774                         goto done;
775                 }
776
777                 /* treat ldap://hostpart and ldap://hostpart/ the same */
778                 if ( srv->lud_dn && srv->lud_dn[0] == '\0' ) {
779                         LDAP_FREE( srv->lud_dn );
780                         srv->lud_dn = NULL;
781                 }
782
783                 /* check connection for re-bind in progress */
784                 if (( lc = find_connection( ld, srv, 1 )) != NULL ) {
785                         if( lc->lconn_rebind_inprogress) {
786                                 /* We are already chasing a referral or search reference and a
787                                  * bind on that connection is in progress.  We must queue
788                                  * referrals on that connection, so we don't get a request
789                                  * going out before the bind operation completes. This happens
790                                  * if two search references come in one behind the other
791                                  * for the same server with different contexts.
792                                  */
793                                 Debug( LDAP_DEBUG_TRACE,
794                                         "ldap_chase_v3referrals: queue referral \"%s\"\n",
795                                         refarray[i], 0, 0);
796                                 if( lc->lconn_rebind_queue == NULL ) {
797                                         /* Create a referral list */
798                                         lc->lconn_rebind_queue =
799                                                 (char ***) LDAP_MALLOC( sizeof(void *) * 2);
800
801                                         if( lc->lconn_rebind_queue == NULL) {
802                                                 ld->ld_errno = LDAP_NO_MEMORY;
803                                                 rc = -1;
804                                                 goto done;
805                                         }
806
807                                         lc->lconn_rebind_queue[0] = refarray;
808                                         lc->lconn_rebind_queue[1] = NULL;
809                                         refarray = NULL;
810
811                                 } else {
812                                         /* Count how many referral arrays we already have */
813                                         for( j = 0; lc->lconn_rebind_queue[j] != NULL; j++) {
814                                                 /* empty */;
815                                         }
816
817                                         /* Add the new referral to the list */
818                                         lc->lconn_rebind_queue = (char ***) LDAP_REALLOC(
819                                                 lc->lconn_rebind_queue, sizeof(void *) * (j + 2));
820
821                                         if( lc->lconn_rebind_queue == NULL ) {
822                                                 ld->ld_errno = LDAP_NO_MEMORY;
823                                                 rc = -1;
824                                                 goto done;
825                                         }
826                                         lc->lconn_rebind_queue[j] = refarray;
827                                         lc->lconn_rebind_queue[j+1] = NULL;
828                                         refarray = NULL;
829                                 }
830
831                                 /* We have queued the referral/reference, now just return */
832                                 rc = 0;
833                                 *hadrefp = 1;
834                                 count = 1; /* Pretend we already followed referral */
835                                 goto done;
836                         }
837                 } 
838                 /* Re-encode the request with the new starting point of the search.
839                  * Note: In the future we also need to replace the filter if one
840                  * was provided with the search reference
841                  */
842
843                 /* For references we don't want old dn if new dn empty */
844                 if ( sref && srv->lud_dn == NULL ) {
845                         srv->lud_dn = LDAP_STRDUP( "" );
846                 }
847
848                 LDAP_NEXT_MSGID( ld, id );
849                 ber = re_encode_request( ld, origreq->lr_ber, id,
850                         sref, srv, &rinfo.ri_request );
851
852                 if( ber == NULL ) {
853                         ld->ld_errno = LDAP_ENCODING_ERROR;
854                         rc = -1;
855                         goto done;
856                 }
857
858                 Debug( LDAP_DEBUG_TRACE,
859                         "ldap_chase_v3referral: msgid %d, url \"%s\"\n",
860                         lr->lr_msgid, refarray[i], 0);
861
862                 /* Send the new request to the server - may require a bind */
863                 rinfo.ri_msgid = origreq->lr_origid;
864                 rinfo.ri_url = refarray[i];
865 #ifdef LDAP_R_COMPILE
866                 ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
867 #endif
868                 rc = ldap_send_server_request( ld, ber, id,
869                         origreq, srv, NULL, &rinfo );
870 #ifdef LDAP_R_COMPILE
871                 ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
872 #endif
873                 if ( rc < 0 ) {
874                         /* Failure, try next referral in the list */
875                         Debug( LDAP_DEBUG_ANY, "Unable to chase referral \"%s\" (%s)\n", 
876                                 refarray[i], ldap_err2string( ld->ld_errno ), 0);
877                         unfollowedcnt += ldap_append_referral( ld, &unfollowed, refarray[i]);
878                         ldap_free_urllist(srv);
879                         srv = NULL;
880                 } else {
881                         /* Success, no need to try this referral list further */
882                         rc = 0;
883                         ++count;
884                         *hadrefp = 1;
885
886                         /* check if there is a queue of referrals that came in during bind */
887                         if( lc == NULL) {
888                                 if (( lc = find_connection( ld, srv, 1 )) == NULL ) {
889                                         ld->ld_errno = LDAP_OPERATIONS_ERROR;
890                                         rc = -1;
891                                         goto done;
892                                 }
893                         }
894
895                         if( lc->lconn_rebind_queue != NULL) {
896                                 /* Release resources of previous list */
897                                 LDAP_VFREE(refarray);
898                                 refarray = NULL;
899                                 ldap_free_urllist(srv);
900                                 srv = NULL;
901
902                                 /* Pull entries off end of queue so list always null terminated */
903                                 for( j = 0; lc->lconn_rebind_queue[j] != NULL; j++) {
904                                         ;
905                                 }
906                                 refarray = lc->lconn_rebind_queue[j-1];
907                                 lc->lconn_rebind_queue[j-1] = NULL;
908                                 /* we pulled off last entry from queue, free queue */
909                                 if ( j == 1 ) {
910                                         LDAP_FREE( lc->lconn_rebind_queue);
911                                         lc->lconn_rebind_queue = NULL;
912                                 }
913                                 /* restart the loop the with new referral list */
914                                 i = -1;
915                                 continue;
916                         }
917                         break; /* referral followed, break out of for loop */
918                 }
919         } /* end for loop */
920 done:
921         LDAP_VFREE(refarray);
922         ldap_free_urllist(srv);
923         LDAP_FREE( *errstrp );
924         
925         if( rc == 0) {
926                 *errstrp = NULL;
927                 LDAP_FREE( unfollowed );
928                 return count;
929         } else {
930                 ld->ld_errno = LDAP_REFERRAL;
931                 *errstrp = unfollowed;
932                 return rc;
933         }
934 }
935
936 /*
937  * XXX merging of errors in this routine needs to be improved
938  */
939 int
940 ldap_chase_referrals( LDAP *ld,
941         LDAPRequest *lr,
942         char **errstrp,
943         int sref,
944         int *hadrefp )
945 {
946         int             rc, count, id;
947         unsigned        len;
948         char            *p, *ref, *unfollowed;
949         LDAPRequest     *origreq;
950         LDAPURLDesc     *srv;
951         BerElement      *ber;
952         LDAPreqinfo  rinfo;
953
954         Debug( LDAP_DEBUG_TRACE, "ldap_chase_referrals\n", 0, 0, 0 );
955
956         ld->ld_errno = LDAP_SUCCESS;    /* optimistic */
957         *hadrefp = 0;
958
959         if ( *errstrp == NULL ) {
960                 return( 0 );
961         }
962
963         len = strlen( *errstrp );
964         for ( p = *errstrp; len >= LDAP_REF_STR_LEN; ++p, --len ) {
965                 if ( strncasecmp( p, LDAP_REF_STR, LDAP_REF_STR_LEN ) == 0 ) {
966                         *p = '\0';
967                         p += LDAP_REF_STR_LEN;
968                         break;
969                 }
970         }
971
972         if ( len < LDAP_REF_STR_LEN ) {
973                 return( 0 );
974         }
975
976         if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) {
977                 Debug( LDAP_DEBUG_ANY,
978                     "more than %d referral hops (dropping)\n",
979                     ld->ld_refhoplimit, 0, 0 );
980                     /* XXX report as error in ld->ld_errno? */
981                     return( 0 );
982         }
983
984         /* find original request */
985         for ( origreq = lr; origreq->lr_parent != NULL;
986              origreq = origreq->lr_parent ) {
987                 /* empty */;
988         }
989
990         unfollowed = NULL;
991         rc = count = 0;
992
993         /* parse out & follow referrals */
994         for ( ref = p; rc == 0 && ref != NULL; ref = p ) {
995                 if (( p = strchr( ref, '\n' )) != NULL ) {
996                         *p++ = '\0';
997                 } else {
998                         p = NULL;
999                 }
1000
1001                 rc = ldap_url_parse_ext( ref, &srv );
1002
1003                 if ( rc != LDAP_URL_SUCCESS ) {
1004                         Debug( LDAP_DEBUG_TRACE,
1005                             "ignoring unknown referral <%s>\n", ref, 0, 0 );
1006                         rc = ldap_append_referral( ld, &unfollowed, ref );
1007                         *hadrefp = 1;
1008                         continue;
1009                 }
1010
1011                 if( srv->lud_dn != NULL && srv->lud_dn == '\0' ) {
1012                         LDAP_FREE( srv->lud_dn );
1013                         srv->lud_dn = NULL;
1014                 }
1015
1016                 Debug( LDAP_DEBUG_TRACE,
1017                     "chasing LDAP referral: <%s>\n", ref, 0, 0 );
1018
1019                 *hadrefp = 1;
1020
1021                 LDAP_NEXT_MSGID( ld, id );
1022                 ber = re_encode_request( ld, origreq->lr_ber,
1023                     id, sref, srv, &rinfo.ri_request );
1024
1025                 if( ber == NULL ) {
1026                         return -1 ;
1027                 }
1028
1029                 /* copy the complete referral for rebind process */
1030                 rinfo.ri_url = LDAP_STRDUP( ref );
1031
1032                 rinfo.ri_msgid = origreq->lr_origid;
1033
1034 #ifdef LDAP_R_COMPILE
1035         ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
1036 #endif
1037                 rc = ldap_send_server_request( ld, ber, id,
1038                     lr, srv, NULL, &rinfo );
1039 #ifdef LDAP_R_COMPILE
1040         ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
1041 #endif
1042
1043                 LDAP_FREE( rinfo.ri_url );
1044
1045                 if( rc >= 0 ) {
1046                         ++count;
1047                 } else {
1048                         Debug( LDAP_DEBUG_ANY,
1049                             "Unable to chase referral (%s)\n", 
1050                             ldap_err2string( ld->ld_errno ), 0, 0 );
1051                         rc = ldap_append_referral( ld, &unfollowed, ref );
1052                 }
1053
1054                 ldap_free_urllist(srv);
1055         }
1056
1057         LDAP_FREE( *errstrp );
1058         *errstrp = unfollowed;
1059
1060         return(( rc == 0 ) ? count : rc );
1061 }
1062
1063
1064 int
1065 ldap_append_referral( LDAP *ld, char **referralsp, char *s )
1066 {
1067         int     first;
1068
1069         if ( *referralsp == NULL ) {
1070                 first = 1;
1071                 *referralsp = (char *)LDAP_MALLOC( strlen( s ) + LDAP_REF_STR_LEN
1072                     + 1 );
1073         } else {
1074                 first = 0;
1075                 *referralsp = (char *)LDAP_REALLOC( *referralsp,
1076                     strlen( *referralsp ) + strlen( s ) + 2 );
1077         }
1078
1079         if ( *referralsp == NULL ) {
1080                 ld->ld_errno = LDAP_NO_MEMORY;
1081                 return( -1 );
1082         }
1083
1084         if ( first ) {
1085                 strcpy( *referralsp, LDAP_REF_STR );
1086         } else {
1087                 strcat( *referralsp, "\n" );
1088         }
1089         strcat( *referralsp, s );
1090
1091         return( 0 );
1092 }
1093
1094
1095
1096 static BerElement *
1097 re_encode_request( LDAP *ld,
1098         BerElement *origber,
1099         ber_int_t msgid,
1100         int sref,
1101         LDAPURLDesc *srv,
1102         int *type )
1103 {
1104         /*
1105          * XXX this routine knows way too much about how the lber library works!
1106          */
1107         ber_int_t       along;
1108         ber_tag_t       tag;
1109         ber_tag_t       rtag;
1110         ber_int_t       ver;
1111         ber_int_t       scope;
1112         int             rc;
1113         BerElement      tmpber, *ber;
1114         char            *orig_dn;
1115         char            *dn;
1116
1117         Debug( LDAP_DEBUG_TRACE,
1118             "re_encode_request: new msgid %ld, new dn <%s>\n",
1119             (long) msgid,
1120                 ( srv == NULL || srv->lud_dn == NULL) ? "NONE" : srv->lud_dn, 0 );
1121
1122         tmpber = *origber;
1123
1124         /*
1125          * all LDAP requests are sequences that start with a message id.
1126          * For all except delete, this is followed by a sequence that is
1127          * tagged with the operation code.  For delete, the provided DN
1128          * is not wrapped by a sequence.
1129          */
1130         rtag = ber_scanf( &tmpber, "{it", /*}*/ &along, &tag );
1131
1132         if ( rtag == LBER_ERROR ) {
1133                 ld->ld_errno = LDAP_DECODING_ERROR;
1134                 return( NULL );
1135         }
1136
1137         assert( tag != 0);
1138         if ( tag == LDAP_REQ_BIND ) {
1139                 /* bind requests have a version number before the DN & other stuff */
1140                 rtag = ber_scanf( &tmpber, "{ia" /*}*/, &ver, &orig_dn );
1141
1142         } else if ( tag == LDAP_REQ_DELETE ) {
1143                 /* delete requests don't have a DN wrapping sequence */
1144                 rtag = ber_scanf( &tmpber, "a", &orig_dn );
1145
1146         } else if ( tag == LDAP_REQ_SEARCH ) {
1147                 /* search requests need to be re-scope-ed */
1148                 rtag = ber_scanf( &tmpber, "{ae" /*"}"*/, &orig_dn, &scope );
1149
1150                 if( srv->lud_scope != LDAP_SCOPE_DEFAULT ) {
1151                         /* use the scope provided in reference */
1152                         scope = srv->lud_scope;
1153
1154                 } else if ( sref ) {
1155                         /* use scope implied by previous operation
1156                          *   base -> base
1157                          *   one -> base
1158                          *   subtree -> subtree
1159                          *   subordinate -> subtree
1160                          */
1161                         switch( scope ) {
1162                         default:
1163                         case LDAP_SCOPE_BASE:
1164                         case LDAP_SCOPE_ONELEVEL:
1165                                 scope = LDAP_SCOPE_BASE;
1166                                 break;
1167                         case LDAP_SCOPE_SUBTREE:
1168 #ifdef LDAP_SCOPE_SUBORDINATE
1169                         case LDAP_SCOPE_SUBORDINATE:
1170 #endif
1171                                 scope = LDAP_SCOPE_SUBTREE;
1172                                 break;
1173                         }
1174                 }
1175
1176         } else {
1177                 rtag = ber_scanf( &tmpber, "{a" /*}*/, &orig_dn );
1178         }
1179
1180         if( rtag == LBER_ERROR ) {
1181                 ld->ld_errno = LDAP_DECODING_ERROR;
1182                 return NULL;
1183         }
1184
1185         if (( ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
1186                 return NULL;
1187         }
1188
1189         if ( srv->lud_dn == NULL ) {
1190                 dn = orig_dn;
1191         } else {
1192                 dn = srv->lud_dn;
1193         }
1194
1195         if ( tag == LDAP_REQ_BIND ) {
1196                 rc = ber_printf( ber, "{it{is" /*}}*/, msgid, tag, ver, dn );
1197         } else if ( tag == LDAP_REQ_DELETE ) {
1198                 rc = ber_printf( ber, "{itsN}", msgid, tag, dn );
1199         } else if ( tag == LDAP_REQ_SEARCH ) {
1200                 rc = ber_printf( ber, "{it{se" /*}}*/, msgid, tag, dn, scope );
1201         } else {
1202                 rc = ber_printf( ber, "{it{s" /*}}*/, msgid, tag, dn );
1203         }
1204
1205         LDAP_FREE( orig_dn );
1206
1207         if ( rc == -1 ) {
1208                 ld->ld_errno = LDAP_ENCODING_ERROR;
1209                 ber_free( ber, 1 );
1210                 return NULL;
1211         }
1212
1213         if ( tag != LDAP_REQ_DELETE && (
1214                 ber_write(ber, tmpber.ber_ptr, ( tmpber.ber_end - tmpber.ber_ptr ), 0)
1215                 != ( tmpber.ber_end - tmpber.ber_ptr ) ||
1216             ber_printf( ber, /*{{*/ "N}N}" ) == -1 ) )
1217         {
1218                 ld->ld_errno = LDAP_ENCODING_ERROR;
1219                 ber_free( ber, 1 );
1220                 return NULL;
1221         }
1222
1223 #ifdef LDAP_DEBUG
1224         if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
1225                 Debug( LDAP_DEBUG_ANY, "re_encode_request new request is:\n",
1226                     0, 0, 0 );
1227                 ber_log_dump( LDAP_DEBUG_BER, ldap_debug, ber, 0 );
1228         }
1229 #endif /* LDAP_DEBUG */
1230
1231         *type = tag;    /* return request type */
1232         return ber;
1233 }
1234
1235
1236 LDAPRequest *
1237 ldap_find_request_by_msgid( LDAP *ld, ber_int_t msgid )
1238 {
1239         LDAPRequest     *lr;
1240
1241 #ifdef LDAP_R_COMPILE
1242         ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
1243 #endif
1244         for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
1245                 if( lr->lr_status == LDAP_REQST_COMPLETED ) {
1246                         continue;       /* Skip completed requests */
1247                 }
1248                 if ( msgid == lr->lr_msgid ) {
1249                         break;
1250                 }
1251         }
1252 #ifdef LDAP_R_COMPILE
1253         ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
1254 #endif
1255
1256         return( lr );
1257 }
1258
1259