Commit message: ITS#9423 ldap_X509dn2bv: check for invalid BER after RDN count
CVE: CVE-2020-36230
CWE: CWE-617
Vulnerability description: A flaw was discovered in OpenLDAP before 2.4.57 leading in an assertion failure in slapd in the X.509 DN parsing in decode.c ber_next_element, resulting in denial of service.

Project: openldap
File: tls2.c

find_oid( struct berval *oid )
{
	int i;

	for ( i=0; !BER_BVISNULL( &oids[i].oid ); i++ ) {
		if ( oids[i].oid.bv_len != oid->bv_len ) continue;
		if ( !strcmp( oids[i].oid.bv_val, oid->bv_val ))
			return &oids[i];
	}
	return NULL;
}

Project: openldap
File: tls2.c

ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server )
{
	int rc = 0;
	tls_impl *ti = tls_imp;
	struct ldaptls lts = lo->ldo_tls_info;

	if ( lo->ldo_tls_ctx )
		return 0;

	tls_init( ti );

	if ( is_server && !lts.lt_certfile && !lts.lt_keyfile &&
		!lts.lt_cacertfile && !lts.lt_cacertdir ) {
		/* minimum configuration not provided */
		return LDAP_NOT_SUPPORTED;
	}

#ifdef HAVE_EBCDIC
	/* This ASCII/EBCDIC handling is a real pain! */
	if ( lts.lt_ciphersuite ) {
		lts.lt_ciphersuite = LDAP_STRDUP( lts.lt_ciphersuite );
		__atoe( lts.lt_ciphersuite );
	}
	if ( lts.lt_cacertfile ) {
		lts.lt_cacertfile = LDAP_STRDUP( lts.lt_cacertfile );
		__atoe( lts.lt_cacertfile );
	}
	if ( lts.lt_certfile ) {
		lts.lt_certfile = LDAP_STRDUP( lts.lt_certfile );
		__atoe( lts.lt_certfile );
	}
	if ( lts.lt_keyfile ) {
		lts.lt_keyfile = LDAP_STRDUP( lts.lt_keyfile );
		__atoe( lts.lt_keyfile );
	}
	if ( lts.lt_crlfile ) {
		lts.lt_crlfile = LDAP_STRDUP( lts.lt_crlfile );
		__atoe( lts.lt_crlfile );
	}
	if ( lts.lt_cacertdir ) {
		lts.lt_cacertdir = LDAP_STRDUP( lts.lt_cacertdir );
		__atoe( lts.lt_cacertdir );
	}
	if ( lts.lt_dhfile ) {
		lts.lt_dhfile = LDAP_STRDUP( lts.lt_dhfile );
		__atoe( lts.lt_dhfile );
	}
	if ( lts.lt_ecname ) {
		lts.lt_ecname = LDAP_STRDUP( lts.lt_ecname );
		__atoe( lts.lt_ecname );
	}
#endif
	lo->ldo_tls_ctx = ti->ti_ctx_new( lo );
	if ( lo->ldo_tls_ctx == NULL ) {
		Debug( LDAP_DEBUG_ANY,
		   "TLS: could not allocate default ctx.\n",
			0,0,0);
		rc = -1;
		goto error_exit;
	}

	rc = ti->ti_ctx_init( lo, &lts, is_server );

error_exit:
	if ( rc < 0 && lo->ldo_tls_ctx != NULL ) {
		ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx );
		lo->ldo_tls_ctx = NULL;
	}
#ifdef HAVE_EBCDIC
	LDAP_FREE( lts.lt_ciphersuite );
	LDAP_FREE( lts.lt_cacertfile );
	LDAP_FREE( lts.lt_certfile );
	LDAP_FREE( lts.lt_keyfile );
	LDAP_FREE( lts.lt_crlfile );
	LDAP_FREE( lts.lt_cacertdir );
	LDAP_FREE( lts.lt_dhfile );
	LDAP_FREE( lts.lt_ecname );
#endif
	return rc;
}

Project: openldap
File: tls2.c

ldap_int_tls_destroy( struct ldapoptions *lo )
{
	if ( lo->ldo_tls_ctx ) {
		ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx );
		lo->ldo_tls_ctx = NULL;
	}

	if ( lo->ldo_tls_certfile ) {
		LDAP_FREE( lo->ldo_tls_certfile );
		lo->ldo_tls_certfile = NULL;
	}
	if ( lo->ldo_tls_keyfile ) {
		LDAP_FREE( lo->ldo_tls_keyfile );
		lo->ldo_tls_keyfile = NULL;
	}
	if ( lo->ldo_tls_dhfile ) {
		LDAP_FREE( lo->ldo_tls_dhfile );
		lo->ldo_tls_dhfile = NULL;
	}
	if ( lo->ldo_tls_ecname ) {
		LDAP_FREE( lo->ldo_tls_ecname );
		lo->ldo_tls_ecname = NULL;
	}
	if ( lo->ldo_tls_cacertfile ) {
		LDAP_FREE( lo->ldo_tls_cacertfile );
		lo->ldo_tls_cacertfile = NULL;
	}
	if ( lo->ldo_tls_cacertdir ) {
		LDAP_FREE( lo->ldo_tls_cacertdir );
		lo->ldo_tls_cacertdir = NULL;
	}
	if ( lo->ldo_tls_ciphersuite ) {
		LDAP_FREE( lo->ldo_tls_ciphersuite );
		lo->ldo_tls_ciphersuite = NULL;
	}
	if ( lo->ldo_tls_crlfile ) {
		LDAP_FREE( lo->ldo_tls_crlfile );
		lo->ldo_tls_crlfile = NULL;
	}
}

Project: openldap
File: tls2.c

ldap_start_tls_s ( LDAP *ld,
	LDAPControl **serverctrls,
	LDAPControl **clientctrls )
{
#ifndef HAVE_TLS
	return LDAP_NOT_SUPPORTED;
#else
	int rc;
	char *rspoid = NULL;
	struct berval *rspdata = NULL;

	/* XXYYZ: this initiates operation only on default connection! */

	if ( ldap_tls_inplace( ld ) ) {
		return LDAP_LOCAL_ERROR;
	}

	rc = ldap_extended_operation_s( ld, LDAP_EXOP_START_TLS,
		NULL, serverctrls, clientctrls, &rspoid, &rspdata );

	if ( rspoid != NULL ) {
		LDAP_FREE(rspoid);
	}

	if ( rspdata != NULL ) {
		ber_bvfree( rspdata );
	}

	if ( rc == LDAP_SUCCESS ) {
		rc = ldap_int_tls_start( ld, ld->ld_defconn, NULL );
	}

	return rc;
#endif
}

Project: openldap
File: tls2.c

ldap_pvt_tls_sb_ctx( Sockbuf *sb )
{
	void			*p = NULL;
	
	ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&p );
	return p;
}

Project: openldap
File: tls2.c

ldap_int_tls_config( LDAP *ld, int option, const char *arg )
{
	int i;

	switch( option ) {
	case LDAP_OPT_X_TLS_CACERTFILE:
	case LDAP_OPT_X_TLS_CACERTDIR:
	case LDAP_OPT_X_TLS_CERTFILE:
	case LDAP_OPT_X_TLS_KEYFILE:
	case LDAP_OPT_X_TLS_RANDOM_FILE:
	case LDAP_OPT_X_TLS_CIPHER_SUITE:
	case LDAP_OPT_X_TLS_DHFILE:
	case LDAP_OPT_X_TLS_ECNAME:
	case LDAP_OPT_X_TLS_CRLFILE:	/* GnuTLS only */
		return ldap_pvt_tls_set_option( ld, option, (void *) arg );

	case LDAP_OPT_X_TLS_REQUIRE_CERT:
	case LDAP_OPT_X_TLS_REQUIRE_SAN:
	case LDAP_OPT_X_TLS:
		i = -1;
		if ( strcasecmp( arg, "never" ) == 0 ) {
			i = LDAP_OPT_X_TLS_NEVER ;

		} else if ( strcasecmp( arg, "demand" ) == 0 ) {
			i = LDAP_OPT_X_TLS_DEMAND ;

		} else if ( strcasecmp( arg, "allow" ) == 0 ) {
			i = LDAP_OPT_X_TLS_ALLOW ;

		} else if ( strcasecmp( arg, "try" ) == 0 ) {
			i = LDAP_OPT_X_TLS_TRY ;

		} else if ( ( strcasecmp( arg, "hard" ) == 0 ) ||
			( strcasecmp( arg, "on" ) == 0 ) ||
			( strcasecmp( arg, "yes" ) == 0) ||
			( strcasecmp( arg, "true" ) == 0 ) )
		{
			i = LDAP_OPT_X_TLS_HARD ;
		}

		if (i >= 0) {
			return ldap_pvt_tls_set_option( ld, option, &i );
		}
		return -1;
	case LDAP_OPT_X_TLS_PROTOCOL_MIN: {
		char *next;
		long l;
		l = strtol( arg, &next, 10 );
		if ( l < 0 || l > 0xff || next == arg ||
			( *next != '\0' && *next != '.' ) )
			return -1;
		i = l << 8;
		if (*next == '.') {
			arg = next + 1;
			l = strtol( arg, &next, 10 );
			if ( l < 0 || l > 0xff || next == arg || *next != '\0' )
				return -1;
			i += l;
		}
		return ldap_pvt_tls_set_option( ld, option, &i );
		}
#ifdef HAVE_OPENSSL_CRL
	case LDAP_OPT_X_TLS_CRLCHECK:	/* OpenSSL only */
		i = -1;
		if ( strcasecmp( arg, "none" ) == 0 ) {
			i = LDAP_OPT_X_TLS_CRL_NONE ;
		} else if ( strcasecmp( arg, "peer" ) == 0 ) {
			i = LDAP_OPT_X_TLS_CRL_PEER ;
		} else if ( strcasecmp( arg, "all" ) == 0 ) {
			i = LDAP_OPT_X_TLS_CRL_ALL ;
		}
		if (i >= 0) {
			return ldap_pvt_tls_set_option( ld, option, &i );
		}
		return -1;
#endif
	}
	return -1;
}

Project: openldap
File: tls2.c

ldap_pvt_tls_get_peer_dn( void *s, struct berval *dn,
	LDAPDN_rewrite_dummy *func, unsigned flags )
{
	tls_session *session = s;
	struct berval bvdn;
	int rc;

	rc = tls_imp->ti_session_peer_dn( session, &bvdn );
	if ( rc ) return rc;

	rc = ldap_X509dn2bv( &bvdn, dn, 
			    (LDAPDN_rewrite_func *)func, flags);
	return rc;
}

Project: openldap
File: tls2.c

der_to_ldap_BitString (struct berval *berValue,
                                   struct berval *ldapValue)
{
	ber_len_t bitPadding=0;
	ber_len_t bits, maxBits;
	char *tmpStr;
	unsigned char byte;
	ber_len_t bitLength;
	ber_len_t valLen;
	unsigned char* valPtr;

	ldapValue->bv_len=0;
	ldapValue->bv_val=NULL;

	/* Gets padding and points to binary data */
	valLen=berValue->bv_len;
	valPtr=(unsigned char*)berValue->bv_val;
	if (valLen) {
		bitPadding=(ber_len_t)(valPtr[0]);
		valLen--;
		valPtr++;
	}
	/* If Block is non DER encoding fixes to DER encoding */
	if (bitPadding >= BITS_PER_BYTE) {
		if (valLen*BITS_PER_BYTE > bitPadding ) {
			valLen-=(bitPadding/BITS_PER_BYTE);
			bitPadding%=BITS_PER_BYTE;
		} else {
			valLen=0;
			bitPadding=0;
		}
	}
	/* Just in case bad encoding */
	if (valLen*BITS_PER_BYTE < bitPadding ) {
		bitPadding=0;
		valLen=0;
	}

	/* Gets buffer to hold RFC4517 Bit String format */
	bitLength=valLen*BITS_PER_BYTE-bitPadding;
	tmpStr=LDAP_MALLOC(bitLength + STR_OVERHEAD + 1);

	if (!tmpStr)
		return LDAP_NO_MEMORY;

	ldapValue->bv_val=tmpStr;
	ldapValue->bv_len=bitLength + STR_OVERHEAD;

	/* Formatting in '*binary-digit'B format */
	maxBits=BITS_PER_BYTE;
	*tmpStr++ ='\'';
	while(valLen) {
		byte=*valPtr;
		if (valLen==1)
			maxBits-=bitPadding;
		for (bits=0; bits<maxBits; bits++) {
			if (0x80 & byte)
				*tmpStr='1';
			else
				*tmpStr='0';
			tmpStr++;
			byte<<=1;
		}
		valPtr++;
		valLen--;
	}
	*tmpStr++ ='\'';
	*tmpStr++ ='B';
	*tmpStr=0;

	return LDAP_SUCCESS;
}

Project: openldap
File: tls2.c

ldap_pvt_tls_destroy( void )
{
	struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();   

	ldap_int_tls_destroy( lo );

	tls_imp->ti_tls_destroy();
}

Project: openldap
File: tls2.c

ldap_int_tls_connect( LDAP *ld, LDAPConn *conn, const char *host )
{
	Sockbuf *sb = conn->lconn_sb;
	int	err;
	tls_session	*ssl = NULL;

	if ( HAS_TLS( sb )) {
		ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&ssl );
	} else {
		struct ldapoptions *lo;
		tls_ctx *ctx;

		ctx = ld->ld_options.ldo_tls_ctx;

		ssl = alloc_handle( ctx, 0 );

		if ( ssl == NULL ) return -1;

#ifdef LDAP_DEBUG
		ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
			LBER_SBIOD_LEVEL_TRANSPORT, (void *)"tls_" );
#endif
		ber_sockbuf_add_io( sb, tls_imp->ti_sbio,
			LBER_SBIOD_LEVEL_TRANSPORT, (void *)ssl );

		lo = LDAP_INT_GLOBAL_OPT();   
		if( ctx == NULL ) {
			ctx = lo->ldo_tls_ctx;
			ld->ld_options.ldo_tls_ctx = ctx;
			tls_ctx_ref( ctx );
		}
		if ( ld->ld_options.ldo_tls_connect_cb )
			ld->ld_options.ldo_tls_connect_cb( ld, ssl, ctx,
			ld->ld_options.ldo_tls_connect_arg );
		if ( lo && lo->ldo_tls_connect_cb && lo->ldo_tls_connect_cb !=
			ld->ld_options.ldo_tls_connect_cb )
			lo->ldo_tls_connect_cb( ld, ssl, ctx, lo->ldo_tls_connect_arg );
	}

	err = tls_imp->ti_session_connect( ld, ssl );

#ifdef HAVE_WINSOCK
	errno = WSAGetLastError();
#endif

	if ( err == 0 ) {
		err = ldap_pvt_tls_check_hostname( ld, ssl, host );
	}

	if ( err < 0 )
	{
		char buf[256], *msg;
		if ( update_flags( sb, ssl, err )) {
			return 1;
		}

		msg = tls_imp->ti_session_errmsg( ssl, err, buf, sizeof(buf) );
		if ( msg ) {
			if ( ld->ld_error ) {
				LDAP_FREE( ld->ld_error );
			}
			ld->ld_error = LDAP_STRDUP( msg );
#ifdef HAVE_EBCDIC
			if ( ld->ld_error ) __etoa(ld->ld_error);
#endif
		}

		Debug( LDAP_DEBUG_ANY,"TLS: can't connect: %s.\n",
			ld->ld_error ? ld->ld_error : "" ,0,0);

		ber_sockbuf_remove_io( sb, tls_imp->ti_sbio,
			LBER_SBIOD_LEVEL_TRANSPORT );
#ifdef LDAP_DEBUG
		ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug,
			LBER_SBIOD_LEVEL_TRANSPORT );
#endif
		return -1;
	}

	return 0;
}

Project: openldap
File: tls2.c

ldap_start_tls( LDAP *ld,
	LDAPControl **serverctrls,
	LDAPControl **clientctrls,
	int *msgidp )
{
	return ldap_extended_operation( ld, LDAP_EXOP_START_TLS,
		NULL, serverctrls, clientctrls, msgidp );
}

Project: openldap
File: tls2.c

ldap_pvt_tls_accept( Sockbuf *sb, void *ctx_arg )
{
	int	err;
	tls_session	*ssl = NULL;

	if ( HAS_TLS( sb )) {
		ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_SSL, (void *)&ssl );
	} else {
		ssl = alloc_handle( ctx_arg, 1 );
		if ( ssl == NULL ) return -1;

#ifdef LDAP_DEBUG
		ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
			LBER_SBIOD_LEVEL_TRANSPORT, (void *)"tls_" );
#endif
		ber_sockbuf_add_io( sb, tls_imp->ti_sbio,
			LBER_SBIOD_LEVEL_TRANSPORT, (void *)ssl );
	}

	err = tls_imp->ti_session_accept( ssl );

#ifdef HAVE_WINSOCK
	errno = WSAGetLastError();
#endif

	if ( err < 0 )
	{
		if ( update_flags( sb, ssl, err )) return 1;

		if ( DebugTest( LDAP_DEBUG_ANY ) ) {
			char buf[256], *msg;
			msg = tls_imp->ti_session_errmsg( ssl, err, buf, sizeof(buf) );
			Debug( LDAP_DEBUG_ANY,"TLS: can't accept: %s.\n",
				msg ? msg : "(unknown)", 0, 0 );
		}

		ber_sockbuf_remove_io( sb, tls_imp->ti_sbio,
			LBER_SBIOD_LEVEL_TRANSPORT );
#ifdef LDAP_DEBUG
		ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug,
			LBER_SBIOD_LEVEL_TRANSPORT );
#endif
		return -1;
	}
	return 0;
}

Project: openldap
File: tls2.c

tls_init(tls_impl *impl )
{
	static int tls_initialized = 0;

	if ( !tls_initialized++ ) {
#ifdef LDAP_R_COMPILE
		ldap_pvt_thread_mutex_init( &tls_def_ctx_mutex );
#endif
	}

	if ( impl->ti_inited++ ) return 0;

#ifdef LDAP_R_COMPILE
	impl->ti_thr_init();
#endif
	return impl->ti_tls_init();
}

Project: openldap
File: tls2.c

ldap_tls_inplace( LDAP *ld )
{
	Sockbuf		*sb = NULL;

	if ( ld->ld_defconn && ld->ld_defconn->lconn_sb ) {
		sb = ld->ld_defconn->lconn_sb;

	} else if ( ld->ld_sb ) {
		sb = ld->ld_sb;

	} else {
		return 0;
	}

	return ldap_pvt_tls_inplace( sb );
}

Project: openldap
File: tls2.c

ldap_pvt_tls_get_option( LDAP *ld, int option, void *arg )
{
	struct ldapoptions *lo;

	if( option == LDAP_OPT_X_TLS_PACKAGE ) {
		*(char **)arg = LDAP_STRDUP( tls_imp->ti_name );
		return 0;
	}

	if( ld != NULL ) {
		assert( LDAP_VALID( ld ) );

		if( !LDAP_VALID( ld ) ) {
			return LDAP_OPT_ERROR;
		}

		lo = &ld->ld_options;

	} else {
		/* Get pointer to global option structure */
		lo = LDAP_INT_GLOBAL_OPT();   
		if ( lo == NULL ) {
			return LDAP_NO_MEMORY;
		}
	}

	switch( option ) {
	case LDAP_OPT_X_TLS:
		*(int *)arg = lo->ldo_tls_mode;
		break;
	case LDAP_OPT_X_TLS_CTX:
		*(void **)arg = lo->ldo_tls_ctx;
		if ( lo->ldo_tls_ctx ) {
			tls_ctx_ref( lo->ldo_tls_ctx );
		}
		break;
	case LDAP_OPT_X_TLS_CACERTFILE:
		*(char **)arg = lo->ldo_tls_cacertfile ?
			LDAP_STRDUP( lo->ldo_tls_cacertfile ) : NULL;
		break;
	case LDAP_OPT_X_TLS_CACERTDIR:
		*(char **)arg = lo->ldo_tls_cacertdir ?
			LDAP_STRDUP( lo->ldo_tls_cacertdir ) : NULL;
		break;
	case LDAP_OPT_X_TLS_CERTFILE:
		*(char **)arg = lo->ldo_tls_certfile ?
			LDAP_STRDUP( lo->ldo_tls_certfile ) : NULL;
		break;
	case LDAP_OPT_X_TLS_KEYFILE:
		*(char **)arg = lo->ldo_tls_keyfile ?
			LDAP_STRDUP( lo->ldo_tls_keyfile ) : NULL;
		break;
	case LDAP_OPT_X_TLS_DHFILE:
		*(char **)arg = lo->ldo_tls_dhfile ?
			LDAP_STRDUP( lo->ldo_tls_dhfile ) : NULL;
		break;
	case LDAP_OPT_X_TLS_ECNAME:
		*(char **)arg = lo->ldo_tls_ecname ?
			LDAP_STRDUP( lo->ldo_tls_ecname ) : NULL;
		break;
	case LDAP_OPT_X_TLS_CRLFILE:	/* GnuTLS only */
		*(char **)arg = lo->ldo_tls_crlfile ?
			LDAP_STRDUP( lo->ldo_tls_crlfile ) : NULL;
		break;
	case LDAP_OPT_X_TLS_REQUIRE_CERT:
		*(int *)arg = lo->ldo_tls_require_cert;
		break;
	case LDAP_OPT_X_TLS_REQUIRE_SAN:
		*(int *)arg = lo->ldo_tls_require_san;
		break;
#ifdef HAVE_OPENSSL_CRL
	case LDAP_OPT_X_TLS_CRLCHECK:	/* OpenSSL only */
		*(int *)arg = lo->ldo_tls_crlcheck;
		break;
#endif
	case LDAP_OPT_X_TLS_CIPHER_SUITE:
		*(char **)arg = lo->ldo_tls_ciphersuite ?
			LDAP_STRDUP( lo->ldo_tls_ciphersuite ) : NULL;
		break;
	case LDAP_OPT_X_TLS_PROTOCOL_MIN:
		*(int *)arg = lo->ldo_tls_protocol_min;
		break;
	case LDAP_OPT_X_TLS_RANDOM_FILE:
		*(char **)arg = lo->ldo_tls_randfile ?
			LDAP_STRDUP( lo->ldo_tls_randfile ) : NULL;
		break;
	case LDAP_OPT_X_TLS_SSL_CTX: {
		void *retval = 0;
		if ( ld != NULL ) {
			LDAPConn *conn = ld->ld_defconn;
			if ( conn != NULL ) {
				Sockbuf *sb = conn->lconn_sb;
				retval = ldap_pvt_tls_sb_ctx( sb );
			}
		}
		*(void **)arg = retval;
		break;
	}
	case LDAP_OPT_X_TLS_CONNECT_CB:
		*(LDAP_TLS_CONNECT_CB **)arg = lo->ldo_tls_connect_cb;
		break;
	case LDAP_OPT_X_TLS_CONNECT_ARG:
		*(void **)arg = lo->ldo_tls_connect_arg;
		break;
	default:
		return -1;
	}
	return 0;
}

Project: openldap
File: tls2.c

ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv )
{
	Sockbuf *sb;
	char *host;
	void *ssl;
	int ret, async;
#ifdef LDAP_USE_NON_BLOCKING_TLS
	struct timeval start_time_tv, tv, tv0;
	ber_socket_t	sd = AC_SOCKET_ERROR;
#endif /* LDAP_USE_NON_BLOCKING_TLS */

	if ( !conn )
		return LDAP_PARAM_ERROR;

	sb = conn->lconn_sb;
	if( srv ) {
		host = srv->lud_host;
	} else {
 		host = conn->lconn_server->lud_host;
	}

	/* avoid NULL host */
	if( host == NULL ) {
		host = "localhost";
	}

	(void) tls_init( tls_imp );

#ifdef LDAP_USE_NON_BLOCKING_TLS
	/*
	 * Use non-blocking io during SSL Handshake when a timeout is configured
	 */
	async = LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_CONNECT_ASYNC );
	if ( ld->ld_options.ldo_tm_net.tv_sec >= 0 ) {
		if ( !async ) {
			/* if async, this has already been set */
			ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_NONBLOCK, (void*)1 );
		}
		ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
		tv = ld->ld_options.ldo_tm_net;
		tv0 = tv;
#ifdef HAVE_GETTIMEOFDAY
		gettimeofday( &start_time_tv, NULL );
#else /* ! HAVE_GETTIMEOFDAY */
		time( &start_time_tv.tv_sec );
		start_time_tv.tv_usec = 0;
#endif /* ! HAVE_GETTIMEOFDAY */
	}

#endif /* LDAP_USE_NON_BLOCKING_TLS */

	ld->ld_errno = LDAP_SUCCESS;
	ret = ldap_int_tls_connect( ld, conn, host );

	 /* this mainly only happens for non-blocking io
	  * but can also happen when the handshake is too
	  * big for a single network message.
	  */
	while ( ret > 0 ) {
#ifdef LDAP_USE_NON_BLOCKING_TLS
		if ( async ) {
			struct timeval curr_time_tv, delta_tv;
			int wr=0;

			if ( sb->sb_trans_needs_read ) {
				wr=0;
			} else if ( sb->sb_trans_needs_write ) {
				wr=1;
			}
			Debug( LDAP_DEBUG_TRACE, "ldap_int_tls_start: ldap_int_tls_connect needs %s\n",
					wr ? "write": "read", 0, 0 );

			/* This is mostly copied from result.c:wait4msg(), should
			 * probably be moved into a separate function */
#ifdef HAVE_GETTIMEOFDAY
			gettimeofday( &curr_time_tv, NULL );
#else /* ! HAVE_GETTIMEOFDAY */
			time( &curr_time_tv.tv_sec );
			curr_time_tv.tv_usec = 0;
#endif /* ! HAVE_GETTIMEOFDAY */

			/* delta = curr - start */
			delta_tv.tv_sec = curr_time_tv.tv_sec - start_time_tv.tv_sec;
			delta_tv.tv_usec = curr_time_tv.tv_usec - start_time_tv.tv_usec;
			if ( delta_tv.tv_usec < 0 ) {
				delta_tv.tv_sec--;
				delta_tv.tv_usec += 1000000;
			}

			/* tv0 < delta ? */
			if ( ( tv0.tv_sec < delta_tv.tv_sec ) ||
				 ( ( tv0.tv_sec == delta_tv.tv_sec ) &&
				   ( tv0.tv_usec < delta_tv.tv_usec ) ) )
			{
				ret = -1;
				ld->ld_errno = LDAP_TIMEOUT;
				break;
			}
			/* timeout -= delta_time */
			tv0.tv_sec -= delta_tv.tv_sec;
			tv0.tv_usec -= delta_tv.tv_usec;
			if ( tv0.tv_usec < 0 ) {
				tv0.tv_sec--;
				tv0.tv_usec += 1000000;
			}
			start_time_tv.tv_sec = curr_time_tv.tv_sec;
			start_time_tv.tv_usec = curr_time_tv.tv_usec;
			tv = tv0;
			Debug( LDAP_DEBUG_TRACE, "ldap_int_tls_start: ld %p %ld s %ld us to go\n",
				(void *)ld, (long) tv.tv_sec, (long) tv.tv_usec );
			ret = ldap_int_poll( ld, sd, &tv, wr);
			if ( ret < 0 ) {
				ld->ld_errno = LDAP_TIMEOUT;
				break;
			}
		}
#endif /* LDAP_USE_NON_BLOCKING_TLS */
		ret = ldap_int_tls_connect( ld, conn, host );
	}

	if ( ret < 0 ) {
		if ( ld->ld_errno == LDAP_SUCCESS )
			ld->ld_errno = LDAP_CONNECT_ERROR;
		return (ld->ld_errno);
	}

	return LDAP_SUCCESS;
}

Project: openldap
File: tls2.c

update_flags( Sockbuf *sb, tls_session * ssl, int rc )
{
	sb->sb_trans_needs_read  = 0;
	sb->sb_trans_needs_write = 0;

	return tls_imp->ti_session_upflags( sb, ssl, rc );
}

Project: openldap
File: tls2.c

ldap_pvt_tls_ctx_free ( void *c )
{
	if ( !c ) return;
	tls_imp->ti_ctx_free( c );
}

Project: openldap
File: tls2.c

ldap_pvt_tls_init_def_ctx( int is_server )
{
	struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();   
	int rc;
	LDAP_MUTEX_LOCK( &tls_def_ctx_mutex );
	rc = ldap_int_tls_init_ctx( lo, is_server );
	LDAP_MUTEX_UNLOCK( &tls_def_ctx_mutex );
	return rc;
}

Project: openldap
File: tls2.c

ldap_install_tls( LDAP *ld )
{
#ifndef HAVE_TLS
	return LDAP_NOT_SUPPORTED;
#else
	if ( ldap_tls_inplace( ld ) ) {
		return LDAP_LOCAL_ERROR;
	}

	return ldap_int_tls_start( ld, ld->ld_defconn, NULL );
#endif
}

Project: openldap
File: tls2.c

ldap_pvt_tls_inplace ( Sockbuf *sb )
{
	return HAS_TLS( sb ) ? 1 : 0;
}

Project: openldap
File: tls2.c

ldap_pvt_tls_check_hostname( LDAP *ld, void *s, const char *name_in )
{
	tls_session *session = s;

	if (ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER &&
	    ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_ALLOW) {
		ld->ld_errno = tls_imp->ti_session_chkhost( ld, session, name_in );
		if (ld->ld_errno != LDAP_SUCCESS) {
			return ld->ld_errno;
		}
	}

	return LDAP_SUCCESS;
}

Project: openldap
File: tls2.c

ldap_pvt_tls_get_strength( void *s )
{
	tls_session *session = s;

	return tls_imp->ti_session_strength( session );
}

Project: openldap
File: tls2.c

ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg )
{
	struct ldapoptions *lo;

	if( ld != NULL ) {
		assert( LDAP_VALID( ld ) );

		if( !LDAP_VALID( ld ) ) {
			return LDAP_OPT_ERROR;
		}

		lo = &ld->ld_options;

	} else {
		/* Get pointer to global option structure */
		lo = LDAP_INT_GLOBAL_OPT();   
		if ( lo == NULL ) {
			return LDAP_NO_MEMORY;
		}
	}

	switch( option ) {
	case LDAP_OPT_X_TLS:
		if ( !arg ) return -1;

		switch( *(int *) arg ) {
		case LDAP_OPT_X_TLS_NEVER:
		case LDAP_OPT_X_TLS_DEMAND:
		case LDAP_OPT_X_TLS_ALLOW:
		case LDAP_OPT_X_TLS_TRY:
		case LDAP_OPT_X_TLS_HARD:
			if (lo != NULL) {
				lo->ldo_tls_mode = *(int *)arg;
			}

			return 0;
		}
		return -1;

	case LDAP_OPT_X_TLS_CTX:
		if ( lo->ldo_tls_ctx )
			ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx );
		lo->ldo_tls_ctx = arg;
		tls_ctx_ref( lo->ldo_tls_ctx );
		return 0;
	case LDAP_OPT_X_TLS_CONNECT_CB:
		lo->ldo_tls_connect_cb = (LDAP_TLS_CONNECT_CB *)arg;
		return 0;
	case LDAP_OPT_X_TLS_CONNECT_ARG:
		lo->ldo_tls_connect_arg = arg;
		return 0;
	case LDAP_OPT_X_TLS_CACERTFILE:
		if ( lo->ldo_tls_cacertfile ) LDAP_FREE( lo->ldo_tls_cacertfile );
		lo->ldo_tls_cacertfile = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL;
		return 0;
	case LDAP_OPT_X_TLS_CACERTDIR:
		if ( lo->ldo_tls_cacertdir ) LDAP_FREE( lo->ldo_tls_cacertdir );
		lo->ldo_tls_cacertdir = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL;
		return 0;
	case LDAP_OPT_X_TLS_CERTFILE:
		if ( lo->ldo_tls_certfile ) LDAP_FREE( lo->ldo_tls_certfile );
		lo->ldo_tls_certfile = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL;
		return 0;
	case LDAP_OPT_X_TLS_KEYFILE:
		if ( lo->ldo_tls_keyfile ) LDAP_FREE( lo->ldo_tls_keyfile );
		lo->ldo_tls_keyfile = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL;
		return 0;
	case LDAP_OPT_X_TLS_DHFILE:
		if ( lo->ldo_tls_dhfile ) LDAP_FREE( lo->ldo_tls_dhfile );
		lo->ldo_tls_dhfile = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL;
		return 0;
	case LDAP_OPT_X_TLS_ECNAME:
		if ( lo->ldo_tls_ecname ) LDAP_FREE( lo->ldo_tls_ecname );
		lo->ldo_tls_ecname = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL;
		return 0;
	case LDAP_OPT_X_TLS_CRLFILE:	/* GnuTLS only */
		if ( lo->ldo_tls_crlfile ) LDAP_FREE( lo->ldo_tls_crlfile );
		lo->ldo_tls_crlfile = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL;
		return 0;
	case LDAP_OPT_X_TLS_REQUIRE_CERT:
		if ( !arg ) return -1;
		switch( *(int *) arg ) {
		case LDAP_OPT_X_TLS_NEVER:
		case LDAP_OPT_X_TLS_DEMAND:
		case LDAP_OPT_X_TLS_ALLOW:
		case LDAP_OPT_X_TLS_TRY:
		case LDAP_OPT_X_TLS_HARD:
			lo->ldo_tls_require_cert = * (int *) arg;
			return 0;
		}
		return -1;
	case LDAP_OPT_X_TLS_REQUIRE_SAN:
		if ( !arg ) return -1;
		switch( *(int *) arg ) {
		case LDAP_OPT_X_TLS_NEVER:
		case LDAP_OPT_X_TLS_DEMAND:
		case LDAP_OPT_X_TLS_ALLOW:
		case LDAP_OPT_X_TLS_TRY:
		case LDAP_OPT_X_TLS_HARD:
			lo->ldo_tls_require_san = * (int *) arg;
			return 0;
		}
		return -1;
#ifdef HAVE_OPENSSL_CRL
	case LDAP_OPT_X_TLS_CRLCHECK:	/* OpenSSL only */
		if ( !arg ) return -1;
		switch( *(int *) arg ) {
		case LDAP_OPT_X_TLS_CRL_NONE:
		case LDAP_OPT_X_TLS_CRL_PEER:
		case LDAP_OPT_X_TLS_CRL_ALL:
			lo->ldo_tls_crlcheck = * (int *) arg;
			return 0;
		}
		return -1;
#endif
	case LDAP_OPT_X_TLS_CIPHER_SUITE:
		if ( lo->ldo_tls_ciphersuite ) LDAP_FREE( lo->ldo_tls_ciphersuite );
		lo->ldo_tls_ciphersuite = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL;
		return 0;

	case LDAP_OPT_X_TLS_PROTOCOL_MIN:
		if ( !arg ) return -1;
		lo->ldo_tls_protocol_min = *(int *)arg;
		return 0;
	case LDAP_OPT_X_TLS_RANDOM_FILE:
		if ( ld != NULL )
			return -1;
		if ( lo->ldo_tls_randfile ) LDAP_FREE (lo->ldo_tls_randfile );
		lo->ldo_tls_randfile = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL;
		break;
	case LDAP_OPT_X_TLS_NEWCTX:
		if ( !arg ) return -1;
		if ( lo->ldo_tls_ctx )
			ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx );
		lo->ldo_tls_ctx = NULL;
		return ldap_int_tls_init_ctx( lo, *(int *)arg );
	default:
		return -1;
	}
	return 0;
}

Project: openldap
File: tls2.c

ldap_pvt_tls_get_my_dn( void *s, struct berval *dn, LDAPDN_rewrite_dummy *func, unsigned flags )
{
	tls_session *session = s;
	struct berval der_dn;
	int rc;

	rc = tls_imp->ti_session_my_dn( session, &der_dn );
	if ( rc == LDAP_SUCCESS )
		rc = ldap_X509dn2bv(&der_dn, dn, (LDAPDN_rewrite_func *)func, flags );
	return rc;
}

Project: openldap
File: tls2.c

ldap_pvt_tls_init( void )
{
	return tls_init( tls_imp );
}

Project: openldap
File: tls2.c

tls_ctx_ref( tls_ctx *ctx )
{
	if ( !ctx ) return;

	tls_imp->ti_ctx_ref( ctx );
}

Project: openldap
File: tls2.c

alloc_handle( void *ctx_arg, int is_server )
{
	tls_ctx	*ctx;
	tls_session	*ssl;

	if ( ctx_arg ) {
		ctx = ctx_arg;
	} else {
		struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();   
		if ( ldap_pvt_tls_init_def_ctx( is_server ) < 0 ) return NULL;
		ctx = lo->ldo_tls_ctx;
	}

	ssl = tls_imp->ti_session_new( ctx, is_server );
	if ( ssl == NULL ) {
		Debug( LDAP_DEBUG_ANY,"TLS: can't create ssl handle.\n",0,0,0);
		return NULL;
	}
	return ssl;
}