xref: /illumos-gate/usr/src/lib/libldap5/sources/ldap/common/request.c (revision ab1dc24c6acfdc9f747c86754a3465807c31869c)
1  /*
2   * Copyright 2001-2003 Sun Microsystems, Inc.  All rights reserved.
3   * Use is subject to license terms.
4   */
5  
6  /*
7   * The contents of this file are subject to the Netscape Public
8   * License Version 1.1 (the "License"); you may not use this file
9   * except in compliance with the License. You may obtain a copy of
10   * the License at http://www.mozilla.org/NPL/
11   *
12   * Software distributed under the License is distributed on an "AS
13   * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14   * implied. See the License for the specific language governing
15   * rights and limitations under the License.
16   *
17   * The Original Code is Mozilla Communicator client code, released
18   * March 31, 1998.
19   *
20   * The Initial Developer of the Original Code is Netscape
21   * Communications Corporation. Portions created by Netscape are
22   * Copyright (C) 1998-1999 Netscape Communications Corporation. All
23   * Rights Reserved.
24   *
25   * Contributor(s):
26   */
27  /*
28   *  Copyright (c) 1995 Regents of the University of Michigan.
29   *  All rights reserved.
30   */
31  /*
32   *  request.c - sending of ldap requests; handling of referrals
33   */
34  
35  #if 0
36  #ifndef lint
37  static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
38  #endif
39  #endif
40  
41  #include "ldap-int.h"
42  
43  static LDAPConn *find_connection( LDAP *ld, LDAPServer *srv, int any );
44  static void use_connection( LDAP *ld, LDAPConn *lc );
45  static void free_servers( LDAPServer *srvlist );
46  static int chase_one_referral( LDAP *ld, LDAPRequest *lr, LDAPRequest *origreq,
47      char *refurl, char *desc, int *unknownp );
48  static int re_encode_request( LDAP *ld, BerElement *origber,
49      int msgid, LDAPURLDesc *ludp, BerElement **berp );
50  
51  #ifdef LDAP_DNS
52  static LDAPServer *dn2servers( LDAP *ld, char *dn );
53  #endif /* LDAP_DNS */
54  
55  
56  /* returns an LDAP error code and also sets error inside LDAP * */
57  int
58  nsldapi_alloc_ber_with_options( LDAP *ld, BerElement **berp )
59  {
60  	int	err;
61  
62  	LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
63      	if (( *berp = ber_alloc_t( ld->ld_lberoptions )) == NULLBER ) {
64  		err = LDAP_NO_MEMORY;
65  		LDAP_SET_LDERRNO( ld, err, NULL, NULL );
66  	} else {
67  		err = LDAP_SUCCESS;
68  #ifdef STR_TRANSLATION
69  		nsldapi_set_ber_options( ld, *berp );
70  #endif /* STR_TRANSLATION */
71  	}
72  	LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
73  
74  	return( err );
75  }
76  
77  
78  void
79  nsldapi_set_ber_options( LDAP *ld, BerElement *ber )
80  {
81  	ber->ber_options = ld->ld_lberoptions;
82  #ifdef STR_TRANSLATION
83  	if (( ld->ld_lberoptions & LBER_OPT_TRANSLATE_STRINGS ) != 0 ) {
84  		ber_set_string_translators( ber,
85  		    ld->ld_lber_encode_translate_proc,
86  		    ld->ld_lber_decode_translate_proc );
87  	}
88  #endif /* STR_TRANSLATION */
89  }
90  
91  
92  /* returns the message id of the request or -1 if an error occurs */
93  int
94  nsldapi_send_initial_request( LDAP *ld, int msgid, unsigned long msgtype,
95  	char *dn, BerElement *ber )
96  {
97  	LDAPServer	*servers;
98  
99  	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_send_initial_request\n", 0,0,0 );
100  
101  #ifdef LDAP_DNS
102  	LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
103  	if (( ld->ld_options & LDAP_BITOPT_DNS ) != 0 && ldap_is_dns_dn( dn )) {
104  		if (( servers = dn2servers( ld, dn )) == NULL ) {
105  			ber_free( ber, 1 );
106  			LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
107  			return( -1 );
108  		}
109  
110  #ifdef LDAP_DEBUG
111  		if ( ldap_debug & LDAP_DEBUG_TRACE ) {
112  			LDAPServer	*srv;
113  			char    msg[256];
114  
115  			for ( srv = servers; srv != NULL;
116  			    srv = srv->lsrv_next ) {
117  				sprintf( msg,
118  				    "LDAP server %s:  dn %s, port %d\n",
119  				    srv->lsrv_host, ( srv->lsrv_dn == NULL ) ?
120  				    "(default)" : srv->lsrv_dn,
121  				    srv->lsrv_port );
122  				ber_err_print( msg );
123  			}
124  		}
125  #endif /* LDAP_DEBUG */
126  	} else {
127  #endif /* LDAP_DNS */
128  		/*
129  		 * use of DNS is turned off or this is an LDAP DN...
130  		 * use our default connection
131  		 */
132  		servers = NULL;
133  #ifdef LDAP_DNS
134  	}
135  	LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
136  #endif /* LDAP_DNS */
137  
138  	return( nsldapi_send_server_request( ld, ber, msgid, NULL,
139  	    servers, NULL, ( msgtype == LDAP_REQ_BIND ) ? dn : NULL, 0 ));
140  }
141  
142  
143  /* returns the message id of the request or -1 if an error occurs */
144  int
145  nsldapi_send_server_request(
146      LDAP *ld,			/* session handle */
147      BerElement *ber,		/* message to send */
148      int msgid,			/* ID of message to send */
149      LDAPRequest *parentreq,	/* non-NULL for referred requests */
150      LDAPServer *srvlist,	/* servers to connect to (NULL for default) */
151      LDAPConn *lc,		/* connection to use (NULL for default) */
152      char *bindreqdn,		/* non-NULL for bind requests */
153      int bind			/* perform a bind after opening new conn.? */
154  )
155  {
156  	LDAPRequest	*lr;
157  	int		err;
158  	int		incparent;	/* did we bump parent's ref count? */
159  
160  	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_send_server_request\n", 0, 0, 0 );
161  
162  	incparent = 0;
163  	LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK );
164  	if ( lc == NULL ) {
165  		if ( srvlist == NULL ) {
166  			if ( ld->ld_defconn == NULL ) {
167  				LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
168  				if ( bindreqdn == NULL && ( ld->ld_options
169  				    & LDAP_BITOPT_RECONNECT ) != 0 ) {
170  					LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN,
171  					    NULL, NULL );
172  					ber_free( ber, 1 );
173  					LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
174  					LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
175  					return( -1 );
176  				}
177  				LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
178  
179  				if ( nsldapi_open_ldap_defconn( ld ) < 0 ) {
180  					ber_free( ber, 1 );
181  					LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
182  					return( -1 );
183  				}
184  			}
185  			lc = ld->ld_defconn;
186  		} else {
187  			if (( lc = find_connection( ld, srvlist, 1 )) ==
188  			    NULL ) {
189  				if ( bind && (parentreq != NULL) ) {
190  					/* Remember the bind in the parent */
191  					incparent = 1;
192  					++parentreq->lr_outrefcnt;
193  				}
194  
195  				lc = nsldapi_new_connection( ld, &srvlist, 0,
196  					1, bind );
197  			}
198  			free_servers( srvlist );
199  		}
200  	}
201  
202  
203      /*
204       * the logic here is:
205       * if
206       * 1. no connections exists,
207       * or
208       * 2. if the connection is either not in the connected
209       *     or connecting state in an async io model
210       * or
211       * 3. the connection is notin a connected state with normal (non async io)
212       */
213  	if (   lc == NULL
214  		|| (  (ld->ld_options & LDAP_BITOPT_ASYNC
215                 && lc->lconn_status != LDAP_CONNST_CONNECTING
216  		    && lc->lconn_status != LDAP_CONNST_CONNECTED)
217                || (!(ld->ld_options & LDAP_BITOPT_ASYNC )
218  		    && lc->lconn_status != LDAP_CONNST_CONNECTED) ) ) {
219  
220  		ber_free( ber, 1 );
221  		if ( lc != NULL ) {
222  			LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
223  		}
224  		if ( incparent ) {
225  			/* Forget about the bind */
226  			--parentreq->lr_outrefcnt;
227  		}
228  		LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
229  		return( -1 );
230  	}
231  
232  	use_connection( ld, lc );
233  	if (( lr = (LDAPRequest *)NSLDAPI_CALLOC( 1, sizeof( LDAPRequest ))) ==
234  	    NULL || ( bindreqdn != NULL && ( bindreqdn =
235  	    nsldapi_strdup( bindreqdn )) == NULL )) {
236  		if ( lr != NULL ) {
237  			NSLDAPI_FREE( lr );
238  		}
239  		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
240  		nsldapi_free_connection( ld, lc, NULL, NULL, 0, 0 );
241  		ber_free( ber, 1 );
242  		if ( incparent ) {
243  			/* Forget about the bind */
244  			--parentreq->lr_outrefcnt;
245  		}
246  		LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
247  		return( -1 );
248  	}
249  	lr->lr_binddn = bindreqdn;
250  	lr->lr_msgid = msgid;
251  	lr->lr_status = LDAP_REQST_INPROGRESS;
252  	lr->lr_res_errno = LDAP_SUCCESS;	/* optimistic */
253  	lr->lr_ber = ber;
254  	lr->lr_conn = lc;
255  
256  	if ( parentreq != NULL ) {	/* sub-request */
257  		if ( !incparent ) {
258  			/* Increment if we didn't do it before the bind */
259  			++parentreq->lr_outrefcnt;
260  		}
261  		lr->lr_origid = parentreq->lr_origid;
262  		lr->lr_parentcnt = parentreq->lr_parentcnt + 1;
263  		lr->lr_parent = parentreq;
264  		if ( parentreq->lr_child != NULL ) {
265  			lr->lr_sibling = parentreq->lr_child;
266  		}
267  		parentreq->lr_child = lr;
268  	} else {			/* original request */
269  		lr->lr_origid = lr->lr_msgid;
270  	}
271  
272  	LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
273  	if (( lr->lr_next = ld->ld_requests ) != NULL ) {
274  		lr->lr_next->lr_prev = lr;
275  	}
276  	ld->ld_requests = lr;
277  	lr->lr_prev = NULL;
278  
279  	if (( err = nsldapi_ber_flush( ld, lc->lconn_sb, ber, 0, 1 )) != 0 ) {
280  
281  		/* need to continue write later */
282  		if (ld->ld_options & LDAP_BITOPT_ASYNC && err == -2 ) {
283  			lr->lr_status = LDAP_REQST_WRITING;
284  			nsldapi_iostatus_interest_write( ld, lc->lconn_sb );
285  		} else {
286  
287  			LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
288  			nsldapi_free_request( ld, lr, 0 );
289  			nsldapi_free_connection( ld, lc, NULL, NULL, 0, 0 );
290  			LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
291  			LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
292  			return( -1 );
293  		}
294  
295  	} else {
296  		if ( parentreq == NULL ) {
297  			ber->ber_end = ber->ber_ptr;
298  			ber->ber_ptr = ber->ber_buf;
299  		}
300  
301  		/* sent -- waiting for a response */
302  		if (ld->ld_options & LDAP_BITOPT_ASYNC) {
303  			lc->lconn_status = LDAP_CONNST_CONNECTED;
304  		}
305  
306  		nsldapi_iostatus_interest_read( ld, lc->lconn_sb );
307  	}
308  	LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
309  	LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK );
310  
311  	LDAP_SET_LDERRNO( ld, LDAP_SUCCESS, NULL, NULL );
312  	return( msgid );
313  }
314  
315  
316  /*
317   * returns -1 if a fatal error occurs.  If async is non-zero and the flush
318   * would block, -2 is returned.
319   */
320  int
321  nsldapi_ber_flush( LDAP *ld, Sockbuf *sb, BerElement *ber, int freeit,
322  	int async )
323  {
324  	int	terrno;
325  
326  	for ( ;; ) {
327  		 /*
328  		  * ber_flush() doesn't set errno on EOF, so we pre-set it to
329  		  * zero to avoid getting tricked by leftover "EAGAIN" errors
330  		  */
331  		LDAP_SET_ERRNO( ld, 0 );
332  
333  		if ( ber_flush( sb, ber, freeit ) == 0 ) {
334  			return( 0 );	/* success */
335  		}
336  
337  		terrno = LDAP_GET_ERRNO( ld );
338  
339          if (ld->ld_options & LDAP_BITOPT_ASYNC) {
340              if ( terrno != 0 && !NSLDAPI_ERRNO_IO_INPROGRESS( terrno )) {
341                  nsldapi_connection_lost_nolock( ld, sb );
342                  return( -1 );	/* fatal error */
343              }
344          }
345          else if ( !NSLDAPI_ERRNO_IO_INPROGRESS( terrno )) {
346  
347  			nsldapi_connection_lost_nolock( ld, sb );
348  			return( -1 );	/* fatal error */
349  		}
350  
351  		if ( async ) {
352  			return( -2 );	/* would block */
353  		}
354  	}
355  }
356  
357  LDAPConn *
358  nsldapi_new_connection( LDAP *ld, LDAPServer **srvlistp, int use_ldsb,
359  	int connect, int bind )
360  {
361      int	rc;
362  
363  	LDAPConn	*lc;
364  	LDAPServer	*prevsrv, *srv;
365  	Sockbuf		*sb = NULL;
366  
367  	/*
368  	 * make a new LDAP server connection
369  	 */
370  	if (( lc = (LDAPConn *)NSLDAPI_CALLOC( 1, sizeof( LDAPConn ))) == NULL
371  	    || ( !use_ldsb && ( sb = ber_sockbuf_alloc()) == NULL )) {
372  		if ( lc != NULL ) {
373  			NSLDAPI_FREE( (char *)lc );
374  		}
375  		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
376  		return( NULL );
377  	}
378  
379  	LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
380  	if ( !use_ldsb ) {
381  		/*
382  		 * we have allocated a new sockbuf
383  		 * set I/O routines to match those in default LDAP sockbuf
384  		 */
385  		IFP				sb_fn;
386  		struct lber_x_ext_io_fns	extiofns;
387  
388  		extiofns.lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
389  
390  		if ( ber_sockbuf_get_option( ld->ld_sbp,
391  		    LBER_SOCKBUF_OPT_EXT_IO_FNS, &extiofns ) == 0 ) {
392  			ber_sockbuf_set_option( sb,
393  			    LBER_SOCKBUF_OPT_EXT_IO_FNS, &extiofns );
394  		}
395  		if ( ber_sockbuf_get_option( ld->ld_sbp,
396  		    LBER_SOCKBUF_OPT_READ_FN, (void *)&sb_fn ) == 0
397  		    && sb_fn != NULL ) {
398  			ber_sockbuf_set_option( sb, LBER_SOCKBUF_OPT_READ_FN,
399  			    (void *)sb_fn );
400  		}
401  		if ( ber_sockbuf_get_option( ld->ld_sbp,
402  		    LBER_SOCKBUF_OPT_WRITE_FN, (void *)&sb_fn ) == 0
403  		    && sb_fn != NULL ) {
404  			ber_sockbuf_set_option( sb, LBER_SOCKBUF_OPT_WRITE_FN,
405  			    (void *)sb_fn );
406  		}
407  	}
408  
409  	lc->lconn_sb = ( use_ldsb ) ? ld->ld_sbp : sb;
410  	lc->lconn_version = ld->ld_version;	/* inherited */
411  	LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK );
412  
413  	if ( connect ) {
414  		prevsrv = NULL;
415          /*
416           * save the return code for later
417           */
418  		for ( srv = *srvlistp; srv != NULL; srv = srv->lsrv_next ) {
419  			rc = nsldapi_connect_to_host( ld, lc->lconn_sb,
420  				   srv->lsrv_host, srv->lsrv_port,
421  			       (  srv->lsrv_options & LDAP_SRV_OPT_SECURE ) != 0,
422  					&lc->lconn_krbinstance );
423  			if (rc != -1) {
424  				break;
425  			}
426  			prevsrv = srv;
427  		}
428  
429  		if ( srv == NULL ) {
430  		    if ( !use_ldsb ) {
431  			NSLDAPI_FREE( (char *)lc->lconn_sb );
432  		    }
433  		    NSLDAPI_FREE( (char *)lc );
434  		    /* nsldapi_open_ldap_connection has already set ld_errno */
435  		    return( NULL );
436  		}
437  
438  		if ( prevsrv == NULL ) {
439  		    *srvlistp = srv->lsrv_next;
440  		} else {
441  		    prevsrv->lsrv_next = srv->lsrv_next;
442  		}
443  		lc->lconn_server = srv;
444  	}
445  
446  	if (ld->ld_options & LDAP_BITOPT_ASYNC && rc == -2)
447      {
448          lc->lconn_status = LDAP_CONNST_CONNECTING;
449      }
450      else {
451          lc->lconn_status = LDAP_CONNST_CONNECTED;
452      }
453  
454  	lc->lconn_next = ld->ld_conns;
455  	ld->ld_conns = lc;
456  
457  	/*
458  	 * XXX for now, we always do a synchronous bind.  This will have
459  	 * to change in the long run...
460  	 */
461  	if ( bind ) {
462  		int		err, lderr, freepasswd, authmethod;
463  		char		*binddn, *passwd;
464  		LDAPConn	*savedefconn;
465  
466  		freepasswd = err = 0;
467  
468  		if ( ld->ld_rebind_fn == NULL ) {
469  			binddn = passwd = "";
470  			authmethod = LDAP_AUTH_SIMPLE;
471  		} else {
472  			if (( lderr = (*ld->ld_rebind_fn)( ld, &binddn, &passwd,
473  			    &authmethod, 0, ld->ld_rebind_arg ))
474  			    == LDAP_SUCCESS ) {
475  				freepasswd = 1;
476  			} else {
477  				LDAP_SET_LDERRNO( ld, lderr, NULL, NULL );
478  				err = -1;
479  			}
480  		}
481  
482  
483  		if ( err == 0 ) {
484  			savedefconn = ld->ld_defconn;
485  			ld->ld_defconn = lc;
486  			++lc->lconn_refcnt;	/* avoid premature free */
487  
488  			/*
489  			 * when binding, we will back down as low as LDAPv2
490  			 * if we get back "protocol error" from bind attempts
491  			 */
492  			for ( ;; ) {
493  				/* LDAP_MUTEX_UNLOCK(ld, LDAP_CONN_LOCK); */
494  				if (( lderr = ldap_bind_s( ld, binddn, passwd,
495  				    authmethod )) == LDAP_SUCCESS ) {
496  					/* LDAP_MUTEX_LOCK(ld, LDAP_CONN_LOCK); */
497  					break;
498  				}
499  				/* LDAP_MUTEX_LOCK(ld, LDAP_CONN_LOCK); */
500  				if ( lc->lconn_version <= LDAP_VERSION2
501  				    || lderr != LDAP_PROTOCOL_ERROR ) {
502  					err = -1;
503  					break;
504  				}
505  				--lc->lconn_version;	/* try lower version */
506  			}
507  			--lc->lconn_refcnt;
508  			ld->ld_defconn = savedefconn;
509  		}
510  
511  		if ( freepasswd ) {
512  			(*ld->ld_rebind_fn)( ld, &binddn, &passwd,
513  				&authmethod, 1, ld->ld_rebind_arg );
514  		}
515  
516  		if ( err != 0 ) {
517  			nsldapi_free_connection( ld, lc, NULL, NULL, 1, 0 );
518  			lc = NULL;
519  		}
520  	}
521  
522  	return( lc );
523  }
524  
525  
526  #define LDAP_CONN_SAMEHOST( h1, h2 ) \
527  	(( (h1) == NULL && (h2) == NULL ) || \
528  	( (h1) != NULL && (h2) != NULL && strcasecmp( (h1), (h2) ) == 0 ))
529  
530  static LDAPConn *
531  find_connection( LDAP *ld, LDAPServer *srv, int any )
532  /*
533   * return an existing connection (if any) to the server srv
534   * if "any" is non-zero, check for any server in the "srv" chain
535   */
536  {
537  	LDAPConn	*lc;
538  	LDAPServer	*ls;
539  
540  	for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
541  		for ( ls = srv; ls != NULL; ls = ls->lsrv_next ) {
542  			if ( LDAP_CONN_SAMEHOST( ls->lsrv_host,
543  			    lc->lconn_server->lsrv_host )
544  			    && ls->lsrv_port == lc->lconn_server->lsrv_port
545  			    && ls->lsrv_options ==
546  			    lc->lconn_server->lsrv_options ) {
547  				return( lc );
548  			}
549  			if ( !any ) {
550  				break;
551  			}
552  		}
553  	}
554  
555  	return( NULL );
556  }
557  
558  
559  
560  static void
561  use_connection( LDAP *ld, LDAPConn *lc )
562  {
563  	++lc->lconn_refcnt;
564  	lc->lconn_lastused = time( 0 );
565  }
566  
567  
568  void
569  nsldapi_free_connection( LDAP *ld, LDAPConn *lc, LDAPControl **serverctrls,
570      LDAPControl **clientctrls, int force, int unbind )
571  {
572  	LDAPConn	*tmplc, *prevlc;
573  
574  	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_free_connection\n", 0, 0, 0 );
575  
576  	if ( force || --lc->lconn_refcnt <= 0 ) {
577  		if ( lc->lconn_status == LDAP_CONNST_CONNECTED ) {
578  			nsldapi_iostatus_interest_clear( ld, lc->lconn_sb );
579  			if ( unbind ) {
580  				nsldapi_send_unbind( ld, lc->lconn_sb,
581  				    serverctrls, clientctrls );
582  			}
583  		}
584  		nsldapi_close_connection( ld, lc->lconn_sb );
585  		prevlc = NULL;
586  		for ( tmplc = ld->ld_conns; tmplc != NULL;
587  		    tmplc = tmplc->lconn_next ) {
588  			if ( tmplc == lc ) {
589  				if ( prevlc == NULL ) {
590  				    ld->ld_conns = tmplc->lconn_next;
591  				} else {
592  				    prevlc->lconn_next = tmplc->lconn_next;
593  				}
594  				break;
595  			}
596  			prevlc = tmplc;
597  		}
598  		free_servers( lc->lconn_server );
599  		if ( lc->lconn_krbinstance != NULL ) {
600  			NSLDAPI_FREE( lc->lconn_krbinstance );
601  		}
602  		/*
603  		 * if this is the default connection (lc->lconn_sb==ld->ld_sbp)
604  		 * we do not free the Sockbuf here since it will be freed
605  		 * later inside ldap_unbind().
606  		 */
607  		if ( lc->lconn_sb != ld->ld_sbp ) {
608  			ber_sockbuf_free( lc->lconn_sb );
609  			lc->lconn_sb = NULL;
610  		}
611  		if ( lc->lconn_ber != NULLBER ) {
612  			ber_free( lc->lconn_ber, 1 );
613  		}
614  		if ( lc->lconn_binddn != NULL ) {
615  			NSLDAPI_FREE( lc->lconn_binddn );
616  		}
617  		NSLDAPI_FREE( lc );
618  		LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_free_connection: actually freed\n",
619  		    0, 0, 0 );
620  	} else {
621  		lc->lconn_lastused = time( 0 );
622  		LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_free_connection: refcnt %d\n",
623  		    lc->lconn_refcnt, 0, 0 );
624  	}
625  }
626  
627  
628  #ifdef LDAP_DEBUG
629  void
630  nsldapi_dump_connection( LDAP *ld, LDAPConn *lconns, int all )
631  {
632  	LDAPConn	*lc;
633  	char        msg[256];
634  /* CTIME for this platform doesn't use this. */
635  #if !defined(SUNOS4) && !defined(_WIN32) && !defined(LINUX)
636  	char		buf[26];
637  #endif
638  
639  	sprintf( msg, "** Connection%s:\n", all ? "s" : "" );
640  	ber_err_print( msg );
641  	for ( lc = lconns; lc != NULL; lc = lc->lconn_next ) {
642  		if ( lc->lconn_server != NULL ) {
643  			sprintf( msg, "* host: %s  port: %d  secure: %s%s\n",
644  			    ( lc->lconn_server->lsrv_host == NULL ) ? "(null)"
645  			    : lc->lconn_server->lsrv_host,
646  			    lc->lconn_server->lsrv_port,
647  			    ( lc->lconn_server->lsrv_options &
648  			    LDAP_SRV_OPT_SECURE ) ? "Yes" :
649  			    "No", ( lc->lconn_sb == ld->ld_sbp ) ?
650  			    "  (default)" : "" );
651  			ber_err_print( msg );
652  		}
653  		sprintf( msg, "  refcnt: %d  status: %s\n", lc->lconn_refcnt,
654  		    ( lc->lconn_status == LDAP_CONNST_NEEDSOCKET ) ?
655  		    "NeedSocket" : ( lc->lconn_status ==
656  		    LDAP_CONNST_CONNECTING ) ? "Connecting" :
657  		    ( lc->lconn_status == LDAP_CONNST_DEAD ) ? "Dead" :
658  		    "Connected" );
659  		ber_err_print( msg );
660  		sprintf( msg, "  last used: %s",
661  		    NSLDAPI_CTIME( (time_t *) &lc->lconn_lastused, buf,
662  				sizeof(buf) ));
663  		ber_err_print( msg );
664  		if ( lc->lconn_ber != NULLBER ) {
665  			ber_err_print( "  partial response has been received:\n" );
666  			ber_dump( lc->lconn_ber, 1 );
667  		}
668  		ber_err_print( "\n" );
669  
670  		if ( !all ) {
671  			break;
672  		}
673  	}
674  }
675  
676  
677  void
678  nsldapi_dump_requests_and_responses( LDAP *ld )
679  {
680  	LDAPRequest	*lr;
681  	LDAPMessage	*lm, *l;
682  	char        msg[256];
683  
684  	ber_err_print( "** Outstanding Requests:\n" );
685  	LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK );
686  	if (( lr = ld->ld_requests ) == NULL ) {
687  		ber_err_print( "   Empty\n" );
688  	}
689  	for ( ; lr != NULL; lr = lr->lr_next ) {
690  	    sprintf( msg, " * msgid %d,  origid %d, status %s\n",
691  		lr->lr_msgid, lr->lr_origid, ( lr->lr_status ==
692  		LDAP_REQST_INPROGRESS ) ? "InProgress" :
693  		( lr->lr_status == LDAP_REQST_CHASINGREFS ) ? "ChasingRefs" :
694  		( lr->lr_status == LDAP_REQST_NOTCONNECTED ) ? "NotConnected" :
695  		( lr->lr_status == LDAP_REQST_CONNDEAD ) ? "Dead" :
696  		"Writing" );
697  	    ber_err_print( msg );
698  	    sprintf( msg, "   outstanding referrals %d, parent count %d\n",
699  		    lr->lr_outrefcnt, lr->lr_parentcnt );
700  	    ber_err_print( msg );
701  	    if ( lr->lr_binddn != NULL ) {
702  		    sprintf( msg, "   pending bind DN: <%s>\n", lr->lr_binddn );
703  		    ber_err_print( msg );
704  	    }
705  	}
706  	LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK );
707  
708  	ber_err_print( "** Response Queue:\n" );
709  	LDAP_MUTEX_LOCK( ld, LDAP_RESP_LOCK );
710  	if (( lm = ld->ld_responses ) == NULLMSG ) {
711  		ber_err_print( "   Empty\n" );
712  	}
713  	for ( ; lm != NULLMSG; lm = lm->lm_next ) {
714  		sprintf( msg, " * msgid %d,  type %d\n",
715  		    lm->lm_msgid, lm->lm_msgtype );
716  		ber_err_print( msg );
717  		if (( l = lm->lm_chain ) != NULL ) {
718  			ber_err_print( "   chained responses:\n" );
719  			for ( ; l != NULLMSG; l = l->lm_chain ) {
720  				sprintf( msg,
721  				    "  * msgid %d,  type %d\n",
722  				    l->lm_msgid, l->lm_msgtype );
723  				ber_err_print( msg );
724  			}
725  		}
726  	}
727  	LDAP_MUTEX_UNLOCK( ld, LDAP_RESP_LOCK );
728  }
729  #endif /* LDAP_DEBUG */
730  
731  
732  void
733  nsldapi_free_request( LDAP *ld, LDAPRequest *lr, int free_conn )
734  {
735  	LDAPRequest	*tmplr, *nextlr;
736  
737  	LDAPDebug( LDAP_DEBUG_TRACE,
738  		"nsldapi_free_request 0x%x (origid %d, msgid %d)\n",
739  		lr, lr->lr_origid, lr->lr_msgid );
740  
741  	if ( lr->lr_parent != NULL ) {
742  		--lr->lr_parent->lr_outrefcnt;
743  	}
744  
745  	/* free all of our spawned referrals (child requests) */
746  	for ( tmplr = lr->lr_child; tmplr != NULL; tmplr = nextlr ) {
747  		nextlr = tmplr->lr_sibling;
748  		nsldapi_free_request( ld, tmplr, free_conn );
749  	}
750  
751  	if ( free_conn ) {
752  		nsldapi_free_connection( ld, lr->lr_conn, NULL, NULL, 0, 1 );
753  	}
754  
755  	if ( lr->lr_prev == NULL ) {
756  		ld->ld_requests = lr->lr_next;
757  	} else {
758  		lr->lr_prev->lr_next = lr->lr_next;
759  	}
760  
761  	if ( lr->lr_next != NULL ) {
762  		lr->lr_next->lr_prev = lr->lr_prev;
763  	}
764  
765  	if ( lr->lr_ber != NULL ) {
766  		ber_free( lr->lr_ber, 1 );
767  	}
768  
769  	if ( lr->lr_res_error != NULL ) {
770  		NSLDAPI_FREE( lr->lr_res_error );
771  	}
772  
773  	if ( lr->lr_res_matched != NULL ) {
774  		NSLDAPI_FREE( lr->lr_res_matched );
775  	}
776  
777  	if ( lr->lr_binddn != NULL ) {
778  		NSLDAPI_FREE( lr->lr_binddn );
779  	}
780  	NSLDAPI_FREE( lr );
781  }
782  
783  
784  static void
785  free_servers( LDAPServer *srvlist )
786  {
787      LDAPServer	*nextsrv;
788  
789      while ( srvlist != NULL ) {
790  	nextsrv = srvlist->lsrv_next;
791  	if ( srvlist->lsrv_dn != NULL ) {
792  		NSLDAPI_FREE( srvlist->lsrv_dn );
793  	}
794  	if ( srvlist->lsrv_host != NULL ) {
795  		NSLDAPI_FREE( srvlist->lsrv_host );
796  	}
797  	NSLDAPI_FREE( srvlist );
798  	srvlist = nextsrv;
799      }
800  }
801  
802  
803  /*
804   * Initiate chasing of LDAPv2+ (Umich extension) referrals.
805   *
806   * Returns an LDAP error code.
807   *
808   * Note that *hadrefp will be set to 1 if one or more referrals were found in
809   * "*errstrp" (even if we can't chase them) and zero if none were found.
810   *
811   * XXX merging of errors in this routine needs to be improved.
812   */
813  int
814  nsldapi_chase_v2_referrals( LDAP *ld, LDAPRequest *lr, char **errstrp,
815      int *totalcountp, int *chasingcountp )
816  {
817  	char		*p, *ref, *unfollowed;
818  	LDAPRequest	*origreq;
819  	int		rc, tmprc, len, unknown;
820  
821  	LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_chase_v2_referrals\n", 0, 0, 0 );
822  
823  	*totalcountp = *chasingcountp = 0;
824  
825  	if ( *errstrp == NULL ) {
826  		return( LDAP_SUCCESS );
827  	}
828  
829  	len = strlen( *errstrp );
830  	for ( p = *errstrp; len >= LDAP_REF_STR_LEN; ++p, --len ) {
831  		if (( *p == 'R' || *p == 'r' ) && strncasecmp( p,
832  		    LDAP_REF_STR, LDAP_REF_STR_LEN ) == 0 ) {
833  			*p = '\0';
834  			p += LDAP_REF_STR_LEN;
835  			break;
836  		}
837  	}
838  
839  	if ( len < LDAP_REF_STR_LEN ) {
840  		return( LDAP_SUCCESS );
841  	}
842  
843  	if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) {
844  		LDAPDebug( LDAP_DEBUG_TRACE,
845  		    "more than %d referral hops (dropping)\n",
846  		    ld->ld_refhoplimit, 0, 0 );
847  		return( LDAP_REFERRAL_LIMIT_EXCEEDED );
848  	}
849  
850  	/* find original request */
851  	for ( origreq = lr; origreq->lr_parent != NULL;
852  	     origreq = origreq->lr_parent ) {
853  		;
854  	}
855  
856  	unfollowed = NULL;
857  	rc = LDAP_SUCCESS;
858  
859  	/* parse out & follow referrals */
860  	for ( ref = p; rc == LDAP_SUCCESS && ref != NULL; ref = p ) {
861  		if (( p = strchr( ref, '\n' )) != NULL ) {
862  			*p++ = '\0';
863  		} else {
864  			p = NULL;
865  		}
866  
867  		++*totalcountp;
868  
869  		rc = chase_one_referral( ld, lr, origreq, ref, "v2 referral",
870  		    &unknown );
871  
872  		if ( rc != LDAP_SUCCESS || unknown ) {
873  			if (( tmprc = nsldapi_append_referral( ld, &unfollowed,
874  			    ref )) != LDAP_SUCCESS ) {
875  				rc = tmprc;
876  			}
877  		} else {
878  			++*chasingcountp;
879  		}
880  	}
881  
882  	NSLDAPI_FREE( *errstrp );
883  	*errstrp = unfollowed;
884  
885  	return( rc );
886  }
887  
888  
889  /* returns an LDAP error code */
890  int
891  nsldapi_chase_v3_refs( LDAP *ld, LDAPRequest *lr, char **v3refs,
892      int is_reference, int *totalcountp, int *chasingcountp )
893  {
894  	int		i, rc, unknown;
895  	LDAPRequest	*origreq;
896  
897  	*totalcountp = *chasingcountp = 0;
898  
899  	if ( v3refs == NULL || v3refs[0] == NULL ) {
900  		return( LDAP_SUCCESS );
901  	}
902  
903  	*totalcountp = 1;
904  
905  	if ( lr->lr_parentcnt >= ld->ld_refhoplimit ) {
906  		LDAPDebug( LDAP_DEBUG_TRACE,
907  		    "more than %d referral hops (dropping)\n",
908  		    ld->ld_refhoplimit, 0, 0 );
909  		return( LDAP_REFERRAL_LIMIT_EXCEEDED );
910  	}
911  
912  	/* find original request */
913  	for ( origreq = lr; origreq->lr_parent != NULL;
914  	    origreq = origreq->lr_parent ) {
915  		;
916  	}
917  
918  	/*
919  	 * in LDAPv3, we just need to follow one referral in the set.
920  	 * we dp this by stopping as soon as we succeed in initiating a
921  	 * chase on any referral (basically this means we were able to connect
922  	 * to the server and bind).
923  	 */
924  	for ( i = 0; v3refs[i] != NULL; ++i ) {
925  		rc = chase_one_referral( ld, lr, origreq, v3refs[i],
926  		    is_reference ? "v3 reference" : "v3 referral", &unknown );
927  		if ( rc == LDAP_SUCCESS && !unknown ) {
928  			*chasingcountp = 1;
929  			break;
930  		}
931  	}
932  
933  	/* XXXmcs: should we save unfollowed referrals somewhere? */
934  
935  	return( rc );	/* last error is as good as any other I guess... */
936  }
937  
938  /*
939   * returns an LDAP error code
940   *
941   * XXXmcs: this function used to have #ifdef LDAP_DNS code in it but I
942   *	removed it when I improved the parsing (we don't define LDAP_DNS
943   *	here at Netscape).
944   */
945  static int
946  chase_one_referral( LDAP *ld, LDAPRequest *lr, LDAPRequest *origreq,
947      char *refurl, char *desc, int *unknownp )
948  {
949  	int		rc, tmprc, secure, msgid;
950  	LDAPServer	*srv;
951  	BerElement	*ber;
952  	LDAPURLDesc	*ludp;
953  
954  	*unknownp = 0;
955  	ludp = NULLLDAPURLDESC;
956  
957  	if ( nsldapi_url_parse( refurl, &ludp, 0 ) != 0 ) {
958  		LDAPDebug( LDAP_DEBUG_TRACE,
959  		    "ignoring unknown %s <%s>\n", desc, refurl, 0 );
960  		*unknownp = 1;
961  		rc = LDAP_SUCCESS;
962  		goto cleanup_and_return;
963  	}
964  
965  	secure = (( ludp->lud_options & LDAP_URL_OPT_SECURE ) != 0 );
966  
967  /* XXXmcs: can't tell if secure is supported by connect callback */
968  	if ( secure && ld->ld_extconnect_fn == NULL ) {
969  		LDAPDebug( LDAP_DEBUG_TRACE,
970  		    "ignoring LDAPS %s <%s>\n", desc, refurl, 0 );
971  		*unknownp = 1;
972  		rc = LDAP_SUCCESS;
973  		goto cleanup_and_return;
974  	}
975  
976  	LDAPDebug( LDAP_DEBUG_TRACE, "chasing LDAP%s %s: <%s>\n",
977  	    secure ? "S" : "", desc, refurl );
978  
979  	LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
980  	msgid = ++ld->ld_msgid;
981  	LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
982  
983  	if (( tmprc = re_encode_request( ld, origreq->lr_ber, msgid,
984  	    ludp, &ber )) != LDAP_SUCCESS ) {
985  		rc = tmprc;
986  		goto cleanup_and_return;
987  	}
988  
989  	if (( srv = (LDAPServer *)NSLDAPI_CALLOC( 1, sizeof( LDAPServer )))
990  	    == NULL ) {
991  		ber_free( ber, 1 );
992  		rc = LDAP_NO_MEMORY;
993  		goto cleanup_and_return;
994  	}
995  
996  	if (ludp->lud_host == NULL && ld->ld_defhost == NULL) {
997  		srv->lsrv_host = NULL;
998  	} else {
999  		if (ludp->lud_host == NULL) {
1000  			srv->lsrv_host =
1001  			    nsldapi_strdup( origreq->lr_conn->lconn_server->lsrv_host );
1002  			LDAPDebug(LDAP_DEBUG_TRACE,
1003  			    "chase_one_referral: using hostname '%s' from original "
1004  			    "request on new request\n",
1005  			    srv->lsrv_host, 0, 0);
1006  		} else {
1007  			srv->lsrv_host = nsldapi_strdup(ludp->lud_host);
1008  			LDAPDebug(LDAP_DEBUG_TRACE,
1009  			    "chase_one_referral: using hostname '%s' as specified "
1010  			    "on new request\n",
1011  			    srv->lsrv_host, 0, 0);
1012  		}
1013  
1014  		if (srv->lsrv_host == NULL) {
1015  			NSLDAPI_FREE((char *)srv);
1016  			ber_free(ber, 1);
1017  			rc = LDAP_NO_MEMORY;
1018  			goto cleanup_and_return;
1019  		}
1020  	}
1021  
1022  	/*
1023  	 * According to our reading of RFCs 2255 and 1738, the
1024  	 * following algorithm applies:
1025  	 * - no hostport (no host, no port) provided in LDAP URL, use those
1026  	 *   of previous request
1027  	 * - no port but a host, use default LDAP port
1028  	 * - else use given hostport
1029  	 */
1030  	if (ludp->lud_port == 0 && ludp->lud_host == NULL) {
1031  		srv->lsrv_port = origreq->lr_conn->lconn_server->lsrv_port;
1032  		LDAPDebug(LDAP_DEBUG_TRACE,
1033  		    "chase_one_referral: using port (%d) from original "
1034  		    "request on new request\n",
1035  		    srv->lsrv_port, 0, 0);
1036  	} else if (ludp->lud_port == 0 && ludp->lud_host != NULL) {
1037  		srv->lsrv_port = (secure) ? LDAPS_PORT : LDAP_PORT;
1038  		LDAPDebug(LDAP_DEBUG_TRACE,
1039  		    "chase_one_referral: using default port (%d) \n",
1040  		    srv->lsrv_port, 0, 0);
1041  	} else {
1042  		srv->lsrv_port = ludp->lud_port;
1043  		LDAPDebug(LDAP_DEBUG_TRACE,
1044  		    "chase_one_referral: using port (%d) as specified on "
1045  		    "new request\n",
1046  		    srv->lsrv_port, 0, 0);
1047  	}
1048  
1049  	if ( secure ) {
1050  		srv->lsrv_options |= LDAP_SRV_OPT_SECURE;
1051  	}
1052  
1053  	if ( nsldapi_send_server_request( ld, ber, msgid,
1054  	    lr, srv, NULL, NULL, 1 ) < 0 ) {
1055  		rc = LDAP_GET_LDERRNO( ld, NULL, NULL );
1056  		LDAPDebug( LDAP_DEBUG_ANY, "Unable to chase %s %s (%s)\n",
1057  		    desc, refurl, ldap_err2string( rc ));
1058  	} else {
1059  		rc = LDAP_SUCCESS;
1060  	}
1061  
1062  cleanup_and_return:
1063  	if ( ludp != NULLLDAPURLDESC ) {
1064  		ldap_free_urldesc( ludp );
1065  	}
1066  
1067  	return( rc );
1068  }
1069  
1070  
1071  /* returns an LDAP error code */
1072  int
1073  nsldapi_append_referral( LDAP *ld, char **referralsp, char *s )
1074  {
1075  	int	first;
1076  
1077  	if ( *referralsp == NULL ) {
1078  		first = 1;
1079  		*referralsp = (char *)NSLDAPI_MALLOC( strlen( s ) +
1080  		    LDAP_REF_STR_LEN + 1 );
1081  	} else {
1082  		first = 0;
1083  		*referralsp = (char *)NSLDAPI_REALLOC( *referralsp,
1084  		    strlen( *referralsp ) + strlen( s ) + 2 );
1085  	}
1086  
1087  	if ( *referralsp == NULL ) {
1088  		return( LDAP_NO_MEMORY );
1089  	}
1090  
1091  	if ( first ) {
1092  		strcpy( *referralsp, LDAP_REF_STR );
1093  	} else {
1094  		strcat( *referralsp, "\n" );
1095  	}
1096  	strcat( *referralsp, s );
1097  
1098  	return( LDAP_SUCCESS );
1099  }
1100  
1101  
1102  
1103  /* returns an LDAP error code */
1104  static int
1105  re_encode_request( LDAP *ld, BerElement *origber, int msgid, LDAPURLDesc *ludp,
1106      BerElement **berp )
1107  {
1108  /*
1109   * XXX this routine knows way too much about how the lber library works!
1110   */
1111  	ber_uint_t		along;
1112  	ber_tag_t		tag;
1113  	ber_int_t		ver;
1114  	int			rc;
1115  	BerElement		*ber;
1116  	struct berelement	tmpber;
1117  	char			*dn, *orig_dn;
1118  
1119  	LDAPDebug( LDAP_DEBUG_TRACE,
1120  	    "re_encode_request: new msgid %d, new dn <%s>\n",
1121  	    msgid, ( ludp->lud_dn == NULL ) ? "NONE" : ludp->lud_dn, 0 );
1122  
1123  	tmpber = *origber;
1124  
1125  	/*
1126  	 * All LDAP requests are sequences that start with a message id.  For
1127  	 * everything except delete requests, this is followed by a sequence
1128  	 * that is tagged with the operation code.  For deletes, there is just
1129  	 * a DN that is tagged with the operation code.
1130  	 */
1131  
1132  	/* skip past msgid and get operation tag */
1133  	if ( ber_scanf( &tmpber, "{it", &along, &tag ) == LBER_ERROR ) {
1134  		return( LDAP_DECODING_ERROR );
1135  	}
1136  
1137  	/*
1138  	 * XXXmcs: we don't support scope or filters in search referrals yet,
1139  	 * so if either were present we return an error which is probably
1140  	 * better than just ignoring the extra info.
1141  	 */
1142  	if ( tag == LDAP_REQ_SEARCH &&
1143  	    ( ludp->lud_scope != -1 || ludp->lud_filter != NULL )) {
1144  		return( LDAP_LOCAL_ERROR );
1145  	}
1146  
1147  	if ( tag == LDAP_REQ_BIND ) {
1148  		/* bind requests have a version number before the DN */
1149  		rc = ber_scanf( &tmpber, "{ia", &ver, &orig_dn );
1150  	} else if ( tag == LDAP_REQ_DELETE ) {
1151  		/* delete requests DNs are not within a sequence */
1152  		rc = ber_scanf( &tmpber, "a", &orig_dn );
1153  	} else {
1154  		rc = ber_scanf( &tmpber, "{a", &orig_dn );
1155  	}
1156  
1157  	if ( rc == LBER_ERROR ) {
1158  		return( LDAP_DECODING_ERROR );
1159  	}
1160  
1161  	if ( ludp->lud_dn == NULL ) {
1162  		dn = orig_dn;
1163  	} else {
1164  		dn = ludp->lud_dn;
1165  		NSLDAPI_FREE( orig_dn );
1166  		orig_dn = NULL;
1167  	}
1168  
1169  	/* allocate and build the new request */
1170          if (( rc = nsldapi_alloc_ber_with_options( ld, &ber ))
1171  	    != LDAP_SUCCESS ) {
1172  		if ( orig_dn != NULL ) {
1173  			NSLDAPI_FREE( orig_dn );
1174  		}
1175                  return( rc );
1176          }
1177  
1178  	if ( tag == LDAP_REQ_BIND ) {
1179  		rc = ber_printf( ber, "{it{is", msgid, tag,
1180  		    (int)ver /* XXX lossy cast */, dn );
1181  	} else if ( tag == LDAP_REQ_DELETE ) {
1182  		rc = ber_printf( ber, "{its}", msgid, tag, dn );
1183  	} else {
1184  		rc = ber_printf( ber, "{it{s", msgid, tag, dn );
1185  	}
1186  
1187  	if ( orig_dn != NULL ) {
1188  		NSLDAPI_FREE( orig_dn );
1189  	}
1190  /*
1191   * can't use "dn" or "orig_dn" from this point on (they've been freed)
1192   */
1193  
1194  	if ( rc == -1 ) {
1195  		ber_free( ber, 1 );
1196  		return( LDAP_ENCODING_ERROR );
1197  	}
1198  
1199  	if ( tag != LDAP_REQ_DELETE &&
1200  	    ( ber_write( ber, tmpber.ber_ptr, ( tmpber.ber_end -
1201  	    tmpber.ber_ptr ), 0 ) != ( tmpber.ber_end - tmpber.ber_ptr )
1202  	    || ber_printf( ber, "}}" ) == -1 )) {
1203  		ber_free( ber, 1 );
1204  		return( LDAP_ENCODING_ERROR );
1205  	}
1206  
1207  #ifdef LDAP_DEBUG
1208  	if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
1209  		LDAPDebug( LDAP_DEBUG_ANY, "re_encode_request new request is:\n",
1210  		    0, 0, 0 );
1211  		ber_dump( ber, 0 );
1212  	}
1213  #endif /* LDAP_DEBUG */
1214  
1215  	*berp = ber;
1216  	return( LDAP_SUCCESS );
1217  }
1218  
1219  
1220  LDAPRequest *
1221  nsldapi_find_request_by_msgid( LDAP *ld, int msgid )
1222  {
1223      	LDAPRequest	*lr;
1224  
1225  	for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
1226  		if ( msgid == lr->lr_msgid ) {
1227  			break;
1228  		}
1229  	}
1230  
1231  	return( lr );
1232  }
1233  
1234  
1235  /*
1236   * nsldapi_connection_lost_nolock() resets "ld" to a non-connected, known
1237   * state.  It should be called whenever a fatal error occurs on the
1238   * Sockbuf "sb."  sb == NULL means we don't know specifically where
1239   * the problem was so we assume all connections are bad.
1240   */
1241  void
1242  nsldapi_connection_lost_nolock( LDAP *ld, Sockbuf *sb )
1243  {
1244  	LDAPRequest	*lr;
1245  
1246  	/*
1247  	 * change status of all pending requests that are associated with "sb
1248  	 *	to "connection dead."
1249  	 * also change the connection status to "dead" and remove it from
1250  	 *	the list of sockets we are interested in.
1251  	 */
1252  	for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
1253  		if ( sb == NULL ||
1254  		    ( lr->lr_conn != NULL && lr->lr_conn->lconn_sb == sb )) {
1255  			lr->lr_status = LDAP_REQST_CONNDEAD;
1256  			if ( lr->lr_conn != NULL ) {
1257  				lr->lr_conn->lconn_status = LDAP_CONNST_DEAD;
1258  				nsldapi_iostatus_interest_clear( ld,
1259  				    lr->lr_conn->lconn_sb );
1260  			}
1261  		}
1262  	}
1263  }
1264  
1265  
1266  #ifdef LDAP_DNS
1267  static LDAPServer *
1268  dn2servers( LDAP *ld, char *dn )	/* dn can also be a domain.... */
1269  {
1270  	char		*p, *domain, *host, *server_dn, **dxs;
1271  	int		i, port;
1272  	LDAPServer	*srvlist, *prevsrv, *srv;
1273  
1274  	if (( domain = strrchr( dn, '@' )) != NULL ) {
1275  		++domain;
1276  	} else {
1277  		domain = dn;
1278  	}
1279  
1280  	if (( dxs = nsldapi_getdxbyname( domain )) == NULL ) {
1281  		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
1282  		return( NULL );
1283  	}
1284  
1285  	srvlist = NULL;
1286  
1287  	for ( i = 0; dxs[ i ] != NULL; ++i ) {
1288  		port = LDAP_PORT;
1289  		server_dn = NULL;
1290  		if ( strchr( dxs[ i ], ':' ) == NULL ) {
1291  			host = dxs[ i ];
1292  		} else if ( strlen( dxs[ i ] ) >= 7 &&
1293  		    strncmp( dxs[ i ], "ldap://", 7 ) == 0 ) {
1294  			host = dxs[ i ] + 7;
1295  			if (( p = strchr( host, ':' )) == NULL ) {
1296  				p = host;
1297  			} else {
1298  				*p++ = '\0';
1299  				port = atoi( p );
1300  			}
1301  			if (( p = strchr( p, '/' )) != NULL ) {
1302  				server_dn = ++p;
1303  				if ( *server_dn == '\0' ) {
1304  					server_dn = NULL;
1305  				}
1306  			}
1307  		} else {
1308  			host = NULL;
1309  		}
1310  
1311  		if ( host != NULL ) {	/* found a server we can use */
1312  			if (( srv = (LDAPServer *)NSLDAPI_CALLOC( 1,
1313  			    sizeof( LDAPServer ))) == NULL ) {
1314  				free_servers( srvlist );
1315  				srvlist = NULL;
1316  				break;		/* exit loop & return */
1317  			}
1318  
1319  			/* add to end of list of servers */
1320  			if ( srvlist == NULL ) {
1321  				srvlist = srv;
1322  			} else {
1323  				prevsrv->lsrv_next = srv;
1324  			}
1325  			prevsrv = srv;
1326  
1327  			/* copy in info. */
1328  			if (( srv->lsrv_host = nsldapi_strdup( host )) == NULL
1329  			    || ( server_dn != NULL && ( srv->lsrv_dn =
1330  			    nsldapi_strdup( server_dn )) == NULL )) {
1331  				free_servers( srvlist );
1332  				srvlist = NULL;
1333  				break;		/* exit loop & return */
1334  			}
1335  			srv->lsrv_port = port;
1336  		}
1337  	}
1338  
1339  	ldap_value_free( dxs );
1340  
1341  	if ( srvlist == NULL ) {
1342  		LDAP_SET_LDERRNO( ld, LDAP_SERVER_DOWN, NULL, NULL );
1343  	}
1344  
1345  	return( srvlist );
1346  }
1347  #endif /* LDAP_DNS */
1348