Пример #1
0
static void
retcode_item_destroy( retcode_item_t *rdi )
{
	ber_memfree( rdi->rdi_line.bv_val );

	ber_memfree( rdi->rdi_dn.bv_val );
	ber_memfree( rdi->rdi_ndn.bv_val );

	if ( !BER_BVISNULL( &rdi->rdi_text ) ) {
		ber_memfree( rdi->rdi_text.bv_val );
	}

	if ( !BER_BVISNULL( &rdi->rdi_matched ) ) {
		ber_memfree( rdi->rdi_matched.bv_val );
	}

	if ( rdi->rdi_ref ) {
		ber_bvarray_free( rdi->rdi_ref );
	}

	BER_BVZERO( &rdi->rdi_e.e_name );
	BER_BVZERO( &rdi->rdi_e.e_nname );

	entry_clean( &rdi->rdi_e );

	if ( !BER_BVISNULL( &rdi->rdi_unsolicited_oid ) ) {
		ber_memfree( rdi->rdi_unsolicited_oid.bv_val );
		if ( !BER_BVISNULL( &rdi->rdi_unsolicited_data ) )
			ber_memfree( rdi->rdi_unsolicited_data.bv_val );
	}

	ch_free( rdi );
}
Пример #2
0
void
entry_free( Entry *e )
{
	entry_clean( e );

	ldap_pvt_thread_mutex_lock( &entry_mutex );
	e->e_private = entry_list;
	entry_list = e;
	ldap_pvt_thread_mutex_unlock( &entry_mutex );
}
Пример #3
0
int
dnssrv_back_search(
    Operation	*op,
    SlapReply	*rs )
{
	int i;
	int rc;
	char *domain = NULL;
	char *hostlist = NULL;
	char **hosts = NULL;
	char *refdn;
	struct berval nrefdn = BER_BVNULL;
	BerVarray urls = NULL;
	int manageDSAit;

	rs->sr_ref = NULL;

	if ( BER_BVISEMPTY( &op->o_req_ndn ) ) {
		/* FIXME: need some means to determine whether the database
		 * is a glue instance; if we got here with empty DN, then
		 * we passed this same test in dnssrv_back_referrals() */
		if ( !SLAP_GLUE_INSTANCE( op->o_bd ) ) {
			rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
			rs->sr_text = "DNS SRV operation upon null (empty) DN disallowed";

		} else {
			rs->sr_err = LDAP_SUCCESS;
		}
		goto done;
	}

	manageDSAit = get_manageDSAit( op );
	/*
	 * FIXME: we may return a referral if manageDSAit is not set
	 */
	if ( !manageDSAit ) {
		send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
				"manageDSAit must be set" );
		goto done;
	}

	if( ldap_dn2domain( op->o_req_dn.bv_val, &domain ) || domain == NULL ) {
		rs->sr_err = LDAP_REFERRAL;
		rs->sr_ref = default_referral;
		send_ldap_result( op, rs );
		rs->sr_ref = NULL;
		goto done;
	}

	Debug( LDAP_DEBUG_TRACE, "DNSSRV: dn=\"%s\" -> domain=\"%s\"\n",
		op->o_req_dn.bv_len ? op->o_req_dn.bv_val : "", domain );

	if( ( rc = ldap_domain2hostlist( domain, &hostlist ) ) ) {
		Debug( LDAP_DEBUG_TRACE, "DNSSRV: domain2hostlist returned %d\n",
			rc );
		send_ldap_error( op, rs, LDAP_NO_SUCH_OBJECT,
			"no DNS SRV RR available for DN" );
		goto done;
	}

	hosts = ldap_str2charray( hostlist, " " );

	if( hosts == NULL ) {
		Debug( LDAP_DEBUG_TRACE, "DNSSRV: str2charray error\n" );
		send_ldap_error( op, rs, LDAP_OTHER,
			"problem processing DNS SRV records for DN" );
		goto done;
	}

	for( i=0; hosts[i] != NULL; i++) {
		struct berval url;

		url.bv_len = STRLENOF( "ldap://" ) + strlen(hosts[i]);
		url.bv_val = ch_malloc( url.bv_len + 1 );

		strcpy( url.bv_val, "ldap://" );
		strcpy( &url.bv_val[STRLENOF( "ldap://" )], hosts[i] );

		if( ber_bvarray_add( &urls, &url ) < 0 ) {
			free( url.bv_val );
			send_ldap_error( op, rs, LDAP_OTHER,
			"problem processing DNS SRV records for DN" );
			goto done;
		}
	}

	Debug( LDAP_DEBUG_STATS,
	    "%s DNSSRV p=%d dn=\"%s\" url=\"%s\"\n",
	    op->o_log_prefix, op->o_protocol,
		op->o_req_dn.bv_len ? op->o_req_dn.bv_val : "", urls[0].bv_val );

	Debug( LDAP_DEBUG_TRACE,
		"DNSSRV: ManageDSAit scope=%d dn=\"%s\" -> url=\"%s\"\n",
		op->oq_search.rs_scope,
		op->o_req_dn.bv_len ? op->o_req_dn.bv_val : "",
		urls[0].bv_val );

	rc = ldap_domain2dn(domain, &refdn);

	if( rc != LDAP_SUCCESS ) {
		send_ldap_error( op, rs, LDAP_OTHER,
			"DNS SRV problem processing manageDSAit control" );
		goto done;

	} else {
		struct berval bv;
		bv.bv_val = refdn;
		bv.bv_len = strlen( refdn );

		rc = dnNormalize( 0, NULL, NULL, &bv, &nrefdn, op->o_tmpmemctx );
		if( rc != LDAP_SUCCESS ) {
			send_ldap_error( op, rs, LDAP_OTHER,
				"DNS SRV problem processing manageDSAit control" );
			goto done;
		}
	}

	if( !dn_match( &nrefdn, &op->o_req_ndn ) ) {
		/* requested dn is subordinate */

		Debug( LDAP_DEBUG_TRACE,
			"DNSSRV: dn=\"%s\" subordinate to refdn=\"%s\"\n",
			op->o_req_dn.bv_len ? op->o_req_dn.bv_val : "",
			refdn == NULL ? "" : refdn );

		rs->sr_matched = refdn;
		rs->sr_err = LDAP_NO_SUCH_OBJECT;
		send_ldap_result( op, rs );
		rs->sr_matched = NULL;

	} else if ( op->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL ) {
		send_ldap_error( op, rs, LDAP_SUCCESS, NULL );

	} else {
		Entry e = { 0 };
		AttributeDescription *ad_objectClass
			= slap_schema.si_ad_objectClass;
		AttributeDescription *ad_ref = slap_schema.si_ad_ref;
		e.e_name.bv_val = ch_strdup( op->o_req_dn.bv_val );
		e.e_name.bv_len = op->o_req_dn.bv_len;
		e.e_nname.bv_val = ch_strdup( op->o_req_ndn.bv_val );
		e.e_nname.bv_len = op->o_req_ndn.bv_len;

		e.e_attrs = NULL;
		e.e_private = NULL;

		attr_merge_one( &e, ad_objectClass, &slap_schema.si_oc_referral->soc_cname, NULL );
		attr_merge_one( &e, ad_objectClass, &slap_schema.si_oc_extensibleObject->soc_cname, NULL );

		if ( ad_dc ) {
			char		*p;
			struct berval	bv;

			bv.bv_val = domain;

			p = strchr( bv.bv_val, '.' );
					
			if ( p == bv.bv_val ) {
				bv.bv_len = 1;

			} else if ( p != NULL ) {
				bv.bv_len = p - bv.bv_val;

			} else {
				bv.bv_len = strlen( bv.bv_val );
			}

			attr_merge_normalize_one( &e, ad_dc, &bv, NULL );
		}

		if ( ad_associatedDomain ) {
			struct berval	bv;

			ber_str2bv( domain, 0, 0, &bv );
			attr_merge_normalize_one( &e, ad_associatedDomain, &bv, NULL );
		}

		attr_merge_normalize_one( &e, ad_ref, urls, NULL );

		rc = test_filter( op, &e, op->oq_search.rs_filter ); 

		if( rc == LDAP_COMPARE_TRUE ) {
			rs->sr_entry = &e;
			rs->sr_attrs = op->oq_search.rs_attrs;
			rs->sr_flags = REP_ENTRY_MODIFIABLE;
			send_search_entry( op, rs );
			rs->sr_entry = NULL;
			rs->sr_attrs = NULL;
			rs->sr_flags = 0;
		}

		entry_clean( &e );

		rs->sr_err = LDAP_SUCCESS;
		send_ldap_result( op, rs );
	}

	free( refdn );
	if ( nrefdn.bv_val ) free( nrefdn.bv_val );

done:
	if( domain != NULL ) ch_free( domain );
	if( hostlist != NULL ) ch_free( hostlist );
	if( hosts != NULL ) ldap_charray_free( hosts );
	if( urls != NULL ) ber_bvarray_free( urls );
	return 0;
}
Пример #4
0
int
passwd_back_search(
    Operation	*op,
    SlapReply	*rs )
{
    struct passwd	*pw;
    time_t		stoptime = (time_t)-1;

    LDAPRDN rdn = NULL;
    struct berval parent = BER_BVNULL;

    AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass;

    if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
        stoptime = op->o_time + op->ors_tlimit;
    }

    /* Handle a query for the base of this backend */
    if ( be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
        struct berval	val;

        rs->sr_matched = op->o_req_dn.bv_val;

        if( op->ors_scope != LDAP_SCOPE_ONELEVEL ) {
            AttributeDescription	*desc = NULL;
            char			*next;
            Entry			e = { 0 };

            /* Create an entry corresponding to the base DN */
            e.e_name.bv_val = ch_strdup( op->o_req_dn.bv_val );
            e.e_name.bv_len = op->o_req_dn.bv_len;
            e.e_nname.bv_val =  ch_strdup( op->o_req_ndn.bv_val );
            e.e_nname.bv_len = op->o_req_ndn.bv_len;

            /* Use the first attribute of the DN
            * as an attribute within the entry itself.
            */
            if( ldap_bv2rdn( &op->o_req_dn, &rdn, &next,
                             LDAP_DN_FORMAT_LDAP ) )
            {
                rs->sr_err = LDAP_INVALID_DN_SYNTAX;
                goto done;
            }

            if( slap_bv2ad( &rdn[0]->la_attr, &desc, &rs->sr_text )) {
                rs->sr_err = LDAP_NO_SUCH_OBJECT;
                ldap_rdnfree(rdn);
                goto done;
            }

            attr_merge_normalize_one( &e, desc, &rdn[0]->la_value, NULL );

            ldap_rdnfree(rdn);
            rdn = NULL;

            /* Every entry needs an objectclass. We don't really
             * know if our hardcoded choice here agrees with the
             * DN that was configured for this backend, but it's
             * better than nothing.
             *
             * should be a configuratable item
             */
            BER_BVSTR( &val, "organizationalUnit" );
            attr_merge_one( &e, ad_objectClass, &val, NULL );

            if ( test_filter( op, &e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
                rs->sr_entry = &e;
                rs->sr_attrs = op->ors_attrs;
                rs->sr_flags = REP_ENTRY_MODIFIABLE;
                send_search_entry( op, rs );
                rs->sr_flags = 0;
                rs->sr_attrs = NULL;
            }

            entry_clean( &e );
        }

        if ( op->ors_scope != LDAP_SCOPE_BASE ) {
            /* check all our "children" */

            ldap_pvt_thread_mutex_lock( &passwd_mutex );
            pw_start( op->o_bd );
            for ( pw = getpwent(); pw != NULL; pw = getpwent() ) {
                Entry		e = { 0 };

                /* check for abandon */
                if ( op->o_abandon ) {
                    endpwent();
                    ldap_pvt_thread_mutex_unlock( &passwd_mutex );
                    return( SLAPD_ABANDON );
                }

                /* check time limit */
                if ( op->ors_tlimit != SLAP_NO_LIMIT
                        && slap_get_time() > stoptime )
                {
                    send_ldap_error( op, rs, LDAP_TIMELIMIT_EXCEEDED, NULL );
                    endpwent();
                    ldap_pvt_thread_mutex_unlock( &passwd_mutex );
                    return( 0 );
                }

                if ( pw2entry( op->o_bd, pw, &e ) ) {
                    rs->sr_err = LDAP_OTHER;
                    endpwent();
                    ldap_pvt_thread_mutex_unlock( &passwd_mutex );
                    goto done;
                }

                if ( test_filter( op, &e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
                    /* check size limit */
                    if ( --op->ors_slimit == -1 ) {
                        send_ldap_error( op, rs, LDAP_SIZELIMIT_EXCEEDED, NULL );
                        endpwent();
                        ldap_pvt_thread_mutex_unlock( &passwd_mutex );
                        return( 0 );
                    }

                    rs->sr_entry = &e;
                    rs->sr_attrs = op->ors_attrs;
                    rs->sr_flags = REP_ENTRY_MODIFIABLE;
                    send_search_entry( op, rs );
                    rs->sr_flags = 0;
                    rs->sr_entry = NULL;
                }

                entry_clean( &e );
            }
            endpwent();
            ldap_pvt_thread_mutex_unlock( &passwd_mutex );
        }

    } else {
        char	*next;
        Entry	e = { 0 };
        int	rc;

        if (! be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
            dnParent( &op->o_req_ndn, &parent );
        }

        /* This backend is only one layer deep. Don't answer requests for
         * anything deeper than that.
         */
        if( !be_issuffix( op->o_bd, &parent ) ) {
            int i;
            for( i=0; op->o_bd->be_nsuffix[i].bv_val != NULL; i++ ) {
                if( dnIsSuffix( &op->o_req_ndn, &op->o_bd->be_nsuffix[i] ) ) {
                    rs->sr_matched = op->o_bd->be_suffix[i].bv_val;
                    break;
                }
            }
            rs->sr_err = LDAP_NO_SUCH_OBJECT;
            goto done;
        }

        if( op->ors_scope == LDAP_SCOPE_ONELEVEL ) {
            goto done;
        }

        if ( ldap_bv2rdn( &op->o_req_dn, &rdn, &next,
                          LDAP_DN_FORMAT_LDAP ))
        {
            rs->sr_err = LDAP_OTHER;
            goto done;
        }

        ldap_pvt_thread_mutex_lock( &passwd_mutex );
        pw_start( op->o_bd );
        pw = getpwnam( rdn[0]->la_value.bv_val );
        if ( pw == NULL ) {
            rs->sr_matched = parent.bv_val;
            rs->sr_err = LDAP_NO_SUCH_OBJECT;
            ldap_pvt_thread_mutex_unlock( &passwd_mutex );
            goto done;
        }

        rc = pw2entry( op->o_bd, pw, &e );
        ldap_pvt_thread_mutex_unlock( &passwd_mutex );
        if ( rc ) {
            rs->sr_err = LDAP_OTHER;
            goto done;
        }

        if ( test_filter( op, &e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
            rs->sr_entry = &e;
            rs->sr_attrs = op->ors_attrs;
            rs->sr_flags = REP_ENTRY_MODIFIABLE;
            send_search_entry( op, rs );
            rs->sr_flags = 0;
            rs->sr_entry = NULL;
            rs->sr_attrs = NULL;
        }

        entry_clean( &e );
    }

done:
    if( rs->sr_err != LDAP_NO_SUCH_OBJECT ) rs->sr_matched = NULL;
    send_ldap_result( op, rs );

    if( rdn != NULL ) ldap_rdnfree( rdn );

    return( 0 );
}
Пример #5
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;
}