xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/open.c (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
1 /*	$NetBSD: open.c,v 1.2 2020/08/11 13:15:37 christos Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2020 The OpenLDAP Foundation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
18  * All rights reserved.
19  */
20 
21 #include <sys/cdefs.h>
22 __RCSID("$NetBSD: open.c,v 1.2 2020/08/11 13:15:37 christos Exp $");
23 
24 #include "portable.h"
25 
26 #include <stdio.h>
27 #ifdef HAVE_LIMITS_H
28 #include <limits.h>
29 #endif
30 
31 #include <ac/stdlib.h>
32 
33 #include <ac/param.h>
34 #include <ac/socket.h>
35 #include <ac/string.h>
36 #include <ac/time.h>
37 
38 #include <ac/unistd.h>
39 
40 #include "ldap-int.h"
41 #include "ldap.h"
42 #include "ldap_log.h"
43 
44 /* Caller must hold the conn_mutex since simultaneous accesses are possible */
45 int ldap_open_defconn( LDAP *ld )
46 {
47 	ld->ld_defconn = ldap_new_connection( ld,
48 		&ld->ld_options.ldo_defludp, 1, 1, NULL, 0, 0 );
49 
50 	if( ld->ld_defconn == NULL ) {
51 		ld->ld_errno = LDAP_SERVER_DOWN;
52 		return -1;
53 	}
54 
55 	++ld->ld_defconn->lconn_refcnt;	/* so it never gets closed/freed */
56 	return 0;
57 }
58 
59 /*
60  * ldap_open - initialize and connect to an ldap server.  A magic cookie to
61  * be used for future communication is returned on success, NULL on failure.
62  * "host" may be a space-separated list of hosts or IP addresses
63  *
64  * Example:
65  *	LDAP	*ld;
66  *	ld = ldap_open( hostname, port );
67  */
68 
69 LDAP *
70 ldap_open( LDAP_CONST char *host, int port )
71 {
72 	int rc;
73 	LDAP		*ld;
74 
75 	Debug( LDAP_DEBUG_TRACE, "ldap_open(%s, %d)\n",
76 		host, port, 0 );
77 
78 	ld = ldap_init( host, port );
79 	if ( ld == NULL ) {
80 		return( NULL );
81 	}
82 
83 	LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
84 	rc = ldap_open_defconn( ld );
85 	LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
86 
87 	if( rc < 0 ) {
88 		ldap_ld_free( ld, 0, NULL, NULL );
89 		ld = NULL;
90 	}
91 
92 	Debug( LDAP_DEBUG_TRACE, "ldap_open: %s\n",
93 		ld != NULL ? "succeeded" : "failed", 0, 0 );
94 
95 	return ld;
96 }
97 
98 
99 
100 int
101 ldap_create( LDAP **ldp )
102 {
103 	LDAP			*ld;
104 	struct ldapoptions	*gopts;
105 
106 	*ldp = NULL;
107 	/* Get pointer to global option structure */
108 	if ( (gopts = LDAP_INT_GLOBAL_OPT()) == NULL) {
109 		return LDAP_NO_MEMORY;
110 	}
111 
112 	/* Initialize the global options, if not already done. */
113 	if( gopts->ldo_valid != LDAP_INITIALIZED ) {
114 		ldap_int_initialize(gopts, NULL);
115 		if ( gopts->ldo_valid != LDAP_INITIALIZED )
116 			return LDAP_LOCAL_ERROR;
117 	}
118 
119 	Debug( LDAP_DEBUG_TRACE, "ldap_create\n", 0, 0, 0 );
120 
121 	if ( (ld = (LDAP *) LDAP_CALLOC( 1, sizeof(LDAP) )) == NULL ) {
122 		return( LDAP_NO_MEMORY );
123 	}
124 
125 	if ( (ld->ldc = (struct ldap_common *) LDAP_CALLOC( 1,
126 			sizeof(struct ldap_common) )) == NULL ) {
127 		LDAP_FREE( (char *)ld );
128 		return( LDAP_NO_MEMORY );
129 	}
130 	/* copy the global options */
131 	LDAP_MUTEX_LOCK( &gopts->ldo_mutex );
132 	AC_MEMCPY(&ld->ld_options, gopts, sizeof(ld->ld_options));
133 #ifdef LDAP_R_COMPILE
134 	/* Properly initialize the structs mutex */
135 	ldap_pvt_thread_mutex_init( &(ld->ld_ldopts_mutex) );
136 #endif
137 	LDAP_MUTEX_UNLOCK( &gopts->ldo_mutex );
138 
139 	ld->ld_valid = LDAP_VALID_SESSION;
140 
141 	/* but not pointers to malloc'ed items */
142 	ld->ld_options.ldo_sctrls = NULL;
143 	ld->ld_options.ldo_cctrls = NULL;
144 	ld->ld_options.ldo_defludp = NULL;
145 	ld->ld_options.ldo_conn_cbs = NULL;
146 
147 #ifdef HAVE_CYRUS_SASL
148 	ld->ld_options.ldo_def_sasl_mech = gopts->ldo_def_sasl_mech
149 		? LDAP_STRDUP( gopts->ldo_def_sasl_mech ) : NULL;
150 	ld->ld_options.ldo_def_sasl_realm = gopts->ldo_def_sasl_realm
151 		? LDAP_STRDUP( gopts->ldo_def_sasl_realm ) : NULL;
152 	ld->ld_options.ldo_def_sasl_authcid = gopts->ldo_def_sasl_authcid
153 		? LDAP_STRDUP( gopts->ldo_def_sasl_authcid ) : NULL;
154 	ld->ld_options.ldo_def_sasl_authzid = gopts->ldo_def_sasl_authzid
155 		? LDAP_STRDUP( gopts->ldo_def_sasl_authzid ) : NULL;
156 #endif
157 
158 #ifdef HAVE_TLS
159 	/* We explicitly inherit the SSL_CTX, don't need the names/paths. Leave
160 	 * them empty to allow new SSL_CTX's to be created from scratch.
161 	 */
162 	memset( &ld->ld_options.ldo_tls_info, 0,
163 		sizeof( ld->ld_options.ldo_tls_info ));
164 	ld->ld_options.ldo_tls_ctx = NULL;
165 #endif
166 
167 	if ( gopts->ldo_defludp ) {
168 		ld->ld_options.ldo_defludp = ldap_url_duplist(gopts->ldo_defludp);
169 
170 		if ( ld->ld_options.ldo_defludp == NULL ) goto nomem;
171 	}
172 
173 	if (( ld->ld_selectinfo = ldap_new_select_info()) == NULL ) goto nomem;
174 
175 	ld->ld_lberoptions = LBER_USE_DER;
176 
177 	ld->ld_sb = ber_sockbuf_alloc( );
178 	if ( ld->ld_sb == NULL ) goto nomem;
179 
180 #ifdef LDAP_R_COMPILE
181 	ldap_pvt_thread_mutex_init( &ld->ld_msgid_mutex );
182 	ldap_pvt_thread_mutex_init( &ld->ld_conn_mutex );
183 	ldap_pvt_thread_mutex_init( &ld->ld_req_mutex );
184 	ldap_pvt_thread_mutex_init( &ld->ld_res_mutex );
185 	ldap_pvt_thread_mutex_init( &ld->ld_abandon_mutex );
186 	ldap_pvt_thread_mutex_init( &ld->ld_ldcmutex );
187 #endif
188 	ld->ld_ldcrefcnt = 1;
189 	*ldp = ld;
190 	return LDAP_SUCCESS;
191 
192 nomem:
193 	ldap_free_select_info( ld->ld_selectinfo );
194 	ldap_free_urllist( ld->ld_options.ldo_defludp );
195 #ifdef HAVE_CYRUS_SASL
196 	LDAP_FREE( ld->ld_options.ldo_def_sasl_authzid );
197 	LDAP_FREE( ld->ld_options.ldo_def_sasl_authcid );
198 	LDAP_FREE( ld->ld_options.ldo_def_sasl_realm );
199 	LDAP_FREE( ld->ld_options.ldo_def_sasl_mech );
200 #endif
201 	LDAP_FREE( (char *)ld );
202 	return LDAP_NO_MEMORY;
203 }
204 
205 /*
206  * ldap_init - initialize the LDAP library.  A magic cookie to be used for
207  * future communication is returned on success, NULL on failure.
208  * "host" may be a space-separated list of hosts or IP addresses
209  *
210  * Example:
211  *	LDAP	*ld;
212  *	ld = ldap_init( host, port );
213  */
214 LDAP *
215 ldap_init( LDAP_CONST char *defhost, int defport )
216 {
217 	LDAP *ld;
218 	int rc;
219 
220 	rc = ldap_create(&ld);
221 	if ( rc != LDAP_SUCCESS )
222 		return NULL;
223 
224 	if (defport != 0)
225 		ld->ld_options.ldo_defport = defport;
226 
227 	if (defhost != NULL) {
228 		rc = ldap_set_option(ld, LDAP_OPT_HOST_NAME, defhost);
229 		if ( rc != LDAP_SUCCESS ) {
230 			ldap_ld_free(ld, 1, NULL, NULL);
231 			return NULL;
232 		}
233 	}
234 
235 	return( ld );
236 }
237 
238 
239 int
240 ldap_initialize( LDAP **ldp, LDAP_CONST char *url )
241 {
242 	int rc;
243 	LDAP *ld;
244 
245 	*ldp = NULL;
246 	rc = ldap_create(&ld);
247 	if ( rc != LDAP_SUCCESS )
248 		return rc;
249 
250 	if (url != NULL) {
251 		rc = ldap_set_option(ld, LDAP_OPT_URI, url);
252 		if ( rc != LDAP_SUCCESS ) {
253 			ldap_ld_free(ld, 1, NULL, NULL);
254 			return rc;
255 		}
256 #ifdef LDAP_CONNECTIONLESS
257 		if (ldap_is_ldapc_url(url))
258 			LDAP_IS_UDP(ld) = 1;
259 #endif
260 	}
261 
262 	*ldp = ld;
263 	return LDAP_SUCCESS;
264 }
265 
266 int
267 ldap_init_fd(
268 	ber_socket_t fd,
269 	int proto,
270 	LDAP_CONST char *url,
271 	LDAP **ldp
272 )
273 {
274 	int rc;
275 	LDAP *ld;
276 	LDAPConn *conn;
277 #ifdef LDAP_CONNECTIONLESS
278 	ber_socklen_t	len;
279 #endif
280 
281 	*ldp = NULL;
282 	rc = ldap_create( &ld );
283 	if( rc != LDAP_SUCCESS )
284 		return( rc );
285 
286 	if (url != NULL) {
287 		rc = ldap_set_option(ld, LDAP_OPT_URI, url);
288 		if ( rc != LDAP_SUCCESS ) {
289 			ldap_ld_free(ld, 1, NULL, NULL);
290 			return rc;
291 		}
292 	}
293 
294 	LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
295 	/* Attach the passed socket as the LDAP's connection */
296 	conn = ldap_new_connection( ld, NULL, 1, 0, NULL, 0, 0 );
297 	if( conn == NULL ) {
298 		ldap_unbind_ext( ld, NULL, NULL );
299 		return( LDAP_NO_MEMORY );
300 	}
301 	if( url )
302 		conn->lconn_server = ldap_url_dup( ld->ld_options.ldo_defludp );
303 	ber_sockbuf_ctrl( conn->lconn_sb, LBER_SB_OPT_SET_FD, &fd );
304 	ld->ld_defconn = conn;
305 	++ld->ld_defconn->lconn_refcnt;	/* so it never gets closed/freed */
306 	LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
307 
308 	switch( proto ) {
309 	case LDAP_PROTO_TCP:
310 #ifdef LDAP_DEBUG
311 		ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
312 			LBER_SBIOD_LEVEL_PROVIDER, (void *)"tcp_" );
313 #endif
314 		ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_tcp,
315 			LBER_SBIOD_LEVEL_PROVIDER, NULL );
316 		break;
317 
318 #ifdef LDAP_CONNECTIONLESS
319 	case LDAP_PROTO_UDP:
320 		LDAP_IS_UDP(ld) = 1;
321 		if( ld->ld_options.ldo_peer )
322 			ldap_memfree( ld->ld_options.ldo_peer );
323 		ld->ld_options.ldo_peer = ldap_memcalloc( 1, sizeof( struct sockaddr_storage ) );
324 		len = sizeof( struct sockaddr_storage );
325 		if( getpeername ( fd, ld->ld_options.ldo_peer, &len ) < 0) {
326 			ldap_unbind_ext( ld, NULL, NULL );
327 			return( AC_SOCKET_ERROR );
328 		}
329 #ifdef LDAP_DEBUG
330 		ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
331 			LBER_SBIOD_LEVEL_PROVIDER, (void *)"udp_" );
332 #endif
333 		ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_udp,
334 			LBER_SBIOD_LEVEL_PROVIDER, NULL );
335 		ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_readahead,
336 			LBER_SBIOD_LEVEL_PROVIDER, NULL );
337 		break;
338 #endif /* LDAP_CONNECTIONLESS */
339 
340 	case LDAP_PROTO_IPC:
341 #ifdef LDAP_DEBUG
342 		ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
343 			LBER_SBIOD_LEVEL_PROVIDER, (void *)"ipc_" );
344 #endif
345 		ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_fd,
346 			LBER_SBIOD_LEVEL_PROVIDER, NULL );
347 		break;
348 
349 	case LDAP_PROTO_EXT:
350 		/* caller must supply sockbuf handlers */
351 		break;
352 
353 	default:
354 		ldap_unbind_ext( ld, NULL, NULL );
355 		return LDAP_PARAM_ERROR;
356 	}
357 
358 #ifdef LDAP_DEBUG
359 	ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
360 		INT_MAX, (void *)"ldap_" );
361 #endif
362 
363 	/* Add the connection to the *LDAP's select pool */
364 	ldap_mark_select_read( ld, conn->lconn_sb );
365 
366 	*ldp = ld;
367 	return LDAP_SUCCESS;
368 }
369 
370 /* Protected by ld_conn_mutex */
371 int
372 ldap_int_open_connection(
373 	LDAP *ld,
374 	LDAPConn *conn,
375 	LDAPURLDesc *srv,
376 	int async )
377 {
378 	int rc = -1;
379 	int proto;
380 
381 	Debug( LDAP_DEBUG_TRACE, "ldap_int_open_connection\n", 0, 0, 0 );
382 
383 	switch ( proto = ldap_pvt_url_scheme2proto( srv->lud_scheme ) ) {
384 		case LDAP_PROTO_TCP:
385 			rc = ldap_connect_to_host( ld, conn->lconn_sb,
386 				proto, srv, async );
387 
388 			if ( rc == -1 ) return rc;
389 #ifdef LDAP_DEBUG
390 			ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
391 				LBER_SBIOD_LEVEL_PROVIDER, (void *)"tcp_" );
392 #endif
393 			ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_tcp,
394 				LBER_SBIOD_LEVEL_PROVIDER, NULL );
395 
396 			break;
397 
398 #ifdef LDAP_CONNECTIONLESS
399 		case LDAP_PROTO_UDP:
400 			LDAP_IS_UDP(ld) = 1;
401 			rc = ldap_connect_to_host( ld, conn->lconn_sb,
402 				proto, srv, async );
403 
404 			if ( rc == -1 ) return rc;
405 #ifdef LDAP_DEBUG
406 			ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
407 				LBER_SBIOD_LEVEL_PROVIDER, (void *)"udp_" );
408 #endif
409 			ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_udp,
410 				LBER_SBIOD_LEVEL_PROVIDER, NULL );
411 
412 			ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_readahead,
413 				LBER_SBIOD_LEVEL_PROVIDER, NULL );
414 
415 			break;
416 #endif
417 		case LDAP_PROTO_IPC:
418 #ifdef LDAP_PF_LOCAL
419 			/* only IPC mechanism supported is PF_LOCAL (PF_UNIX) */
420 			rc = ldap_connect_to_path( ld, conn->lconn_sb,
421 				srv, async );
422 			if ( rc == -1 ) return rc;
423 #ifdef LDAP_DEBUG
424 			ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
425 				LBER_SBIOD_LEVEL_PROVIDER, (void *)"ipc_" );
426 #endif
427 			ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_fd,
428 				LBER_SBIOD_LEVEL_PROVIDER, NULL );
429 
430 			break;
431 #endif /* LDAP_PF_LOCAL */
432 		default:
433 			return -1;
434 			break;
435 	}
436 
437 	conn->lconn_created = time( NULL );
438 
439 #ifdef LDAP_DEBUG
440 	ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
441 		INT_MAX, (void *)"ldap_" );
442 #endif
443 
444 #ifdef LDAP_CONNECTIONLESS
445 	if( proto == LDAP_PROTO_UDP ) return 0;
446 #endif
447 
448 #ifdef HAVE_TLS
449 	if ((rc == 0 || rc == -2) && ( ld->ld_options.ldo_tls_mode == LDAP_OPT_X_TLS_HARD ||
450 		strcmp( srv->lud_scheme, "ldaps" ) == 0 ))
451 	{
452 		++conn->lconn_refcnt;	/* avoid premature free */
453 
454 		rc = ldap_int_tls_start( ld, conn, srv );
455 
456 		--conn->lconn_refcnt;
457 
458 		if (rc != LDAP_SUCCESS) {
459 			/* process connection callbacks */
460 			{
461 				struct ldapoptions *lo;
462 				ldaplist *ll;
463 				ldap_conncb *cb;
464 
465 				lo = &ld->ld_options;
466 				LDAP_MUTEX_LOCK( &lo->ldo_mutex );
467 				if ( lo->ldo_conn_cbs ) {
468 					for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) {
469 						cb = ll->ll_data;
470 						cb->lc_del( ld, conn->lconn_sb, cb );
471 					}
472 				}
473 				LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
474 				lo = LDAP_INT_GLOBAL_OPT();
475 				LDAP_MUTEX_LOCK( &lo->ldo_mutex );
476 				if ( lo->ldo_conn_cbs ) {
477 					for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) {
478 						cb = ll->ll_data;
479 						cb->lc_del( ld, conn->lconn_sb, cb );
480 					}
481 				}
482 				LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
483 			}
484 			ber_int_sb_close( conn->lconn_sb );
485 			return -1;
486 		}
487 	}
488 #endif
489 
490 	return( 0 );
491 }
492 
493 /*
494  * ldap_open_internal_connection - open connection and set file descriptor
495  *
496  * note: ldap_init_fd() may be preferable
497  */
498 
499 int
500 ldap_open_internal_connection( LDAP **ldp, ber_socket_t *fdp )
501 {
502 	int rc;
503 	LDAPConn *c;
504 	LDAPRequest *lr;
505 	LDAP	*ld;
506 
507 	rc = ldap_create( &ld );
508 	if( rc != LDAP_SUCCESS ) {
509 		*ldp = NULL;
510 		return( rc );
511 	}
512 
513 	/* Make it appear that a search request, msgid 0, was sent */
514 	lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ));
515 	if( lr == NULL ) {
516 		ldap_unbind_ext( ld, NULL, NULL );
517 		*ldp = NULL;
518 		return( LDAP_NO_MEMORY );
519 	}
520 	memset(lr, 0, sizeof( LDAPRequest ));
521 	lr->lr_msgid = 0;
522 	lr->lr_status = LDAP_REQST_INPROGRESS;
523 	lr->lr_res_errno = LDAP_SUCCESS;
524 	/* no mutex lock needed, we just created this ld here */
525 	ld->ld_requests = lr;
526 
527 	LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
528 	/* Attach the passed socket as the *LDAP's connection */
529 	c = ldap_new_connection( ld, NULL, 1, 0, NULL, 0, 0 );
530 	if( c == NULL ) {
531 		ldap_unbind_ext( ld, NULL, NULL );
532 		*ldp = NULL;
533 		LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
534 		return( LDAP_NO_MEMORY );
535 	}
536 	ber_sockbuf_ctrl( c->lconn_sb, LBER_SB_OPT_SET_FD, fdp );
537 #ifdef LDAP_DEBUG
538 	ber_sockbuf_add_io( c->lconn_sb, &ber_sockbuf_io_debug,
539 		LBER_SBIOD_LEVEL_PROVIDER, (void *)"int_" );
540 #endif
541 	ber_sockbuf_add_io( c->lconn_sb, &ber_sockbuf_io_tcp,
542 	  LBER_SBIOD_LEVEL_PROVIDER, NULL );
543 	ld->ld_defconn = c;
544 	LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
545 
546 	/* Add the connection to the *LDAP's select pool */
547 	ldap_mark_select_read( ld, c->lconn_sb );
548 
549 	/* Make this connection an LDAP V3 protocol connection */
550 	rc = LDAP_VERSION3;
551 	ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &rc );
552 	*ldp = ld;
553 
554 	++ld->ld_defconn->lconn_refcnt;	/* so it never gets closed/freed */
555 
556 	return( LDAP_SUCCESS );
557 }
558 
559 LDAP *
560 ldap_dup( LDAP *old )
561 {
562 	LDAP			*ld;
563 
564 	if ( old == NULL ) {
565 		return( NULL );
566 	}
567 
568 	Debug( LDAP_DEBUG_TRACE, "ldap_dup\n", 0, 0, 0 );
569 
570 	if ( (ld = (LDAP *) LDAP_CALLOC( 1, sizeof(LDAP) )) == NULL ) {
571 		return( NULL );
572 	}
573 
574 	LDAP_MUTEX_LOCK( &old->ld_ldcmutex );
575 	ld->ldc = old->ldc;
576 	old->ld_ldcrefcnt++;
577 	LDAP_MUTEX_UNLOCK( &old->ld_ldcmutex );
578 	return ( ld );
579 }
580 
581 int
582 ldap_int_check_async_open( LDAP *ld, ber_socket_t sd )
583 {
584 	struct timeval tv = { 0 };
585 	int rc;
586 
587 	rc = ldap_int_poll( ld, sd, &tv, 1 );
588 	switch ( rc ) {
589 	case 0:
590 		/* now ready to start tls */
591 		ld->ld_defconn->lconn_status = LDAP_CONNST_CONNECTED;
592 		break;
593 
594 	default:
595 		ld->ld_errno = LDAP_CONNECT_ERROR;
596 		return -1;
597 
598 	case -2:
599 		/* connect not completed yet */
600 		ld->ld_errno = LDAP_X_CONNECTING;
601 		return rc;
602 	}
603 
604 #ifdef HAVE_TLS
605 	if ( ld->ld_options.ldo_tls_mode == LDAP_OPT_X_TLS_HARD ||
606 		!strcmp( ld->ld_defconn->lconn_server->lud_scheme, "ldaps" )) {
607 
608 		++ld->ld_defconn->lconn_refcnt;	/* avoid premature free */
609 
610 		rc = ldap_int_tls_start( ld, ld->ld_defconn, ld->ld_defconn->lconn_server );
611 
612 		--ld->ld_defconn->lconn_refcnt;
613 	}
614 #endif
615 	return rc;
616 }
617