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
nsldapi_alloc_ber_with_options(LDAP * ld,BerElement ** berp)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
nsldapi_set_ber_options(LDAP * ld,BerElement * ber)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
nsldapi_send_initial_request(LDAP * ld,int msgid,unsigned long msgtype,char * dn,BerElement * ber)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
nsldapi_send_server_request(LDAP * ld,BerElement * ber,int msgid,LDAPRequest * parentreq,LDAPServer * srvlist,LDAPConn * lc,char * bindreqdn,int bind)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
nsldapi_ber_flush(LDAP * ld,Sockbuf * sb,BerElement * ber,int freeit,int async)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 *
nsldapi_new_connection(LDAP * ld,LDAPServer ** srvlistp,int use_ldsb,int connect,int bind)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 *
find_connection(LDAP * ld,LDAPServer * srv,int any)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
use_connection(LDAP * ld,LDAPConn * lc)561 use_connection( LDAP *ld, LDAPConn *lc )
562 {
563 ++lc->lconn_refcnt;
564 lc->lconn_lastused = time( 0 );
565 }
566
567
568 void
nsldapi_free_connection(LDAP * ld,LDAPConn * lc,LDAPControl ** serverctrls,LDAPControl ** clientctrls,int force,int unbind)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
nsldapi_dump_connection(LDAP * ld,LDAPConn * lconns,int all)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
nsldapi_dump_requests_and_responses(LDAP * ld)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
nsldapi_free_request(LDAP * ld,LDAPRequest * lr,int free_conn)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
free_servers(LDAPServer * srvlist)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
nsldapi_chase_v2_referrals(LDAP * ld,LDAPRequest * lr,char ** errstrp,int * totalcountp,int * chasingcountp)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
nsldapi_chase_v3_refs(LDAP * ld,LDAPRequest * lr,char ** v3refs,int is_reference,int * totalcountp,int * chasingcountp)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
chase_one_referral(LDAP * ld,LDAPRequest * lr,LDAPRequest * origreq,char * refurl,char * desc,int * unknownp)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
nsldapi_append_referral(LDAP * ld,char ** referralsp,char * s)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
re_encode_request(LDAP * ld,BerElement * origber,int msgid,LDAPURLDesc * ludp,BerElement ** berp)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 *
nsldapi_find_request_by_msgid(LDAP * ld,int msgid)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
nsldapi_connection_lost_nolock(LDAP * ld,Sockbuf * sb)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 *
dn2servers(LDAP * ld,char * dn)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