bind.c

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

C
1,440
字号
/* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/bind.c,v 1.40.2.29 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"#undef ldap_debug	/* silence a warning in ldap-int.h */#include "../../../libraries/libldap/ldap-int.h"#include "lutil_ldap.h"static intmeta_back_proxy_authz_bind(	metaconn_t		*mc,	int			candidate,	Operation		*op,	SlapReply		*rs,	ldap_back_send_t	sendok );static intmeta_back_single_bind(	Operation		*op,	SlapReply		*rs,	metaconn_t		*mc,	int			candidate );intmeta_back_bind( Operation *op, SlapReply *rs ){	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;	metaconn_t	*mc = NULL;	int		rc = LDAP_OTHER,			i,			gotit = 0,			isroot = 0;	SlapReply	*candidates = meta_back_candidates_get( op );	rs->sr_err = LDAP_SUCCESS;	Debug( LDAP_DEBUG_ARGS, "%s meta_back_bind: dn=\"%s\".\n",		op->o_log_prefix, op->o_req_dn.bv_val, 0 );	/* the test on the bind method should be superfluous */	if ( op->orb_method == LDAP_AUTH_SIMPLE		&& be_isroot_dn( op->o_bd, &op->o_req_ndn ) )	{		if ( !be_isroot_pw( op ) ) {			rs->sr_err = LDAP_INVALID_CREDENTIALS;			rs->sr_text = NULL;			send_ldap_result( op, rs );			return rs->sr_err;		}		if ( META_BACK_DEFER_ROOTDN_BIND( mi ) ) {			rs->sr_err = LDAP_SUCCESS;			rs->sr_text = NULL;			/* frontend will return success */			return rs->sr_err;		}		isroot = 1;	}	/* we need meta_back_getconn() not send result even on error,	 * because we want to intercept the error and make it	 * invalidCredentials */	mc = meta_back_getconn( op, rs, NULL, LDAP_BACK_BIND_DONTSEND );	if ( !mc ) {		if ( StatslogTest( LDAP_DEBUG_ANY ) ) {			char	buf[ SLAP_TEXT_BUFLEN ];			snprintf( buf, sizeof( buf ),				"meta_back_bind: no target "				"for dn \"%s\" (%d%s%s).",				op->o_req_dn.bv_val, rs->sr_err,				rs->sr_text ? ". " : "",				rs->sr_text ? rs->sr_text : "" );			Debug( LDAP_DEBUG_ANY,				"%s %s\n",				op->o_log_prefix, buf, 0 );		}		/* FIXME: there might be cases where we don't want		 * to map the error onto invalidCredentials */		switch ( rs->sr_err ) {		case LDAP_NO_SUCH_OBJECT:		case LDAP_UNWILLING_TO_PERFORM:			rs->sr_err = LDAP_INVALID_CREDENTIALS;			rs->sr_text = NULL;			break;		}		send_ldap_result( op, rs );		return rs->sr_err;	}	/*	 * Each target is scanned ...	 */	mc->mc_authz_target = META_BOUND_NONE;	for ( i = 0; i < mi->mi_ntargets; i++ ) {		metatarget_t	*mt = mi->mi_targets[ i ];		int		lerr;		/*		 * Skip non-candidates		 */		if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {			continue;		}		if ( gotit == 0 ) {			/* set rc to LDAP_SUCCESS only if at least			 * one candidate has been tried */			rc = LDAP_SUCCESS;			gotit = 1;		} else if ( isroot == 0 ) {			/*			 * A bind operation is expected to have			 * ONE CANDIDATE ONLY!			 */			Debug( LDAP_DEBUG_ANY,				"### %s meta_back_bind: more than one"				" candidate selected...\n",				op->o_log_prefix, 0, 0 );		}		if ( isroot ) {			if ( mt->mt_idassert_authmethod == LDAP_AUTH_NONE				|| BER_BVISNULL( &mt->mt_idassert_authcDN ) )			{				metasingleconn_t	*msc = &mc->mc_conns[ i ];				/* skip the target if no pseudorootdn is provided */				if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {					ch_free( msc->msc_bound_ndn.bv_val );					BER_BVZERO( &msc->msc_bound_ndn );				}				if ( !BER_BVISNULL( &msc->msc_cred ) ) {					/* destroy sensitive data */					memset( msc->msc_cred.bv_val, 0,						msc->msc_cred.bv_len );					ch_free( msc->msc_cred.bv_val );					BER_BVZERO( &msc->msc_cred );				}				continue;			}						(void)meta_back_proxy_authz_bind( mc, i, op, rs, LDAP_BACK_DONTSEND );			lerr = rs->sr_err;		} else {			lerr = meta_back_single_bind( op, rs, mc, i );		}		if ( lerr != LDAP_SUCCESS ) {			rc = rs->sr_err = lerr;			/* FIXME: in some cases (e.g. unavailable)			 * do not assume it's not candidate; rather			 * mark this as an error to be eventually			 * reported to client */			META_CANDIDATE_CLEAR( &candidates[ i ] );			break;		}	}	/* must re-insert if local DN changed as result of bind */	if ( rc == LDAP_SUCCESS ) {		if ( isroot ) {			mc->mc_authz_target = META_BOUND_ALL;			ber_dupbv( &op->orb_edn, be_root_dn( op->o_bd ) );		}		if ( !LDAP_BACK_PCONN_ISPRIV( mc )			&& !dn_match( &op->o_req_ndn, &mc->mc_local_ndn ) )		{			metaconn_t	*tmpmc;			int		lerr;			/* wait for all other ops to release the connection */retry_lock:;			ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );			if ( mc->mc_refcnt > 1 ) {				ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );				ldap_pvt_thread_yield();				goto retry_lock;			}			assert( mc->mc_refcnt == 1 );#if META_BACK_PRINT_CONNTREE > 0			meta_back_print_conntree( mi, ">>> meta_back_bind" );#endif /* META_BACK_PRINT_CONNTREE */			tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc,				meta_back_conndn_cmp );			assert( tmpmc == mc );			/* delete all cached connections with the current connection */			if ( LDAP_BACK_SINGLECONN( mi ) ) {				while ( ( tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conn_cmp ) ) != NULL )				{					Debug( LDAP_DEBUG_TRACE,						"=>meta_back_bind: destroying conn %ld (refcnt=%u)\n",						LDAP_BACK_PCONN_ID( mc ), mc->mc_refcnt, 0 );					if ( tmpmc->mc_refcnt != 0 ) {						/* taint it */						LDAP_BACK_CONN_TAINTED_SET( tmpmc );					} else {						/*						 * Needs a test because the handler may be corrupted,						 * and calling ldap_unbind on a corrupted header results						 * in a segmentation fault						 */						meta_back_conn_free( tmpmc );					}				}			}			ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn );			if ( isroot ) {				LDAP_BACK_CONN_ISPRIV_SET( mc );				LDAP_BACK_PCONN_SET( mc, op );			}			lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc,				meta_back_conndn_cmp, meta_back_conndn_dup );#if META_BACK_PRINT_CONNTREE > 0			meta_back_print_conntree( mi, "<<< meta_back_bind" );#endif /* META_BACK_PRINT_CONNTREE */			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );			if ( lerr == -1 ) {				/* we can do this because mc_refcnt == 1 */				assert( mc->mc_refcnt == 1 );				mc->mc_refcnt = 0;				meta_back_conn_free( mc );				mc = NULL;			}		}	}	if ( mc != NULL ) {		meta_back_release_conn( mi, mc );	}	/*	 * rc is LDAP_SUCCESS if at least one bind succeeded,	 * err is the last error that occurred during a bind;	 * if at least (and at most?) one bind succeeds, fine.	 */	if ( rc != LDAP_SUCCESS ) {				/*		 * deal with bind failure ...		 */		/*		 * no target was found within the naming context, 		 * so bind must fail with invalid credentials		 */		if ( rs->sr_err == LDAP_SUCCESS && gotit == 0 ) {			rs->sr_err = LDAP_INVALID_CREDENTIALS;		} else {			rs->sr_err = slap_map_api2result( rs );		}		send_ldap_result( op, rs );		return rs->sr_err;	}	return LDAP_SUCCESS;}static intmeta_back_bind_op_result(	Operation		*op,	SlapReply		*rs,	metaconn_t		*mc,	int			candidate,	int			msgid,	ldap_back_send_t	sendok ){	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;	metatarget_t		*mt = mi->mi_targets[ candidate ];	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];	LDAPMessage		*res;	struct timeval		tv;	int			rc;	int			nretries = mt->mt_nretries;	char			buf[ SLAP_TEXT_BUFLEN ];	Debug( LDAP_DEBUG_TRACE,		">>> %s meta_back_bind_op_result[%d]\n",		op->o_log_prefix, candidate, 0 );	if ( rs->sr_err == LDAP_SUCCESS ) {		time_t		stoptime = (time_t)(-1),				timeout;		int		timeout_err = op->o_protocol >= LDAP_VERSION3 ?				LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;		const char	*timeout_text = "Operation timed out";		slap_op_t	opidx = slap_req2op( op->o_tag );		/* since timeout is not specified, compute and use		 * the one specific to the ongoing operation */		if ( opidx == LDAP_REQ_SEARCH ) {			if ( op->ors_tlimit <= 0 ) {				timeout = 0;			} else {				timeout = op->ors_tlimit;				timeout_err = LDAP_TIMELIMIT_EXCEEDED;				timeout_text = NULL;			}		} else {			timeout = mt->mt_timeout[ opidx ];		}		/* better than nothing :) */		if ( timeout == 0 ) {			if ( mi->mi_idle_timeout ) {				timeout = mi->mi_idle_timeout;			} else if ( mi->mi_conn_ttl ) {				timeout = mi->mi_conn_ttl;			}		}		if ( timeout ) {			stoptime = op->o_time + timeout;		}		LDAP_BACK_TV_SET( &tv );		/*		 * handle response!!!		 */retry:;		rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );		switch ( rc ) {		case 0:			if ( nretries != META_RETRY_NEVER 				|| ( timeout && slap_get_time() <= stoptime ) )			{				ldap_pvt_thread_yield();				if ( nretries > 0 ) {					nretries--;				}				tv = mt->mt_bind_timeout;				goto retry;			}			/* don't let anyone else use this handler,			 * because there's a pending bind that will not			 * be acknowledged */			ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );			assert( LDAP_BACK_CONN_BINDING( msc ) );#ifdef DEBUG_205			Debug( LDAP_DEBUG_ANY, "### %s meta_back_bind_op_result ldap_unbind_ext[%d] ld=%p\n",				op->o_log_prefix, candidate, (void *)msc->msc_ld );#endif /* DEBUG_205 */			meta_clear_one_candidate( op, mc, candidate );			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );			rs->sr_err = timeout_err;			rs->sr_text = timeout_text;			break;		case -1:			ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE,				&rs->sr_err );			snprintf( buf, sizeof( buf ),				"err=%d (%s) nretries=%d",				rs->sr_err, ldap_err2string( rs->sr_err ), nretries );			Debug( LDAP_DEBUG_ANY,				"### %s meta_back_bind_op_result[%d]: %s.\n",				op->o_log_prefix, candidate, buf );			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;			}			/* FIXME: matched? referrals? response controls? */			rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,					NULL, NULL, NULL, NULL, 1 );			if ( rc != LDAP_SUCCESS ) {				rs->sr_err = rc;			}			break;		}	}	rs->sr_err = slap_map_api2result( rs );	Debug( LDAP_DEBUG_TRACE,		"<<< %s meta_back_bind_op_result[%d] err=%d\n",		op->o_log_prefix, candidate, rs->sr_err );	return rs->sr_err;}/* * meta_back_single_bind * * attempts to perform a bind with creds */static intmeta_back_single_bind(	Operation		*op,	SlapReply		*rs,	metaconn_t		*mc,	int			candidate ){	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;	metatarget_t		*mt = mi->mi_targets[ candidate ];	struct berval		mdn = BER_BVNULL;	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];	int			msgid;	dncookie		dc;		if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {		ch_free( msc->msc_bound_ndn.bv_val );		BER_BVZERO( &msc->msc_bound_ndn );	}	if ( !BER_BVISNULL( &msc->msc_cred ) ) {		/* destroy sensitive data */		memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );		ch_free( msc->msc_cred.bv_val );		BER_BVZERO( &msc->msc_cred );	}	/*	 * Rewrite the bind dn if needed	 */	dc.target = mt;	dc.conn = op->o_conn;	dc.rs = rs;	dc.ctx = "bindDN";

⌨️ 快捷键说明

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