コード例 #1
0
ファイル: bind.c プロジェクト: Smilefant/ReOpenLDAP
static int
meta_back_bind_op_result(
	Operation		*op,
	SlapReply		*rs,
	metaconn_t		*mc,
	int			candidate,
	int			msgid,
	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 ];
	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 );

	/* make sure this is clean */
	assert( rs->sr_ctrls == NULL );

	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 == (slap_op_t) 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 */
			if ( dolock) {
				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 );
			if ( dolock ) {
				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_ERROR_NUMBER,
				&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;
			}
			rs->sr_err = slap_map_api2result( rs );
			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;
}
コード例 #2
0
ファイル: bind.c プロジェクト: Smilefant/ReOpenLDAP
/*
 * meta_back_dobind
 */
int
meta_back_dobind(
	Operation		*op,
	SlapReply		*rs,
	metaconn_t		*mc,
	ldap_back_send_t	sendok )
{
	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;

	int			bound = 0,
				i,
				isroot = 0;

	SlapReply		*candidates;

	if ( be_isroot( op ) ) {
		isroot = 1;
	}

	if ( LogTest( LDAP_DEBUG_TRACE ) ) {
		char buf[STRLENOF("4294967295U") + 1] = { 0 };
		mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) );

		Debug( LDAP_DEBUG_TRACE,
			"%s meta_back_dobind: conn=%s%s\n",
			op->o_log_prefix, buf,
			isroot ? " (isroot)" : "" );
	}

	/*
	 * all the targets are bound as pseudoroot
	 */
	if ( mc->mc_authz_target == META_BOUND_ALL ) {
		bound = 1;
		goto done;
	}

	candidates = meta_back_candidates_get( op );

	for ( i = 0; i < mi->mi_ntargets; i++ ) {
		metatarget_t		*mt = mi->mi_targets[ i ];
		metasingleconn_t	*msc = &mc->mc_conns[ i ];
		int			rc;

		/*
		 * Not a candidate
		 */
		if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
			continue;
		}

		assert( msc->msc_ld != NULL );

		/*
		 * If the target is already bound it is skipped
		 */

retry_binding:;
		ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
		if ( LDAP_BACK_CONN_ISBOUND( msc )
			|| ( LDAP_BACK_CONN_ISANON( msc )
				&& mt->mt_idassert_authmethod == LDAP_AUTH_NONE ) )
		{
			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
			++bound;
			continue;

		} else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) )
		{
			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
			ldap_pvt_thread_yield();
			goto retry_binding;

		}

		LDAP_BACK_CONN_BINDING_SET( msc );
		ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );

		rc = meta_back_single_dobind( op, rs, &mc, i,
			LDAP_BACK_DONTSEND, mt->mt_nretries, 1 );
		/*
		 * NOTE: meta_back_single_dobind() already retries;
		 * in case of failure, it resets mc...
		 */
		if ( rc != LDAP_SUCCESS ) {
			char		buf[ SLAP_TEXT_BUFLEN ];

			if ( mc == NULL ) {
				/* meta_back_single_dobind() already sent
				 * response and released connection */
				goto send_err;
			}


			if ( rc == LDAP_UNAVAILABLE ) {
				/* FIXME: meta_back_retry() already re-calls
				 * meta_back_single_dobind() */
				if ( meta_back_retry( op, rs, &mc, i, sendok ) ) {
					goto retry_ok;
				}

				if ( mc != NULL ) {
					ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
					LDAP_BACK_CONN_BINDING_CLEAR( msc );
					meta_back_release_conn_lock( mi, mc, 0 );
					ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
				}

				return 0;
			}

			ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
			LDAP_BACK_CONN_BINDING_CLEAR( msc );
			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );

			snprintf( buf, sizeof( buf ),
				"meta_back_dobind[%d]: (%s) err=%d (%s).",
				i, isroot ? op->o_bd->be_rootdn.bv_val : "anonymous",
				rc, ldap_err2string( rc ) );
			Debug( LDAP_DEBUG_ANY,
				"%s %s\n",
				op->o_log_prefix, buf );

			/*
			 * null cred bind should always succeed
			 * as anonymous, so a failure means
			 * the target is no longer candidate possibly
			 * due to technical reasons (remote host down?)
			 * so better clear the handle
			 */
			/* leave the target candidate, but record the error for later use */
			candidates[ i ].sr_err = rc;
			if ( META_BACK_ONERR_STOP( mi ) ) {
				bound = 0;
				goto done;
			}

			continue;
		} /* else */

retry_ok:;
		Debug( LDAP_DEBUG_TRACE,
			"%s meta_back_dobind[%d]: "
			"(%s)\n",
			op->o_log_prefix, i,
			isroot ? op->o_bd->be_rootdn.bv_val : "anonymous" );

		ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
		LDAP_BACK_CONN_BINDING_CLEAR( msc );
		if ( isroot ) {
			LDAP_BACK_CONN_ISBOUND_SET( msc );
		} else {
			LDAP_BACK_CONN_ISANON_SET( msc );
		}
		ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
		++bound;
	}

done:;
	if ( LogTest( LDAP_DEBUG_TRACE ) ) {
		char buf[STRLENOF("4294967295U") + 1] = { 0 };
		mi->mi_ldap_extra->connid2str( &mc->mc_base, buf, sizeof(buf) );

		Debug( LDAP_DEBUG_TRACE,
			"%s meta_back_dobind: conn=%s bound=%d\n",
			op->o_log_prefix, buf, bound );
	}

	if ( bound == 0 ) {
		meta_back_release_conn( mi, mc );

send_err:;
		if ( sendok & LDAP_BACK_SENDERR ) {
			if ( rs->sr_err == LDAP_SUCCESS ) {
				rs->sr_err = LDAP_BUSY;
			}
			send_ldap_result( op, rs );
		}

		return 0;
	}

	return ( bound > 0 );
}
コード例 #3
0
ファイル: bind.c プロジェクト: cptaffe/openldap
/*
 * asyncmeta_dobind_init()
 *
 * initiates bind for a candidate target
 */
meta_search_candidate_t
asyncmeta_dobind_init(Operation *op, SlapReply *rs, bm_context_t *bc, a_metaconn_t *mc, int candidate)
{
	SlapReply		*candidates = bc->candidates;
	a_metainfo_t		*mi = ( a_metainfo_t * )mc->mc_info;
	a_metatarget_t		*mt = mi->mi_targets[ candidate ];
	a_metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
	ber_socket_t s;
	struct berval		binddn = msc->msc_bound_ndn,
				cred = msc->msc_cred;
	int			method;

	int			rc;
	ber_int_t	msgid;

	meta_search_candidate_t	retcode;

	Debug( LDAP_DEBUG_TRACE, "%s >>> asyncmeta_search_dobind_init[%d]\n",
		op->o_log_prefix, candidate, 0 );

	if ( mc->mc_authz_target == META_BOUND_ALL ) {
		return META_SEARCH_CANDIDATE;
	}

	retcode = META_SEARCH_BINDING;
	if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
		/* already bound (or anonymous) */

#ifdef DEBUG_205
		char	buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
		int	bound = 0;

		if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
			bound = 1;
		}

		snprintf( buf, sizeof( buf ), " mc=%p ld=%p%s DN=\"%s\"",
			(void *)mc, (void *)msc->msc_ld,
			bound ? " bound" : " anonymous",
			bound == 0 ? "" : msc->msc_bound_ndn.bv_val );
		Debug( LDAP_DEBUG_ANY, "### %s asyncmeta_search_dobind_init[%d]%s\n",
			op->o_log_prefix, candidate, buf );
#endif /* DEBUG_205 */

		retcode = META_SEARCH_CANDIDATE;

	} else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) ) {
		/* another thread is binding the target for this conn; wait */

#ifdef DEBUG_205
		char	buf[ SLAP_TEXT_BUFLEN ] = { '\0' };

		snprintf( buf, sizeof( buf ), " mc=%p ld=%p needbind",
			(void *)mc, (void *)msc->msc_ld );
		Debug( LDAP_DEBUG_ANY, "### %s asyncmeta_search_dobind_init[%d]%s\n",
			op->o_log_prefix, candidate, buf );
#endif /* DEBUG_205 */

		candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND;
		retcode = META_SEARCH_NEED_BIND;

	} else {
		/* we'll need to bind the target for this conn */

#ifdef DEBUG_205
		char buf[ SLAP_TEXT_BUFLEN ];

		snprintf( buf, sizeof( buf ), " mc=%p ld=%p binding",
			(void *)mc, (void *)msc->msc_ld );
		Debug( LDAP_DEBUG_ANY, "### %s asyncmeta_search_dobind_init[%d]%s\n",
			op->o_log_prefix, candidate, buf );
#endif /* DEBUG_205 */

		if ( msc->msc_ld == NULL ) {
			/* for some reason (e.g. because formerly in "binding"
			 * state, with eventual connection expiration or invalidation)
			 * it was not initialized as expected */

			Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_dobind_init[%d] mc=%p ld=NULL\n",
				op->o_log_prefix, candidate, (void *)mc );

			rc = asyncmeta_init_one_conn( op, rs, mc, candidate,
				LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 );
			switch ( rc ) {
			case LDAP_SUCCESS:
				assert( msc->msc_ld != NULL );
				break;

			case LDAP_SERVER_DOWN:
			case LDAP_UNAVAILABLE:
				goto down;

			default:
				goto other;
			}
		}

		LDAP_BACK_CONN_BINDING_SET( msc );
	}

	if ( retcode != META_SEARCH_BINDING ) {
		return retcode;
	}

	if ( op->o_conn != NULL &&
		!op->o_do_not_cache &&
		( BER_BVISNULL( &msc->msc_bound_ndn ) ||
			BER_BVISEMPTY( &msc->msc_bound_ndn ) ||
			( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
	{
		rc = asyncmeta_back_proxy_authz_cred( mc, candidate, op, rs, LDAP_BACK_DONTSEND, &binddn, &cred, &method );
		switch ( rc ) {
		case LDAP_SUCCESS:
			break;
		case LDAP_UNAVAILABLE:
			goto down;
		default:
			goto other;
		}

		/* NOTE: we copy things here, even if bind didn't succeed yet,
		 * because the connection is not shared until bind is over */
		if ( !BER_BVISNULL( &binddn ) ) {
			ldap_pvt_thread_mutex_lock(&mc->mc_om_mutex);

			ber_bvreplace( &msc->msc_bound_ndn, &binddn );
			if ( META_BACK_TGT_SAVECRED( mt ) && !BER_BVISNULL( &cred ) ) {
				if ( !BER_BVISNULL( &msc->msc_cred ) ) {
					memset( msc->msc_cred.bv_val, 0,
						msc->msc_cred.bv_len );
				}
				ber_bvreplace( &msc->msc_cred, &cred );
			}
			ldap_pvt_thread_mutex_unlock(&mc->mc_om_mutex);
		}
		if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
			/* apparently, idassert was configured with SASL bind,
			 * so bind occurred inside meta_back_proxy_authz_cred() */
			LDAP_BACK_CONN_BINDING_CLEAR( msc );
			return META_SEARCH_CANDIDATE;
		}

		/* paranoid */
		switch ( method ) {
		case LDAP_AUTH_NONE:
		case LDAP_AUTH_SIMPLE:
			/* do a simple bind with binddn, cred */
			break;

		default:
			assert( 0 );
			break;
		}
	}

	assert( msc->msc_ld != NULL );

	if ( !BER_BVISEMPTY( &binddn ) && BER_BVISEMPTY( &cred ) ) {
		/* bind anonymously? */
		Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_dobind_init[%d] mc=%p: "
			"non-empty dn with empty cred; binding anonymously\n",
			op->o_log_prefix, candidate, (void *)mc );
		cred = slap_empty_bv;

	} else if ( BER_BVISEMPTY( &binddn ) && !BER_BVISEMPTY( &cred ) ) {
		/* error */
		Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_dobind_init[%d] mc=%p: "
			"empty dn with non-empty cred: error\n",
			op->o_log_prefix, candidate, (void *)mc );
		rc = LDAP_OTHER;
		goto other;
	}
retry_bind:
	rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred,
			NULL, NULL, &msgid );
	ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rc );

	if (rc == LDAP_SERVER_DOWN ) {
		goto down;
	}
	candidates[ candidate ].sr_msgid = msgid;
	asyncmeta_set_msc_time(msc);
#ifdef DEBUG_205
	{
		char buf[ SLAP_TEXT_BUFLEN ];

		snprintf( buf, sizeof( buf ), "asyncmeta_search_dobind_init[%d] mc=%p ld=%p rc=%d",
			candidate, (void *)mc, (void *)mc->mc_conns[ candidate ].msc_ld, rc );
		Debug( LDAP_DEBUG_ANY, "### %s %s\n",
			op->o_log_prefix, buf, 0 );
	}
#endif /* DEBUG_205 */

	switch ( rc ) {
	case LDAP_SUCCESS:
		assert( msgid >= 0 );
		META_BINDING_SET( &candidates[ candidate ] );
		rs->sr_err = LDAP_SUCCESS;
		return META_SEARCH_BINDING;

	case LDAP_X_CONNECTING:
		/* must retry, same conn */
		candidates[ candidate ].sr_msgid = META_MSGID_CONNECTING;
		LDAP_BACK_CONN_BINDING_CLEAR( msc );
		goto retry_bind;

	case LDAP_SERVER_DOWN:
down:;
		retcode = META_SEARCH_ERR;
		rs->sr_err = LDAP_UNAVAILABLE;
		candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
		break;

		/* fall thru */

	default:
other:;
		rs->sr_err = rc;
		rc = slap_map_api2result( rs );
		candidates[ candidate ].sr_err = rc;
		if ( META_BACK_ONERR_STOP( mi ) ) {
			retcode = META_SEARCH_ERR;

		} else {
			retcode = META_SEARCH_NOT_CANDIDATE;
		}
		candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
		break;
	}

	return retcode;
}