Example #1
0
int
ldap_back_compare(
		Operation	*op,
		SlapReply	*rs )
{
	ldapinfo_t		*li = (ldapinfo_t *)op->o_bd->be_private;

	ldapconn_t		*lc = NULL;
	ber_int_t		msgid;
	ldap_back_send_t	retrying = LDAP_BACK_RETRYING;
	LDAPControl		**ctrls = NULL;
	int			rc = LDAP_SUCCESS;

	if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
		lc = NULL;
		goto cleanup;
	}

retry:
	ctrls = op->o_ctrls;
	rc = ldap_back_controls_add( op, rs, lc, &ctrls );
	if ( rc != LDAP_SUCCESS ) {
		send_ldap_result( op, rs );
		goto cleanup;
	}

	rs->sr_err = ldap_compare_ext( lc->lc_ld, op->o_req_dn.bv_val,
			op->orc_ava->aa_desc->ad_cname.bv_val,
			&op->orc_ava->aa_value,
			ctrls, NULL, &msgid );
	rc = ldap_back_op_result( lc, op, rs, msgid,
		li->li_timeout[ SLAP_OP_COMPARE ],
		( LDAP_BACK_SENDRESULT | retrying ) );
	if ( rc == LDAP_UNAVAILABLE && retrying ) {
		retrying &= ~LDAP_BACK_RETRYING;
		if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
			/* if the identity changed, there might be need to re-authz */
			(void)ldap_back_controls_free( op, rs, &ctrls );
			goto retry;
		}
	}

	ldap_pvt_thread_mutex_lock( &li->li_counter_mutex );
	ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_COMPARE ], 1 );
	ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex );

cleanup:
	(void)ldap_back_controls_free( op, rs, &ctrls );

	if ( lc != NULL ) {
		ldap_back_release_conn( li, lc );
	}

	return rs->sr_err;
}
Example #2
0
int
ldap_back_delete(
		Operation	*op,
		SlapReply	*rs )
{
	ldapinfo_t		*li = (ldapinfo_t *)op->o_bd->be_private;

	ldapconn_t		*lc = NULL;
	ber_int_t		msgid;
	LDAPControl		**ctrls = NULL;
	ldap_back_send_t	retrying = LDAP_BACK_RETRYING;
	int			rc = LDAP_SUCCESS;

	if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
		return rs->sr_err;
	}

retry:
	ctrls = op->o_ctrls;
	rc = ldap_back_controls_add( op, rs, lc, &ctrls );
	if ( rc != LDAP_SUCCESS ) {
		send_ldap_result( op, rs );
		rc = rs->sr_err;
		goto cleanup;
	}

	rs->sr_err = ldap_delete_ext( lc->lc_ld, op->o_req_dn.bv_val,
			ctrls, NULL, &msgid );
	rc = ldap_back_op_result( lc, op, rs, msgid,
		li->li_timeout[ SLAP_OP_DELETE ],
		( LDAP_BACK_SENDRESULT | retrying ) );
	if ( rs->sr_err == LDAP_UNAVAILABLE && retrying ) {
		retrying &= ~LDAP_BACK_RETRYING;
		if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
			/* if the identity changed, there might be need to re-authz */
			(void)ldap_back_controls_free( op, rs, &ctrls );
			goto retry;
		}
	}

cleanup:
	(void)ldap_back_controls_free( op, rs, &ctrls );

	if ( lc != NULL ) {
		ldap_back_release_conn( li, lc );
	}

	return rc;
}
Example #3
0
static int
ldap_back_extended_one( Operation *op, SlapReply *rs, ldap_back_exop_f exop )
{
	ldapinfo_t	*li = (ldapinfo_t *) op->o_bd->be_private;

	ldapconn_t	*lc = NULL;
	LDAPControl	**ctrls = NULL, **oldctrls = NULL;
	int		rc;

	/* FIXME: this needs to be called here, so it is
	 * called twice; maybe we could avoid the 
	 * ldap_back_dobind() call inside each extended()
	 * call ... */
	if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
		return -1;
	}

	ctrls = op->o_ctrls;
	if ( ldap_back_controls_add( op, rs, lc, &ctrls ) )
	{
		op->o_ctrls = oldctrls;
		send_ldap_extended( op, rs );
		rs->sr_text = NULL;
		/* otherwise frontend resends result */
		rc = rs->sr_err = SLAPD_ABANDON;
		goto done;
	}

	op->o_ctrls = ctrls;
	rc = exop( op, rs, &lc );

	op->o_ctrls = oldctrls;
	(void)ldap_back_controls_free( op, rs, &ctrls );

done:;
	if ( lc != NULL ) {
		ldap_back_release_conn( li, lc );
	}
			
	return rc;
}
Example #4
0
int
ldap_back_modify(
		Operation	*op,
		SlapReply	*rs )
{
	ldapinfo_t		*li = (ldapinfo_t *)op->o_bd->be_private;

	ldapconn_t		*lc = NULL;
	LDAPMod			**modv = NULL,
				*mods = NULL;
	Modifications		*ml;
	int			i, j, rc;
	ber_int_t		msgid;
	int			isupdate;
	ldap_back_send_t	retrying = LDAP_BACK_RETRYING;
	LDAPControl		**ctrls = NULL;

	if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
		return rs->sr_err;
	}

	for ( i = 0, ml = op->orm_modlist; ml; i++, ml = ml->sml_next )
		/* just count mods */ ;

	modv = (LDAPMod **)ch_malloc( ( i + 1 )*sizeof( LDAPMod * )
			+ i*sizeof( LDAPMod ) );
	if ( modv == NULL ) {
		rc = LDAP_NO_MEMORY;
		goto cleanup;
	}
	mods = (LDAPMod *)&modv[ i + 1 ];

	isupdate = be_shadow_update( op );
	for ( i = 0, ml = op->orm_modlist; ml; ml = ml->sml_next ) {
		if ( !isupdate && !get_relax( op ) && ml->sml_desc->ad_type->sat_no_user_mod  )
		{
			continue;
		}

		modv[ i ] = &mods[ i ];
		mods[ i ].mod_op = ( ml->sml_op | LDAP_MOD_BVALUES );
		mods[ i ].mod_type = ml->sml_desc->ad_cname.bv_val;

		if ( ml->sml_values != NULL ) {
			if ( ml->sml_values == NULL ) {	
				continue;
			}

			for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ )
				/* just count mods */ ;
			mods[ i ].mod_bvalues =
				(struct berval **)ch_malloc( ( j + 1 )*sizeof( struct berval * ) );
			for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ )
			{
				mods[ i ].mod_bvalues[ j ] = &ml->sml_values[ j ];
			}
			mods[ i ].mod_bvalues[ j ] = NULL;

		} else {
			mods[ i ].mod_bvalues = NULL;
		}

		i++;
	}
	modv[ i ] = 0;

retry:;
	ctrls = op->o_ctrls;
	rc = ldap_back_controls_add( op, rs, lc, &ctrls );
	if ( rc != LDAP_SUCCESS ) {
		send_ldap_result( op, rs );
		rc = -1;
		goto cleanup;
	}

	rs->sr_err = ldap_modify_ext( lc->lc_ld, op->o_req_dn.bv_val, modv,
			ctrls, NULL, &msgid );
	rc = ldap_back_op_result( lc, op, rs, msgid,
		li->li_timeout[ SLAP_OP_MODIFY ],
		( LDAP_BACK_SENDRESULT | retrying ) );
	if ( rs->sr_err == LDAP_UNAVAILABLE && retrying ) {
		retrying &= ~LDAP_BACK_RETRYING;
		if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
			/* if the identity changed, there might be need to re-authz */
			(void)ldap_back_controls_free( op, rs, &ctrls );
			goto retry;
		}
	}

cleanup:;
	(void)ldap_back_controls_free( op, rs, &ctrls );

	for ( i = 0; modv[ i ]; i++ ) {
		ch_free( modv[ i ]->mod_bvalues );
	}
	ch_free( modv );

	if ( lc != NULL ) {
		ldap_back_release_conn( li, lc );
	}

	return rc;
}
Example #5
0
int
ldap_back_add(
	Operation	*op,
	SlapReply	*rs )
{
	ldapinfo_t		*li = (ldapinfo_t *)op->o_bd->be_private;

	ldapconn_t		*lc = NULL;
	int			i = 0,
				j = 0;
	Attribute		*a;
	LDAPMod			**attrs = NULL,
				*attrs2 = NULL;
	ber_int_t		msgid;
	int			isupdate;
	ldap_back_send_t	retrying = LDAP_BACK_RETRYING;
	LDAPControl		**ctrls = NULL;

	rs->sr_err = LDAP_SUCCESS;
	
	Debug( LDAP_DEBUG_ARGS, "==> ldap_back_add(\"%s\")\n",
			op->o_req_dn.bv_val, 0, 0 );

	if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
		lc = NULL;
		goto cleanup;
	}

	/* Count number of attributes in entry */
	for ( i = 1, a = op->oq_add.rs_e->e_attrs; a; i++, a = a->a_next )
		/* just count attrs */ ;
	
	/* Create array of LDAPMods for ldap_add() */
	attrs = (LDAPMod **)ch_malloc( sizeof( LDAPMod * )*i 
			+ sizeof( LDAPMod )*( i - 1 ) );
	attrs2 = ( LDAPMod * )&attrs[ i ];

	isupdate = be_shadow_update( op );
	for ( i = 0, a = op->oq_add.rs_e->e_attrs; a; a = a->a_next ) {
		if ( !isupdate && !get_relax( op ) && a->a_desc->ad_type->sat_no_user_mod  )
		{
			continue;
		}

		attrs[ i ] = &attrs2[ i ];
		attrs[ i ]->mod_op = LDAP_MOD_BVALUES;
		attrs[ i ]->mod_type = a->a_desc->ad_cname.bv_val;

		for ( j = 0; a->a_vals[ j ].bv_val; j++ )
			/* just count vals */ ;
		attrs[i]->mod_vals.modv_bvals = 
			ch_malloc( ( j + 1 )*sizeof( struct berval * ) );
		for ( j = 0; a->a_vals[ j ].bv_val; j++ ) {
			attrs[ i ]->mod_vals.modv_bvals[ j ] = &a->a_vals[ j ];
		}
		attrs[ i ]->mod_vals.modv_bvals[ j ] = NULL;
		i++;
	}
	attrs[ i ] = NULL;

retry:
	ctrls = op->o_ctrls;
	rs->sr_err = ldap_back_controls_add( op, rs, lc, &ctrls );
	if ( rs->sr_err != LDAP_SUCCESS ) {
		send_ldap_result( op, rs );
		goto cleanup;
	}

	rs->sr_err = ldap_add_ext( lc->lc_ld, op->o_req_dn.bv_val, attrs,
			ctrls, NULL, &msgid );
	rs->sr_err = ldap_back_op_result( lc, op, rs, msgid,
		li->li_timeout[ SLAP_OP_ADD ],
		( LDAP_BACK_SENDRESULT | retrying ) );
	if ( rs->sr_err == LDAP_UNAVAILABLE && retrying ) {
		retrying &= ~LDAP_BACK_RETRYING;
		if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
			/* if the identity changed, there might be need to re-authz */
			(void)ldap_back_controls_free( op, rs, &ctrls );
			goto retry;
		}
	}

	ldap_pvt_thread_mutex_lock( &li->li_counter_mutex );
	ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_ADD ], 1 );
	ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex );

cleanup:
	(void)ldap_back_controls_free( op, rs, &ctrls );

	if ( attrs ) {
		for ( --i; i >= 0; --i ) {
			ch_free( attrs[ i ]->mod_vals.modv_bvals );
		}
		ch_free( attrs );
	}

	if ( lc ) {
		ldap_back_release_conn( li, lc );
	}

	Debug( LDAP_DEBUG_ARGS, "<== ldap_back_add(\"%s\"): %d\n",
			op->o_req_dn.bv_val, rs->sr_err, 0 );

	return rs->sr_err;
}
Example #6
0
int
ldap_back_modrdn(
		Operation	*op,
 		SlapReply	*rs )
{
	ldapinfo_t		*li = (ldapinfo_t *)op->o_bd->be_private;

	ldapconn_t		*lc = NULL;
	ber_int_t		msgid;
	LDAPControl		**ctrls = NULL;
	ldap_back_send_t	retrying = LDAP_BACK_RETRYING;
	int			rc = LDAP_SUCCESS;
	char			*newSup = NULL;
	struct berval		newrdn = BER_BVNULL;

	if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
		return rs->sr_err;
	}

	if ( op->orr_newSup ) {
		/* needs LDAPv3 */
		switch ( li->li_version ) {
		case LDAP_VERSION3:
			break;

		case 0:
			if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
				break;
			}
			/* fall thru */

		default:
			/* op->o_protocol cannot be anything but LDAPv3,
			 * otherwise wouldn't be here */
			rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
			send_ldap_result( op, rs );
			goto cleanup;
		}
		
		newSup = op->orr_newSup->bv_val;
	}

	/* NOTE: we need to copy the newRDN in case it was formed
	 * from a DN by simply changing the length (ITS#5397) */
	newrdn = op->orr_newrdn;
	if ( newrdn.bv_val[ newrdn.bv_len ] != '\0' ) {
		ber_dupbv_x( &newrdn, &op->orr_newrdn, op->o_tmpmemctx );
	}

retry:
	ctrls = op->o_ctrls;
	rc = ldap_back_controls_add( op, rs, lc, &ctrls );
	if ( rc != LDAP_SUCCESS ) {
		send_ldap_result( op, rs );
		rc = -1;
		goto cleanup;
	}

	rs->sr_err = ldap_rename( lc->lc_ld, op->o_req_dn.bv_val,
			newrdn.bv_val, newSup,
			op->orr_deleteoldrdn, ctrls, NULL, &msgid );
	rc = ldap_back_op_result( lc, op, rs, msgid,
		li->li_timeout[ SLAP_OP_MODRDN ],
		( LDAP_BACK_SENDRESULT | retrying ) );
	if ( rs->sr_err == LDAP_UNAVAILABLE && retrying ) {
		retrying &= ~LDAP_BACK_RETRYING;
		if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
			/* if the identity changed, there might be need to re-authz */
			(void)ldap_back_controls_free( op, rs, &ctrls );
			goto retry;
		}
	}

cleanup:
	(void)ldap_back_controls_free( op, rs, &ctrls );

	if ( newrdn.bv_val != op->orr_newrdn.bv_val ) {
		op->o_tmpfree( newrdn.bv_val, op->o_tmpmemctx );
	}

	if ( lc != NULL ) {
		ldap_back_release_conn( li, lc );
	}

	return rc;
}
Example #7
0
/* return 0 IFF we can retrieve the entry with ndn
 */
int
ldap_back_entry_get(
		Operation		*op,
		struct berval		*ndn,
		ObjectClass		*oc,
		AttributeDescription	*at,
		int			rw,
		Entry			**ent )
{
	ldapinfo_t	*li = (ldapinfo_t *) op->o_bd->be_private;

	ldapconn_t	*lc = NULL;
	int		rc,
			do_not_cache;
	ber_tag_t	tag;
	struct berval	bdn;
	LDAPMessage	*result = NULL,
			*e = NULL;
	char		*attr[3], **attrp = NULL;
	char		*filter = NULL;
	SlapReply	rs;
	int		do_retry = 1;
	LDAPControl	**ctrls = NULL;

	*ent = NULL;

	/* Tell getconn this is a privileged op */
	do_not_cache = op->o_do_not_cache;
	tag = op->o_tag;
	/* do not cache */
	op->o_do_not_cache = 1;
	/* ldap_back_entry_get() is an entry lookup, so it does not need
	 * to know what the entry is being looked up for */
	op->o_tag = LDAP_REQ_SEARCH;
	rc = ldap_back_dobind( &lc, op, &rs, LDAP_BACK_DONTSEND );
	op->o_do_not_cache = do_not_cache;
	op->o_tag = tag;
	if ( !rc ) {
		return rs.sr_err;
	}

	if ( at ) {
		attrp = attr;
		if ( oc && at != slap_schema.si_ad_objectClass ) {
			attr[0] = slap_schema.si_ad_objectClass->ad_cname.bv_val;
			attr[1] = at->ad_cname.bv_val;
			attr[2] = NULL;

		} else {
			attr[0] = at->ad_cname.bv_val;
			attr[1] = NULL;
		}
	}

	if ( oc ) {
		char	*ptr;

		filter = op->o_tmpalloc( STRLENOF( "(objectClass=" ")" ) 
				+ oc->soc_cname.bv_len + 1, op->o_tmpmemctx );
		ptr = lutil_strcopy( filter, "(objectClass=" );
		ptr = lutil_strcopy( ptr, oc->soc_cname.bv_val );
		*ptr++ = ')';
		*ptr++ = '\0';
	}

retry:
	ctrls = op->o_ctrls;
	rc = ldap_back_controls_add( op, &rs, lc, &ctrls );
	if ( rc != LDAP_SUCCESS ) {
		goto cleanup;
	}

	/* TODO: timeout? */
	rc = ldap_pvt_search_s( lc->lc_ld, ndn->bv_val, LDAP_SCOPE_BASE, filter,
				attrp, LDAP_DEREF_NEVER, ctrls, NULL,
				NULL, LDAP_NO_LIMIT, 0, &result );
	if ( rc != LDAP_SUCCESS ) {
		if ( rc == LDAP_SERVER_DOWN && do_retry ) {
			do_retry = 0;
			if ( ldap_back_retry( &lc, op, &rs, LDAP_BACK_DONTSEND ) ) {
				/* if the identity changed, there might be need to re-authz */
				(void)ldap_back_controls_free( op, &rs, &ctrls );
				goto retry;
			}
		}
		goto cleanup;
	}

	e = ldap_first_entry( lc->lc_ld, result );
	if ( e == NULL ) {
		/* the entry exists, but it doesn't match the filter? */
		goto cleanup;
	}

	*ent = entry_alloc();
	if ( *ent == NULL ) {
		rc = LDAP_NO_MEMORY;
		goto cleanup;
	}

	rc = ldap_build_entry( op, e, *ent, &bdn );

	if ( rc != LDAP_SUCCESS ) {
		entry_free( *ent );
		*ent = NULL;
	}

cleanup:
	(void)ldap_back_controls_free( op, &rs, &ctrls );

	if ( result ) {
		ldap_msgfree( result );
	}

	if ( filter ) {
		op->o_tmpfree( filter, op->o_tmpmemctx );
	}

	if ( lc != NULL ) {
		ldap_back_release_conn( li, lc );
	}

	return rc;
}
Example #8
0
int
ldap_back_search(
		Operation	*op,
		SlapReply	*rs )
{
	ldapinfo_t	*li = (ldapinfo_t *) op->o_bd->be_private;

	ldapconn_t	*lc = NULL;
	struct timeval	tv;
	time_t		stoptime = (time_t)(-1);
	LDAPMessage	*res,
			*e;
	int		rc = 0,
			msgid; 
	struct berval	match = BER_BVNULL,
			filter = BER_BVNULL;
	int		i, x;
	char		**attrs = NULL;
	int		freetext = 0, filter_undef = 0;
	int		do_retry = 1, dont_retry = 0;
	LDAPControl	**ctrls = NULL;
	char		**references = NULL;

	rs_assert_ready( rs );
	rs->sr_flags &= ~REP_ENTRY_MASK; /* paranoia, we can set rs = non-entry */

	if ( !ldap_back_dobind( &lc, op, rs, LDAP_BACK_SENDERR ) ) {
		return rs->sr_err;
	}

	/*
	 * FIXME: in case of values return filter, we might want
	 * to map attrs and maybe rewrite value
	 */

	if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
		tv.tv_sec = op->ors_tlimit;
		tv.tv_usec = 0;
		stoptime = op->o_time + op->ors_tlimit;

	} else {
		LDAP_BACK_TV_SET( &tv );
	}

	i = 0;
	if ( op->ors_attrs ) {
		for ( ; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++ )
			/* just count attrs */ ;
	}

	x = 0;
	if ( op->o_bd->be_extra_anlist ) {
		for ( ; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ )
			/* just count attrs */ ;
	}

	if ( i > 0 || x > 0 ) {
		int j = 0;

		attrs = op->o_tmpalloc( ( i + x + 1 )*sizeof( char * ),
			op->o_tmpmemctx );
		if ( attrs == NULL ) {
			rs->sr_err = LDAP_NO_MEMORY;
			rc = -1;
			goto finish;
		}

		if ( i > 0 ) {	
			for ( i = 0; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++, j++ ) {
				attrs[ j ] = op->ors_attrs[i].an_name.bv_val;
			}
		}

		if ( x > 0 ) {
			for ( x = 0; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++, j++ ) {
				if ( op->o_bd->be_extra_anlist[x].an_desc &&
					ad_inlist( op->o_bd->be_extra_anlist[x].an_desc, op->ors_attrs ) )
				{
					continue;
				}

				attrs[ j ] = op->o_bd->be_extra_anlist[x].an_name.bv_val;
			}
		}

		attrs[ j ] = NULL;
	}

	ctrls = op->o_ctrls;
	rc = ldap_back_controls_add( op, rs, lc, &ctrls );
	if ( rc != LDAP_SUCCESS ) {
		goto finish;
	}

	/* deal with <draft-zeilenga-ldap-t-f> filters */
	filter = op->ors_filterstr;
retry:
	/* this goes after retry because ldap_back_munge_filter()
	 * optionally replaces RFC 4526 T-F filters (&) (|)
	 * if already computed, they will be re-installed
	 * by filter2bv_undef_x() later */
	if ( !LDAP_BACK_T_F( li ) ) {
		ldap_back_munge_filter( op, &filter );
	}

	rs->sr_err = ldap_pvt_search( lc->lc_ld, op->o_req_dn.bv_val,
			op->ors_scope, filter.bv_val,
			attrs, op->ors_attrsonly, ctrls, NULL,
			tv.tv_sec ? &tv : NULL,
			op->ors_slimit, op->ors_deref, &msgid );

	ldap_pvt_thread_mutex_lock( &li->li_counter_mutex );
	ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_SEARCH ], 1 );
	ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex );

	if ( rs->sr_err != LDAP_SUCCESS ) {
		switch ( rs->sr_err ) {
		case LDAP_SERVER_DOWN:
			if ( do_retry ) {
				do_retry = 0;
				if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_DONTSEND ) ) {
					goto retry;
				}
			}

			if ( lc == NULL ) {
				/* reset by ldap_back_retry ... */
				rs->sr_err = slap_map_api2result( rs );

			} else {
				rc = ldap_back_op_result( lc, op, rs, msgid, 0, LDAP_BACK_DONTSEND );
			}
				
			goto finish;

		case LDAP_FILTER_ERROR:
			/* first try? */
			if ( !filter_undef &&
				strstr( filter.bv_val, "(?" ) &&
				!LDAP_BACK_NOUNDEFFILTER( li ) )
			{
				BER_BVZERO( &filter );
				filter2bv_undef_x( op, op->ors_filter, 1, &filter );
				filter_undef = 1;
				goto retry;
			}

			/* invalid filters return success with no data */
			rs->sr_err = LDAP_SUCCESS;
			rs->sr_text = NULL;
			goto finish;
		
		default:
			rs->sr_err = slap_map_api2result( rs );
			rs->sr_text = NULL;
			goto finish;
		}
	}

	/* if needed, initialize timeout */
	if ( li->li_timeout[ SLAP_OP_SEARCH ] ) {
		if ( tv.tv_sec == 0 || tv.tv_sec > li->li_timeout[ SLAP_OP_SEARCH ] ) {
			tv.tv_sec = li->li_timeout[ SLAP_OP_SEARCH ];
			tv.tv_usec = 0;
		}
	}

	/* We pull apart the ber result, stuff it into a slapd entry, and
	 * let send_search_entry stuff it back into ber format. Slow & ugly,
	 * but this is necessary for version matching, and for ACL processing.
	 */

	for ( rc = -2; rc != -1; rc = ldap_result( lc->lc_ld, msgid, LDAP_MSG_ONE, &tv, &res ) )
	{
		/* check for abandon */
		if ( op->o_abandon || LDAP_BACK_CONN_ABANDON( lc ) ) {
			if ( rc > 0 ) {
				ldap_msgfree( res );
			}
			(void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
			rc = SLAPD_ABANDON;
			goto finish;
		}

		if ( rc == 0 || rc == -2 ) {
			ldap_pvt_thread_yield();

			/* check timeout */
			if ( li->li_timeout[ SLAP_OP_SEARCH ] ) {
				if ( rc == 0 ) {
					(void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
					rs->sr_text = "Operation timed out";
					rc = rs->sr_err = op->o_protocol >= LDAP_VERSION3 ?
						LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
					goto finish;
				}

			} else {
				LDAP_BACK_TV_SET( &tv );
			}

			/* check time limit */
			if ( op->ors_tlimit != SLAP_NO_LIMIT
					&& slap_get_time() > stoptime )
			{
				(void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
				rc = rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
				goto finish;
			}
			continue;

		} else {
			/* only touch when activity actually took place... */
			if ( li->li_idle_timeout && lc ) {
				lc->lc_time = op->o_time;
			}

			/* don't retry any more */
			dont_retry = 1;
		}


		if ( rc == LDAP_RES_SEARCH_ENTRY ) {
			Entry		ent = { 0 };
			struct berval	bdn = BER_BVNULL;

			do_retry = 0;

			e = ldap_first_entry( lc->lc_ld, res );
			rc = ldap_build_entry( op, e, &ent, &bdn );
			if ( rc == LDAP_SUCCESS ) {
				ldap_get_entry_controls( lc->lc_ld, res, &rs->sr_ctrls );
				rs->sr_entry = &ent;
				rs->sr_attrs = op->ors_attrs;
				rs->sr_operational_attrs = NULL;
				rs->sr_flags = 0;
				rs->sr_err = LDAP_SUCCESS;
				rc = rs->sr_err = send_search_entry( op, rs );
				if ( rs->sr_ctrls ) {
					ldap_controls_free( rs->sr_ctrls );
					rs->sr_ctrls = NULL;
				}
				rs->sr_entry = NULL;
				rs->sr_flags = 0;
				if ( !BER_BVISNULL( &ent.e_name ) ) {
					assert( ent.e_name.bv_val != bdn.bv_val );
					op->o_tmpfree( ent.e_name.bv_val, op->o_tmpmemctx );
					BER_BVZERO( &ent.e_name );
				}
				if ( !BER_BVISNULL( &ent.e_nname ) ) {
					op->o_tmpfree( ent.e_nname.bv_val, op->o_tmpmemctx );
					BER_BVZERO( &ent.e_nname );
				}
				entry_clean( &ent );
			}
			ldap_msgfree( res );
			switch ( rc ) {
			case LDAP_SUCCESS:
			case LDAP_INSUFFICIENT_ACCESS:
				break;

			default:
				if ( rc == LDAP_UNAVAILABLE ) {
					rc = rs->sr_err = LDAP_OTHER;
				} else {
					(void)ldap_back_cancel( lc, op, rs, msgid, LDAP_BACK_DONTSEND );
				}
				goto finish;
			}

		} else if ( rc == LDAP_RES_SEARCH_REFERENCE ) {
			if ( LDAP_BACK_NOREFS( li ) ) {
				ldap_msgfree( res );
				continue;
			}

			do_retry = 0;
			rc = ldap_parse_reference( lc->lc_ld, res,
					&references, &rs->sr_ctrls, 1 );

			if ( rc != LDAP_SUCCESS ) {
				continue;
			}

			/* FIXME: there MUST be at least one */
			if ( references && references[ 0 ] && references[ 0 ][ 0 ] ) {
				int		cnt;

				for ( cnt = 0; references[ cnt ]; cnt++ )
					/* NO OP */ ;

				/* FIXME: there MUST be at least one */
				rs->sr_ref = op->o_tmpalloc( ( cnt + 1 ) * sizeof( struct berval ),
					op->o_tmpmemctx );

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

				/* ignore return value by now */
				RS_ASSERT( !(rs->sr_flags & REP_ENTRY_MASK) );
				rs->sr_entry = NULL;
				( void )send_search_reference( op, rs );

			} else {
				Debug( LDAP_DEBUG_ANY,
					"%s ldap_back_search: "
					"got SEARCH_REFERENCE "
					"with no referrals\n",
					op->o_log_prefix, 0, 0 );
			}

			/* cleanup */
			if ( references ) {
				ber_memvfree( (void **)references );
				op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
				rs->sr_ref = NULL;
				references = NULL;
			}

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

		} else if ( rc == LDAP_RES_INTERMEDIATE ) {
			/* FIXME: response controls
			 * are passed without checks */
			rc = ldap_parse_intermediate( lc->lc_ld,
				res,
				(char **)&rs->sr_rspoid,
				&rs->sr_rspdata,
				&rs->sr_ctrls,
				0 );
			if ( rc != LDAP_SUCCESS ) {
				continue;
			}

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

		} else {
			char		*err = NULL;

			rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err,
					&match.bv_val, &err,
					&references, &rs->sr_ctrls, 1 );
			if ( rc == LDAP_SUCCESS ) {
				if ( err ) {
					rs->sr_text = err;
					freetext = 1;
				}
			} 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 ( references 
				&& references[ 0 ]
				&& references[ 0 ][ 0 ] )
			{
				if ( rs->sr_err != LDAP_REFERRAL ) {
					Debug( LDAP_DEBUG_ANY,
						"%s ldap_back_search: "
						"got referrals with err=%d\n",
						op->o_log_prefix,
						rs->sr_err, 0 );

				} else {
					int	cnt;

					for ( cnt = 0; references[ cnt ]; cnt++ )
						/* NO OP */ ;
				
					rs->sr_ref = op->o_tmpalloc( ( cnt + 1 ) * sizeof( struct berval ),
						op->o_tmpmemctx );

					for ( cnt = 0; references[ cnt ]; cnt++ ) {
						/* duplicating ...*/
						ber_str2bv( references[ cnt ], 0, 0, &rs->sr_ref[ cnt ] );
					}
					BER_BVZERO( &rs->sr_ref[ cnt ] );
				}

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

				rs->sr_err = LDAP_NO_SUCH_OBJECT;
			}

			if ( match.bv_val != NULL ) {
				match.bv_len = strlen( match.bv_val );
			}

			rc = 0;
			break;
		}

		/* if needed, restore timeout */
		if ( li->li_timeout[ SLAP_OP_SEARCH ] ) {
			if ( tv.tv_sec == 0 || tv.tv_sec > li->li_timeout[ SLAP_OP_SEARCH ] ) {
				tv.tv_sec = li->li_timeout[ SLAP_OP_SEARCH ];
				tv.tv_usec = 0;
			}
		}
	}

 	if ( rc == -1 ) {
		if ( dont_retry == 0 ) {
			if ( do_retry ) {
				do_retry = 0;
				if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_DONTSEND ) ) {
					goto retry;
				}
			}

			rs->sr_err = LDAP_SERVER_DOWN;
			rs->sr_err = slap_map_api2result( rs );
			goto finish;

		} else if ( LDAP_BACK_ONERR_STOP( li ) ) {
			/* if onerr == STOP */
			rs->sr_err = LDAP_SERVER_DOWN;
			rs->sr_err = slap_map_api2result( rs );
			goto finish;
		}
	}

	/*
	 * Rewrite the matched portion of the search base, if required
	 */
	if ( !BER_BVISNULL( &match ) && !BER_BVISEMPTY( &match ) ) {
		struct berval	pmatch;

		if ( dnPretty( NULL, &match, &pmatch, op->o_tmpmemctx ) != LDAP_SUCCESS ) {
			pmatch.bv_val = match.bv_val;
			match.bv_val = NULL;
		}
		rs->sr_matched = pmatch.bv_val;
		rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
	}

finish:;
	if ( !BER_BVISNULL( &match ) ) {
		ber_memfree( match.bv_val );
	}

	if ( rs->sr_v2ref ) {
		rs->sr_err = LDAP_REFERRAL;
	}

	if ( LDAP_BACK_QUARANTINE( li ) ) {
		ldap_back_quarantine( op, rs );
	}

	if ( filter.bv_val != op->ors_filterstr.bv_val ) {
		op->o_tmpfree( filter.bv_val, op->o_tmpmemctx );
	}

#if 0
	/* let send_ldap_result play cleanup handlers (ITS#4645) */
	if ( rc != SLAPD_ABANDON )
#endif
	{
		send_ldap_result( op, rs );
	}

	(void)ldap_back_controls_free( op, rs, &ctrls );

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

	if ( rs->sr_text ) {
		if ( freetext ) {
			ber_memfree( (char *)rs->sr_text );
		}
		rs->sr_text = NULL;
	}

	if ( rs->sr_ref ) {
		op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
		rs->sr_ref = NULL;
	}

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

	if ( attrs ) {
		op->o_tmpfree( attrs, op->o_tmpmemctx );
	}

	if ( lc != NULL ) {
		ldap_back_release_conn( li, lc );
	}

	return rs->sr_err;
}