示例#1
0
文件: bind.c 项目: LiptonB/freeipa
static void on_bind_readable(verto_ctx *vctx, verto_ev *ev)
{
    const char *errstr = "error";
    LDAPMessage *results;
    struct otpd_queue_item *item = NULL;
    int i, rslt;
    (void)vctx;

    rslt = ldap_result(verto_get_private(ev), LDAP_RES_ANY, 0, NULL, &results);
    if (rslt != LDAP_RES_BIND) {
        if (rslt <= 0)
            results = NULL;
        ldap_msgfree(results);
        otpd_log_err(EIO, "IO error received on bind socket");
        verto_break(ctx.vctx);
        ctx.exitstatus = 1;
        return;
    }

    item = otpd_queue_pop_msgid(&ctx.bind.responses, ldap_msgid(results));
    if (item == NULL) {
        ldap_msgfree(results);
        return;
    }
    item->msgid = -1;

    rslt = ldap_parse_result(verto_get_private(ev), results, &i,
                             NULL, NULL, NULL, NULL, 0);
    if (rslt != LDAP_SUCCESS) {
        errstr = ldap_err2string(rslt);
        goto error;
    }

    rslt = i;
    if (rslt != LDAP_SUCCESS) {
        errstr = ldap_err2string(rslt);
        goto error;
    }

    item->sent = 0;
    i = krad_packet_new_response(ctx.kctx, SECRET,
                                 krad_code_name2num("Access-Accept"),
                                 NULL, item->req, &item->rsp);
    if (i != 0) {
        errstr = krb5_get_error_message(ctx.kctx, i);
        goto error;
    }

error:
    if (item != NULL)
        otpd_log_req(item->req, "bind end: %s",
                item->rsp != NULL ? "success" : errstr);

    ldap_msgfree(results);
    otpd_queue_push(&ctx.stdio.responses, item);
    verto_set_flags(ctx.stdio.writer, VERTO_EV_FLAG_PERSIST |
                                      VERTO_EV_FLAG_IO_ERROR |
                                      VERTO_EV_FLAG_IO_READ |
                                      VERTO_EV_FLAG_IO_WRITE);
}
示例#2
0
int
asyncmeta_handle_search_msg(LDAPMessage *res, a_metaconn_t *mc, bm_context_t *bc, int candidate)
{
	a_metainfo_t	*mi;
	a_metatarget_t	*mt;
	a_metasingleconn_t *msc;
	Operation *op = bc->op;
	SlapReply *rs;
	int	   i, rc = LDAP_SUCCESS, sres;
	SlapReply *candidates;
	char		**references = NULL;
	LDAPControl	**ctrls = NULL;
	a_dncookie dc;
	LDAPMessage *msg;
	ber_int_t id;

	rs = &bc->rs;
	mi = mc->mc_info;
	mt = mi->mi_targets[ candidate ];
	msc = &mc->mc_conns[ candidate ];
	dc.op = op;
	dc.target = mt;
	dc.to_from = MASSAGE_REP;
	id = ldap_msgid(res);


	candidates = bc->candidates;
	i = candidate;

	while (res && !META_BACK_CONN_INVALID(msc)) {
	for (msg = ldap_first_message(msc->msc_ldr, res); msg; msg = ldap_next_message(msc->msc_ldr, msg)) {
		switch(ldap_msgtype(msg)) {
		case LDAP_RES_SEARCH_ENTRY:
			Debug( LDAP_DEBUG_TRACE,
				"%s asyncmeta_handle_search_msg: msc %p entry\n",
				op->o_log_prefix, msc );
			if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
				/* don't retry any more... */
				candidates[ i ].sr_type = REP_RESULT;
			}
			/* count entries returned by target */
			candidates[ i ].sr_nentries++;
			if (bc->c_peer_name.bv_val == op->o_conn->c_peer_name.bv_val && !op->o_abandon) {
				rs->sr_err = asyncmeta_send_entry( &bc->copy_op, rs, mc, i, msg );
			} else {
				goto err_cleanup;
			}
			switch ( rs->sr_err ) {
			case LDAP_SIZELIMIT_EXCEEDED:
				asyncmeta_send_ldap_result(bc, op, rs);
				rs->sr_err = LDAP_SUCCESS;
				goto err_cleanup;
			case LDAP_UNAVAILABLE:
				rs->sr_err = LDAP_OTHER;
				break;
			default:
				break;
			}
			bc->is_ok++;
			break;

		case LDAP_RES_SEARCH_REFERENCE:
			if ( META_BACK_TGT_NOREFS( mt ) ) {
				rs->sr_err = LDAP_OTHER;
				asyncmeta_send_ldap_result(bc, op, rs);
				goto err_cleanup;
			}
			if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
				/* don't retry any more... */
				candidates[ i ].sr_type = REP_RESULT;
			}
			bc->is_ok++;
			rc = ldap_parse_reference( msc->msc_ldr, msg,
				   &references, &rs->sr_ctrls, 0 );

			if ( rc != LDAP_SUCCESS || references == NULL ) {
				rs->sr_err = LDAP_OTHER;
				asyncmeta_send_ldap_result(bc, op, rs);
				goto err_cleanup;
			}

			/* FIXME: merge all and return at the end */

			{
				int cnt;
				for ( cnt = 0; references[ cnt ]; cnt++ )
					;

				rs->sr_ref = ber_memalloc_x( sizeof( struct berval ) * ( cnt + 1 ),
								 op->o_tmpmemctx );

				for ( cnt = 0; references[ cnt ]; cnt++ ) {
					ber_str2bv_x( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ],
							  op->o_tmpmemctx );
				}
				BER_BVZERO( &rs->sr_ref[ cnt ] );
			}

			{
				dc.memctx = op->o_tmpmemctx;
				( void )asyncmeta_referral_result_rewrite( &dc, rs->sr_ref );
			}

			if ( rs->sr_ref != NULL ) {
				if (!BER_BVISNULL( &rs->sr_ref[ 0 ] ) ) {
					/* ignore return value by now */
					( void )send_search_reference( op, rs );
				}

				ber_bvarray_free_x( rs->sr_ref, op->o_tmpmemctx );
				rs->sr_ref = NULL;
			}

			/* cleanup */
			if ( references ) {
				ber_memvfree( (void **)references );
			}

			if ( rs->sr_ctrls ) {
				ldap_controls_free( rs->sr_ctrls );
				rs->sr_ctrls = NULL;
			}
			break;

		case LDAP_RES_INTERMEDIATE:
			if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
				/* don't retry any more... */
				candidates[ i ].sr_type = REP_RESULT;
			}
			bc->is_ok++;

			/* FIXME: response controls
			 * are passed without checks */
			rs->sr_err = ldap_parse_intermediate( msc->msc_ldr,
								  msg,
								  (char **)&rs->sr_rspoid,
								  &rs->sr_rspdata,
								  &rs->sr_ctrls,
								  0 );
			if ( rs->sr_err != LDAP_SUCCESS ) {
				candidates[ i ].sr_type = REP_RESULT;
				rs->sr_err = LDAP_OTHER;
				asyncmeta_send_ldap_result(bc, op, rs);
				goto err_cleanup;
			}

			slap_send_ldap_intermediate( op, rs );

			if ( rs->sr_rspoid != NULL ) {
				ber_memfree( (char *)rs->sr_rspoid );
				rs->sr_rspoid = NULL;
			}

			if ( rs->sr_rspdata != NULL ) {
				ber_bvfree( rs->sr_rspdata );
				rs->sr_rspdata = NULL;
			}

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

		case LDAP_RES_SEARCH_RESULT:
			if ( mi->mi_idle_timeout != 0 ) {
				asyncmeta_set_msc_time(msc);
			}
			Debug( LDAP_DEBUG_TRACE,
			       "%s asyncmeta_handle_search_msg: msc %p result\n",
			       op->o_log_prefix, msc );
			candidates[ i ].sr_type = REP_RESULT;
			candidates[ i ].sr_msgid = META_MSGID_IGNORE;
			/* NOTE: ignores response controls
			 * (and intermediate response controls
			 * as well, except for those with search
			 * references); this may not be correct,
			 * but if they're not ignored then
			 * back-meta would need to merge them
			 * consistently (think of pagedResults...)
			 */
			/* FIXME: response controls? */
			rs->sr_err = ldap_parse_result( msc->msc_ldr,
							msg,
							&candidates[ i ].sr_err,
								(char **)&candidates[ i ].sr_matched,
							(char **)&candidates[ i ].sr_text,
							&references,
							&ctrls /* &candidates[ i ].sr_ctrls (unused) */ ,
							0 );
			if ( rs->sr_err != LDAP_SUCCESS ) {
				candidates[ i ].sr_err = rs->sr_err;
				sres = slap_map_api2result( &candidates[ i ] );
				candidates[ i ].sr_type = REP_RESULT;
				goto finish;
			}

			rs->sr_err = candidates[ i ].sr_err;

			/* massage matchedDN if need be */
			if ( candidates[ i ].sr_matched != NULL ) {
				struct berval	match, mmatch;

				ber_str2bv( candidates[ i ].sr_matched,
						0, 0, &match );
				candidates[ i ].sr_matched = NULL;

				dc.memctx = NULL;
				asyncmeta_dn_massage( &dc, &match, &mmatch );
				if ( mmatch.bv_val == match.bv_val ) {
					candidates[ i ].sr_matched
						= ch_strdup( mmatch.bv_val );

				} else {
					candidates[ i ].sr_matched = mmatch.bv_val;
				}

				bc->candidate_match++;
				ldap_memfree( match.bv_val );
			}

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

				} else {
					BerVarray	sr_ref;
					int		cnt;

					for ( cnt = 0; references[ cnt ]; cnt++ )
						;

					sr_ref = ber_memalloc_x( sizeof( struct berval ) * ( cnt + 1 ),
								 op->o_tmpmemctx );

					for ( cnt = 0; references[ cnt ]; cnt++ ) {
						ber_str2bv_x( references[ cnt ], 0, 1, &sr_ref[ cnt ],
								  op->o_tmpmemctx );
					}
					BER_BVZERO( &sr_ref[ cnt ] );

					dc.memctx = op->o_tmpmemctx;
					( void )asyncmeta_referral_result_rewrite( &dc, sr_ref );

					if ( rs->sr_v2ref == NULL ) {
						rs->sr_v2ref = sr_ref;

					} else {
						for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) {
							ber_bvarray_add_x( &rs->sr_v2ref, &sr_ref[ cnt ],
									   op->o_tmpmemctx );
						}
						ber_memfree_x( sr_ref, op->o_tmpmemctx );
					}
				}

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

				rs->sr_err = LDAP_NO_SUCH_OBJECT;
			}

			/* cleanup */
			ber_memvfree( (void **)references );

			sres = slap_map_api2result( rs );

			if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
				Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_search_result[%d] "
				       "match=\"%s\" err=%ld",
				       op->o_log_prefix, i,
				       candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
				       (long) candidates[ i ].sr_err );
			} else {
					Debug( LDAP_DEBUG_ANY,  "%s asyncmeta_search_result[%d] "
				       "match=\"%s\" err=%ld (%s)",
				       op->o_log_prefix, i,
				       candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
					       (long) candidates[ i ].sr_err, ldap_err2string( candidates[ i ].sr_err ) );
			}

			switch ( sres ) {
			case LDAP_NO_SUCH_OBJECT:
				/* is_ok is touched any time a valid
				 * (even intermediate) result is
				 * returned; as a consequence, if
				 * a candidate returns noSuchObject
				 * it is ignored and the candidate
				 * is simply demoted. */
				if ( bc->is_ok ) {
					sres = LDAP_SUCCESS;
				}
				break;

			case LDAP_SUCCESS:
				if ( ctrls != NULL && ctrls[0] != NULL ) {
#ifdef SLAPD_META_CLIENT_PR
					LDAPControl *pr_c;

					pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, ctrls, NULL );
					if ( pr_c != NULL ) {
						BerElementBuffer berbuf;
						BerElement *ber = (BerElement *)&berbuf;
						ber_tag_t tag;
						ber_int_t prsize;
						struct berval prcookie;

						/* unsolicited, do not accept */
						if ( mt->mt_ps == 0 ) {
							rs->sr_err = LDAP_OTHER;
							goto err_pr;
						}

						ber_init2( ber, &pr_c->ldctl_value, LBER_USE_DER );

						tag = ber_scanf( ber, "{im}", &prsize, &prcookie );
						if ( tag == LBER_ERROR ) {
							rs->sr_err = LDAP_OTHER;
							goto err_pr;
						}

						/* more pages? new search request */
						if ( !BER_BVISNULL( &prcookie ) && !BER_BVISEMPTY( &prcookie ) ) {
							if ( mt->mt_ps > 0 ) {
								/* ignore size if specified */
								prsize = 0;

							} else if ( prsize == 0 ) {
								/* guess the page size from the entries returned so far */
								prsize = candidates[ i ].sr_nentries;
							}

							candidates[ i ].sr_nentries = 0;
							candidates[ i ].sr_msgid = META_MSGID_IGNORE;
							candidates[ i ].sr_type = REP_INTERMEDIATE;

							assert( candidates[ i ].sr_matched == NULL );
							assert( candidates[ i ].sr_text == NULL );
							assert( candidates[ i ].sr_ref == NULL );

							switch ( asyncmeta_back_search_start( &bc->copy_op, rs, mc, bc, i, &prcookie, prsize, 1 ) )
							{
							case META_SEARCH_CANDIDATE:
								assert( candidates[ i ].sr_msgid >= 0 );
								ldap_controls_free( ctrls );
								//	goto free_message;

							case META_SEARCH_ERR:
							case META_SEARCH_NEED_BIND:
err_pr:;
								candidates[ i ].sr_err = rs->sr_err;
								candidates[ i ].sr_type = REP_RESULT;
								if ( META_BACK_ONERR_STOP( mi ) ) {
									asyncmeta_send_ldap_result(bc, op, rs);
									ldap_controls_free( ctrls );
									goto err_cleanup;
								}
								/* fallthru */

							case META_SEARCH_NOT_CANDIDATE:
								/* means that asyncmeta_back_search_start()
								 * failed but onerr == continue */
								candidates[ i ].sr_msgid = META_MSGID_IGNORE;
								candidates[ i ].sr_type = REP_RESULT;
								break;

							default:
								/* impossible */
								assert( 0 );
								break;
							}
							break;
						}
					}
#endif /* SLAPD_META_CLIENT_PR */

					ldap_controls_free( ctrls );
				}
				/* fallthru */

			case LDAP_REFERRAL:
				bc->is_ok++;
				break;

			case LDAP_SIZELIMIT_EXCEEDED:
				/* if a target returned sizelimitExceeded
				 * and the entry count is equal to the
				 * proxy's limit, the target would have
				 * returned more, and the error must be
				 * propagated to the client; otherwise,
				 * the target enforced a limit lower
				 * than what requested by the proxy;
				 * ignore it */
				candidates[ i ].sr_err = rs->sr_err;
				if ( rs->sr_nentries == op->ors_slimit
					 || META_BACK_ONERR_STOP( mi ) )
				{
					const char *save_text;
got_err:
					save_text = rs->sr_text;
					rs->sr_text = candidates[ i ].sr_text;
					asyncmeta_send_ldap_result(bc, op, rs);
					if (candidates[ i ].sr_text != NULL) {
						ch_free( (char *)candidates[ i ].sr_text );
						candidates[ i ].sr_text = NULL;
					}
					rs->sr_text = save_text;
					ldap_controls_free( ctrls );
					goto err_cleanup;
				}
				break;

			default:
				candidates[ i ].sr_err = rs->sr_err;
				if ( META_BACK_ONERR_STOP( mi ) ) {
					goto got_err;
				}
				break;
			}
			/* if this is the last result we will ever receive, send it back  */
			rc = rs->sr_err;
			if (asyncmeta_is_last_result(mc, bc, i) == 0) {
				Debug( LDAP_DEBUG_TRACE,
					"%s asyncmeta_handle_search_msg: msc %p last result\n",
					op->o_log_prefix, msc );
				asyncmeta_search_last_result(mc, bc, i, sres);
err_cleanup:
				rc = rs->sr_err;
				ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
				asyncmeta_drop_bc( mc, bc);
				asyncmeta_clear_bm_context(bc);
				ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
				ldap_msgfree(res);
				return rc;
			}
finish:
			break;

		default:
			continue;
		}
	}
		ldap_msgfree(res);
		res = NULL;
		if (candidates[ i ].sr_type != REP_RESULT) {
			struct timeval	tv = {0};
			rc = ldap_result( msc->msc_ldr, id, LDAP_MSG_RECEIVED, &tv, &res );
			if (res != NULL) {
				msc->msc_result_time = slap_get_time();
			}
		}
	}
	ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
	bc->bc_active--;
	ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );

	return rc;
}
示例#3
0
void *
asyncmeta_op_handle_result(void *ctx, void *arg)
{
	a_metaconn_t *mc = arg;
	int		i, j, rc, ntargets;
	struct timeval	tv = {0};
	LDAPMessage     *msg;
	a_metasingleconn_t *msc;
	bm_context_t *bc;
	void *oldctx;

	ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
	rc = ++mc->mc_active;
	ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
	if (rc > 1)
		return NULL;

	ntargets = mc->mc_info->mi_ntargets;
	i = ntargets;
	oldctx = slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, ctx, 0);	/* get existing memctx */

again:
	for (j=0; j<ntargets; j++) {
		i++;
		if (i >= ntargets) i = 0;
		msc = &mc->mc_conns[i];
		ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
		if (!mc->mc_conns[i].msc_ldr ||
		    META_BACK_CONN_CREATING( &mc->mc_conns[i] ) ||
		    META_BACK_CONN_INVALID(&mc->mc_conns[i])) {
			ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
			continue;
		}

		msc->msc_active++;
		ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );

		rc = ldap_result( mc->mc_conns[i].msc_ldr, LDAP_RES_ANY, LDAP_MSG_RECEIVED, &tv, &msg );
		if (rc < 1) {
			if (rc < 0) {
				ldap_get_option( mc->mc_conns[i].msc_ldr, LDAP_OPT_ERROR_NUMBER, &rc);
				META_BACK_CONN_INVALID_SET(&mc->mc_conns[i]);
				asyncmeta_op_read_error(mc, i, rc, ctx);
			}
			ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
			msc->msc_active--;
			ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
			continue;
		}
		rc = ldap_msgtype( msg );
		if (rc == LDAP_RES_BIND) {
			if ( LogTest( asyncmeta_debug ) ) {
				char	time_buf[ SLAP_TEXT_BUFLEN ];
				asyncmeta_get_timestamp(time_buf);
				Debug( asyncmeta_debug, "[%s] asyncmeta_op_handle_result received bind msgid=%d msc: %p\n",
				      time_buf, ldap_msgid(msg), msc );
			}
			asyncmeta_handle_bind_result(msg, mc, i, ctx);
			mc->mc_info->mi_targets[i]->mt_timeout_ops = 0;
			ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
			msc->msc_result_time = slap_get_time();
			msc->msc_active--;
			ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
			if (msg)
				ldap_msgfree(msg);

			continue;
		}
retry_bc:
		ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
		bc = asyncmeta_find_message(ldap_msgid(msg), mc, i);
/* The sender might not be yet done with the context. On error it might also remove it
 * so it's best to try and find it again after a wait */
		if (bc && bc->bc_active > 0) {
			ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
			ldap_pvt_thread_yield();
			goto retry_bc;
		}
		if (bc) {
			bc->bc_active++;
		}

		msc->msc_result_time = slap_get_time();
		msc->msc_active--;
		ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
		if (!bc) {
			Debug( asyncmeta_debug,
				"asyncmeta_op_handle_result: Unable to find bc for msguid %d, msc: %p\n", ldap_msgid(msg), msc );
			ldap_msgfree(msg);
			continue;
		}

		/* 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->op->o_abandon) {
			ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
			asyncmeta_drop_bc( mc, bc);
			if ( bc->op->o_tag == LDAP_REQ_SEARCH ) {
				int j;
				for (j=0; j<ntargets; j++) {
					if (bc->candidates[j].sr_msgid >= 0) {
						a_metasingleconn_t *tmp_msc = &mc->mc_conns[j];
						tmp_msc->msc_active++;
						asyncmeta_back_cancel( mc, bc->op,
								       bc->candidates[ j ].sr_msgid, j );
						tmp_msc->msc_active--;
					}
				}
			}
			asyncmeta_clear_bm_context(bc);
			ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
			if (msg)
				ldap_msgfree(msg);
			continue;
		}

		switch (rc) {
		case LDAP_RES_SEARCH_ENTRY:
		case LDAP_RES_SEARCH_REFERENCE:
		case LDAP_RES_SEARCH_RESULT:
		case LDAP_RES_INTERMEDIATE:
			asyncmeta_handle_search_msg(msg, mc, bc, i);
			mc->mc_info->mi_targets[i]->mt_timeout_ops = 0;
			msg = NULL;
			break;
		case LDAP_RES_ADD:
		case LDAP_RES_DELETE:
		case LDAP_RES_MODDN:
		case LDAP_RES_COMPARE:
		case LDAP_RES_MODIFY:
			rc = asyncmeta_handle_common_result(msg, mc, bc, i);
			mc->mc_info->mi_targets[i]->mt_timeout_ops = 0;
			break;
		default:
			{
			Debug( asyncmeta_debug,
				   "asyncmeta_op_handle_result: "
				   "unrecognized response message tag=%d\n",
				   rc );

			}
		}
		if (msg)
			ldap_msgfree(msg);
	}

	ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
	rc = --mc->mc_active;
	ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
	if (rc) {
		i++;
		goto again;
	}
	slap_sl_mem_setctx(ctx, oldctx);
	if (mc->mc_conns) {
		ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
		for (i=0; i<ntargets; i++) {
			if (!slapd_shutdown && !META_BACK_CONN_INVALID(msc)
			    && mc->mc_conns[i].msc_ldr && mc->mc_conns[i].conn) {
				connection_client_enable(mc->mc_conns[i].conn);
			}
		}
		ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
	}
	return NULL;
}
示例#4
0
static bool_t linphone_ldap_contact_provider_iterate(void *data)
{
	LinphoneLDAPContactProvider* obj = LINPHONE_LDAP_CONTACT_PROVIDER(data);
	if( obj->ld && obj->connected && (obj->req_count > 0) ){

		// never block
		struct timeval timeout = {0,0};
		LDAPMessage* results = NULL;

		int ret = ldap_result(obj->ld, LDAP_RES_ANY, LDAP_MSG_ONE, &timeout, &results);

		switch( ret ){
		case -1:
		{
			ms_warning("Error in ldap_result : returned -1 (req_count %d): %s", obj->req_count, ldap_err2string(errno));
			break;
		}
		case 0: break; // nothing to do

		case LDAP_RES_BIND:
		{
			ms_error("iterate: unexpected LDAP_RES_BIND");
			break;
		}
		case LDAP_RES_EXTENDED:
		case LDAP_RES_SEARCH_ENTRY:
		case LDAP_RES_SEARCH_REFERENCE:
		case LDAP_RES_INTERMEDIATE:
		case LDAP_RES_SEARCH_RESULT:
		{
			LDAPMessage* message = ldap_first_message(obj->ld, results);
			LinphoneLDAPContactSearch* req = linphone_ldap_contact_provider_request_search(obj, ldap_msgid(message));
			while( message != NULL ){
				linphone_ldap_contact_provider_handle_search_result(obj, req, message );
				message = ldap_next_message(obj->ld, message);
			}
			if( req && ret == LDAP_RES_SEARCH_RESULT)
				linphone_ldap_contact_provider_cancel_search(
							LINPHONE_CONTACT_PROVIDER(obj),
							LINPHONE_CONTACT_SEARCH(req));
			break;
		}
		case LDAP_RES_MODIFY:
		case LDAP_RES_ADD:
		case LDAP_RES_DELETE:
		case LDAP_RES_MODDN:
		case LDAP_RES_COMPARE:
		default:
			ms_message("Unhandled LDAP result %x", ret);
			break;
		}

		if( results )
			ldap_msgfree(results);
	}

	if( obj->ld && obj->connected ){
		// check for pending searches
		unsigned int i;

		for( i=0; i<obj->req_count; i++){
			LinphoneLDAPContactSearch* search = (LinphoneLDAPContactSearch*)ms_list_nth_data( obj->requests, i );
			if( search && search->msgid == 0){
				int ret;
				ms_message("Found pending search %p (for %s), launching...", search, search->filter);
				ret = linphone_ldap_contact_provider_perform_search(obj, search);
				if( ret != LDAP_SUCCESS ){
					linphone_ldap_contact_provider_cancel_search(
								LINPHONE_CONTACT_PROVIDER(obj),
								LINPHONE_CONTACT_SEARCH(search));
				}
			}
		}
	}

	return TRUE;
}
static void
do_search( char *uri, char *manager, struct berval *passwd,
	char *sbase, int scope, char *filter, LDAP **ldp,
	char **attrs, int noattrs, int nobind,
	int innerloop, int maxretries, int delay, int force, int chaserefs )
{
	LDAP	*ld = ldp ? *ldp : NULL;
	int  	i = 0, do_retry = maxretries;
	int     rc = LDAP_SUCCESS;
	int	version = LDAP_VERSION3;
	char	buf[ BUFSIZ ];
	int		*msgids = NULL, active = 0;

	/* make room for msgid */
	if ( swamp > 1 ) {
		msgids = (int *)calloc( sizeof(int), innerloop );
	}

retry:;
	if ( ld == NULL ) {
		ldap_initialize( &ld, uri );
		if ( ld == NULL ) {
			tester_perror( "ldap_initialize", NULL );
			exit( EXIT_FAILURE );
		}

		(void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); 
		(void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
			chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF );

		if ( do_retry == maxretries ) {
			fprintf( stderr,
				"PID=%ld - Search(%d): "
				"base=\"%s\" scope=%s filter=\"%s\" "
				"attrs=%s%s.\n",
				(long) pid, innerloop,
				sbase, ldap_pvt_scope2str( scope ), filter,
				attrs[0], attrs[1] ? " (more...)" : "" );
		}

		if ( nobind == 0 ) {
			rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL );
			if ( rc != LDAP_SUCCESS ) {
				snprintf( buf, sizeof( buf ),
					"bindDN=\"%s\"", manager );
				tester_ldap_error( ld, "ldap_sasl_bind_s", buf );
				switch ( rc ) {
				case LDAP_BUSY:
				case LDAP_UNAVAILABLE:
					if ( do_retry > 0 ) {
						ldap_unbind_ext( ld, NULL, NULL );
						ld = NULL;
						do_retry--;
						if ( delay != 0 ) {
						    sleep( delay );
						}
						goto retry;
					}
				/* fallthru */
				default:
					break;
				}
				exit( EXIT_FAILURE );
			}
		}
	}

	if ( swamp > 1 ) {
		do {
			LDAPMessage *res = NULL;
			int j, msgid;

			if ( i < innerloop ) {
				rc = ldap_search_ext( ld, sbase, scope,
						filter, NULL, noattrs, NULL, NULL,
						NULL, LDAP_NO_LIMIT, &msgids[i] );

				active++;
#if 0
				fprintf( stderr,
					">>> PID=%ld - Search maxloop=%d cnt=%d active=%d msgid=%d: "
					"base=\"%s\" scope=%s filter=\"%s\"\n",
					(long) pid, innerloop, i, active, msgids[i],
					sbase, ldap_pvt_scope2str( scope ), filter );
#endif
				i++;

				if ( rc ) {
					int first = tester_ignore_err( rc );
					/* if ignore.. */
					if ( first ) {
						/* only log if first occurrence */
						if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
							tester_ldap_error( ld, "ldap_search_ext", NULL );
						}
						continue;
					}
		
					/* busy needs special handling */
					snprintf( buf, sizeof( buf ),
						"base=\"%s\" filter=\"%s\"\n",
						sbase, filter );
					tester_ldap_error( ld, "ldap_search_ext", buf );
					if ( rc == LDAP_BUSY && do_retry > 0 ) {
						ldap_unbind_ext( ld, NULL, NULL );
						ld = NULL;
						do_retry--;
						goto retry;
					}
					break;
				}

				if ( swamp > 2 ) {
					continue;
				}
			}

			rc = ldap_result( ld, LDAP_RES_ANY, 0, NULL, &res );
			switch ( rc ) {
			case -1:
				/* gone really bad */
				goto cleanup;
	
			case 0:
				/* timeout (impossible) */
				break;
	
			case LDAP_RES_SEARCH_ENTRY:
			case LDAP_RES_SEARCH_REFERENCE:
				/* ignore */
				break;
	
			case LDAP_RES_SEARCH_RESULT:
				/* just remove, no error checking (TODO?) */
				msgid = ldap_msgid( res );
				ldap_parse_result( ld, res, &rc, NULL, NULL, NULL, NULL, 1 );
				res = NULL;

				/* linear search, bah */
				for ( j = 0; j < i; j++ ) {
					if ( msgids[ j ] == msgid ) {
						msgids[ j ] = -1;
						active--;
#if 0
						fprintf( stderr,
							"<<< PID=%ld - SearchDone maxloop=%d cnt=%d active=%d msgid=%d: "
							"base=\"%s\" scope=%s filter=\"%s\"\n",
							(long) pid, innerloop, j, active, msgid,
							sbase, ldap_pvt_scope2str( scope ), filter );
#endif
						break;
					}
				}
				break;

			default:
				/* other messages unexpected */
				fprintf( stderr,
					"### PID=%ld - Search(%d): "
					"base=\"%s\" scope=%s filter=\"%s\" "
					"attrs=%s%s. unexpected response tag=%d\n",
					(long) pid, innerloop,
					sbase, ldap_pvt_scope2str( scope ), filter,
					attrs[0], attrs[1] ? " (more...)" : "", rc );
				break;
			}

			if ( res != NULL ) {
				ldap_msgfree( res );
			}
		} while ( i < innerloop || active > 0 );

	} else {
		for ( ; i < innerloop; i++ ) {
			LDAPMessage *res = NULL;

			if (swamp) {
				int msgid;
				rc = ldap_search_ext( ld, sbase, scope,
						filter, NULL, noattrs, NULL, NULL,
						NULL, LDAP_NO_LIMIT, &msgid );
				if ( rc == LDAP_SUCCESS ) continue;
				else break;
			}
	
			rc = ldap_search_ext_s( ld, sbase, scope,
					filter, attrs, noattrs, NULL, NULL,
					NULL, LDAP_NO_LIMIT, &res );
			if ( res != NULL ) {
				ldap_msgfree( res );
			}
	
			if ( rc ) {
				int first = tester_ignore_err( rc );
				/* if ignore.. */
				if ( first ) {
					/* only log if first occurrence */
					if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
						tester_ldap_error( ld, "ldap_search_ext_s", NULL );
					}
					continue;
				}
	
				/* busy needs special handling */
				snprintf( buf, sizeof( buf ),
					"base=\"%s\" filter=\"%s\"\n",
					sbase, filter );
				tester_ldap_error( ld, "ldap_search_ext_s", buf );
				if ( rc == LDAP_BUSY && do_retry > 0 ) {
					ldap_unbind_ext( ld, NULL, NULL );
					ld = NULL;
					do_retry--;
					goto retry;
				}
				break;
			}
		}
	}

cleanup:;
	if ( msgids != NULL ) {
		free( msgids );
	}

	if ( ldp != NULL ) {
		*ldp = ld;

	} else {
		fprintf( stderr, "  PID=%ld - Search done (%d).\n", (long) pid, rc );

		if ( ld != NULL ) {
			ldap_unbind_ext( ld, NULL, NULL );
		}
	}
}
示例#6
0
nsresult
nsLDAPConnection::InvokeMessageCallback(LDAPMessage *aMsgHandle, 
                                        nsILDAPMessage *aMsg,
                                        PRBool aRemoveOpFromConnQ)
{
    PRInt32 msgId;
    nsresult rv;
    nsCOMPtr<nsILDAPOperation> operation;
    nsCOMPtr<nsILDAPMessageListener> listener;

#if defined(DEBUG)
    // We only want this being logged for debug builds so as not to affect performance too much.
    PR_LOG(gLDAPLogModule, PR_LOG_DEBUG, ("InvokeMessageCallback entered\n"));
#endif

    // get the message id corresponding to this operation
    //
    msgId = ldap_msgid(aMsgHandle);
    if (msgId == -1) {
        NS_ERROR("nsLDAPConnection::GetCallbackByMessage(): "
                 "ldap_msgid() failed\n");
        return NS_ERROR_FAILURE;
    }

    // get this in key form.  note that using nsVoidKey in this way assumes
    // that sizeof(void *) >= sizeof PRInt32
    //
    nsVoidKey *key = new nsVoidKey(reinterpret_cast<void *>(msgId));
    if (!key)
        return NS_ERROR_OUT_OF_MEMORY;

    // find the operation in question
    operation = getter_AddRefs(static_cast<nsILDAPOperation *>(mPendingOperations->Get(key)));
    if (!operation) {

        PR_LOG(gLDAPLogModule, PR_LOG_WARNING, 
               ("Warning: InvokeMessageCallback(): couldn't find "
                "nsILDAPOperation corresponding to this message id\n"));
        delete key;

        // this may well be ok, since it could just mean that the operation
        // was aborted while some number of messages were already in transit.
        //
        return NS_OK;
    }


    // Make sure the mOperation member is set to this operation before
    // we call the callback.
    //
    static_cast<nsLDAPMessage *>(aMsg)->mOperation = operation;

    // get the message listener object (this may be a proxy for a
    // callback which should happen on another thread)
    //
    rv = operation->GetMessageListener(getter_AddRefs(listener));
    if (NS_FAILED(rv)) {
        NS_ERROR("nsLDAPConnection::InvokeMessageCallback(): probable "
                 "memory corruption: GetMessageListener() returned error");
        delete key;
        return NS_ERROR_UNEXPECTED;
    }

    // invoke the callback 
    //
    if (listener) {
      listener->OnLDAPMessage(aMsg);
    }
    // if requested (ie the operation is done), remove the operation
    // from the connection queue.
    //
    if (aRemoveOpFromConnQ) {
        nsCOMPtr <nsLDAPOperation> operation = 
          getter_AddRefs(static_cast<nsLDAPOperation *>
                                    (mPendingOperations->Get(key)));
        // try to break cycles
        if (operation)
          operation->Clear();
        rv = mPendingOperations->Remove(key);
        if (NS_FAILED(rv)) {
            NS_ERROR("nsLDAPConnection::InvokeMessageCallback: unable to "
                     "remove operation from the connection queue\n");
            delete key;
            return NS_ERROR_UNEXPECTED;
        }

        PR_LOG(gLDAPLogModule, PR_LOG_DEBUG, 
               ("pending operation removed; total pending operations now ="
                " %d\n", mPendingOperations->Count()));
    }

    delete key;
    return NS_OK;
}
示例#7
0
static int
ldap_connection_handle_message(struct ldap_connection *conn,
			       LDAPMessage *message)
{
	struct ldap_op_queue_entry *req;
	unsigned int i = 0;
	bool finished = FALSE;
	int err = LDAP_SUCCESS;

	/* we need to look at who it was for */
	req = ldap_connection_find_req_by_msgid(conn, ldap_msgid(message), &i);
	if (req != NULL)
		err = req->internal_response_cb(conn, req, message, &finished);
	ldap_msgfree(message);

	switch(err) {
	case LDAP_SUCCESS:
		break;
	case LDAP_SERVER_DOWN:
#ifdef LDAP_CONNECT_ERROR
	case LDAP_CONNECT_ERROR:
#endif
	case LDAP_UNAVAILABLE:
	case LDAP_OPERATIONS_ERROR:
	case LDAP_BUSY:
		/* requeue */
		ldap_connection_kill(conn);
		ldap_connection_send_next(conn);
		finished = FALSE;
		break;
	case LDAP_INVALID_CREDENTIALS: {
		/* fail everything */
		ldap_connection_kill(conn);
		ldap_connection_abort_all_requests(conn);
		return 0;
	}
	case LDAP_SIZELIMIT_EXCEEDED:
	case LDAP_TIMELIMIT_EXCEEDED:
	case LDAP_NO_SUCH_ATTRIBUTE:
	case LDAP_UNDEFINED_TYPE:
	case LDAP_INAPPROPRIATE_MATCHING:
	case LDAP_CONSTRAINT_VIOLATION:
	case LDAP_TYPE_OR_VALUE_EXISTS:
	case LDAP_INVALID_SYNTAX:
	case LDAP_NO_SUCH_OBJECT:
	case LDAP_ALIAS_PROBLEM:
	case LDAP_INVALID_DN_SYNTAX:
	case LDAP_IS_LEAF:
	case LDAP_ALIAS_DEREF_PROBLEM:
	case LDAP_FILTER_ERROR:
	case LDAP_LOCAL_ERROR:
		finished = TRUE;
		break;
	default:
		/* ignore */
		break;
	}

	if (finished) {
		i_assert(req != NULL);
		ldap_connection_request_destroy(&req);
		conn->pending--;
		aqueue_delete(conn->request_queue, i);
		return 1;
	}
	return 0;
}