conn.c

来自「ldap服务器源码」· C语言 代码 · 共 1,810 行 · 第 1/3 页

C
1,810
字号
/* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/conn.c,v 1.31.2.28 2007/01/27 23:56:43 ando Exp $ *//* This work is part of OpenLDAP Software <http://www.openldap.org/>. * * Copyright 1999-2007 The OpenLDAP Foundation. * Portions Copyright 2001-2003 Pierangelo Masarati. * Portions Copyright 1999-2003 Howard Chu. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * <http://www.OpenLDAP.org/license.html>. *//* ACKNOWLEDGEMENTS: * This work was initially developed by the Howard Chu for inclusion * in OpenLDAP Software and subsequently enhanced by Pierangelo * Masarati. */#include "portable.h"#include <stdio.h>#include <ac/errno.h>#include <ac/socket.h>#include <ac/string.h>#define AVL_INTERNAL#include "slap.h"#include "../back-ldap/back-ldap.h"#include "back-meta.h"/* * meta_back_conndn_cmp * * compares two struct metaconn based on the value of the conn pointer * and of the local DN; used by avl stuff */intmeta_back_conndn_cmp(	const void *c1,	const void *c2 ){	metaconn_t	*mc1 = ( metaconn_t * )c1;        metaconn_t	*mc2 = ( metaconn_t * )c2;	int		rc;		/* If local DNs don't match, it is definitely not a match */	/* For shared sessions, conn is NULL. Only explicitly	 * bound sessions will have non-NULL conn.	 */	rc = SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn );	if ( rc == 0 ) {		rc = ber_bvcmp( &mc1->mc_local_ndn, &mc2->mc_local_ndn );	}	return rc;}/* * meta_back_conndnmc_cmp * * compares two struct metaconn based on the value of the conn pointer, * the local DN and the struct pointer; used by avl stuff */static intmeta_back_conndnmc_cmp(	const void *c1,	const void *c2 ){	metaconn_t	*mc1 = ( metaconn_t * )c1;        metaconn_t	*mc2 = ( metaconn_t * )c2;	int		rc;		/* If local DNs don't match, it is definitely not a match */	/* For shared sessions, conn is NULL. Only explicitly	 * bound sessions will have non-NULL conn.	 */	rc = SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn );	if ( rc == 0 ) {		rc = ber_bvcmp( &mc1->mc_local_ndn, &mc2->mc_local_ndn );		if ( rc == 0 ) {			rc = SLAP_PTRCMP( mc1, mc2 );		}	}	return rc;}/* * meta_back_conn_cmp * * compares two struct metaconn based on the value of the conn pointer; * used by avl stuff */intmeta_back_conn_cmp(	const void *c1,	const void *c2 ){	metaconn_t	*mc1 = ( metaconn_t * )c1;        metaconn_t	*mc2 = ( metaconn_t * )c2;		/* For shared sessions, conn is NULL. Only explicitly	 * bound sessions will have non-NULL conn.	 */	return SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn );}/* * meta_back_conndn_dup * * returns -1 in case a duplicate struct metaconn has been inserted; * used by avl stuff */intmeta_back_conndn_dup(	void *c1,	void *c2 ){	metaconn_t	*mc1 = ( metaconn_t * )c1;	metaconn_t	*mc2 = ( metaconn_t * )c2;	/* Cannot have more than one shared session with same DN */	if ( mc1->mc_conn == mc2->mc_conn &&		dn_match( &mc1->mc_local_ndn, &mc2->mc_local_ndn ) )	{		return -1;	}			return 0;}/* * Debug stuff (got it from libavl) */#if META_BACK_PRINT_CONNTREE > 0static voidmeta_back_ravl_print( Avlnode *root, int depth ){	int     	i;	metaconn_t	*mc;		if ( root == 0 ) {		return;	}		meta_back_ravl_print( root->avl_right, depth + 1 );		for ( i = 0; i < depth; i++ ) {		fprintf( stderr, "-" );	}	mc = (metaconn_t *)root->avl_data;	fprintf( stderr, "mc=%p local=\"%s\" conn=%p %s refcnt=%d%s\n",		(void *)mc,		mc->mc_local_ndn.bv_val ? mc->mc_local_ndn.bv_val : "",		(void *)mc->mc_conn,		avl_bf2str( root->avl_bf ), mc->mc_refcnt,		LDAP_BACK_CONN_TAINTED( mc ) ? " tainted" : "" );		meta_back_ravl_print( root->avl_left, depth + 1 );}/* NOTE: duplicate from back-ldap/bind.c */static char* priv2str[] = {	"privileged",	"privileged/TLS",	"anonymous",	"anonymous/TLS",	"bind",	"bind/TLS",	NULL};voidmeta_back_print_conntree( metainfo_t *mi, char *msg ){	int	c;	fprintf( stderr, "========> %s\n", msg );		for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) {		int		i = 0;		metaconn_t	*mc;		fprintf( stderr, "  %s[%d]\n", priv2str[ c ], mi->mi_conn_priv[ c ].mic_num );		LDAP_TAILQ_FOREACH( mc, &mi->mi_conn_priv[ c ].mic_priv, mc_q )		{			fprintf( stderr, "    [%d] mc=%p local=\"%s\" conn=%p refcnt=%d flags=0x%08x\n",				i,				(void *)mc,				mc->mc_local_ndn.bv_val ? mc->mc_local_ndn.bv_val : "",				(void *)mc->mc_conn, mc->mc_refcnt, mc->msc_mscflags );			i++;		}	}		if ( mi->mi_conninfo.lai_tree == NULL ) {		fprintf( stderr, "\t(empty)\n" );	} else {		meta_back_ravl_print( mi->mi_conninfo.lai_tree, 0 );	}		fprintf( stderr, "<======== %s\n", msg );}#endif /* META_BACK_PRINT_CONNTREE *//* * End of debug stuff *//* * metaconn_alloc *  * Allocates a connection structure, making room for all the referenced targets */static metaconn_t *metaconn_alloc(       	Operation 		*op ){	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;	metaconn_t	*mc;	int		ntargets = mi->mi_ntargets;	assert( ntargets > 0 );	/* malloc all in one */	mc = ( metaconn_t * )ch_calloc( 1, sizeof( metaconn_t )		+ sizeof( metasingleconn_t ) * ( ntargets - 1 ) );	if ( mc == NULL ) {		return NULL;	}	mc->mc_info = mi;	mc->mc_authz_target = META_BOUND_NONE;	mc->mc_refcnt = 1;	return mc;}/* * meta_back_init_one_conn *  * Initializes one connection */intmeta_back_init_one_conn(	Operation		*op,	SlapReply		*rs,	metaconn_t		*mc,	int			candidate,	int			ispriv,	ldap_back_send_t	sendok,	int			dolock ){	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;	metatarget_t		*mt = mi->mi_targets[ candidate ];	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];	int			version;	dncookie		dc;	int			isauthz = ( candidate == mc->mc_authz_target );	int			do_return = 0;#ifdef HAVE_TLS	int			is_ldaps = 0;#endif /* HAVE_TLS */	/* if the server is quarantined, and	 * - the current interval did not expire yet, or	 * - no more retries should occur,	 * don't return the connection */	if ( mt->mt_isquarantined ) {		slap_retry_info_t	*ri = &mt->mt_quarantine;		int			dont_retry = 1;		if ( mt->mt_quarantine.ri_interval ) {			ldap_pvt_thread_mutex_lock( &mt->mt_quarantine_mutex );			if ( mt->mt_isquarantined == LDAP_BACK_FQ_YES ) {				dont_retry = ( ri->ri_num[ ri->ri_idx ] == SLAP_RETRYNUM_TAIL					|| slap_get_time() < ri->ri_last + ri->ri_interval[ ri->ri_idx ] );				if ( !dont_retry ) {					if ( StatslogTest( LDAP_DEBUG_ANY ) ) {						char	buf[ SLAP_TEXT_BUFLEN ];						snprintf( buf, sizeof( buf ),							"meta_back_init_one_conn[%d]: quarantine "							"retry block #%d try #%d",							candidate, ri->ri_idx, ri->ri_count );						Debug( LDAP_DEBUG_ANY, "%s %s.\n",							op->o_log_prefix, buf, 0 );					}				}				mt->mt_isquarantined = LDAP_BACK_FQ_RETRYING;			}			ldap_pvt_thread_mutex_unlock( &mt->mt_quarantine_mutex );		}		if ( dont_retry ) {			rs->sr_err = LDAP_UNAVAILABLE;			if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {				rs->sr_text = "Target is quarantined";				send_ldap_result( op, rs );			}			return rs->sr_err;		}	}retry_lock:;	if ( dolock ) {		ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );	}	/*	 * Already init'ed	 */	if ( LDAP_BACK_CONN_ISBOUND( msc )		|| LDAP_BACK_CONN_ISANON( msc ) )	{		assert( msc->msc_ld != NULL );		rs->sr_err = LDAP_SUCCESS;		do_return = 1;	} else if ( META_BACK_CONN_CREATING( msc )		|| LDAP_BACK_CONN_BINDING( msc ) )	{		if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) {			if ( dolock ) {				ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );			}			ldap_pvt_thread_yield();			goto retry_lock;		}		/* sounds more appropriate */		rs->sr_err = LDAP_BUSY;		rs->sr_text = "No connections to target are available";		do_return = 1;	} else if ( META_BACK_CONN_INITED( msc ) ) {		assert( msc->msc_ld != NULL );		rs->sr_err = LDAP_SUCCESS;		do_return = 1;	} else {		/*		 * creating...		 */		META_BACK_CONN_CREATING_SET( msc );	}	if ( dolock ) {		ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );	}	if ( do_return ) {		if ( rs->sr_err != LDAP_SUCCESS			&& op->o_conn			&& ( sendok & LDAP_BACK_SENDERR ) )		{			send_ldap_result( op, rs );		}		return rs->sr_err;	}	assert( msc->msc_ld == NULL );       	/*	 * Attempts to initialize the connection to the target ds	 */	ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );	rs->sr_err = ldap_initialize( &msc->msc_ld, mt->mt_uri );#ifdef HAVE_TLS	is_ldaps = ldap_is_ldaps_url( mt->mt_uri );#endif /* HAVE_TLS */	ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );	if ( rs->sr_err != LDAP_SUCCESS ) {		goto error_return;	}	/*	 * Set LDAP version. This will always succeed: If the client	 * bound with a particular version, then so can we.	 */	if ( mt->mt_version != 0 ) {		version = mt->mt_version;	} else if ( op->o_conn->c_protocol != 0 ) {		version = op->o_conn->c_protocol;	} else {		version = LDAP_VERSION3;	}	ldap_set_option( msc->msc_ld, LDAP_OPT_PROTOCOL_VERSION, &version );	/* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */	ldap_set_option( msc->msc_ld, LDAP_OPT_REFERRALS,		LDAP_BACK_CHASE_REFERRALS( mi ) ? LDAP_OPT_ON : LDAP_OPT_OFF );#ifdef HAVE_TLS	/* start TLS ("tls [try-]{start|propagate}" statement) */	if ( ( LDAP_BACK_USE_TLS( mi )		|| ( op->o_conn->c_is_tls			&& LDAP_BACK_PROPAGATE_TLS( mi ) ) )		&& !is_ldaps )	{#ifdef SLAP_STARTTLS_ASYNCHRONOUS		/*		 * use asynchronous StartTLS; in case, chase referral		 * FIXME: OpenLDAP does not return referral on StartTLS yet		 */		int		msgid;		rs->sr_err = ldap_start_tls( msc->msc_ld, NULL, NULL, &msgid );		if ( rs->sr_err == LDAP_SUCCESS ) {			LDAPMessage	*res = NULL;			int		rc, nretries = mt->mt_nretries;			struct timeval	tv;			LDAP_BACK_TV_SET( &tv );retry:;			rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );			switch ( rc ) {			case -1:				rs->sr_err = LDAP_OTHER;				break;			case 0:				if ( nretries != 0 ) {					if ( nretries > 0 ) {						nretries--;					}					LDAP_BACK_TV_SET( &tv );					goto retry;				}				rs->sr_err = LDAP_OTHER;				break;			default:				/* only touch when activity actually took place... */				if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {					msc->msc_time = op->o_time;				}				break;			}			if ( rc == LDAP_RES_EXTENDED ) {				struct berval	*data = NULL;				/* NOTE: right now, data is unused, so don't get it */				rs->sr_err = ldap_parse_extended_result( msc->msc_ld,					res, NULL, NULL /* &data */ , 0 );				if ( rs->sr_err == LDAP_SUCCESS ) {					int		err;					/* FIXME: matched? referrals? response controls? */					rs->sr_err = ldap_parse_result( msc->msc_ld,						res, &err, NULL, NULL, NULL, NULL, 1 );					res = NULL;					if ( rs->sr_err == LDAP_SUCCESS ) {						rs->sr_err = err;					}										/* FIXME: in case a referral 					 * is returned, should we try					 * using it instead of the 					 * configured URI? */					if ( rs->sr_err == LDAP_SUCCESS ) {						ldap_install_tls( msc->msc_ld );					} else if ( rs->sr_err == LDAP_REFERRAL ) {						/* FIXME: LDAP_OPERATIONS_ERROR? */						rs->sr_err = LDAP_OTHER;						rs->sr_text = "Unwilling to chase referral "							"returned by Start TLS exop";					}					if ( data ) {						ber_bvfree( data );					}				}			} else {				rs->sr_err = LDAP_OTHER;			}			if ( res != NULL ) {				ldap_msgfree( res );			}		}#else /* ! SLAP_STARTTLS_ASYNCHRONOUS */		/*		 * use synchronous StartTLS		 */		rs->sr_err = ldap_start_tls_s( msc->msc_ld, NULL, NULL );#endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */		/* if StartTLS is requested, only attempt it if the URL		 * is not "ldaps://"; this may occur not only in case		 * of misconfiguration, but also when used in the chain 		 * overlay, where the "uri" can be parsed out of a referral */		if ( rs->sr_err == LDAP_SERVER_DOWN			|| ( rs->sr_err != LDAP_SUCCESS				&& LDAP_BACK_TLS_CRITICAL( mi ) ) )		{#ifdef DEBUG_205			Debug( LDAP_DEBUG_ANY,				"### %s meta_back_init_one_conn(TLS) "				"ldap_unbind_ext[%d] ld=%p\n",				op->o_log_prefix, candidate,				(void *)msc->msc_ld );#endif /* DEBUG_205 */			/* need to trash a failed Start TLS */			meta_clear_one_candidate( op, mc, candidate );			goto error_return;		}	}#endif /* HAVE_TLS */	/*	 * Set the network timeout if set	 */	if ( mt->mt_network_timeout != 0 ) {		struct timeval	network_timeout;		network_timeout.tv_usec = 0;		network_timeout.tv_sec = mt->mt_network_timeout;		ldap_set_option( msc->msc_ld, LDAP_OPT_NETWORK_TIMEOUT,				(void *)&network_timeout );	}	/*	 * If the connection DN is not null, an attempt to rewrite it is made	 */	if ( ispriv ) {		if ( !BER_BVISNULL( &mt->mt_idassert_authcDN ) ) {			ber_bvreplace( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN );			if ( !BER_BVISNULL( &mt->mt_idassert_passwd ) ) {				if ( !BER_BVISNULL( &msc->msc_cred ) ) {					memset( msc->msc_cred.bv_val, 0,						msc->msc_cred.bv_len );				}				ber_bvreplace( &msc->msc_cred, &mt->mt_idassert_passwd );			}		} else {			ber_bvreplace( &msc->msc_bound_ndn, &slap_empty_bv );		}	} else {		if ( !BER_BVISNULL( &msc->msc_cred ) ) {			memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );			ber_memfree_x( msc->msc_cred.bv_val, NULL );			BER_BVZERO( &msc->msc_cred );		}		if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {			ber_memfree_x( msc->msc_bound_ndn.bv_val, NULL );			BER_BVZERO( &msc->msc_bound_ndn );		}		if ( !BER_BVISEMPTY( &op->o_ndn )			&& SLAP_IS_AUTHZ_BACKEND( op )			&& isauthz )		{			dc.target = mt;			dc.conn = op->o_conn;			dc.rs = rs;			dc.ctx = "bindDN";					/*			 * Rewrite the bind dn if needed			 */			if ( ldap_back_dn_massage( &dc, &op->o_conn->c_dn,						&msc->msc_bound_ndn ) )			{#ifdef DEBUG_205				Debug( LDAP_DEBUG_ANY,					"### %s meta_back_init_one_conn(rewrite) "					"ldap_unbind_ext[%d] ld=%p\n",					op->o_log_prefix, candidate,					(void *)msc->msc_ld );#endif /* DEBUG_205 */				/* need to trash a connection not fully established */				meta_clear_one_candidate( op, mc, candidate );				goto error_return;			}						/* copy the DN if needed */			if ( msc->msc_bound_ndn.bv_val == op->o_conn->c_dn.bv_val ) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?