xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/open.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1*549b59edSchristos /*	$NetBSD: open.c,v 1.3 2021/08/14 16:14:56 christos Exp $	*/
24e6df137Slukem 
3d11b170bStron /* $OpenLDAP$ */
42de962bdSlukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
52de962bdSlukem  *
6*549b59edSchristos  * Copyright 1998-2021 The OpenLDAP Foundation.
72de962bdSlukem  * All rights reserved.
82de962bdSlukem  *
92de962bdSlukem  * Redistribution and use in source and binary forms, with or without
102de962bdSlukem  * modification, are permitted only as authorized by the OpenLDAP
112de962bdSlukem  * Public License.
122de962bdSlukem  *
132de962bdSlukem  * A copy of this license is available in the file LICENSE in the
142de962bdSlukem  * top-level directory of the distribution or, alternatively, at
152de962bdSlukem  * <http://www.OpenLDAP.org/license.html>.
162de962bdSlukem  */
172de962bdSlukem /* Portions Copyright (c) 1995 Regents of the University of Michigan.
182de962bdSlukem  * All rights reserved.
192de962bdSlukem  */
202de962bdSlukem 
21376af7d7Schristos #include <sys/cdefs.h>
22*549b59edSchristos __RCSID("$NetBSD: open.c,v 1.3 2021/08/14 16:14:56 christos Exp $");
23376af7d7Schristos 
242de962bdSlukem #include "portable.h"
252de962bdSlukem 
262de962bdSlukem #include <stdio.h>
272de962bdSlukem #ifdef HAVE_LIMITS_H
282de962bdSlukem #include <limits.h>
292de962bdSlukem #endif
302de962bdSlukem 
312de962bdSlukem #include <ac/stdlib.h>
322de962bdSlukem 
332de962bdSlukem #include <ac/param.h>
342de962bdSlukem #include <ac/socket.h>
352de962bdSlukem #include <ac/string.h>
362de962bdSlukem #include <ac/time.h>
372de962bdSlukem 
382de962bdSlukem #include <ac/unistd.h>
392de962bdSlukem 
402de962bdSlukem #include "ldap-int.h"
414e27b3e8Schristos #include "ldap.h"
422de962bdSlukem #include "ldap_log.h"
432de962bdSlukem 
44d11b170bStron /* Caller must hold the conn_mutex since simultaneous accesses are possible */
ldap_open_defconn(LDAP * ld)452de962bdSlukem int ldap_open_defconn( LDAP *ld )
462de962bdSlukem {
472de962bdSlukem 	ld->ld_defconn = ldap_new_connection( ld,
48d11b170bStron 		&ld->ld_options.ldo_defludp, 1, 1, NULL, 0, 0 );
492de962bdSlukem 
502de962bdSlukem 	if( ld->ld_defconn == NULL ) {
512de962bdSlukem 		ld->ld_errno = LDAP_SERVER_DOWN;
522de962bdSlukem 		return -1;
532de962bdSlukem 	}
542de962bdSlukem 
552de962bdSlukem 	++ld->ld_defconn->lconn_refcnt;	/* so it never gets closed/freed */
562de962bdSlukem 	return 0;
572de962bdSlukem }
582de962bdSlukem 
592de962bdSlukem /*
60*549b59edSchristos  * ldap_connect - Connect to an ldap server.
61*549b59edSchristos  *
62*549b59edSchristos  * Example:
63*549b59edSchristos  *	LDAP	*ld;
64*549b59edSchristos  *	ldap_initialize( &ld, url );
65*549b59edSchristos  *	ldap_connect( ld );
66*549b59edSchristos  */
67*549b59edSchristos int
ldap_connect(LDAP * ld)68*549b59edSchristos ldap_connect( LDAP *ld )
69*549b59edSchristos {
70*549b59edSchristos 	ber_socket_t sd = AC_SOCKET_INVALID;
71*549b59edSchristos 	int rc = LDAP_SUCCESS;
72*549b59edSchristos 
73*549b59edSchristos 	LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
74*549b59edSchristos 	if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd ) == -1 ) {
75*549b59edSchristos 		rc = ldap_open_defconn( ld );
76*549b59edSchristos 	}
77*549b59edSchristos 	LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
78*549b59edSchristos 
79*549b59edSchristos 	return rc;
80*549b59edSchristos }
81*549b59edSchristos 
82*549b59edSchristos /*
832de962bdSlukem  * ldap_open - initialize and connect to an ldap server.  A magic cookie to
842de962bdSlukem  * be used for future communication is returned on success, NULL on failure.
852de962bdSlukem  * "host" may be a space-separated list of hosts or IP addresses
862de962bdSlukem  *
872de962bdSlukem  * Example:
882de962bdSlukem  *	LDAP	*ld;
892de962bdSlukem  *	ld = ldap_open( hostname, port );
902de962bdSlukem  */
912de962bdSlukem 
922de962bdSlukem LDAP *
ldap_open(LDAP_CONST char * host,int port)932de962bdSlukem ldap_open( LDAP_CONST char *host, int port )
942de962bdSlukem {
952de962bdSlukem 	int rc;
962de962bdSlukem 	LDAP		*ld;
972de962bdSlukem 
98*549b59edSchristos 	Debug2( LDAP_DEBUG_TRACE, "ldap_open(%s, %d)\n",
99*549b59edSchristos 		host, port );
1002de962bdSlukem 
1012de962bdSlukem 	ld = ldap_init( host, port );
1022de962bdSlukem 	if ( ld == NULL ) {
1032de962bdSlukem 		return( NULL );
1042de962bdSlukem 	}
1052de962bdSlukem 
106d11b170bStron 	LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
1072de962bdSlukem 	rc = ldap_open_defconn( ld );
108d11b170bStron 	LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
1092de962bdSlukem 
1102de962bdSlukem 	if( rc < 0 ) {
1112de962bdSlukem 		ldap_ld_free( ld, 0, NULL, NULL );
1122de962bdSlukem 		ld = NULL;
1132de962bdSlukem 	}
1142de962bdSlukem 
115*549b59edSchristos 	Debug1( LDAP_DEBUG_TRACE, "ldap_open: %s\n",
116*549b59edSchristos 		ld != NULL ? "succeeded" : "failed" );
1172de962bdSlukem 
1182de962bdSlukem 	return ld;
1192de962bdSlukem }
1202de962bdSlukem 
1212de962bdSlukem 
1222de962bdSlukem 
1232de962bdSlukem int
ldap_create(LDAP ** ldp)1242de962bdSlukem ldap_create( LDAP **ldp )
1252de962bdSlukem {
1262de962bdSlukem 	LDAP			*ld;
1272de962bdSlukem 	struct ldapoptions	*gopts;
1282de962bdSlukem 
1292de962bdSlukem 	*ldp = NULL;
1302de962bdSlukem 	/* Get pointer to global option structure */
1312de962bdSlukem 	if ( (gopts = LDAP_INT_GLOBAL_OPT()) == NULL) {
1322de962bdSlukem 		return LDAP_NO_MEMORY;
1332de962bdSlukem 	}
1342de962bdSlukem 
1352de962bdSlukem 	/* Initialize the global options, if not already done. */
1362de962bdSlukem 	if( gopts->ldo_valid != LDAP_INITIALIZED ) {
1372de962bdSlukem 		ldap_int_initialize(gopts, NULL);
1382de962bdSlukem 		if ( gopts->ldo_valid != LDAP_INITIALIZED )
1392de962bdSlukem 			return LDAP_LOCAL_ERROR;
1402de962bdSlukem 	}
1412de962bdSlukem 
142*549b59edSchristos 	Debug0( LDAP_DEBUG_TRACE, "ldap_create\n" );
1432de962bdSlukem 
1442de962bdSlukem 	if ( (ld = (LDAP *) LDAP_CALLOC( 1, sizeof(LDAP) )) == NULL ) {
1452de962bdSlukem 		return( LDAP_NO_MEMORY );
1462de962bdSlukem 	}
1472de962bdSlukem 
148d11b170bStron 	if ( (ld->ldc = (struct ldap_common *) LDAP_CALLOC( 1,
149d11b170bStron 			sizeof(struct ldap_common) )) == NULL ) {
150d11b170bStron 		LDAP_FREE( (char *)ld );
151d11b170bStron 		return( LDAP_NO_MEMORY );
152d11b170bStron 	}
1532de962bdSlukem 	/* copy the global options */
154d11b170bStron 	LDAP_MUTEX_LOCK( &gopts->ldo_mutex );
1552de962bdSlukem 	AC_MEMCPY(&ld->ld_options, gopts, sizeof(ld->ld_options));
156d11b170bStron #ifdef LDAP_R_COMPILE
157d11b170bStron 	/* Properly initialize the structs mutex */
158d11b170bStron 	ldap_pvt_thread_mutex_init( &(ld->ld_ldopts_mutex) );
159d11b170bStron #endif
160*549b59edSchristos 
161*549b59edSchristos #ifdef HAVE_TLS
162*549b59edSchristos 	if ( ld->ld_options.ldo_tls_pin_hashalg ) {
163*549b59edSchristos 		int len = strlen( gopts->ldo_tls_pin_hashalg );
164*549b59edSchristos 
165*549b59edSchristos 		ld->ld_options.ldo_tls_pin_hashalg =
166*549b59edSchristos 			LDAP_MALLOC( len + 1 + gopts->ldo_tls_pin.bv_len );
167*549b59edSchristos 		if ( !ld->ld_options.ldo_tls_pin_hashalg ) goto nomem;
168*549b59edSchristos 
169*549b59edSchristos 		ld->ld_options.ldo_tls_pin.bv_val = ld->ld_options.ldo_tls_pin_hashalg
170*549b59edSchristos 			+ len + 1;
171*549b59edSchristos 		AC_MEMCPY( ld->ld_options.ldo_tls_pin_hashalg, gopts->ldo_tls_pin_hashalg,
172*549b59edSchristos 				len + 1 + gopts->ldo_tls_pin.bv_len );
173*549b59edSchristos 	} else if ( !BER_BVISEMPTY(&ld->ld_options.ldo_tls_pin) ) {
174*549b59edSchristos 		ber_dupbv( &ld->ld_options.ldo_tls_pin, &gopts->ldo_tls_pin );
175*549b59edSchristos 	}
176*549b59edSchristos #endif
177d11b170bStron 	LDAP_MUTEX_UNLOCK( &gopts->ldo_mutex );
1782de962bdSlukem 
1792de962bdSlukem 	ld->ld_valid = LDAP_VALID_SESSION;
1802de962bdSlukem 
1812de962bdSlukem 	/* but not pointers to malloc'ed items */
1822de962bdSlukem 	ld->ld_options.ldo_sctrls = NULL;
1832de962bdSlukem 	ld->ld_options.ldo_cctrls = NULL;
1842de962bdSlukem 	ld->ld_options.ldo_defludp = NULL;
1854e6df137Slukem 	ld->ld_options.ldo_conn_cbs = NULL;
1862de962bdSlukem 
187*549b59edSchristos 	ld->ld_options.ldo_defbase = gopts->ldo_defbase
188*549b59edSchristos 		? LDAP_STRDUP( gopts->ldo_defbase ) : NULL;
189*549b59edSchristos 
1902de962bdSlukem #ifdef HAVE_CYRUS_SASL
1912de962bdSlukem 	ld->ld_options.ldo_def_sasl_mech = gopts->ldo_def_sasl_mech
1922de962bdSlukem 		? LDAP_STRDUP( gopts->ldo_def_sasl_mech ) : NULL;
1932de962bdSlukem 	ld->ld_options.ldo_def_sasl_realm = gopts->ldo_def_sasl_realm
1942de962bdSlukem 		? LDAP_STRDUP( gopts->ldo_def_sasl_realm ) : NULL;
1952de962bdSlukem 	ld->ld_options.ldo_def_sasl_authcid = gopts->ldo_def_sasl_authcid
1962de962bdSlukem 		? LDAP_STRDUP( gopts->ldo_def_sasl_authcid ) : NULL;
1972de962bdSlukem 	ld->ld_options.ldo_def_sasl_authzid = gopts->ldo_def_sasl_authzid
1982de962bdSlukem 		? LDAP_STRDUP( gopts->ldo_def_sasl_authzid ) : NULL;
1992de962bdSlukem #endif
2002de962bdSlukem 
2012de962bdSlukem #ifdef HAVE_TLS
2022de962bdSlukem 	/* We explicitly inherit the SSL_CTX, don't need the names/paths. Leave
2032de962bdSlukem 	 * them empty to allow new SSL_CTX's to be created from scratch.
2042de962bdSlukem 	 */
2052de962bdSlukem 	memset( &ld->ld_options.ldo_tls_info, 0,
2062de962bdSlukem 		sizeof( ld->ld_options.ldo_tls_info ));
2072de962bdSlukem 	ld->ld_options.ldo_tls_ctx = NULL;
2082de962bdSlukem #endif
2092de962bdSlukem 
2102de962bdSlukem 	if ( gopts->ldo_defludp ) {
2112de962bdSlukem 		ld->ld_options.ldo_defludp = ldap_url_duplist(gopts->ldo_defludp);
2122de962bdSlukem 
2132de962bdSlukem 		if ( ld->ld_options.ldo_defludp == NULL ) goto nomem;
2142de962bdSlukem 	}
2152de962bdSlukem 
2162de962bdSlukem 	if (( ld->ld_selectinfo = ldap_new_select_info()) == NULL ) goto nomem;
2172de962bdSlukem 
218*549b59edSchristos 	ld->ld_options.ldo_local_ip_addrs.local_ip_addrs = NULL;
219*549b59edSchristos 	if( gopts->ldo_local_ip_addrs.local_ip_addrs ) {
220*549b59edSchristos 		ld->ld_options.ldo_local_ip_addrs.local_ip_addrs =
221*549b59edSchristos 			LDAP_STRDUP( gopts->ldo_local_ip_addrs.local_ip_addrs );
222*549b59edSchristos 		if ( ld->ld_options.ldo_local_ip_addrs.local_ip_addrs == NULL )
223*549b59edSchristos 			goto nomem;
224*549b59edSchristos 	}
225*549b59edSchristos 
2262de962bdSlukem 	ld->ld_lberoptions = LBER_USE_DER;
2272de962bdSlukem 
2282de962bdSlukem 	ld->ld_sb = ber_sockbuf_alloc( );
2292de962bdSlukem 	if ( ld->ld_sb == NULL ) goto nomem;
2302de962bdSlukem 
2312de962bdSlukem #ifdef LDAP_R_COMPILE
232d11b170bStron 	ldap_pvt_thread_mutex_init( &ld->ld_msgid_mutex );
233d11b170bStron 	ldap_pvt_thread_mutex_init( &ld->ld_conn_mutex );
2342de962bdSlukem 	ldap_pvt_thread_mutex_init( &ld->ld_req_mutex );
2352de962bdSlukem 	ldap_pvt_thread_mutex_init( &ld->ld_res_mutex );
236d11b170bStron 	ldap_pvt_thread_mutex_init( &ld->ld_abandon_mutex );
237d11b170bStron 	ldap_pvt_thread_mutex_init( &ld->ld_ldcmutex );
2382de962bdSlukem #endif
239d11b170bStron 	ld->ld_ldcrefcnt = 1;
2402de962bdSlukem 	*ldp = ld;
2412de962bdSlukem 	return LDAP_SUCCESS;
2422de962bdSlukem 
2432de962bdSlukem nomem:
2442de962bdSlukem 	ldap_free_select_info( ld->ld_selectinfo );
2452de962bdSlukem 	ldap_free_urllist( ld->ld_options.ldo_defludp );
2462de962bdSlukem #ifdef HAVE_CYRUS_SASL
2472de962bdSlukem 	LDAP_FREE( ld->ld_options.ldo_def_sasl_authzid );
2482de962bdSlukem 	LDAP_FREE( ld->ld_options.ldo_def_sasl_authcid );
2492de962bdSlukem 	LDAP_FREE( ld->ld_options.ldo_def_sasl_realm );
2502de962bdSlukem 	LDAP_FREE( ld->ld_options.ldo_def_sasl_mech );
2512de962bdSlukem #endif
252*549b59edSchristos 
253*549b59edSchristos #ifdef HAVE_TLS
254*549b59edSchristos 	/* tls_pin_hashalg and tls_pin share the same buffer */
255*549b59edSchristos 	if ( ld->ld_options.ldo_tls_pin_hashalg ) {
256*549b59edSchristos 		LDAP_FREE( ld->ld_options.ldo_tls_pin_hashalg );
257*549b59edSchristos 	} else {
258*549b59edSchristos 		LDAP_FREE( ld->ld_options.ldo_tls_pin.bv_val );
259*549b59edSchristos 	}
260*549b59edSchristos #endif
2612de962bdSlukem 	LDAP_FREE( (char *)ld );
2622de962bdSlukem 	return LDAP_NO_MEMORY;
2632de962bdSlukem }
2642de962bdSlukem 
2652de962bdSlukem /*
2662de962bdSlukem  * ldap_init - initialize the LDAP library.  A magic cookie to be used for
2672de962bdSlukem  * future communication is returned on success, NULL on failure.
2682de962bdSlukem  * "host" may be a space-separated list of hosts or IP addresses
2692de962bdSlukem  *
2702de962bdSlukem  * Example:
2712de962bdSlukem  *	LDAP	*ld;
2722de962bdSlukem  *	ld = ldap_init( host, port );
2732de962bdSlukem  */
2742de962bdSlukem LDAP *
ldap_init(LDAP_CONST char * defhost,int defport)2752de962bdSlukem ldap_init( LDAP_CONST char *defhost, int defport )
2762de962bdSlukem {
2772de962bdSlukem 	LDAP *ld;
2782de962bdSlukem 	int rc;
2792de962bdSlukem 
2802de962bdSlukem 	rc = ldap_create(&ld);
2812de962bdSlukem 	if ( rc != LDAP_SUCCESS )
2822de962bdSlukem 		return NULL;
2832de962bdSlukem 
2842de962bdSlukem 	if (defport != 0)
2852de962bdSlukem 		ld->ld_options.ldo_defport = defport;
2862de962bdSlukem 
2872de962bdSlukem 	if (defhost != NULL) {
2882de962bdSlukem 		rc = ldap_set_option(ld, LDAP_OPT_HOST_NAME, defhost);
2892de962bdSlukem 		if ( rc != LDAP_SUCCESS ) {
2902de962bdSlukem 			ldap_ld_free(ld, 1, NULL, NULL);
2912de962bdSlukem 			return NULL;
2922de962bdSlukem 		}
2932de962bdSlukem 	}
2942de962bdSlukem 
2952de962bdSlukem 	return( ld );
2962de962bdSlukem }
2972de962bdSlukem 
2982de962bdSlukem 
2992de962bdSlukem int
ldap_initialize(LDAP ** ldp,LDAP_CONST char * url)3002de962bdSlukem ldap_initialize( LDAP **ldp, LDAP_CONST char *url )
3012de962bdSlukem {
3022de962bdSlukem 	int rc;
3032de962bdSlukem 	LDAP *ld;
3042de962bdSlukem 
3052de962bdSlukem 	*ldp = NULL;
3062de962bdSlukem 	rc = ldap_create(&ld);
3072de962bdSlukem 	if ( rc != LDAP_SUCCESS )
3082de962bdSlukem 		return rc;
3092de962bdSlukem 
3102de962bdSlukem 	if (url != NULL) {
3112de962bdSlukem 		rc = ldap_set_option(ld, LDAP_OPT_URI, url);
3122de962bdSlukem 		if ( rc != LDAP_SUCCESS ) {
3132de962bdSlukem 			ldap_ld_free(ld, 1, NULL, NULL);
3142de962bdSlukem 			return rc;
3152de962bdSlukem 		}
3162de962bdSlukem #ifdef LDAP_CONNECTIONLESS
3172de962bdSlukem 		if (ldap_is_ldapc_url(url))
3182de962bdSlukem 			LDAP_IS_UDP(ld) = 1;
3192de962bdSlukem #endif
3202de962bdSlukem 	}
3212de962bdSlukem 
3222de962bdSlukem 	*ldp = ld;
3232de962bdSlukem 	return LDAP_SUCCESS;
3242de962bdSlukem }
3252de962bdSlukem 
3262de962bdSlukem int
ldap_init_fd(ber_socket_t fd,int proto,LDAP_CONST char * url,LDAP ** ldp)3272de962bdSlukem ldap_init_fd(
3282de962bdSlukem 	ber_socket_t fd,
3292de962bdSlukem 	int proto,
3302de962bdSlukem 	LDAP_CONST char *url,
3312de962bdSlukem 	LDAP **ldp
3322de962bdSlukem )
3332de962bdSlukem {
3342de962bdSlukem 	int rc;
3352de962bdSlukem 	LDAP *ld;
3362de962bdSlukem 	LDAPConn *conn;
337d11b170bStron #ifdef LDAP_CONNECTIONLESS
338d11b170bStron 	ber_socklen_t	len;
339d11b170bStron #endif
3402de962bdSlukem 
3412de962bdSlukem 	*ldp = NULL;
3422de962bdSlukem 	rc = ldap_create( &ld );
3432de962bdSlukem 	if( rc != LDAP_SUCCESS )
3442de962bdSlukem 		return( rc );
3452de962bdSlukem 
3462de962bdSlukem 	if (url != NULL) {
3472de962bdSlukem 		rc = ldap_set_option(ld, LDAP_OPT_URI, url);
3482de962bdSlukem 		if ( rc != LDAP_SUCCESS ) {
3492de962bdSlukem 			ldap_ld_free(ld, 1, NULL, NULL);
3502de962bdSlukem 			return rc;
3512de962bdSlukem 		}
3522de962bdSlukem 	}
3532de962bdSlukem 
354d11b170bStron 	LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
3552de962bdSlukem 	/* Attach the passed socket as the LDAP's connection */
356d11b170bStron 	conn = ldap_new_connection( ld, NULL, 1, 0, NULL, 0, 0 );
3572de962bdSlukem 	if( conn == NULL ) {
358*549b59edSchristos 		LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
3592de962bdSlukem 		ldap_unbind_ext( ld, NULL, NULL );
3602de962bdSlukem 		return( LDAP_NO_MEMORY );
3612de962bdSlukem 	}
3624e6df137Slukem 	if( url )
3634e6df137Slukem 		conn->lconn_server = ldap_url_dup( ld->ld_options.ldo_defludp );
3642de962bdSlukem 	ber_sockbuf_ctrl( conn->lconn_sb, LBER_SB_OPT_SET_FD, &fd );
3652de962bdSlukem 	ld->ld_defconn = conn;
3662de962bdSlukem 	++ld->ld_defconn->lconn_refcnt;	/* so it never gets closed/freed */
367d11b170bStron 	LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
3682de962bdSlukem 
3692de962bdSlukem 	switch( proto ) {
3702de962bdSlukem 	case LDAP_PROTO_TCP:
3712de962bdSlukem #ifdef LDAP_DEBUG
3722de962bdSlukem 		ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
3732de962bdSlukem 			LBER_SBIOD_LEVEL_PROVIDER, (void *)"tcp_" );
3742de962bdSlukem #endif
3752de962bdSlukem 		ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_tcp,
3762de962bdSlukem 			LBER_SBIOD_LEVEL_PROVIDER, NULL );
3772de962bdSlukem 		break;
3782de962bdSlukem 
3792de962bdSlukem #ifdef LDAP_CONNECTIONLESS
3802de962bdSlukem 	case LDAP_PROTO_UDP:
381d11b170bStron 		LDAP_IS_UDP(ld) = 1;
382d11b170bStron 		if( ld->ld_options.ldo_peer )
383d11b170bStron 			ldap_memfree( ld->ld_options.ldo_peer );
384d11b170bStron 		ld->ld_options.ldo_peer = ldap_memcalloc( 1, sizeof( struct sockaddr_storage ) );
385d11b170bStron 		len = sizeof( struct sockaddr_storage );
386d11b170bStron 		if( getpeername ( fd, ld->ld_options.ldo_peer, &len ) < 0) {
387d11b170bStron 			ldap_unbind_ext( ld, NULL, NULL );
388d11b170bStron 			return( AC_SOCKET_ERROR );
389d11b170bStron 		}
3902de962bdSlukem #ifdef LDAP_DEBUG
3912de962bdSlukem 		ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
3922de962bdSlukem 			LBER_SBIOD_LEVEL_PROVIDER, (void *)"udp_" );
3932de962bdSlukem #endif
3942de962bdSlukem 		ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_udp,
3952de962bdSlukem 			LBER_SBIOD_LEVEL_PROVIDER, NULL );
3962de962bdSlukem 		ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_readahead,
3972de962bdSlukem 			LBER_SBIOD_LEVEL_PROVIDER, NULL );
3982de962bdSlukem 		break;
3992de962bdSlukem #endif /* LDAP_CONNECTIONLESS */
4002de962bdSlukem 
4012de962bdSlukem 	case LDAP_PROTO_IPC:
4022de962bdSlukem #ifdef LDAP_DEBUG
4032de962bdSlukem 		ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
4042de962bdSlukem 			LBER_SBIOD_LEVEL_PROVIDER, (void *)"ipc_" );
4052de962bdSlukem #endif
4062de962bdSlukem 		ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_fd,
4072de962bdSlukem 			LBER_SBIOD_LEVEL_PROVIDER, NULL );
4082de962bdSlukem 		break;
4092de962bdSlukem 
4102de962bdSlukem 	case LDAP_PROTO_EXT:
4112de962bdSlukem 		/* caller must supply sockbuf handlers */
4122de962bdSlukem 		break;
4132de962bdSlukem 
4142de962bdSlukem 	default:
4152de962bdSlukem 		ldap_unbind_ext( ld, NULL, NULL );
4162de962bdSlukem 		return LDAP_PARAM_ERROR;
4172de962bdSlukem 	}
4182de962bdSlukem 
4192de962bdSlukem #ifdef LDAP_DEBUG
4202de962bdSlukem 	ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
4212de962bdSlukem 		INT_MAX, (void *)"ldap_" );
4222de962bdSlukem #endif
4232de962bdSlukem 
4242de962bdSlukem 	/* Add the connection to the *LDAP's select pool */
4252de962bdSlukem 	ldap_mark_select_read( ld, conn->lconn_sb );
4262de962bdSlukem 
4272de962bdSlukem 	*ldp = ld;
4282de962bdSlukem 	return LDAP_SUCCESS;
4292de962bdSlukem }
4302de962bdSlukem 
431d11b170bStron /* Protected by ld_conn_mutex */
4322de962bdSlukem int
ldap_int_open_connection(LDAP * ld,LDAPConn * conn,LDAPURLDesc * srv,int async)4332de962bdSlukem ldap_int_open_connection(
4342de962bdSlukem 	LDAP *ld,
4352de962bdSlukem 	LDAPConn *conn,
4362de962bdSlukem 	LDAPURLDesc *srv,
4372de962bdSlukem 	int async )
4382de962bdSlukem {
4392de962bdSlukem 	int rc = -1;
4404e6df137Slukem 	int proto;
4412de962bdSlukem 
442*549b59edSchristos 	Debug0( LDAP_DEBUG_TRACE, "ldap_int_open_connection\n" );
4432de962bdSlukem 
4442de962bdSlukem 	switch ( proto = ldap_pvt_url_scheme2proto( srv->lud_scheme ) ) {
4452de962bdSlukem 		case LDAP_PROTO_TCP:
4462de962bdSlukem 			rc = ldap_connect_to_host( ld, conn->lconn_sb,
4474e6df137Slukem 				proto, srv, async );
4482de962bdSlukem 
4492de962bdSlukem 			if ( rc == -1 ) return rc;
4502de962bdSlukem #ifdef LDAP_DEBUG
4512de962bdSlukem 			ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
4522de962bdSlukem 				LBER_SBIOD_LEVEL_PROVIDER, (void *)"tcp_" );
4532de962bdSlukem #endif
4542de962bdSlukem 			ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_tcp,
4552de962bdSlukem 				LBER_SBIOD_LEVEL_PROVIDER, NULL );
4562de962bdSlukem 
4572de962bdSlukem 			break;
4582de962bdSlukem 
4592de962bdSlukem #ifdef LDAP_CONNECTIONLESS
4602de962bdSlukem 		case LDAP_PROTO_UDP:
4612de962bdSlukem 			LDAP_IS_UDP(ld) = 1;
4622de962bdSlukem 			rc = ldap_connect_to_host( ld, conn->lconn_sb,
4634e6df137Slukem 				proto, srv, async );
4642de962bdSlukem 
4652de962bdSlukem 			if ( rc == -1 ) return rc;
4662de962bdSlukem #ifdef LDAP_DEBUG
4672de962bdSlukem 			ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
4682de962bdSlukem 				LBER_SBIOD_LEVEL_PROVIDER, (void *)"udp_" );
4692de962bdSlukem #endif
4702de962bdSlukem 			ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_udp,
4712de962bdSlukem 				LBER_SBIOD_LEVEL_PROVIDER, NULL );
4722de962bdSlukem 
4732de962bdSlukem 			ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_readahead,
4742de962bdSlukem 				LBER_SBIOD_LEVEL_PROVIDER, NULL );
4752de962bdSlukem 
4762de962bdSlukem 			break;
4772de962bdSlukem #endif
4782de962bdSlukem 		case LDAP_PROTO_IPC:
4792de962bdSlukem #ifdef LDAP_PF_LOCAL
4802de962bdSlukem 			/* only IPC mechanism supported is PF_LOCAL (PF_UNIX) */
4812de962bdSlukem 			rc = ldap_connect_to_path( ld, conn->lconn_sb,
4824e6df137Slukem 				srv, async );
4832de962bdSlukem 			if ( rc == -1 ) return rc;
4842de962bdSlukem #ifdef LDAP_DEBUG
4852de962bdSlukem 			ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
4862de962bdSlukem 				LBER_SBIOD_LEVEL_PROVIDER, (void *)"ipc_" );
4872de962bdSlukem #endif
4882de962bdSlukem 			ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_fd,
4892de962bdSlukem 				LBER_SBIOD_LEVEL_PROVIDER, NULL );
4902de962bdSlukem 
4912de962bdSlukem 			break;
4922de962bdSlukem #endif /* LDAP_PF_LOCAL */
4932de962bdSlukem 		default:
4942de962bdSlukem 			return -1;
4952de962bdSlukem 			break;
4962de962bdSlukem 	}
4972de962bdSlukem 
4982de962bdSlukem 	conn->lconn_created = time( NULL );
4992de962bdSlukem 
5002de962bdSlukem #ifdef LDAP_DEBUG
5012de962bdSlukem 	ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
5022de962bdSlukem 		INT_MAX, (void *)"ldap_" );
5032de962bdSlukem #endif
5042de962bdSlukem 
5052de962bdSlukem #ifdef LDAP_CONNECTIONLESS
5062de962bdSlukem 	if( proto == LDAP_PROTO_UDP ) return 0;
5072de962bdSlukem #endif
5082de962bdSlukem 
5092de962bdSlukem #ifdef HAVE_TLS
5104e27b3e8Schristos 	if ((rc == 0 || rc == -2) && ( ld->ld_options.ldo_tls_mode == LDAP_OPT_X_TLS_HARD ||
511d11b170bStron 		strcmp( srv->lud_scheme, "ldaps" ) == 0 ))
5122de962bdSlukem 	{
5132de962bdSlukem 		++conn->lconn_refcnt;	/* avoid premature free */
5142de962bdSlukem 
5152de962bdSlukem 		rc = ldap_int_tls_start( ld, conn, srv );
5162de962bdSlukem 
5172de962bdSlukem 		--conn->lconn_refcnt;
5182de962bdSlukem 
5192de962bdSlukem 		if (rc != LDAP_SUCCESS) {
5204e27b3e8Schristos 			/* process connection callbacks */
5214e27b3e8Schristos 			{
5224e27b3e8Schristos 				struct ldapoptions *lo;
5234e27b3e8Schristos 				ldaplist *ll;
5244e27b3e8Schristos 				ldap_conncb *cb;
5254e27b3e8Schristos 
5264e27b3e8Schristos 				lo = &ld->ld_options;
5274e27b3e8Schristos 				LDAP_MUTEX_LOCK( &lo->ldo_mutex );
5284e27b3e8Schristos 				if ( lo->ldo_conn_cbs ) {
5294e27b3e8Schristos 					for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) {
5304e27b3e8Schristos 						cb = ll->ll_data;
5314e27b3e8Schristos 						cb->lc_del( ld, conn->lconn_sb, cb );
5324e27b3e8Schristos 					}
5334e27b3e8Schristos 				}
5344e27b3e8Schristos 				LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
5354e27b3e8Schristos 				lo = LDAP_INT_GLOBAL_OPT();
5364e27b3e8Schristos 				LDAP_MUTEX_LOCK( &lo->ldo_mutex );
5374e27b3e8Schristos 				if ( lo->ldo_conn_cbs ) {
5384e27b3e8Schristos 					for ( ll=lo->ldo_conn_cbs; ll; ll=ll->ll_next ) {
5394e27b3e8Schristos 						cb = ll->ll_data;
5404e27b3e8Schristos 						cb->lc_del( ld, conn->lconn_sb, cb );
5414e27b3e8Schristos 					}
5424e27b3e8Schristos 				}
5434e27b3e8Schristos 				LDAP_MUTEX_UNLOCK( &lo->ldo_mutex );
5444e27b3e8Schristos 			}
545255afcfeSchristos 			ber_int_sb_close( conn->lconn_sb );
5462de962bdSlukem 			return -1;
5472de962bdSlukem 		}
5482de962bdSlukem 	}
5492de962bdSlukem #endif
5502de962bdSlukem 
5512de962bdSlukem 	return( 0 );
5522de962bdSlukem }
5532de962bdSlukem 
554d11b170bStron /*
555d11b170bStron  * ldap_open_internal_connection - open connection and set file descriptor
556d11b170bStron  *
557d11b170bStron  * note: ldap_init_fd() may be preferable
558d11b170bStron  */
5592de962bdSlukem 
5602de962bdSlukem int
ldap_open_internal_connection(LDAP ** ldp,ber_socket_t * fdp)5612de962bdSlukem ldap_open_internal_connection( LDAP **ldp, ber_socket_t *fdp )
5622de962bdSlukem {
5632de962bdSlukem 	int rc;
5642de962bdSlukem 	LDAPConn *c;
5652de962bdSlukem 	LDAPRequest *lr;
566d11b170bStron 	LDAP	*ld;
5672de962bdSlukem 
568d11b170bStron 	rc = ldap_create( &ld );
5692de962bdSlukem 	if( rc != LDAP_SUCCESS ) {
5702de962bdSlukem 		*ldp = NULL;
5712de962bdSlukem 		return( rc );
5722de962bdSlukem 	}
5732de962bdSlukem 
5742de962bdSlukem 	/* Make it appear that a search request, msgid 0, was sent */
5752de962bdSlukem 	lr = (LDAPRequest *)LDAP_CALLOC( 1, sizeof( LDAPRequest ));
5762de962bdSlukem 	if( lr == NULL ) {
577d11b170bStron 		ldap_unbind_ext( ld, NULL, NULL );
5782de962bdSlukem 		*ldp = NULL;
5792de962bdSlukem 		return( LDAP_NO_MEMORY );
5802de962bdSlukem 	}
5812de962bdSlukem 	memset(lr, 0, sizeof( LDAPRequest ));
5822de962bdSlukem 	lr->lr_msgid = 0;
5832de962bdSlukem 	lr->lr_status = LDAP_REQST_INPROGRESS;
5842de962bdSlukem 	lr->lr_res_errno = LDAP_SUCCESS;
5852de962bdSlukem 	/* no mutex lock needed, we just created this ld here */
586*549b59edSchristos 	rc = ldap_tavl_insert( &ld->ld_requests, lr, ldap_req_cmp, ldap_avl_dup_error );
587*549b59edSchristos 	assert( rc == LDAP_SUCCESS );
5882de962bdSlukem 
589d11b170bStron 	LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
5902de962bdSlukem 	/* Attach the passed socket as the *LDAP's connection */
591d11b170bStron 	c = ldap_new_connection( ld, NULL, 1, 0, NULL, 0, 0 );
5922de962bdSlukem 	if( c == NULL ) {
593d11b170bStron 		ldap_unbind_ext( ld, NULL, NULL );
5942de962bdSlukem 		*ldp = NULL;
595d11b170bStron 		LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
5962de962bdSlukem 		return( LDAP_NO_MEMORY );
5972de962bdSlukem 	}
5982de962bdSlukem 	ber_sockbuf_ctrl( c->lconn_sb, LBER_SB_OPT_SET_FD, fdp );
5992de962bdSlukem #ifdef LDAP_DEBUG
6002de962bdSlukem 	ber_sockbuf_add_io( c->lconn_sb, &ber_sockbuf_io_debug,
6012de962bdSlukem 		LBER_SBIOD_LEVEL_PROVIDER, (void *)"int_" );
6022de962bdSlukem #endif
6032de962bdSlukem 	ber_sockbuf_add_io( c->lconn_sb, &ber_sockbuf_io_tcp,
6042de962bdSlukem 	  LBER_SBIOD_LEVEL_PROVIDER, NULL );
605d11b170bStron 	ld->ld_defconn = c;
606d11b170bStron 	LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
6072de962bdSlukem 
6082de962bdSlukem 	/* Add the connection to the *LDAP's select pool */
609d11b170bStron 	ldap_mark_select_read( ld, c->lconn_sb );
6102de962bdSlukem 
6112de962bdSlukem 	/* Make this connection an LDAP V3 protocol connection */
6122de962bdSlukem 	rc = LDAP_VERSION3;
613d11b170bStron 	ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &rc );
614d11b170bStron 	*ldp = ld;
615d11b170bStron 
616d11b170bStron 	++ld->ld_defconn->lconn_refcnt;	/* so it never gets closed/freed */
6172de962bdSlukem 
6182de962bdSlukem 	return( LDAP_SUCCESS );
6192de962bdSlukem }
620d11b170bStron 
621d11b170bStron LDAP *
ldap_dup(LDAP * old)622d11b170bStron ldap_dup( LDAP *old )
623d11b170bStron {
624d11b170bStron 	LDAP			*ld;
625d11b170bStron 
626d11b170bStron 	if ( old == NULL ) {
627d11b170bStron 		return( NULL );
628d11b170bStron 	}
629d11b170bStron 
630*549b59edSchristos 	Debug0( LDAP_DEBUG_TRACE, "ldap_dup\n" );
631d11b170bStron 
632d11b170bStron 	if ( (ld = (LDAP *) LDAP_CALLOC( 1, sizeof(LDAP) )) == NULL ) {
633d11b170bStron 		return( NULL );
634d11b170bStron 	}
635d11b170bStron 
636d11b170bStron 	LDAP_MUTEX_LOCK( &old->ld_ldcmutex );
637d11b170bStron 	ld->ldc = old->ldc;
638d11b170bStron 	old->ld_ldcrefcnt++;
639d11b170bStron 	LDAP_MUTEX_UNLOCK( &old->ld_ldcmutex );
640d11b170bStron 	return ( ld );
641d11b170bStron }
642d11b170bStron 
643d11b170bStron int
ldap_int_check_async_open(LDAP * ld,ber_socket_t sd)644d11b170bStron ldap_int_check_async_open( LDAP *ld, ber_socket_t sd )
645d11b170bStron {
646d11b170bStron 	struct timeval tv = { 0 };
647d11b170bStron 	int rc;
648d11b170bStron 
649d11b170bStron 	rc = ldap_int_poll( ld, sd, &tv, 1 );
650d11b170bStron 	switch ( rc ) {
651d11b170bStron 	case 0:
652d11b170bStron 		/* now ready to start tls */
653d11b170bStron 		ld->ld_defconn->lconn_status = LDAP_CONNST_CONNECTED;
654d11b170bStron 		break;
655d11b170bStron 
656d11b170bStron 	default:
657d11b170bStron 		ld->ld_errno = LDAP_CONNECT_ERROR;
658d11b170bStron 		return -1;
659d11b170bStron 
660d11b170bStron 	case -2:
661d11b170bStron 		/* connect not completed yet */
662d11b170bStron 		ld->ld_errno = LDAP_X_CONNECTING;
663d11b170bStron 		return rc;
664d11b170bStron 	}
665d11b170bStron 
666d11b170bStron #ifdef HAVE_TLS
667d11b170bStron 	if ( ld->ld_options.ldo_tls_mode == LDAP_OPT_X_TLS_HARD ||
668d11b170bStron 		!strcmp( ld->ld_defconn->lconn_server->lud_scheme, "ldaps" )) {
669d11b170bStron 
670d11b170bStron 		++ld->ld_defconn->lconn_refcnt;	/* avoid premature free */
671d11b170bStron 
672d11b170bStron 		rc = ldap_int_tls_start( ld, ld->ld_defconn, ld->ld_defconn->lconn_server );
673d11b170bStron 
674d11b170bStron 		--ld->ld_defconn->lconn_refcnt;
675d11b170bStron 	}
676d11b170bStron #endif
677d11b170bStron 	return rc;
678d11b170bStron }
679