Esempio n. 1
0
int 
destroy_matchrule_indexer(Slapi_PBlock *pb)
{
	Slapi_Value **keys = NULL;
	IFP mrDESTROY = NULL;
	if (!slapi_pblock_get (pb, SLAPI_PLUGIN_DESTROY_FN, &mrDESTROY))
	{
	    if (mrDESTROY != NULL)
        {
    		mrDESTROY (pb);
        }
	}
	/* matching rule indexers which handle Slapi_Value**
	   directly will own the keys, free them, and set
	   SLAPI_PLUGIN_MR_KEYS to NULL in the destroy
	   function - the old style matching rule indexers
	   which only deal with struct berval ** will not
	   free the Slapi_Value** wrappers so we have to free
	   them here */
	slapi_pblock_get(pb, SLAPI_PLUGIN_MR_KEYS, &keys);
	if (keys) {
		valuearray_free(&keys);
		slapi_pblock_set(pb, SLAPI_PLUGIN_MR_KEYS, NULL);
	}
	return 0;
}
Esempio n. 2
0
static void
mr_private_indexer_done(struct mr_private *mrpriv)
{
	if (mrpriv && mrpriv->sva) {
		valuearray_free(&mrpriv->sva);
	}
	if (mrpriv && mrpriv->bva) {
		ber_bvecfree(mrpriv->bva);
		mrpriv->bva = NULL;
	}
}
Esempio n. 3
0
void
slapi_valueset_done(Slapi_ValueSet *vs)
{
	if(vs!=NULL)
	{
		if(vs->va!=NULL)
		{
			valuearray_free(&vs->va);
			vs->va= NULL;
		}
	}
}
Esempio n. 4
0
/*
 * 
 * Find value "v" using AVL tree "valuetree"
 *
 * returns LDAP_SUCCESS if "v" was found, LDAP_NO_SUCH_ATTRIBUTE
 *	if "v" was not found and LDAP_OPERATIONS_ERROR if some unexpected error occurs.
 */
static int
valuetree_find( const struct slapi_attr *a, const Slapi_Value *v, Avlnode *valuetree, int *index)
{
	const Slapi_Value *oneval[2];
	Slapi_Value **keyvals;
	valuetree_node *vaip, tmpvain;

	PR_ASSERT(a!=NULL);
	PR_ASSERT(a->a_plugin!=NULL);
	PR_ASSERT(v!=NULL);
	PR_ASSERT(valuetree!=NULL);
	PR_ASSERT(index!=NULL);

	if ( a == NULL || v == NULL || valuetree == NULL )
	{
		return( LDAP_OPERATIONS_ERROR );
	}
 
	keyvals = NULL;
	oneval[0] = v;
	oneval[1] = NULL;
	if ( slapi_attr_values2keys_sv( a, (Slapi_Value**)oneval, &keyvals, LDAP_FILTER_EQUALITY ) != 0 /* jcm cast */
	    || keyvals == NULL
	    || keyvals[0] == NULL )
	{
		LDAPDebug( LDAP_DEBUG_ANY, "valuetree_find_and_replace: "
		    "slapi_attr_values2keys_sv failed for type %s\n",
		    a->a_type, 0, 0 );
		return( LDAP_OPERATIONS_ERROR );
	}

	tmpvain.index = 0;
	tmpvain.sval = keyvals[0];
	vaip = (valuetree_node *)avl_find( valuetree, &tmpvain, valuetree_node_cmp );

	if ( keyvals != NULL )
	{
		valuearray_free( &keyvals );
	}

	if (vaip == NULL)
	{
		return( LDAP_NO_SUCH_ATTRIBUTE );
	}
	else
	{
		*index= vaip->index;
	}

	return( LDAP_SUCCESS );
}
Esempio n. 5
0
/* quickly throw away any old contents of this valueset, and stick in the
 * new ones.
 *
 * return value: LDAP_SUCCESS - OK
 *             : LDAP_OPERATIONS_ERROR - duplicated values given
 */
int
valueset_replace(Slapi_Attr *a, Slapi_ValueSet *vs, Slapi_Value **valstoreplace)
{
    int rc = LDAP_SUCCESS;
    int numberofvalstoreplace= valuearray_count(valstoreplace);
    /* verify the given values are not duplicated.
       if replacing with one value, no need to check.  just replace it.
     */
    if (numberofvalstoreplace > 1)
    {
        Avlnode *vtree = NULL;
        rc = valuetree_add_valuearray( a, valstoreplace, &vtree, NULL );
        valuetree_free(&vtree);
        if ( LDAP_SUCCESS != rc &&
             /* bz 247413: don't override LDAP_TYPE_OR_VALUE_EXISTS */
             LDAP_TYPE_OR_VALUE_EXISTS != rc )
        {
            /* There were already duplicate values in the value set */
            rc = LDAP_OPERATIONS_ERROR;
        }
    }

    if ( rc == LDAP_SUCCESS )
    {
        /* values look good - replace the values in the attribute */
        if(!valuearray_isempty(vs->va))
        {
            /* remove old values */
            slapi_valueset_done(vs);
        }
        /* we now own valstoreplace */
        vs->va = valstoreplace;
    }
    else
    {
        /* caller expects us to own valstoreplace - since we cannot
           use them, just delete them */
        valuearray_free(&valstoreplace);
    }
    return rc;
}
Esempio n. 6
0
/* this function takes SLAPI_PLUGIN_MR_VALUES as struct berval ** and
   returns SLAPI_PLUGIN_MR_KEYS as struct berval **
*/
static int
mr_wrap_mr_index_fn(Slapi_PBlock* pb)
{
	int rc = -1;
	struct berval **in_vals = NULL;
	struct berval **out_vals = NULL;
	struct mr_private *mrpriv = NULL;
	Slapi_Value **in_vals_sv = NULL;
	Slapi_Value **out_vals_sv = NULL;

	slapi_pblock_get(pb, SLAPI_PLUGIN_MR_VALUES, &in_vals); /* get bervals */
	/* convert bervals to sv ary */
	valuearray_init_bervalarray(in_vals, &in_vals_sv);
	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_VALUES, in_vals_sv); /* use sv */
	rc = mr_wrap_mr_index_sv_fn(pb);
	/* clean up in_vals_sv */
	valuearray_free(&in_vals_sv);
	/* restore old in_vals */
	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_VALUES, in_vals);
	/* get result sv keys */
	slapi_pblock_get(pb, SLAPI_PLUGIN_MR_KEYS, &out_vals_sv);
	/* convert to bvec */
	valuearray_get_bervalarray(out_vals_sv, &out_vals);
	/* NOTE: mrpriv owns out_vals_sv (mpriv->sva) - will
	   get freed by mr_private_indexer_done() */
	/* we have to save out_vals to free next time or during destroy */
	slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &mrpriv);

	/* In case SLAPI_PLUGIN_OBJECT is not set 
	 * (e.g. custom index/filter create function did not initialize it
	 */
	if (mrpriv) {
		mr_private_indexer_done(mrpriv); /* free old vals, if any */
		mrpriv->bva = out_vals; /* save pointer for later */
	}
	/* set return value berval array for caller */
	slapi_pblock_set(pb, SLAPI_PLUGIN_MR_KEYS, out_vals);

	return rc;
}
Esempio n. 7
0
File: add.c Progetto: Firstyear/ds
/* Code shared between regular and internal add operation */
static void op_shared_add (Slapi_PBlock *pb)
{
	Slapi_Operation *operation;
	Slapi_Entry	*e, *pse;
	Slapi_Backend *be = NULL;
	int	err;
	int internal_op, repl_op, legacy_op, lastmod;
	char *pwdtype = NULL;
	Slapi_Attr *attr = NULL;
	Slapi_Entry *referral;
	char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE];
	struct slapdplugin  *p = NULL;
	char *proxydn = NULL;
	char *proxystr = NULL;
	int proxy_err = LDAP_SUCCESS;
	char *errtext = NULL;
	Slapi_DN *sdn = NULL;
	passwdPolicy *pwpolicy;

	slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
	slapi_pblock_get (pb, SLAPI_ADD_ENTRY, &e);
	slapi_pblock_get (pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op);	
	slapi_pblock_get (pb, SLAPI_IS_LEGACY_REPLICATED_OPERATION, &legacy_op);
	internal_op= operation_is_flag_set(operation, OP_FLAG_INTERNAL);
	pwpolicy = new_passwdPolicy(pb, slapi_entry_get_dn(e));

	/* target spec is used to decide which plugins are applicable for the operation */
	operation_set_target_spec (operation, slapi_entry_get_sdn (e));

	if ((err = slapi_entry_add_rdn_values(e)) != LDAP_SUCCESS) 
	{
	  send_ldap_result(pb, err, NULL, "failed to add RDN values", 0, NULL);
	  goto done;
	}

	/* get the proxy auth dn if the proxy auth control is present */
	proxy_err = proxyauth_get_dn(pb, &proxydn, &errtext);

	if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_ACCESS))
	{
		if (proxydn)
		{
			proxystr = slapi_ch_smprintf(" authzid=\"%s\"", proxydn);
		}

		if ( !internal_op )
		{
			slapi_log_access(LDAP_DEBUG_STATS, "conn=%" NSPRIu64 " op=%d ADD dn=\"%s\"%s\n",
							 pb->pb_conn->c_connid,
							 operation->o_opid,
							 slapi_entry_get_dn_const(e),
							 proxystr ? proxystr : "");
		}
		else
		{
			slapi_log_access(LDAP_DEBUG_ARGS, "conn=%s op=%d ADD dn=\"%s\"\n",
							 LOG_INTERNAL_OP_CON_ID,
							 LOG_INTERNAL_OP_OP_ID,
							 slapi_entry_get_dn_const(e));
		}
	}

	/* If we encountered an error parsing the proxy control, return an error
	 * to the client.  We do this here to ensure that we log the operation first. */
	if (proxy_err != LDAP_SUCCESS)
	{
		send_ldap_result(pb, proxy_err, NULL, errtext, 0, NULL);
		goto done;
	}

	/*
	 * We could be serving multiple database backends.  Select the
	 * appropriate one.
	 */
	if ((err = slapi_mapping_tree_select(pb, &be, &referral, errorbuf, sizeof(errorbuf))) != LDAP_SUCCESS) {
		send_ldap_result(pb, err, NULL, errorbuf, 0, NULL);
		be = NULL;
		goto done;
	}

	if (referral)
	{
		int managedsait;

		slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
		if (managedsait)
		{
			send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
							 "cannot update referral", 0, NULL);
			slapi_entry_free(referral);
			goto done;
		}
	
		slapi_pblock_set(pb, SLAPI_TARGET_SDN, (void*)operation_get_target_spec (operation));
		send_referrals_from_entry(pb,referral);
		slapi_entry_free(referral);
		goto done;
	}

	if (!slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA)) {
		Slapi_Value **unhashed_password_vals = NULL;
		Slapi_Value **present_values = NULL;

		/* Setting unhashed password to the entry extension. */
		if (repl_op) {
			/* replicated add ==> get unhashed pw from entry, if any.
			 * set it to the extension */
			slapi_entry_attr_find(e, PSEUDO_ATTR_UNHASHEDUSERPASSWORD, &attr);
			if (attr) {
				present_values = attr_get_present_values(attr);
				valuearray_add_valuearray(&unhashed_password_vals,
				                          present_values, 0);
#if !defined(USE_OLD_UNHASHED)
			 	/* and remove it from the entry. */
				slapi_entry_attr_delete(e, PSEUDO_ATTR_UNHASHEDUSERPASSWORD);
#endif
			}
		} else {
			/* ordinary add ==>
			 * get unhashed pw from userpassword before encrypting it */
			/* look for user password attribute */
			slapi_entry_attr_find(e, SLAPI_USERPWD_ATTR, &attr);
			if (attr) {
				Slapi_Value **vals = NULL;

				/* Set the backend in the pblock. 
				 * The slapi_access_allowed function
				 * needs this set to work properly. */
				slapi_pblock_set(pb, SLAPI_BACKEND,
				                 slapi_be_select(slapi_entry_get_sdn_const(e)));

				/* Check ACI before checking password syntax */
				if ((err = slapi_access_allowed(pb, e, SLAPI_USERPWD_ATTR, NULL,
				                              SLAPI_ACL_ADD)) != LDAP_SUCCESS) {
					send_ldap_result(pb, err, NULL,
					                 "Insufficient 'add' privilege to the "
					                 "'userPassword' attribute", 0, NULL);
					goto done;
				}

				/*
				 * Check password syntax, unless this is a pwd admin/rootDN
				 */
				present_values = attr_get_present_values(attr);
				if (!pw_is_pwp_admin(pb, pwpolicy) &&
				    check_pw_syntax(pb, slapi_entry_get_sdn_const(e),
				                    present_values, NULL, e, 0) != 0) {
					/* error result is sent from check_pw_syntax */
					goto done;
				}
				/* pw syntax is valid */
				valuearray_add_valuearray(&unhashed_password_vals,
				                          present_values, 0);
				valuearray_add_valuearray(&vals, present_values, 0);
				pw_encodevals_ext(pb, slapi_entry_get_sdn (e), vals);
				add_password_attrs(pb, operation, e);
				slapi_entry_attr_replace_sv(e, SLAPI_USERPWD_ATTR, vals);
				valuearray_free(&vals);
#if defined(USE_OLD_UNHASHED)
				/* Add the unhashed password pseudo-attribute to the entry */
				pwdtype = 
				  slapi_attr_syntax_normalize(PSEUDO_ATTR_UNHASHEDUSERPASSWORD);
				slapi_entry_add_values_sv(e, pwdtype, unhashed_password_vals);
#endif
			}
		}
		if (unhashed_password_vals &&
		    (SLAPD_UNHASHED_PW_OFF != config_get_unhashed_pw_switch())) {
			/* unhashed_password_vals is consumed if successful. */
			err = slapi_pw_set_entry_ext(e, unhashed_password_vals,
			                             SLAPI_EXT_SET_ADD);
			if (err) {
				valuearray_free(&unhashed_password_vals);
			}
		}

#if defined(THISISTEST)
		{
			/* test code to retrieve an unhashed pw from the entry extention &
			 * PSEUDO_ATTR_UNHASHEDUSERPASSWORD attribute */
			char *test_str = slapi_get_first_clear_text_pw(e);
			if (test_str) {
				slapi_log_err(SLAPI_LOG_ERR,
				              "Value from extension: %s\n", test_str);
				slapi_ch_free_string(&test_str);
			}
#if defined(USE_OLD_UNHASHED)
			test_str = slapi_entry_attr_get_charptr(e,
			                                  PSEUDO_ATTR_UNHASHEDUSERPASSWORD);
			if (test_str) {
				slapi_log_err(SLAPI_LOG_ERR,
				              "Value from attr: %s\n", test_str);
				slapi_ch_free_string(&test_str);
			}
#endif /* USE_OLD_UNHASHED */
		}
#endif /* THISISTEST */

        /* look for multiple backend local credentials or replication local credentials */
        for ( p = get_plugin_list(PLUGIN_LIST_REVER_PWD_STORAGE_SCHEME); p != NULL && !repl_op;
            p = p->plg_next )
        {
            char *L_attr = NULL;
            int i=0;

            /* Get the appropriate decoding function */
            for ( L_attr = p->plg_argv[i]; i<p->plg_argc; L_attr = p->plg_argv[++i])
            {
                /* look for multiple backend local credentials or replication local credentials */
                char *L_normalized = slapi_attr_syntax_normalize(L_attr);
                slapi_entry_attr_find(e, L_normalized, &attr);
                if (attr)
                {
                    Slapi_Value **present_values = NULL;
                    Slapi_Value **vals = NULL;

                    present_values= attr_get_present_values(attr);

                    valuearray_add_valuearray(&vals, present_values, 0);
                    pw_rever_encode(vals, L_normalized);
                    slapi_entry_attr_replace_sv(e, L_normalized, vals);
                    valuearray_free(&vals);
                }
                if (L_normalized)
                    slapi_ch_free ((void**)&L_normalized);
            }
        }
    }

	slapi_pblock_set(pb, SLAPI_BACKEND, be);

	if (!repl_op)
	{
		/* can get lastmod only after backend is selected */
		slapi_pblock_get(pb, SLAPI_BE_LASTMOD, &lastmod);

		if (lastmod && add_created_attrs(pb, e) != 0)
		{
			send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
				"cannot insert computed attributes", 0, NULL);
			goto done;
		}
		/* expand objectClass values to reflect the inheritance hierarchy */
		slapi_schema_expand_objectclasses( e );
	}

    /* uniqueid needs to be generated for entries added during legacy replication */
    if (legacy_op){
    	if (add_uniqueid(e) != UID_SUCCESS)
    	{
    		send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
    				"cannot insert computed attributes", 0, NULL);
    		goto done;
    	}
    }

	/*
	 * call the pre-add plugins. if they succeed, call
	 * the backend add function. then call the post-add
	 * plugins.
	 */
	
	sdn = slapi_sdn_dup(slapi_entry_get_sdn_const(e));
	slapi_pblock_set(pb, SLAPI_ADD_TARGET_SDN, (void *)sdn);
	if (plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_PRE_ADD_FN :
	                        SLAPI_PLUGIN_PRE_ADD_FN) == SLAPI_PLUGIN_SUCCESS)
	{
		int	rc;
		Slapi_Entry	*ec;
		Slapi_DN *add_target_sdn = NULL;
		Slapi_Entry *save_e = NULL;

		slapi_pblock_set(pb, SLAPI_PLUGIN, be->be_database);
		set_db_default_result_handlers(pb);
		/* because be_add frees the entry */
		ec = slapi_entry_dup(e);
		add_target_sdn = slapi_sdn_dup(slapi_entry_get_sdn_const(ec));
		slapi_pblock_get(pb, SLAPI_ADD_TARGET_SDN, &sdn);
		slapi_sdn_free(&sdn);
		slapi_pblock_set(pb, SLAPI_ADD_TARGET_SDN, add_target_sdn);
		
		if (be->be_add != NULL)
		{
			rc = (*be->be_add)(pb);
			/* backend may change this if errors and not consumed */
			slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &save_e);
			slapi_pblock_set(pb, SLAPI_ADD_ENTRY, ec);
			if (rc == 0)
			{
				/* acl is not enabled for internal operations */
				/* don't update aci store for remote acis     */
				if ((!internal_op) && 
					(!slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA)))
				{
					plugin_call_acl_mods_update (pb, SLAPI_OPERATION_ADD);
				}

				if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_AUDIT))
				{ 
					write_audit_log_entry(pb); /* Record the operation in the audit log */
				}

				slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &pse);
				do_ps_service(pse, NULL, LDAP_CHANGETYPE_ADD, 0);
				/* 
				 * If be_add succeeded, then e is consumed except the resurrect case.
				 * If it is resurrect, the corresponding tombstone entry is resurrected
				 * and put into the cache.
				 * Otherwise, we set e to NULL to prevent freeing it ourselves.
				 */
				if (operation_is_flag_set(operation,OP_FLAG_RESURECT_ENTRY) && save_e) {
					e = save_e;
				} else {
					e = NULL;
				}
			}
			else
			{
				/* PR_ASSERT(!save_e); save_e is supposed to be freed in the backend.  */
				e = save_e;
				if (rc == SLAPI_FAIL_DISKFULL)
				{
					operation_out_of_disk_space();
					goto done;
				}
				/* If the disk is full we don't want to make it worse ... */
				if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_AUDIT))
				{ 
					write_auditfail_log_entry(pb); /* Record the operation in the audit log */
				}
			}
		}
		else
		{
			send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
							 "Function not implemented", 0, NULL);
		}
		slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &rc);
		plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_POST_ADD_FN : 
							SLAPI_PLUGIN_POST_ADD_FN);
		slapi_entry_free(ec);
	}
	slapi_pblock_get(pb, SLAPI_ADD_TARGET_SDN, &sdn);
	slapi_sdn_free(&sdn);

done:
	if (be)
		slapi_be_Unlock(be);
	slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &pse);
	slapi_entry_free(pse);
	slapi_ch_free((void **)&operation->o_params.p.p_add.parentuniqueid);
	slapi_entry_free(e);
	slapi_pblock_set(pb, SLAPI_ADD_ENTRY, NULL);
	slapi_ch_free((void**)&pwdtype);
	slapi_ch_free_string(&proxydn);
	slapi_ch_free_string(&proxystr);
}
Esempio n. 8
0
/*
 * Remove an array of values from a value set.
 * The removed values are passed back in an array.
 *
 * Flags
 *  SLAPI_VALUE_FLAG_PRESERVECSNSET - csnset in the value set is duplicated and
 *                                    preserved in the matched element of the
 *                                    array of values.
 *  SLAPI_VALUE_FLAG_IGNOREERROR - ignore an error: Couldn't find the value to
 *                                 be deleted.
 *  SLAPI_VALUE_FLAG_USENEWVALUE - replace the value between the value set and
 *                                 the matched element of the array of values
 *                                 (used by entry_add_present_values_wsi).
 *
 * Returns
 *  LDAP_SUCCESS - OK.
 *  LDAP_NO_SUCH_ATTRIBUTE - A value to be deleted was not in the value set.
 *  LDAP_OPERATIONS_ERROR - Something very bad happened.
 */
int
valueset_remove_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slapi_Value **valuestodelete, int flags, Slapi_Value ***va_out)
{
	int rc= LDAP_SUCCESS;
	if(!valuearray_isempty(vs->va))
	{
		int numberofvaluestodelete= valuearray_count(valuestodelete);
		struct valuearrayfast vaf_out;
		if ( va_out )
		{
			valuearrayfast_init(&vaf_out,*va_out);
		}

		/*
		 * If there are more then one values, build an AVL tree to check
		 * the duplicated values.
		 */
		if ( numberofvaluestodelete > 1 )
		{
			/*
			 * Several values to delete: first build an AVL tree that
			 * holds all of the existing values and use that to find
			 * the values we want to delete.
			 */
			Avlnode	*vtree = NULL;
			int numberofexistingvalues= slapi_valueset_count(vs);
			rc= valuetree_add_valuearray( a, vs->va, &vtree, NULL );
			if ( rc!=LDAP_SUCCESS )
			{
				/*
				 * failed while constructing AVL tree of existing
				 * values... something bad happened.
				 */
				rc= LDAP_OPERATIONS_ERROR;
			}
			else
			{
				int i;
				/*
				 * find and mark all the values that are to be deleted
				 */
				for ( i = 0; rc == LDAP_SUCCESS && valuestodelete[i] != NULL; ++i )
				{
					int index= 0;
					rc = valuetree_find( a, valuestodelete[i], vtree, &index );
					if(rc==LDAP_SUCCESS)
					{
						if(vs->va[index]!=NULL)
						{
							/* Move the value to be removed to the out array */
							if ( va_out )
							{
								if (vs->va[index]->v_csnset &&
									(flags & (SLAPI_VALUE_FLAG_PRESERVECSNSET|
                                              SLAPI_VALUE_FLAG_USENEWVALUE)))
								{
									valuestodelete[i]->v_csnset = csnset_dup (vs->va[index]->v_csnset);
								}
								if (flags & SLAPI_VALUE_FLAG_USENEWVALUE)
								{
									valuearrayfast_add_value_passin(&vaf_out,valuestodelete[i]);
									valuestodelete[i] = vs->va[index];
									vs->va[index] = NULL;
								}
								else
								{
									valuearrayfast_add_value_passin(&vaf_out,vs->va[index]);
									vs->va[index] = NULL;
								}
							}
							else
							{
								if (flags & SLAPI_VALUE_FLAG_PRESERVECSNSET)
								{
									valuestodelete[i]->v_csnset = vs->va[index]->v_csnset;
									vs->va[index]->v_csnset = NULL;
								}
								slapi_value_free ( & vs->va[index] );
							}
						}
						else
						{
							/* We already deleted this value... */
							if((flags & SLAPI_VALUE_FLAG_IGNOREERROR) == 0)
							{
								/* ...that's an error. */
								rc= LDAP_NO_SUCH_ATTRIBUTE;
							}
						}
					}
					else
					{
						/* Couldn't find the value to be deleted */
						if(rc==LDAP_NO_SUCH_ATTRIBUTE && (flags & SLAPI_VALUE_FLAG_IGNOREERROR ))
						{
							rc= LDAP_SUCCESS;
						}
					}
				}
				valuetree_free( &vtree );

				if ( rc != LDAP_SUCCESS )
				{
					LDAPDebug( LDAP_DEBUG_ANY,"could not find value %d for attr %s (%s)\n", i-1, a->a_type, ldap_err2string( rc ));
				}
				else
				{
					/* Shunt up all the remaining values to cover the deleted ones. */
					valuearray_compress(vs->va,numberofexistingvalues);
				}
			}
		}
		else
		{
			/* We delete one or no value, so we use brute force. */
			int i;
			for ( i = 0; rc==LDAP_SUCCESS && valuestodelete[i] != NULL; ++i )
			{
				Slapi_Value *found= valueset_remove_value(a, vs, valuestodelete[i]);
				if(found!=NULL)
				{
					if ( va_out )
					{
						if (found->v_csnset &&
							(flags & (SLAPI_VALUE_FLAG_PRESERVECSNSET|
                                      SLAPI_VALUE_FLAG_USENEWVALUE)))
						{
							valuestodelete[i]->v_csnset = csnset_dup (found->v_csnset);
						}
						if (flags & SLAPI_VALUE_FLAG_USENEWVALUE)
						{
							valuearrayfast_add_value_passin(&vaf_out,valuestodelete[i]);
							valuestodelete[i] = found;
						}
						else
						{
							valuearrayfast_add_value_passin(&vaf_out,found);
						}
					}
					else
					{
						if (flags & SLAPI_VALUE_FLAG_PRESERVECSNSET)
						{
							valuestodelete[i]->v_csnset = found->v_csnset;
							found->v_csnset = NULL;
						}
						slapi_value_free ( & found );
					}
				}
				else
				{
					if((flags & SLAPI_VALUE_FLAG_IGNOREERROR) == 0)
					{
						LDAPDebug( LDAP_DEBUG_ARGS,"could not find value %d for attr %s\n", i-1, a->a_type, 0 );
						rc= LDAP_NO_SUCH_ATTRIBUTE;
					}
				}
			}
		}
		if ( va_out )
		{
			*va_out= vaf_out.va;
			if(rc!=LDAP_SUCCESS)
			{
				valuearray_free(va_out);
			}
		}
	}
	return rc;
}