xref: /onnv-gate/usr/src/lib/libldap4/common/request.c (revision 0:68f95e015346)
1 /*
2  * Copyright 1998-2002 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 /*
9  *  Copyright (c) 1995 Regents of the University of Michigan.
10  *  All rights reserved.
11  *
12  *  request.c - sending of ldap requests; handling of referrals
13  */
14 
15 #ifndef lint
16 static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
17 #endif
18 
19 #include <stdio.h>
20 #include <string.h>
21 #ifdef MACOS
22 #include <stdlib.h>
23 #include <time.h>
24 #include "macos.h"
25 #else /* MACOS */
26 #if defined( DOS ) || defined( _WIN32 )
27 #include "msdos.h"
28 #include <time.h>
29 #include <stdlib.h>
30 #ifdef PCNFS
31 #include <tklib.h>
32 #include <tk_errno.h>
33 #include <bios.h>
34 #endif /* PCNFS */
35 #ifdef NCSA
36 #include "externs.h"
37 #endif /* NCSA */
38 #else /* DOS */
39 #include <sys/time.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <errno.h>
43 #ifdef _AIX
44 #include <sys/select.h>
45 #endif /* _AIX */
46 #include "portable.h"
47 #endif /* DOS */
48 #endif /* MACOS */
49 #ifdef VMS
50 #include "ucx_select.h"
51 #endif
52 #include "lber.h"
53 #include "ldap.h"
54 #include "ldap-private.h"
55 #include "ldap-int.h"
56 
57 #ifdef USE_SYSCONF
58 #include <unistd.h>
59 #endif /* USE_SYSCONF */
60 
61 #ifdef NEEDPROTOS
62 static LDAPConn *find_connection( LDAP *ld, LDAPServer *srv, int any );
63 static void use_connection( LDAP *ld, LDAPConn *lc );
64 static void free_servers( LDAPServer *srvlist );
65 #else /* NEEDPROTOS */
66 static LDAPConn *find_connection();
67 static void use_connection();
68 static void free_servers();
69 #endif /* NEEDPROTOS */
70 
71 
72 #ifdef LDAP_DNS
73 #ifdef NEEDPROTOS
74 static LDAPServer *dn2servers( LDAP *ld, char *dn );
75 #else /* NEEDPROTOS */
76 static LDAPServer *dn2servers();
77 #endif /* NEEDPROTOS */
78 #endif /* LDAP_DNS */
79 
80 
81 BerElement *
alloc_ber_with_options(LDAP * ld)82 alloc_ber_with_options( LDAP *ld )
83 {
84 	BerElement	*ber;
85 
86     	if (( ber = ber_alloc_t( ld->ld_lberoptions )) == NULLBER ) {
87 		ld->ld_errno = LDAP_NO_MEMORY;
88 #ifdef STR_TRANSLATION
89 	} else {
90 		set_ber_options( ld, ber );
91 #endif /* STR_TRANSLATION */
92 	}
93 
94 	return( ber );
95 }
96 
97 
98 void
set_ber_options(LDAP * ld,BerElement * ber)99 set_ber_options( LDAP *ld, BerElement *ber )
100 {
101 	ber->ber_options = ld->ld_lberoptions;
102 #ifdef STR_TRANSLATION
103 	if (( ld->ld_lberoptions & LBER_TRANSLATE_STRINGS ) != 0 ) {
104 		ber_set_string_translators( ber,
105 		    ld->ld_lber_encode_translate_proc,
106 		    ld->ld_lber_decode_translate_proc );
107 	}
108 #endif /* STR_TRANSLATION */
109 }
110 
111 
112 int
send_initial_request(LDAP * ld,unsigned int msgtype,char * dn,BerElement * ber)113 send_initial_request( LDAP *ld, unsigned int msgtype, char *dn,
114 	BerElement *ber )
115 {
116 	LDAPServer	*servers;
117 	int rv;
118 
119 #ifdef _REENTRANT
120         LOCK_LDAP(ld);
121 #endif
122 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 209, "send_initial_request\n"), 0, 0, 0 );
123 
124 #ifdef LDAP_DNS
125 	if (( ld->ld_options & LDAP_OPT_DNS ) != 0 && ldap_is_dns_dn( dn )) {
126 		if (( servers = dn2servers( ld, dn )) == NULL ) {
127 			ber_free( ber, 1 );
128 #ifdef _REENTRANT
129 			UNLOCK_LDAP(ld);
130 #endif
131 			return( -1 );
132 		}
133 
134 #ifdef LDAP_DEBUG
135 		if ( ldap_debug & LDAP_DEBUG_TRACE ) {
136 			LDAPServer	*srv;
137 
138 			for ( srv = servers; srv != NULL;
139 			    srv = srv->lsrv_next ) {
140 				fprintf( stderr,
141 				    "LDAP server %s:  dn %s, port %d\n",
142 				    srv->lsrv_host, ( srv->lsrv_dn == NULL ) ?
143 				    "(default)" : srv->lsrv_dn,
144 				    srv->lsrv_port );
145 			}
146 		}
147 #endif /* LDAP_DEBUG */
148 	} else {
149 #endif /* LDAP_DNS */
150 		/*
151 		 * use of DNS is turned off or this is an X.500 DN...
152 		 * use our default connection
153 		 */
154 		servers = NULL;
155 #ifdef LDAP_DNS
156 	}
157 #endif /* LDAP_DNS */
158 
159 #ifdef _REENTRANT
160     UNLOCK_LDAP(ld);
161 #endif
162 	rv = send_server_request( ld, ber, ld->ld_msgid, NULL, servers,
163 							  NULL, 0 );
164 	return ( rv );
165 }
166 
167 int
send_server_request(LDAP * ld,BerElement * ber,int msgid,LDAPRequest * parentreq,LDAPServer * srvlist,LDAPConn * lc,int bind)168 send_server_request( LDAP *ld, BerElement *ber, int msgid, LDAPRequest
169 	*parentreq, LDAPServer *srvlist, LDAPConn *lc, int bind )
170 {
171 	LDAPRequest	*lr;
172 	int err;
173 
174 #ifdef _REENTRANT
175         LOCK_LDAP(ld);
176 #endif
177 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 210, "send_server_request\n"), 0, 0, 0 );
178 
179 	ld->ld_errno = LDAP_SUCCESS;	/* optimistic */
180 	/* Be optimistic : increment parentreq initially.
181 	   If it fails we must decrement it */
182 	if (parentreq != NULL){
183 		parentreq->lr_outrefcnt++;
184 	}
185 
186 	if ( lc == NULL ) {
187 		if ( srvlist == NULL ) {
188 			if  (ld->ld_defconn == NULL){ /* Not connected yet on the default connection, ie init was called not open */
189 				if ((err = open_default_ldap_connection(ld)) != LDAP_SUCCESS){
190 					ld->ld_errno = err;
191 					ber_free(ber, 1);
192 					if (parentreq != NULL){
193 						parentreq->lr_outrefcnt--;
194 					}
195 #ifdef _REENTRANT
196 					UNLOCK_LDAP(ld);
197 #endif
198 					return( -1 );
199 				}
200 			}
201 
202 			lc = ld->ld_defconn;
203 		} else {
204 			if (( lc = find_connection( ld, srvlist, 1 )) ==
205 			    NULL ) {
206 				lc = new_connection( ld, &srvlist, 0, 1, bind );
207 			}
208 			free_servers( srvlist );
209 		}
210 	}
211 
212 	if ( lc == NULL || lc->lconn_status != LDAP_CONNST_CONNECTED ) {
213 		ber_free( ber, 1 );
214 		if ( ld->ld_errno == LDAP_SUCCESS ) {
215 			ld->ld_errno = LDAP_SERVER_DOWN;
216 		}
217 		if (parentreq != NULL){
218 			parentreq->lr_outrefcnt--;
219 		}
220 #ifdef _REENTRANT
221 		UNLOCK_LDAP(ld);
222 #endif
223 		return( -1 );
224 	}
225 
226 	use_connection( ld, lc );
227 	if (( lr = (LDAPRequest *)calloc( 1, sizeof( LDAPRequest ))) ==
228 	    NULL ) {
229 		ld->ld_errno = LDAP_NO_MEMORY;
230 		free_connection( ld, lc, 0, 0 );
231 		ber_free( ber, 1 );
232 #ifdef _REENTRANT
233 		UNLOCK_LDAP(ld);
234 #endif
235 		return( -1 );
236 	}
237 	lr->lr_msgid = msgid;
238 	lr->lr_status = LDAP_REQST_INPROGRESS;
239 	lr->lr_res_errno = LDAP_SUCCESS;	/* optimistic */
240 	lr->lr_ber = ber;
241 	lr->lr_conn = lc;
242 	if ( parentreq != NULL ) {	/* sub-request */
243 /* 		++parentreq->lr_outrefcnt; */
244 		lr->lr_origid = parentreq->lr_origid;
245 		lr->lr_parentcnt = parentreq->lr_parentcnt + 1;
246 		lr->lr_parent = parentreq;
247 		lr->lr_refnext = parentreq->lr_refnext;
248 		parentreq->lr_refnext = lr;
249 	} else {			/* original request */
250 		lr->lr_origid = lr->lr_msgid;
251 	}
252 
253 	if (( lr->lr_next = ld->ld_requests ) != NULL ) {
254 		lr->lr_next->lr_prev = lr;
255 	}
256 	ld->ld_requests = lr;
257 	lr->lr_prev = NULL;
258 
259 	if ( ber_flush( lc->lconn_sb, ber, 0 ) != 0 ) {
260 #ifdef notyet
261 		extern int	errno;
262 
263 		if ( errno == EWOULDBLOCK ) {
264 			/* need to continue write later */
265 			lr->lr_status = LDAP_REQST_WRITING;
266 			mark_select_write( ld, lc->lconn_sb );
267 		} else {
268 #else /* notyet */
269 			ld->ld_errno = LDAP_SERVER_DOWN;
270 			free_request( ld, lr );
271 			free_connection( ld, lc, 0, 0 );
272 #ifdef _REENTRANT
273 			UNLOCK_LDAP(ld);
274 #endif
275 			return( -1 );
276 #endif /* notyet */
277 #ifdef notyet
278 		}
279 #endif /* notyet */
280 	} else {
281 		if ( parentreq == NULL ) {
282 			ber->ber_end = ber->ber_ptr;
283 			ber->ber_ptr = ber->ber_buf;
284 		}
285 
286 		/* sent -- waiting for a response */
287 		mark_select_read( ld, lc->lconn_sb );
288 	}
289 
290 	ld->ld_errno = LDAP_SUCCESS;
291 #ifdef _REENTRANT
292         UNLOCK_LDAP(ld);
293 #endif
294 	return( msgid );
295 }
296 
297 
298 LDAPConn *
new_connection(LDAP * ld,LDAPServer ** srvlistp,int use_ldsb,int connect,int bind)299 new_connection( LDAP *ld, LDAPServer **srvlistp, int use_ldsb,
300 	int connect, int bind )
301 {
302 	LDAPConn	*lc;
303 	LDAPServer	*prevsrv, *srv;
304 	Sockbuf		*sb;
305 
306 	/*
307 	 * make a new LDAP server connection
308 	 * XXX open connection synchronously for now
309 	 */
310 	if (( lc = (LDAPConn *)calloc( 1, sizeof( LDAPConn ))) == NULL ||
311 	    ( !use_ldsb && ( sb = (Sockbuf *)calloc( 1, sizeof( Sockbuf )))
312 	    == NULL )) {
313 		if ( lc != NULL ) {
314 			free( (char *)lc );
315 		}
316 		ld->ld_errno = LDAP_NO_MEMORY;
317 		return( NULL );
318 	}
319 
320 #ifdef _REENTRANT
321 	LOCK_LDAP(ld);
322 #endif
323 	lc->lconn_sb = ( use_ldsb ) ? &ld->ld_sb : sb;
324 
325 	if ( connect ) {
326 		prevsrv = NULL;
327 
328 		for ( srv = *srvlistp; srv != NULL; srv = srv->lsrv_next ) {
329 			if ( open_ldap_connection( ld, lc->lconn_sb,
330 			    srv->lsrv_host, srv->lsrv_port,
331 			    &lc->lconn_krbinstance, 0 ) != -1 ) {
332 				break;
333 			}
334 			prevsrv = srv;
335 		}
336 
337 		if ( srv == NULL ) {
338 		    if ( !use_ldsb ) {
339 				free( (char *)lc->lconn_sb );
340 		    }
341 		    free( (char *)lc );
342 		    ld->ld_errno = LDAP_SERVER_DOWN;
343 #ifdef _REENTRANT
344 		    UNLOCK_LDAP(ld);
345 #endif
346 		    return( NULL );
347 		}
348 
349 		if ( prevsrv == NULL ) {
350 		    *srvlistp = srv->lsrv_next;
351 		} else {
352 		    prevsrv->lsrv_next = srv->lsrv_next;
353 		}
354 		lc->lconn_server = srv;
355 	}
356 
357 	lc->lconn_status = LDAP_CONNST_CONNECTED;
358 	lc->lconn_next = ld->ld_conns;
359 	ld->ld_conns = lc;
360 
361 	/*
362 	 * XXX for now, we always do a synchronous bind.  This will have
363 	 * to change in the long run...
364 	 */
365 	if ( bind ) {
366 		int		err, freepasswd, authmethod;
367 		char		*binddn, *passwd;
368 		LDAPConn	*savedefconn;
369 
370 		freepasswd = err = 0;
371 
372 		if ( ld->ld_version == LDAP_VERSION3 && ld->ld_rebindproc == NULL){
373 			/* Nothing to do */
374 			Debug(LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 1280, "new_connection: bind no needed with ldapv3\n"), 0,0,0);
375 		} else {
376 			if ( ld->ld_rebindproc == NULL ) {
377 				binddn = passwd = "";
378 				authmethod = LDAP_AUTH_SIMPLE;
379 			} else {
380 				if (( err = (*ld->ld_rebindproc)( ld, &binddn, &passwd,
381 												  &authmethod, 0, ld->ld_rebind_extra_arg )) == LDAP_SUCCESS ) {
382 					freepasswd = 1;
383 				} else {
384 					ld->ld_errno = err;
385 					err = -1;
386 				}
387 			}
388 
389 			if ( err == 0 ) {
390 				savedefconn = ld->ld_defconn;
391 				ld->ld_defconn = lc;
392 				++lc->lconn_refcnt;	/* avoid premature free */
393 
394 				if ( ldap_bind_s( ld, binddn, passwd, authmethod ) !=
395 					 LDAP_SUCCESS ) {
396 					err = -1;
397 				}
398 				--lc->lconn_refcnt;
399 				ld->ld_defconn = savedefconn;
400 			}
401 
402 			if ( freepasswd ) {
403 				(*ld->ld_rebindproc)( ld, &binddn, &passwd,
404 									  &authmethod, 1, ld->ld_rebind_extra_arg );
405 			}
406 
407 			if ( err != 0 ) {
408 				free_connection( ld, lc, 1, 0 );
409 				lc = NULL;
410 			}
411 		}
412 	}
413 
414 #ifdef _REENTRANT
415 	UNLOCK_LDAP(ld);
416 #endif
417 	return( lc );
418 }
419 
420 
421 static LDAPConn *
find_connection(LDAP * ld,LDAPServer * srv,int any)422 find_connection( LDAP *ld, LDAPServer *srv, int any )
423 /*
424  * return an existing connection (if any) to the server srv
425  * if "any" is non-zero, check for any server in the "srv" chain
426  */
427 {
428 	LDAPConn	*lc;
429 	LDAPServer	*ls;
430 
431 #ifdef _REENTRANT
432         LOCK_LDAP(ld);
433 #endif
434 	for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
435 		for ( ls = srv; ls != NULL; ls = ls->lsrv_next ) {
436 			if ( lc->lconn_server->lsrv_host != NULL &&
437 			    ls->lsrv_host != NULL && strcasecmp(
438 			    ls->lsrv_host, lc->lconn_server->lsrv_host ) == 0
439 			    && ls->lsrv_port == lc->lconn_server->lsrv_port ) {
440 #ifdef _REENTRANT
441 				UNLOCK_LDAP(ld);
442 #endif
443 				return( lc );
444 			}
445 			if ( !any ) {
446 				break;
447 			}
448 		}
449 	}
450 
451 #ifdef _REENTRANT
452         UNLOCK_LDAP(ld);
453 #endif
454 	return( NULL );
455 }
456 
457 
458 
459 static void
use_connection(LDAP * ld,LDAPConn * lc)460 use_connection( LDAP *ld, LDAPConn *lc )
461 {
462 	++lc->lconn_refcnt;
463 	lc->lconn_lastused = time( 0 );
464 }
465 
466 
467 void
free_connection(LDAP * ld,LDAPConn * lc,int force,int unbind)468 free_connection( LDAP *ld, LDAPConn *lc, int force, int unbind )
469 {
470 	LDAPConn	*tmplc, *prevlc;
471 
472 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 211, "free_connection\n"), 0, 0, 0 );
473 
474 	if ( force || --lc->lconn_refcnt <= 0 ) {
475 		if ( lc->lconn_status == LDAP_CONNST_CONNECTED ) {
476 			mark_select_clear( ld, lc->lconn_sb );
477 			if ( unbind ) {
478 				send_unbind( ld, lc->lconn_sb );
479 			}
480 			close_ldap_connection( lc->lconn_sb );
481 			if ( lc->lconn_sb->sb_ber.ber_buf != NULL ) {
482 				free( lc->lconn_sb->sb_ber.ber_buf );
483 				lc->lconn_sb->sb_ber.ber_buf = NULL;
484 			}
485 		}
486 		prevlc = NULL;
487 		for ( tmplc = ld->ld_conns; tmplc != NULL;
488 		    tmplc = tmplc->lconn_next ) {
489 			if ( tmplc == lc ) {
490 				if ( prevlc == NULL ) {
491 				    ld->ld_conns = tmplc->lconn_next;
492 				} else {
493 				    prevlc->lconn_next = tmplc->lconn_next;
494 				}
495 				break;
496 			}
497 		}
498 		free_servers( lc->lconn_server );
499 		if ( lc->lconn_krbinstance != NULL ) {
500 			free( lc->lconn_krbinstance );
501 		}
502 		if ( lc->lconn_sb != &ld->ld_sb ) {
503 			free( (char *)lc->lconn_sb );
504 		}
505 		free( lc );
506 		Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 212, "free_connection: actually freed\n"),
507 		    0, 0, 0 );
508 	} else {
509 		lc->lconn_lastused = time( 0 );
510 		Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 213, "free_connection: refcnt %d\n"),
511 		    lc->lconn_refcnt, 0, 0 );
512 	}
513 }
514 
515 
516 #ifdef LDAP_DEBUG
517 void
dump_connection(LDAP * ld,LDAPConn * lconns,int all)518 dump_connection( LDAP *ld, LDAPConn *lconns, int all )
519 {
520 	LDAPConn	*lc;
521 
522 	fprintf( stderr, "** Connection%s:\n", all ? "s" : "" );
523 	for ( lc = lconns; lc != NULL; lc = lc->lconn_next ) {
524 		if ( lc->lconn_server != NULL ) {
525 			fprintf( stderr, "* host: %s  port: %d%s\n",
526 			    ( lc->lconn_server->lsrv_host == NULL ) ? "(null)"
527 			    : lc->lconn_server->lsrv_host,
528 			    lc->lconn_server->lsrv_port, ( lc->lconn_sb ==
529 			    &ld->ld_sb ) ? "  (default)" : "" );
530 		}
531 		fprintf( stderr, "  refcnt: %d  status: %s\n", lc->lconn_refcnt,
532 		    ( lc->lconn_status == LDAP_CONNST_NEEDSOCKET ) ?
533 		    "NeedSocket" : ( lc->lconn_status ==
534 		    LDAP_CONNST_CONNECTING ) ? "Connecting" : "Connected" );
535 		fprintf( stderr, "  last used: %s\n",
536 		    ctime( &lc->lconn_lastused ));
537 		if ( !all ) {
538 			break;
539 		}
540 	}
541 }
542 
543 
544 void
dump_requests_and_responses(LDAP * ld)545 dump_requests_and_responses( LDAP *ld )
546 {
547 	LDAPRequest	*lr;
548 	LDAPMessage	*lm, *l;
549 
550 	fprintf( stderr, "** Outstanding Requests:\n" );
551 	if (( lr = ld->ld_requests ) == NULL ) {
552 		fprintf( stderr, "   Empty\n" );
553 	}
554 	for ( ; lr != NULL; lr = lr->lr_next ) {
555 	    fprintf( stderr, " * msgid %d,  origid %d, status %s\n",
556 		lr->lr_msgid, lr->lr_origid, ( lr->lr_status ==
557 		LDAP_REQST_INPROGRESS ) ? "InProgress" :
558 		( lr->lr_status == LDAP_REQST_CHASINGREFS ) ? "ChasingRefs" :
559 		( lr->lr_status == LDAP_REQST_NOTCONNECTED ) ? "NotConnected" :
560 		"Writing" );
561 	    fprintf( stderr, "   outstanding referrals %d, parent count %d\n",
562 		    lr->lr_outrefcnt, lr->lr_parentcnt );
563 	}
564 
565 	fprintf( stderr, "** Response Queue:\n" );
566 #ifdef _REENTRANT
567         LOCK_RESPONSE(ld);
568 #endif
569 	if (( lm = ld->ld_responses ) == NULLMSG ) {
570 		fprintf( stderr, "   Empty\n" );
571 	}
572 	for ( ; lm != NULLMSG; lm = lm->lm_next ) {
573 		fprintf( stderr, " * msgid %d,  type %d\n",
574 		    lm->lm_msgid, lm->lm_msgtype );
575 		if (( l = lm->lm_chain ) != NULL ) {
576 			fprintf( stderr, "   chained responses:\n" );
577 			for ( ; l != NULLMSG; l = l->lm_chain ) {
578 				fprintf( stderr,
579 				    "  * msgid %d,  type %d\n",
580 				    l->lm_msgid, l->lm_msgtype );
581 			}
582 		}
583 	}
584 #ifdef _REENTRANT
585 	UNLOCK_RESPONSE(ld);
586 #endif
587 }
588 #endif /* LDAP_DEBUG */
589 
590 
591 void
free_request(LDAP * ld,LDAPRequest * lr)592 free_request( LDAP *ld, LDAPRequest *lr )
593 {
594 	LDAPRequest	*tmplr, *nextlr;
595 	int i;
596 
597 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 214, "free_request (origid %1$d, msgid %2$d)\n"),
598 		lr->lr_origid, lr->lr_msgid, 0 );
599 
600 	if ( lr->lr_parent != NULL ) {
601 		--lr->lr_parent->lr_outrefcnt;
602 	} else {
603 		/* free all referrals (child requests) */
604 		for ( tmplr = lr->lr_refnext; tmplr != NULL; tmplr = nextlr ) {
605 			nextlr = tmplr->lr_refnext;
606 			free_request( ld, tmplr );
607 		}
608 	}
609 
610 	if ( lr->lr_prev == NULL ) {
611 		ld->ld_requests = lr->lr_next;
612 	} else {
613 		lr->lr_prev->lr_next = lr->lr_next;
614 	}
615 
616 	if ( lr->lr_next != NULL ) {
617 		lr->lr_next->lr_prev = lr->lr_prev;
618 	}
619 
620 	if ( lr->lr_ber != NULL ) {
621 		ber_free( lr->lr_ber, 1 );
622 	}
623 
624 	if ( lr->lr_res_error != NULL ) {
625 		free( lr->lr_res_error );
626 	}
627 
628 	if ( lr->lr_res_matched != NULL ) {
629 		free( lr->lr_res_matched );
630 	}
631 
632 	if ( lr->lr_ref_tofollow != NULL ) {
633 		for (i= 0; lr->lr_ref_tofollow[i] != NULL; i++)
634 			free(lr->lr_ref_tofollow[i]);
635 		free(lr->lr_ref_tofollow);
636 	}
637 	if ( lr->lr_ref_unfollowed != NULL ) {
638 		for (i= 0; lr->lr_ref_unfollowed[i] != NULL; i++)
639 			free(lr->lr_ref_unfollowed[i]);
640 		free(lr->lr_ref_unfollowed);
641 	}
642 	if ( lr->lr_ref_followed != NULL ) {
643 		for (i= 0; lr->lr_ref_followed[i] != NULL; i++)
644 			free(lr->lr_ref_followed[i]);
645 		free(lr->lr_ref_followed);
646 	}
647 
648 	free( lr );
649 }
650 
651 
652 static void
free_servers(LDAPServer * srvlist)653 free_servers( LDAPServer *srvlist )
654 {
655     LDAPServer	*nextsrv;
656 
657     while ( srvlist != NULL ) {
658 	nextsrv = srvlist->lsrv_next;
659 	if ( srvlist->lsrv_dn != NULL ) {
660 		free( srvlist->lsrv_dn );
661 	}
662 	if ( srvlist->lsrv_host != NULL ) {
663 		free( srvlist->lsrv_host );
664 	}
665 	free( srvlist );
666 	srvlist = nextsrv;
667     }
668 }
669 
670 /*
671  * nsldapi_connection_lost_nolock() resets "ld" to a non-connected, known
672  * state.  It should be called whenever a fatal error occurs on the
673  * Sockbuf "sb."  sb == NULL means we don't know specifically where
674  * the problem was so we assume all connections are bad.
675  */
676 void
nsldapi_connection_lost_nolock(LDAP * ld,Sockbuf * sb)677 nsldapi_connection_lost_nolock( LDAP *ld, Sockbuf *sb )
678 {
679 	LDAPRequest	*lr;
680 
681 	/*
682 	 * change status of all pending requests that are associated with "sb
683 	 *	to "connection dead."
684 	 * also change the connection status to "dead" and remove it from
685 	 *	the list of sockets we are interested in.
686 	 */
687 	for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
688 		if ( sb == NULL ||
689 		    ( lr->lr_conn != NULL && lr->lr_conn->lconn_sb == sb )) {
690 			lr->lr_status = LDAP_REQST_CONNDEAD;
691 			if ( lr->lr_conn != NULL ) {
692 				lr->lr_conn->lconn_status = LDAP_CONNST_DEAD;
693 			}
694 		}
695 	}
696 }
697 
698 #ifdef LDAP_DNS
699 static LDAPServer *
dn2servers(LDAP * ld,char * dn)700 dn2servers( LDAP *ld, char *dn )	/* dn can also be a domain.... */
701 {
702 	char		*p, *domain, *host, *server_dn, **dxs;
703 	int		i, port;
704 	LDAPServer	*srvlist, *prevsrv, *srv;
705 
706 	if (( domain = strrchr( dn, '@' )) != NULL ) {
707 		++domain;
708 	} else {
709 		domain = dn;
710 	}
711 
712 	if (( dxs = getdxbyname( domain )) == NULL ) {
713 		ld->ld_errno = LDAP_NO_MEMORY;
714 		return( NULL );
715 	}
716 
717 	srvlist = NULL;
718 
719 	for ( i = 0; dxs[ i ] != NULL; ++i ) {
720 		port = LDAP_PORT;
721 		server_dn = NULL;
722 		if ( strchr( dxs[ i ], ':' ) == NULL ) {
723 			host = dxs[ i ];
724 		} else if ( strlen( dxs[ i ] ) >= 7 &&
725 		    strncmp( dxs[ i ], "ldap://", 7 ) == 0 ) {
726 			host = dxs[ i ] + 7;
727 			if (( p = strchr( host, ':' )) == NULL ) {
728 				p = host;
729 			} else {
730 				*p++ = '\0';
731 				port = atoi( p );
732 			}
733 			if (( p = strchr( p, '/' )) != NULL ) {
734 				server_dn = ++p;
735 				if ( *server_dn == '\0' ) {
736 					server_dn = NULL;
737 				}
738 			}
739 		} else {
740 			host = NULL;
741 		}
742 
743 		if ( host != NULL ) {	/* found a server we can use */
744 			if (( srv = (LDAPServer *)calloc( 1,
745 			    sizeof( LDAPServer ))) == NULL ) {
746 				free_servers( srvlist );
747 				srvlist = NULL;
748 				break;		/* exit loop & return */
749 			}
750 
751 			/* add to end of list of servers */
752 			if ( srvlist == NULL ) {
753 				srvlist = srv;
754 			} else {
755 				prevsrv->lsrv_next = srv;
756 			}
757 			prevsrv = srv;
758 
759 			/* copy in info. */
760 			if (( srv->lsrv_host = strdup( host )) == NULL ||
761 			    ( server_dn != NULL && ( srv->lsrv_dn =
762 			    strdup( server_dn )) == NULL )) {
763 				free_servers( srvlist );
764 				srvlist = NULL;
765 				break;		/* exit loop & return */
766 			}
767 			srv->lsrv_port = port;
768 		}
769 	}
770 
771 	ldap_value_free( dxs );
772 
773 	if ( srvlist == NULL ) {
774 		ld->ld_errno = LDAP_SERVER_DOWN;
775 	}
776 
777 	return( srvlist );
778 }
779 #endif /* LDAP_DNS */
780