Esempio n. 1
0
Operation *
slap_op_alloc(
    BerElement		*ber,
    ber_int_t	msgid,
    ber_tag_t	tag,
    ber_int_t	id
)
{
	Operation	*op;

	ldap_pvt_thread_mutex_lock( &slap_op_mutex );
	if (op = LDAP_STAILQ_FIRST( &slap_free_ops )) {
		LDAP_STAILQ_REMOVE_HEAD( &slap_free_ops, o_next );
	}
	ldap_pvt_thread_mutex_unlock( &slap_op_mutex );

	if (!op)
		op = (Operation *) ch_calloc( 1, sizeof(Operation) );

	op->o_ber = ber;
	op->o_msgid = msgid;
	op->o_tag = tag;

	op->o_time = slap_get_time();
	op->o_opid = id;
#ifdef LDAP_CONNECTIONLESS
	op->o_res_ber = NULL;
#endif

#if defined( LDAP_SLAPI )
	op->o_pb = slapi_pblock_new();
#endif /* defined( LDAP_SLAPI ) */

	return( op );
}
Esempio n. 2
0
void slap_op_destroy(void)
{
	Operation *o;

	while ( (o = LDAP_STAILQ_FIRST( &slap_free_ops )) != NULL) {
		LDAP_STAILQ_REMOVE_HEAD( &slap_free_ops, o_next );
		LDAP_STAILQ_NEXT(o, o_next) = NULL;
		ch_free( o );
	}
	ldap_pvt_thread_mutex_destroy( &slap_op_mutex );
}
Esempio n. 3
0
meta_search_candidate_t
asyncmeta_send_all_pending_ops(a_metaconn_t *mc, int candidate, void *ctx, int dolock)
{
	a_metainfo_t	*mi = mc->mc_info;
	bm_context_t *bc, *onext;
	a_metasingleconn_t *msc = &mc->mc_conns[candidate];

	if ( dolock )
		ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );

	msc->msc_active++;
	for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) {
		meta_search_candidate_t ret;
		onext = LDAP_STAILQ_NEXT(bc, bc_next);
		if (bc->candidates[candidate].sr_msgid != META_MSGID_NEED_BIND || bc->bc_active > 0 || bc->op->o_abandon > 0) {
			continue;
		}
		bc->op->o_threadctx = ctx;
		bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
		slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);
		bc->bc_active++;
		ret = asyncmeta_send_pending_op(bc, candidate);
		if (ret != META_SEARCH_CANDIDATE) {
			bc->candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
			bc->candidates[ candidate ].sr_type = REP_RESULT;
			bc->candidates[ candidate ].sr_err = bc->rs.sr_err;
			if (bc->op->o_tag != LDAP_REQ_SEARCH || (META_BACK_ONERR_STOP( mi )) ||
			    (asyncmeta_is_last_result(mc, bc, candidate) == 0)) {
				LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
				mc->pending_ops--;
				asyncmeta_send_ldap_result(bc, bc->op, &bc->rs);
				asyncmeta_clear_bm_context(bc);
			}
		} else {
			bc->bc_active--;
		}
	}
	msc->msc_active--;

	if ( dolock )
		ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );

	return META_SEARCH_CANDIDATE;
}
Esempio n. 4
0
void* asyncmeta_timeout_loop(void *ctx, void *arg)
{
	struct re_s* rtask = arg;
	a_metainfo_t *mi = rtask->arg;
	bm_context_t *bc, *onext;
	time_t current_time = slap_get_time();
	int i, j;
	LDAP_STAILQ_HEAD(BCList, bm_context_t) timeout_list;
	LDAP_STAILQ_INIT( &timeout_list );

	Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] start at [%ld] \n", rtask, current_time );
	void *oldctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 0);
	for (i=0; i<mi->mi_num_conns; i++) {
		a_metaconn_t * mc= &mi->mi_conns[i];
		ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
		for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) {
			onext = LDAP_STAILQ_NEXT(bc, bc_next);
			if (bc->bc_active > 0) {
				continue;
			}

			if (bc->op->o_abandon ) {
					/* set our memctx */
				bc->op->o_threadctx = ctx;
				bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
				slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);
				Operation *op = bc->op;

				LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
				mc->pending_ops--;
				for (j=0; j<mi->mi_ntargets; j++) {
					if (bc->candidates[j].sr_msgid >= 0) {
						a_metasingleconn_t *msc = &mc->mc_conns[j];
						if ( op->o_tag == LDAP_REQ_SEARCH ) {
							msc->msc_active++;
							asyncmeta_back_cancel( mc, op,
									       bc->candidates[ j ].sr_msgid, j );
							msc->msc_active--;
						}
					}
				}
				asyncmeta_clear_bm_context(bc);
				continue;
			}
			if (bc->bc_invalid) {
				LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
				mc->pending_ops--;
				LDAP_STAILQ_INSERT_TAIL( &timeout_list, bc, bc_next);
				continue;
			}

			if (bc->timeout && bc->stoptime < current_time) {
				Operation *op = bc->op;
				LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
				mc->pending_ops--;
				LDAP_STAILQ_INSERT_TAIL( &timeout_list, bc, bc_next);
				for (j=0; j<mi->mi_ntargets; j++) {
					if (bc->candidates[j].sr_msgid >= 0) {
						a_metasingleconn_t *msc = &mc->mc_conns[j];
						asyncmeta_set_msc_time(msc);
						if ( op->o_tag == LDAP_REQ_SEARCH ) {
							msc->msc_active++;
							asyncmeta_back_cancel( mc, op,
									       bc->candidates[ j ].sr_msgid, j );
							msc->msc_active--;
						}
					}
				}
			}
		}
		ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );

		for (bc = LDAP_STAILQ_FIRST(&timeout_list); bc; bc = onext) {
			Operation *op = bc->op;
			SlapReply *rs = &bc->rs;
			int		timeout_err;
			const char *timeout_text;

			onext = LDAP_STAILQ_NEXT(bc, bc_next);
			LDAP_STAILQ_REMOVE(&timeout_list, bc, bm_context_t, bc_next);
			/* set our memctx */
			bc->op->o_threadctx = ctx;
			bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
			slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);

			if (bc->searchtime) {
				timeout_err = LDAP_TIMELIMIT_EXCEEDED;
			} else {
				timeout_err = op->o_protocol >= LDAP_VERSION3 ?
					LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
			}

			if ( bc->bc_invalid ) {
				timeout_text = "Operation is invalid - target connection has been reset";
			} else {
				a_metasingleconn_t *log_msc =  &mc->mc_conns[0];
				Debug( asyncmeta_debug,
				       "asyncmeta_timeout_loop:Timeout op %s loop[%p], "
				       "current_time:%ld, op->o_time:%ld msc: %p, "
				       "msc->msc_binding_time: %x, msc->msc_flags:%x \n",
				       bc->op->o_log_prefix, rtask, current_time, bc->op->o_time,
				       log_msc, (unsigned int)log_msc->msc_binding_time, log_msc->msc_mscflags );

				if (bc->searchtime) {
					timeout_text = NULL;
				} else {
					timeout_text = "Operation timed out";
				}

				for (j=0; j<mi->mi_ntargets; j++) {
					if (bc->candidates[j].sr_msgid >= 0) {
						a_metatarget_t     *mt = mi->mi_targets[j];
						if (!META_BACK_TGT_QUARANTINE( mt ) ||
						    bc->candidates[j].sr_type == REP_RESULT) {
							continue;
						}

						if (mt->mt_isquarantined > LDAP_BACK_FQ_NO) {
							timeout_err = LDAP_UNAVAILABLE;
						} else {
							mt->mt_timeout_ops++;
							if ((mi->mi_max_timeout_ops > 0) &&
							    (mt->mt_timeout_ops > mi->mi_max_timeout_ops)) {
								timeout_err = LDAP_UNAVAILABLE;
								rs->sr_err = timeout_err;
								if (mt->mt_isquarantined == LDAP_BACK_FQ_NO)
									asyncmeta_quarantine(op, mi, rs, j);
							}
						}
					}
				}
			}
			rs->sr_err = timeout_err;
			rs->sr_text = timeout_text;
			if (!bc->op->o_abandon ) {
				asyncmeta_send_ldap_result( bc, bc->op, &bc->rs );
			}
			asyncmeta_clear_bm_context(bc);
		}

		ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
		if (mi->mi_idle_timeout) {
			for (j=0; j<mi->mi_ntargets; j++) {
				a_metasingleconn_t *msc = &mc->mc_conns[j];
				if ( msc->msc_active > 0 ) {
					continue;
				}
				if (mc->pending_ops > 0) {
					continue;
				}
				current_time = slap_get_time();
				if (msc->msc_ld && msc->msc_time > 0 && msc->msc_time + mi->mi_idle_timeout < current_time) {
					asyncmeta_clear_one_msc(NULL, mc, j, 1, __FUNCTION__);
				}
			}
		}
		ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
	}

	slap_sl_mem_setctx(ctx, oldctx);
	current_time = slap_get_time();
	Debug( asyncmeta_debug, "asyncmeta_timeout_loop[%p] stop at [%ld] \n", rtask, current_time );
	ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
	if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask )) {
		ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
	}
	rtask->interval.tv_sec = 1;
	rtask->interval.tv_usec = 0;
	ldap_pvt_runqueue_resched(&slapd_rq, rtask, 0);
	ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
	return NULL;
}
Esempio n. 5
0
/* This takes care to clean out the outbound queue in case we have a read error
 * sending back responses to the client */
int
asyncmeta_op_read_error(a_metaconn_t *mc, int candidate, int error, void* ctx)
{
	bm_context_t *bc, *onext;
	int cleanup;
	Operation *op;
	SlapReply *rs;
	SlapReply *candidates;
	/* no outstanding ops, nothing to do but log */
	Debug( LDAP_DEBUG_TRACE,
	       "asyncmeta_op_read_error: ldr=%p\n",
	       mc->mc_conns[candidate].msc_ldr );

	ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
	/*someone may be trying to write */
	if (mc->mc_conns[candidate].msc_active <= 1) {
		asyncmeta_clear_one_msc(NULL, mc, candidate, 0, __FUNCTION__);
	} else {
		META_BACK_CONN_INVALID_SET(&mc->mc_conns[candidate]);
	}

	if (mc->pending_ops <= 0) {
		ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
		return LDAP_SUCCESS;
	}

	for (bc = LDAP_STAILQ_FIRST(&mc->mc_om_list); bc; bc = onext) {
		onext = LDAP_STAILQ_NEXT(bc, bc_next);
		cleanup = 0;
		candidates = bc->candidates;
		/* was this op affected? */
		if ( !META_IS_CANDIDATE( &candidates[ candidate ] ) )
			continue;

		if (bc->op->o_abandon) {
			bc->bc_invalid = 1;
			continue;
		}

		if (bc->bc_active > 0) {
			continue;
		}

		bc->op->o_threadctx = ctx;
		bc->op->o_tid = ldap_pvt_thread_pool_tid( ctx );
		slap_sl_mem_setctx(ctx, bc->op->o_tmpmemctx);

		op = bc->op;
		rs = &bc->rs;
		switch (op->o_tag) {
		case LDAP_REQ_ADD:
		case LDAP_REQ_MODIFY:
		case LDAP_REQ_MODRDN:
		case LDAP_REQ_COMPARE:
		case LDAP_REQ_DELETE:
			rs->sr_err = LDAP_UNAVAILABLE;
			rs->sr_text = "Read error on connection to target";
			asyncmeta_send_ldap_result( bc, op, rs );
			cleanup = 1;
			break;
		case LDAP_REQ_SEARCH:
		{
			a_metainfo_t *mi = mc->mc_info;
			rs->sr_err = LDAP_UNAVAILABLE;
			rs->sr_text = "Read error on connection to target";
			candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
			candidates[ candidate ].sr_type = REP_RESULT;
			if ( (META_BACK_ONERR_STOP( mi ) ||
			      asyncmeta_is_last_result(mc, bc, candidate)) && op->o_conn) {
				asyncmeta_send_ldap_result( bc, op, rs );
				cleanup = 1;
			}
		}
			break;
		default:
			break;
		}

		if (cleanup) {
			int j;
			a_metainfo_t *mi = mc->mc_info;
			for (j=0; j<mi->mi_ntargets; j++) {
				if (j != candidate && bc->candidates[j].sr_msgid >= 0
				    && mc->mc_conns[j].msc_ld != NULL) {
					asyncmeta_back_cancel( mc, op,
							       bc->candidates[ j ].sr_msgid, j );
				}
			}
			LDAP_STAILQ_REMOVE(&mc->mc_om_list, bc, bm_context_t, bc_next);
			mc->pending_ops--;
			asyncmeta_clear_bm_context(bc);
		}
	}
	ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
	return LDAP_SUCCESS;
}
Esempio n. 6
0
int
starttls_extop ( Operation *op, SlapReply *rs )
{
	int rc;

	Statslog( LDAP_DEBUG_STATS, "%s STARTTLS\n",
	    op->o_log_prefix, 0, 0, 0, 0 );

	if ( op->ore_reqdata != NULL ) {
		/* no request data should be provided */
		rs->sr_text = "no request data expected";
		return LDAP_PROTOCOL_ERROR;
	}

	/* acquire connection lock */
	ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );

	/* can't start TLS if it is already started */
	if (op->o_conn->c_is_tls != 0) {
		rs->sr_text = "TLS already started";
		rc = LDAP_OPERATIONS_ERROR;
		goto done;
	}

	/* can't start TLS if there are other op's around */
	if (( !LDAP_STAILQ_EMPTY(&op->o_conn->c_ops) &&
			(LDAP_STAILQ_FIRST(&op->o_conn->c_ops) != op ||
			LDAP_STAILQ_NEXT(op, o_next) != NULL)) ||
		( !LDAP_STAILQ_EMPTY(&op->o_conn->c_pending_ops) ))
	{
		rs->sr_text = "cannot start TLS when operations are outstanding";
		rc = LDAP_OPERATIONS_ERROR;
		goto done;
	}

	if ( !( global_disallows & SLAP_DISALLOW_TLS_2_ANON ) &&
		( op->o_conn->c_dn.bv_len != 0 ) )
	{
		Statslog( LDAP_DEBUG_STATS,
			"%s AUTHZ anonymous mech=starttls ssf=0\n",
			op->o_log_prefix, 0, 0, 0, 0 );

		/* force to anonymous */
		connection2anonymous( op->o_conn );
	}

	if ( ( global_disallows & SLAP_DISALLOW_TLS_AUTHC ) &&
		( op->o_conn->c_dn.bv_len != 0 ) )
	{
		rs->sr_text = "cannot start TLS after authentication";
		rc = LDAP_OPERATIONS_ERROR;
		goto done;
	}

	/* fail if TLS could not be initialized */
	if ( slap_tls_ctx == NULL ) {
		if (default_referral != NULL) {
			/* caller will put the referral in the result */
			rc = LDAP_REFERRAL;
			goto done;
		}

		rs->sr_text = "Could not initialize TLS";
		rc = LDAP_UNAVAILABLE;
		goto done;
	}

    op->o_conn->c_is_tls = 1;
    op->o_conn->c_needs_tls_accept = 1;

    rc = LDAP_SUCCESS;

done:
	/* give up connection lock */
	ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );

	/* FIXME: RACE CONDITION! we give up lock before sending result
	 * Should be resolved by reworking connection state, not
	 * by moving send here (so as to ensure proper TLS sequencing)
	 */

	return rc;
}