⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bind.c

📁 ldap服务器源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* bind.c - ldap backend bind function *//* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/bind.c,v 1.85.2.33 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 2000-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 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.h"#undef ldap_debug	/* silence a warning in ldap-int.h */#include "../../../libraries/libldap/ldap-int.h"#include "lutil_ldap.h"#define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ	"2.16.840.1.113730.3.4.12"#if LDAP_BACK_PRINT_CONNTREE > 0static voidldap_back_ravl_print( Avlnode *root, int depth ){	int		i;	ldapconn_t	*lc;		if ( root == 0 ) {		return;	}		ldap_back_ravl_print( root->avl_right, depth+1 );		for ( i = 0; i < depth; i++ ) {		fprintf( stderr, "-" );	}	lc = root->avl_data;	fprintf( stderr, "lc=%p local=\"%s\" conn=%p %s refcnt=%d flags=0x%08x\n",		(void *)lc,		lc->lc_local_ndn.bv_val ? lc->lc_local_ndn.bv_val : "",		(void *)lc->lc_conn,		avl_bf2str( root->avl_bf ), lc->lc_refcnt, lc->lc_lcflags );		ldap_back_ravl_print( root->avl_left, depth+1 );}static char* priv2str[] = {	"privileged",	"privileged/TLS",	"anonymous",	"anonymous/TLS",	"bind",	"bind/TLS",	NULL};voidldap_back_print_conntree( ldapinfo_t *li, char *msg ){	int	c;	fprintf( stderr, "========> %s\n", msg );	for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) {		int		i = 0;		ldapconn_t	*lc;		fprintf( stderr, "  %s[%d]\n", priv2str[ c ], li->li_conn_priv[ c ].lic_num );		LDAP_TAILQ_FOREACH( lc, &li->li_conn_priv[ c ].lic_priv, lc_q )		{			fprintf( stderr, "    [%d] lc=%p local=\"%s\" conn=%p refcnt=%d flags=0x%08x\n",				i,				(void *)lc,				lc->lc_local_ndn.bv_val ? lc->lc_local_ndn.bv_val : "",				(void *)lc->lc_conn, lc->lc_refcnt, lc->lc_lcflags );			i++;		}	}		if ( li->li_conninfo.lai_tree == 0 ) {		fprintf( stderr, "\t(empty)\n" );	} else {		ldap_back_ravl_print( li->li_conninfo.lai_tree, 0 );	}		fprintf( stderr, "<======== %s\n", msg );}#endif /* LDAP_BACK_PRINT_CONNTREE */static intldap_back_freeconn( ldapinfo_t *li, ldapconn_t *lc, int dolock );static ldapconn_t *ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok,	struct berval *binddn, struct berval *bindcred );static intldap_back_is_proxy_authz( Operation *op, SlapReply *rs, ldap_back_send_t sendok,	struct berval *binddn, struct berval *bindcred );static intldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs,	ldap_back_send_t sendok, struct berval *binddn, struct berval *bindcred );static intldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs,	ldap_back_send_t sendok );static intldap_back_conndnlc_cmp( const void *c1, const void *c2 );ldapconn_t *ldap_back_conn_delete( ldapinfo_t *li, ldapconn_t *lc ){	if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {		if ( LDAP_BACK_CONN_CACHED( lc ) ) {			assert( lc->lc_q.tqe_prev != NULL );			assert( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num > 0 );			li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num--;			LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );			LDAP_TAILQ_ENTRY_INIT( lc, lc_q );			LDAP_BACK_CONN_CACHED_CLEAR( lc );		} else {			assert( LDAP_BACK_CONN_TAINTED( lc ) );			assert( lc->lc_q.tqe_prev == NULL );		}	} else {		ldapconn_t	*tmplc = NULL;		if ( LDAP_BACK_CONN_CACHED( lc ) ) {			assert( !LDAP_BACK_CONN_TAINTED( lc ) );			tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,				ldap_back_conndnlc_cmp );			assert( tmplc == lc );			LDAP_BACK_CONN_CACHED_CLEAR( lc );		}		assert( LDAP_BACK_CONN_TAINTED( lc ) || tmplc == lc );	}	return lc;}intldap_back_bind( Operation *op, SlapReply *rs ){	ldapinfo_t		*li = (ldapinfo_t *) op->o_bd->be_private;	ldapconn_t		*lc;	int			rc = 0;	ber_int_t		msgid;	ldap_back_send_t	retrying = LDAP_BACK_RETRYING;	lc = ldap_back_getconn( op, rs, LDAP_BACK_BIND_SERR, NULL, NULL );	if ( !lc ) {		return rs->sr_err;	}	/* we can do (almost) whatever we want with this conn,	 * because either it's temporary, or it's marked as binding */	if ( !BER_BVISNULL( &lc->lc_bound_ndn ) ) {		ch_free( lc->lc_bound_ndn.bv_val );		BER_BVZERO( &lc->lc_bound_ndn );	}	if ( !BER_BVISNULL( &lc->lc_cred ) ) {		memset( lc->lc_cred.bv_val, 0, lc->lc_cred.bv_len );		ch_free( lc->lc_cred.bv_val );		BER_BVZERO( &lc->lc_cred );	}	LDAP_BACK_CONN_ISBOUND_CLEAR( lc );retry:;	/* method is always LDAP_AUTH_SIMPLE if we got here */	rs->sr_err = ldap_sasl_bind( lc->lc_ld, op->o_req_dn.bv_val,			LDAP_SASL_SIMPLE,			&op->orb_cred, op->o_ctrls, NULL, &msgid );	/* FIXME: should we always retry, or only when piping the bind	 * in the "override" connection pool? */	rc = ldap_back_op_result( lc, op, rs, msgid,		li->li_timeout[ SLAP_OP_BIND ],		LDAP_BACK_BIND_SERR | retrying );	if ( rc == LDAP_UNAVAILABLE && retrying ) {		retrying &= ~LDAP_BACK_RETRYING;		if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_BIND_SERR ) ) {			goto retry;		}	}	if ( rc == LDAP_SUCCESS ) {		/* If defined, proxyAuthz will be used also when		 * back-ldap is the authorizing backend; for this		 * purpose, after a successful bind the connection		 * is left for further binds, and further operations 		 * on this client connection will use a default		 * connection with identity assertion */		/* NOTE: use with care */		if ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {			ldap_back_release_conn( li, lc );			return( rc );		}		/* rebind is now done inside ldap_back_proxy_authz_bind()		 * in case of success */		LDAP_BACK_CONN_ISBOUND_SET( lc );		ber_dupbv( &lc->lc_bound_ndn, &op->o_req_ndn );		if ( !BER_BVISNULL( &lc->lc_cred ) ) {			memset( lc->lc_cred.bv_val, 0,					lc->lc_cred.bv_len );		}		if ( LDAP_BACK_SAVECRED( li ) ) {			ber_bvreplace( &lc->lc_cred, &op->orb_cred );			ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );		} else {			lc->lc_cred.bv_len = 0;		}	}	/* must re-insert if local DN changed as result of bind */	if ( !LDAP_BACK_CONN_ISBOUND( lc )		|| ( !dn_match( &op->o_req_ndn, &lc->lc_local_ndn )			&& !LDAP_BACK_PCONN_ISPRIV( lc ) ) )	{		int		lerr = -1;		ldapconn_t	*tmplc;		/* wait for all other ops to release the connection */retry_lock:;		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );		if ( lc->lc_refcnt > 1 ) {			ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );			ldap_pvt_thread_yield();			goto retry_lock;		}#if LDAP_BACK_PRINT_CONNTREE > 0		ldap_back_print_conntree( li, ">>> ldap_back_bind" );#endif /* LDAP_BACK_PRINT_CONNTREE */		assert( lc->lc_refcnt == 1 );		ldap_back_conn_delete( li, lc );		/* delete all cached connections with the current connection */		if ( LDAP_BACK_SINGLECONN( li ) ) {			while ( ( tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc, ldap_back_conn_cmp ) ) != NULL )			{				Debug( LDAP_DEBUG_TRACE,					"=>ldap_back_bind: destroying conn %ld (refcnt=%u)\n",					LDAP_BACK_PCONN_ID( lc ), lc->lc_refcnt, 0 );				if ( tmplc->lc_refcnt != 0 ) {					/* taint it */					LDAP_BACK_CONN_TAINTED_SET( tmplc );					LDAP_BACK_CONN_CACHED_CLEAR( tmplc );				} else {					/*					 * Needs a test because the handler may be corrupted,					 * and calling ldap_unbind on a corrupted header results					 * in a segmentation fault					 */					ldap_back_conn_free( tmplc );				}			}		}		if ( LDAP_BACK_CONN_ISBOUND( lc ) ) {			ber_bvreplace( &lc->lc_local_ndn, &op->o_req_ndn );			if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) {				LDAP_BACK_PCONN_ROOTDN_SET( lc, op );			}			lerr = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,				ldap_back_conndn_cmp, ldap_back_conndn_dup );		}#if LDAP_BACK_PRINT_CONNTREE > 0		ldap_back_print_conntree( li, "<<< ldap_back_bind" );#endif /* LDAP_BACK_PRINT_CONNTREE */			ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );		switch ( lerr ) {		case 0:			LDAP_BACK_CONN_CACHED_SET( lc );			break;		case -1:			/* duplicate; someone else successfully bound			 * on the same connection with the same identity;			 * we can do this because lc_refcnt == 1 */			ldap_back_conn_free( lc );			lc = NULL;		}	}	if ( lc != NULL ) {		ldap_back_release_conn( li, lc );	}	return( rc );}/* * ldap_back_conndn_cmp * * compares two ldapconn_t based on the value of the conn pointer * and of the local DN; used by avl stuff for insert, lookup * and direct delete */intldap_back_conndn_cmp( const void *c1, const void *c2 ){	const ldapconn_t	*lc1 = (const ldapconn_t *)c1;	const ldapconn_t	*lc2 = (const ldapconn_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( lc1->lc_conn, lc2->lc_conn );	if ( rc == 0 ) {		rc = ber_bvcmp( &lc1->lc_local_ndn, &lc2->lc_local_ndn );	}	return rc;}/* * ldap_back_conndnlc_cmp * * compares two ldapconn_t based on the value of the conn pointer, * the local DN and the lc pointer; used by avl stuff for insert, lookup * and direct delete */static intldap_back_conndnlc_cmp( const void *c1, const void *c2 ){	const ldapconn_t	*lc1 = (const ldapconn_t *)c1;	const ldapconn_t	*lc2 = (const ldapconn_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( lc1->lc_conn, lc2->lc_conn );	if ( rc == 0 ) {		rc = ber_bvcmp( &lc1->lc_local_ndn, &lc2->lc_local_ndn );		if ( rc == 0 ) {			rc = SLAP_PTRCMP( lc1, lc2 );		}	}	return rc;}/* * ldap_back_conn_cmp * * compares two ldapconn_t based on the value of the conn pointer; * used by avl stuff for delete of all conns with the same connid */intldap_back_conn_cmp( const void *c1, const void *c2 ){	const ldapconn_t	*lc1 = (const ldapconn_t *)c1;	const ldapconn_t	*lc2 = (const ldapconn_t *)c2;	/* For shared sessions, conn is NULL. Only explicitly	 * bound sessions will have non-NULL conn.	 */	return SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );}/* * ldap_back_conndn_dup * * returns -1 in case a duplicate ldapconn_t has been inserted; * used by avl stuff */intldap_back_conndn_dup( void *c1, void *c2 ){	ldapconn_t	*lc1 = (ldapconn_t *)c1;	ldapconn_t	*lc2 = (ldapconn_t *)c2;	/* Cannot have more than one shared session with same DN */	if ( lc1->lc_conn == lc2->lc_conn &&		dn_match( &lc1->lc_local_ndn, &lc2->lc_local_ndn ) )	{		return -1;	}			return 0;}static intldap_back_freeconn( ldapinfo_t *li, ldapconn_t *lc, int dolock ){	if ( dolock ) {		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );	}#if LDAP_BACK_PRINT_CONNTREE > 0	ldap_back_print_conntree( li, ">>> ldap_back_freeconn" );#endif /* LDAP_BACK_PRINT_CONNTREE */	(void)ldap_back_conn_delete( li, lc );	if ( lc->lc_refcnt == 0 ) {		ldap_back_conn_free( (void *)lc );	}#if LDAP_BACK_PRINT_CONNTREE > 0	ldap_back_print_conntree( li, "<<< ldap_back_freeconn" );#endif /* LDAP_BACK_PRINT_CONNTREE */	if ( dolock ) {		ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );	}	return 0;}#ifdef HAVE_TLSstatic intldap_back_start_tls(	LDAP		*ld,	int		protocol,	int		*is_tls,	const char	*url,	unsigned	flags,	int		retries,	const char	**text ){	int		rc = LDAP_SUCCESS;	/* start TLS ("tls-[try-]{start,propagate}" statements) */	if ( ( LDAP_BACK_USE_TLS_F( flags ) || ( *is_tls && LDAP_BACK_PROPAGATE_TLS_F( flags ) ) )				&& !ldap_is_ldaps_url( url ) )	{#ifdef SLAP_STARTTLS_ASYNCHRONOUS		/*		 * use asynchronous StartTLS		 * in case, chase referral (not implemented yet)		 */		int		msgid;		if ( protocol == 0 ) {			ldap_get_option( ld, LDAP_OPT_PROTOCOL_VERSION,					(void *)&protocol );		}		if ( protocol < LDAP_VERSION3 ) {			/* we should rather bail out... */			rc = LDAP_UNWILLING_TO_PERFORM;			*text = "invalid protocol version";		}		if ( rc == LDAP_SUCCESS ) {			rc = ldap_start_tls( ld, NULL, NULL, &msgid );		}		if ( rc == LDAP_SUCCESS ) {			LDAPMessage	*res = NULL;			struct timeval	tv;			LDAP_BACK_TV_SET( &tv );retry:;			rc = ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res );			if ( rc < 0 ) {				rc = LDAP_UNAVAILABLE;			} else if ( rc == 0 ) {				if ( retries != LDAP_BACK_RETRY_NEVER ) {					ldap_pvt_thread_yield();					if ( retries > 0 ) {						retries--;					}					LDAP_BACK_TV_SET( &tv );					goto retry;				}				rc = LDAP_UNAVAILABLE;			} else if ( rc == LDAP_RES_EXTENDED ) {				struct berval	*data = NULL;				rc = ldap_parse_extended_result( ld, res,						NULL, &data, 0 );				if ( rc == LDAP_SUCCESS ) {					int err;					rc = ldap_parse_result( ld, res, &err,						NULL, NULL, NULL, NULL, 1 );					if ( rc == LDAP_SUCCESS ) {						rc = err;					}					res = NULL;										/* FIXME: in case a referral 					 * is returned, should we try					 * using it instead of the 					 * configured URI? */					if ( rc == LDAP_SUCCESS ) {						rc = ldap_install_tls( ld );					} else if ( rc == LDAP_REFERRAL ) {						rc = LDAP_UNWILLING_TO_PERFORM;						*text = "unwilling to chase referral returned by Start TLS exop";					}					if ( data ) {						if ( data->bv_val ) {							ber_memfree( data->bv_val );						}						ber_memfree( data );					}				}			} else {				rc = LDAP_OTHER;			}			if ( res != NULL ) {				ldap_msgfree( res );			}		}#else /* ! SLAP_STARTTLS_ASYNCHRONOUS */		/*		 * use synchronous StartTLS		 */		rc = ldap_start_tls_s( 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 */		switch ( rc ) {		case LDAP_SUCCESS:			*is_tls = 1;			break;		case LDAP_SERVER_DOWN:			break;		default:			if ( LDAP_BACK_TLS_CRITICAL_F( flags ) ) {				*text = "could not start TLS";				break;			}			/* in case Start TLS is not critical */			*is_tls = 0;			rc = LDAP_SUCCESS;			break;		}	} else {		*is_tls = 0;	}	return rc;}#endif /* HAVE_TLS */static intldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok ){	ldapinfo_t	*li = (ldapinfo_t *)op->o_bd->be_private;	int		version;	LDAP		*ld = NULL;#ifdef HAVE_TLS

⌨️ 快捷键说明

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