Ejemplo n.º 1
0
/*
 * Call this to do a TLS accept on a sockbuf.
 * Everything else is the same as with tls_connect.
 */
int
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;
}
Ejemplo n.º 2
0
static void
mdbx_debug(int type, const char *function, int line, const char *msg, va_list args)
{
#if LDAP_DEBUG > 1
	int level = LDAP_DEBUG_ANY;
#else
	int level = 0;

	if (type & MDBX_DBG_ASSERT)
		level |= LDAP_DEBUG_ANY;

	if (type & MDBX_DBG_PRINT)
		level |= LDAP_DEBUG_NONE;

	if (type & (MDBX_DBG_TRACE | MDBX_DBG_EXTRA))
		level |= LDAP_DEBUG_TRACE;
#endif /* LDAP_DEBUG */

	if (DebugTest(level))
		ldap_debug_va(msg, args);
}
Ejemplo n.º 3
0
/* protected by res_mutex */
static int
wait4msg(
	LDAP *ld,
	ber_int_t msgid,
	int all,
	struct timeval *timeout,
	LDAPMessage **result )
{
	int		rc;
	struct timeval	tv = { 0 },
			tv0 = { 0 },
			start_time_tv = { 0 },
			*tvp = NULL;
	LDAPConn	*lc;

	assert( ld != NULL );
	assert( result != NULL );

	LDAP_ASSERT_MUTEX_OWNER( &ld->ld_res_mutex );

	if ( timeout == NULL && ld->ld_options.ldo_tm_api.tv_sec >= 0 ) {
		tv = ld->ld_options.ldo_tm_api;
		timeout = &tv;
	}

#ifdef LDAP_DEBUG
	if ( timeout == NULL ) {
		Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p msgid %d (infinite timeout)\n",
			(void *)ld, msgid );
	} else {
		Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p msgid %d (timeout %ld usec)\n",
			(void *)ld, msgid, (long)timeout->tv_sec * 1000000 + timeout->tv_usec );
	}
#endif /* LDAP_DEBUG */

	if ( timeout != NULL && timeout->tv_sec != -1 ) {
		tv0 = *timeout;
		tv = *timeout;
		tvp = &tv;
		ldap_timeval_realtime( &start_time_tv );
	}

	rc = LDAP_MSG_X_KEEP_LOOKING;
	while ( rc == LDAP_MSG_X_KEEP_LOOKING ) {
#ifdef LDAP_DEBUG
		if ( DebugTest(LDAP_DEBUG_TRACE) ) {
			Debug( LDAP_DEBUG_TRACE, "wait4msg continue ld %p msgid %d all %d\n",
				(void *)ld, msgid, all );
			ldap_dump_connection( ld, ld->ld_conns, 1 );
			LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
			ldap_dump_requests_and_responses( ld );
			LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
		}
#endif /* LDAP_DEBUG */

		if ( ( *result = chkResponseList( ld, msgid, all ) ) != NULL ) {
			rc = (*result)->lm_msgtype;

		} else {
			int lc_ready = 0;

			LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
			for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
				if ( ber_sockbuf_ctrl( lc->lconn_sb,
					LBER_SB_OPT_DATA_READY, NULL ) )
				{
					lc_ready = 2;	/* ready at ber level, not socket level */
					break;
				}
			}

			if ( !lc_ready ) {
				int err;
				rc = ldap_int_select( ld, tvp );
				if ( rc == -1 ) {
					err = sock_errno();
#ifdef LDAP_DEBUG
					Debug( LDAP_DEBUG_TRACE,
						"ldap_int_select returned -1: errno %d\n",
						err );
#endif
				}

				if ( rc == 0 || ( rc == -1 && (
					!LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART)
						|| err != EINTR ) ) )
				{
					ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
						LDAP_TIMEOUT);
					LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
					return( rc );
				}

				if ( rc == -1 ) {
					rc = LDAP_MSG_X_KEEP_LOOKING;	/* select interrupted: loop */

				} else {
					lc_ready = 1;
				}
			}
			if ( lc_ready ) {
				LDAPConn *lnext;
				int serviced = 0;
				rc = LDAP_MSG_X_KEEP_LOOKING;
				LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
				if ( ld->ld_requests &&
					ld->ld_requests->lr_status == LDAP_REQST_WRITING &&
					ldap_is_write_ready( ld,
						ld->ld_requests->lr_conn->lconn_sb ) )
				{
					serviced = 1;
					ldap_int_flush_request( ld, ld->ld_requests );
				}
				for ( lc = ld->ld_conns;
					rc == LDAP_MSG_X_KEEP_LOOKING && lc != NULL;
					lc = lnext )
				{
					if ( lc->lconn_status == LDAP_CONNST_CONNECTED &&
						ldap_is_read_ready( ld, lc->lconn_sb ) )
					{
						serviced = 1;
						/* Don't let it get freed out from under us */
						++lc->lconn_refcnt;
						rc = try_read1msg( ld, msgid, all, lc, result );
						lnext = lc->lconn_next;

						/* Only take locks if we're really freeing */
						if ( lc->lconn_refcnt <= 1 ) {
							ldap_free_connection( ld, lc, 0, 1 );
						} else {
							--lc->lconn_refcnt;
						}
					} else {
						lnext = lc->lconn_next;
					}
				}
				LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
				/* Quit looping if no one handled any socket events */
				if (!serviced && lc_ready == 1)
					rc = -1;
			}
			LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
		}

		if ( rc == LDAP_MSG_X_KEEP_LOOKING ) {
			struct timeval	curr_time_tv = { 0 },
					delta_time_tv = { 0 };

			if ( ld->ld_gentle_shutdown && ld->ld_gentle_shutdown( ld ) )
				return LDAP_SERVER_DOWN;
			if ( tvp == NULL )
				continue;

			ldap_timeval_realtime( &curr_time_tv );

			/* delta_time = tmp_time - start_time */
			delta_time_tv.tv_sec = curr_time_tv.tv_sec - start_time_tv.tv_sec;
			delta_time_tv.tv_usec = curr_time_tv.tv_usec - start_time_tv.tv_usec;
			if ( delta_time_tv.tv_usec < 0 ) {
				delta_time_tv.tv_sec--;
				delta_time_tv.tv_usec += 1000000;
			}

			/* tv0 < delta_time ? */
			if ( ( tv0.tv_sec < delta_time_tv.tv_sec ) ||
			     ( ( tv0.tv_sec == delta_time_tv.tv_sec ) && ( tv0.tv_usec < delta_time_tv.tv_usec ) ) )
			{
				rc = 0; /* timed out */
				ld->ld_errno = LDAP_TIMEOUT;
				break;
			}

			/* tv0 -= delta_time */
			tv0.tv_sec -= delta_time_tv.tv_sec;
			tv0.tv_usec -= delta_time_tv.tv_usec;
			if ( tv0.tv_usec < 0 ) {
				tv0.tv_sec--;
				tv0.tv_usec += 1000000;
			}

			tv.tv_sec = tv0.tv_sec;
			tv.tv_usec = tv0.tv_usec;

			Debug( LDAP_DEBUG_TRACE, "wait4msg ld %p %ld s %ld us to go\n",
				(void *)ld, (long) tv.tv_sec, (long) tv.tv_usec );

			start_time_tv.tv_sec = curr_time_tv.tv_sec;
			start_time_tv.tv_usec = curr_time_tv.tv_usec;
		}
	}

	return( rc );
}
Ejemplo n.º 4
0
/*
 * FIXME: error return must be handled in a cleaner way ...
 */
int
meta_back_op_result(
	metaconn_t		*mc,
	Operation		*op,
	SlapReply		*rs,
	int			candidate,
	ber_int_t		msgid,
	time_t			timeout,
	ldap_back_send_t	sendok )
{
	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;

	const char	*save_text = rs->sr_text,
			*save_matched = rs->sr_matched;
	BerVarray	save_ref = rs->sr_ref;
	LDAPControl	**save_ctrls = rs->sr_ctrls;
	void		*matched_ctx = NULL;

	char		*matched = NULL;
	char		*text = NULL;
	char		**refs = NULL;
	LDAPControl	**ctrls = NULL;

	assert( mc != NULL );

	rs->sr_text = NULL;
	rs->sr_matched = NULL;
	rs->sr_ref = NULL;
	rs->sr_ctrls = NULL;

	if ( candidate != META_TARGET_NONE ) {
		metatarget_t		*mt = mi->mi_targets[ candidate ];
		metasingleconn_t	*msc = &mc->mc_conns[ candidate ];

		if ( LDAP_ERR_OK( rs->sr_err ) ) {
			int		rc;
			struct timeval	tv;
			LDAPMessage	*res = NULL;
			time_t		stoptime = (time_t)(-1);
			int		timeout_err = op->o_protocol >= LDAP_VERSION3 ?
						LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
			const char	*timeout_text = "Operation timed out";

			/* if timeout is not specified, compute and use
			 * the one specific to the ongoing operation */
			if ( timeout == (time_t)(-1) ) {
				slap_op_t	opidx = slap_req2op( op->o_tag );

				if ( opidx == SLAP_OP_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 );

retry:;
			rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
			switch ( rc ) {
			case 0:
				if ( timeout && ldap_time_steady() > stoptime ) {
					(void)meta_back_cancel( mc, op, rs, msgid, candidate, sendok );
					rs->sr_err = timeout_err;
					rs->sr_text = timeout_text;
					break;
				}

				LDAP_BACK_TV_SET( &tv );
				ldap_pvt_thread_yield();
				goto retry;

			case -1:
				ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE,
						&rs->sr_err );
				break;


			/* otherwise get the result; if it is not
			 * LDAP_SUCCESS, record it in the reply
			 * structure (this includes
			 * LDAP_COMPARE_{TRUE|FALSE}) */
			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;
				}

				rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
						&matched, &text, &refs, &ctrls, 1 );
				res = NULL;
				if ( rc == LDAP_SUCCESS ) {
					rs->sr_text = text;
				} else {
					rs->sr_err = rc;
				}
				rs->sr_err = slap_map_api2result( rs );

				/* RFC 4511: referrals can only appear
				 * if result code is LDAP_REFERRAL */
				if ( refs != NULL
					&& refs[ 0 ] != NULL
					&& refs[ 0 ][ 0 ] != '\0' )
				{
					if ( rs->sr_err != LDAP_REFERRAL ) {
						Debug( LDAP_DEBUG_ANY,
							"%s meta_back_op_result[%d]: "
							"got referrals with err=%d\n",
							op->o_log_prefix,
							candidate, rs->sr_err );

					} else {
						int	i;

						for ( i = 0; refs[ i ] != NULL; i++ )
							/* count */ ;
						rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ),
							op->o_tmpmemctx );
						for ( i = 0; refs[ i ] != NULL; i++ ) {
							ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] );
						}
						BER_BVZERO( &rs->sr_ref[ i ] );
					}

				} else if ( rs->sr_err == LDAP_REFERRAL ) {
					Debug( LDAP_DEBUG_ANY,
						"%s meta_back_op_result[%d]: "
						"got err=%d with null "
						"or empty referrals\n",
						op->o_log_prefix,
						candidate, rs->sr_err );

					rs->sr_err = LDAP_NO_SUCH_OBJECT;
				}

				if ( ctrls != NULL ) {
					rs->sr_ctrls = ctrls;
				}
			}

			assert( res == NULL );
		}

		/* if the error in the reply structure is not
		 * LDAP_SUCCESS, try to map it from client
		 * to server error */
		if ( !LDAP_ERR_OK( rs->sr_err ) ) {
			rs->sr_err = slap_map_api2result( rs );

			/* internal ops ( op->o_conn == NULL )
			 * must not reply to client */
			if ( op->o_conn && !op->o_do_not_cache && matched ) {

				/* record the (massaged) matched
				 * DN into the reply structure */
				rs->sr_matched = matched;
			}
		}

		if ( META_BACK_TGT_QUARANTINE( mt ) ) {
			meta_back_quarantine( op, rs, candidate );
		}

	} else {
		int	i,
			err = rs->sr_err;

		for ( i = 0; i < mi->mi_ntargets; i++ ) {
			metasingleconn_t	*msc = &mc->mc_conns[ i ];
			char			*xtext = NULL;
			char			*xmatched = NULL;

			if ( msc->msc_ld == NULL ) {
				continue;
			}

			rs->sr_err = LDAP_SUCCESS;

			ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rs->sr_err );
			if ( rs->sr_err != LDAP_SUCCESS ) {
				/*
				 * better check the type of error. In some cases
				 * (search ?) it might be better to return a
				 * success if at least one of the targets gave
				 * positive result ...
				 */
				ldap_get_option( msc->msc_ld,
						LDAP_OPT_DIAGNOSTIC_MESSAGE, &xtext );
				if ( xtext != NULL && xtext [ 0 ] == '\0' ) {
					ldap_memfree( xtext );
					xtext = NULL;
				}

				ldap_get_option( msc->msc_ld,
						LDAP_OPT_MATCHED_DN, &xmatched );
				if ( xmatched != NULL && xmatched[ 0 ] == '\0' ) {
					ldap_memfree( xmatched );
					xmatched = NULL;
				}

				rs->sr_err = slap_map_api2result( rs );

				if ( DebugTest( LDAP_DEBUG_ANY ) ) {
					char	buf[ SLAP_TEXT_BUFLEN ];

					snprintf( buf, sizeof( buf ),
						"meta_back_op_result[%d] "
						"err=%d text=\"%s\" matched=\"%s\"",
						i, rs->sr_err,
						( xtext ? xtext : "" ),
						( xmatched ? xmatched : "" ) );
					Debug( LDAP_DEBUG_ANY, "%s %s.\n",
						op->o_log_prefix, buf );
				}

				/*
				 * FIXME: need to rewrite "match" (need rwinfo)
				 */
				switch ( rs->sr_err ) {
				default:
					err = rs->sr_err;
					if ( xtext != NULL ) {
						if ( text ) {
							ldap_memfree( text );
						}
						text = xtext;
						xtext = NULL;
					}
					if ( xmatched != NULL ) {
						if ( matched ) {
							ldap_memfree( matched );
						}
						matched = xmatched;
						xmatched = NULL;
					}
					break;
				}

				if ( xtext ) {
					ldap_memfree( xtext );
				}

				if ( xmatched ) {
					ldap_memfree( xmatched );
				}
			}

			if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) {
				meta_back_quarantine( op, rs, i );
			}
		}

		if ( err != LDAP_SUCCESS ) {
			rs->sr_err = err;
		}
	}

	if ( matched != NULL ) {
		struct berval	dn, pdn;

		ber_str2bv( matched, 0, 0, &dn );
		if ( dnPretty( NULL, &dn, &pdn, op->o_tmpmemctx ) == LDAP_SUCCESS ) {
			ldap_memfree( matched );
			matched_ctx = op->o_tmpmemctx;
			matched = pdn.bv_val;
		}
		rs->sr_matched = matched;
	}

	if ( rs->sr_err == LDAP_UNAVAILABLE ) {
		if ( !( sendok & LDAP_BACK_RETRYING ) ) {
			if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
				if ( rs->sr_text == NULL ) rs->sr_text = "Proxy operation retry failed";
				send_ldap_result( op, rs );
			}
		}

	} else if ( op->o_conn &&
		( ( ( sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) )
			|| ( ( sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) )
	{
		send_ldap_result( op, rs );
	}
	if ( matched ) {
		op->o_tmpfree( (char *)rs->sr_matched, matched_ctx );
	}
	if ( text ) {
		ldap_memfree( text );
	}
	if ( rs->sr_ref ) {
		op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
		rs->sr_ref = NULL;
	}
	if ( refs ) {
		ber_memvfree( (void **)refs );
	}
	if ( ctrls ) {
		assert( rs->sr_ctrls != NULL );
		ldap_controls_free( ctrls );
	}

	rs->sr_text = save_text;
	rs->sr_matched = save_matched;
	rs->sr_ref = save_ref;
	rs->sr_ctrls = save_ctrls;

	return( LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err );
}
Ejemplo n.º 5
0
/*
 * 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 ( DebugTest( 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 ( DebugTest( 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 );
}
Ejemplo n.º 6
0
int
meta_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;

	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 );

	/* the test on the bind method should be superfluous */
	switch ( be_rootdn_bind( op, rs ) ) {
	case LDAP_SUCCESS:
		if ( META_BACK_DEFER_ROOTDN_BIND( mi ) ) {
			/* frontend will return success */
			return rs->sr_err;
		}

		isroot = 1;
		/* fallthru */

	case SLAP_CB_CONTINUE:
		break;

	default:
		/* be_rootdn_bind() sent result */
		return rs->sr_err;
	}

	/* 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 ( DebugTest( 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 );
		}

		/* 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;
	}

	candidates = meta_back_candidates_get( op );

	/*
	 * 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 ) {
			/*
			 * 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 );
		}

		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, 1 );
			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;
		}

		if ( !LDAP_BACK_PCONN_ISPRIV( mc )
			&& !dn_match( &op->o_req_ndn, &mc->mc_local_ndn ) )
		{
			int		lerr;

			/* wait for all other ops to release the connection */
			ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
			assert( mc->mc_refcnt == 1 );
#if META_BACK_PRINT_CONNTREE > 0
			meta_back_print_conntree( mi, ">>> meta_back_bind" );
#endif /* META_BACK_PRINT_CONNTREE */

			/* delete all cached connections with the current connection */
			if ( LDAP_BACK_SINGLECONN( mi ) ) {
				metaconn_t	*tmpmc;

				while ( ( tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conn_cmp ) ) != NULL )
				{
					assert( !LDAP_BACK_PCONN_ISPRIV( mc ) );
					Debug( LDAP_DEBUG_TRACE,
						"=>meta_back_bind: destroying conn %lu (refcnt=%u)\n",
						mc->mc_conn->c_connid, mc->mc_refcnt );

					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 );
			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 */
			if ( lerr == 0 ) {
#if 0
				/* NOTE: a connection cannot be privileged
				 * and be in the avl tree at the same time
				 */
				if ( isroot ) {
					LDAP_BACK_CONN_ISPRIV_SET( mc );
					LDAP_BACK_PCONN_SET( mc, op );
				}
#endif
				LDAP_BACK_CONN_CACHED_SET( mc );

			} else {
				LDAP_BACK_CONN_CACHED_CLEAR( mc );
			}
			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
		}
	}

	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;
}