diff --git a/servers/slapd/acl.c b/servers/slapd/acl.c index 99bb8364e73064d9a6e7f87be03e046aa062661e..ef85ad2614e8ab6617bf1f04bdcdf6a1dc4b502b 100644 --- a/servers/slapd/acl.c +++ b/servers/slapd/acl.c @@ -1990,8 +1990,15 @@ acl_check_modlist( /* fall thru to check value to add */ case LDAP_MOD_ADD: + case SLAP_MOD_ADD_IF_NOT_PRESENT: assert( mlist->sml_values != NULL ); + if ( mlist->sml_op == SLAP_MOD_ADD_IF_NOT_PRESENT + && attr_find( e->e_attrs, mlist->sml_desc ) ) + { + break; + } + for ( bv = mlist->sml_nvalues ? mlist->sml_nvalues : mlist->sml_values; bv->bv_val != NULL; bv++ ) @@ -2008,6 +2015,7 @@ acl_check_modlist( break; case LDAP_MOD_DELETE: + case SLAP_MOD_SOFTDEL: if ( mlist->sml_values == NULL ) { if ( ! access_allowed( op, e, mlist->sml_desc, NULL, diff --git a/servers/slapd/back-bdb/modify.c b/servers/slapd/back-bdb/modify.c index c5c5e6a9b81c7ddd16ad18eeb119b2b71d624182..896c06fb390f765b4e6c7bb96b53d90a543e551e 100644 --- a/servers/slapd/back-bdb/modify.c +++ b/servers/slapd/back-bdb/modify.c @@ -215,6 +215,56 @@ int bdb_modify_internal( } break; + case SLAP_MOD_SOFTDEL: + Debug(LDAP_DEBUG_ARGS, + "bdb_modify_internal: softdel %s\n", + mod->sm_desc->ad_cname.bv_val, 0, 0); + /* Avoid problems in index_delete_mods() + * We need to add index if necessary. + */ + mod->sm_op = LDAP_MOD_DELETE; + + err = modify_delete_values( e, mod, get_permissiveModify(op), + text, textbuf, textlen ); + + mod->sm_op = SLAP_MOD_SOFTDEL; + + if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) { + err = LDAP_SUCCESS; + } + + if( err != LDAP_SUCCESS ) { + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n", + err, *text, 0); + } + break; + + case SLAP_MOD_ADD_IF_NOT_PRESENT: + if ( attr_find( e->e_attrs, mod->sm_desc ) != NULL ) { + /* skip */ + err = LDAP_SUCCESS; + break; + } + + Debug(LDAP_DEBUG_ARGS, + "bdb_modify_internal: add_if_not_present %s\n", + mod->sm_desc->ad_cname.bv_val, 0, 0); + /* Avoid problems in index_add_mods() + * We need to add index if necessary. + */ + mod->sm_op = LDAP_MOD_ADD; + + err = modify_add_values( e, mod, get_permissiveModify(op), + text, textbuf, textlen ); + + mod->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT; + + if( err != LDAP_SUCCESS ) { + Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n", + err, *text, 0); + } + break; + default: Debug(LDAP_DEBUG_ANY, "bdb_modify_internal: invalid op %d\n", mod->sm_op, 0, 0); diff --git a/servers/slapd/back-ldif/ldif.c b/servers/slapd/back-ldif/ldif.c index e4ff2fe8908c71257770c21360d6e81e6acf743b..5e7cdc9d3acb0a116802118edebe3e1058f1ebf5 100644 --- a/servers/slapd/back-ldif/ldif.c +++ b/servers/slapd/back-ldif/ldif.c @@ -1198,6 +1198,31 @@ apply_modify_to_entry( rc = LDAP_SUCCESS; } break; + + case SLAP_MOD_SOFTDEL: + mods->sm_op = LDAP_MOD_DELETE; + rc = modify_delete_values(entry, mods, + get_permissiveModify(op), + &rs->sr_text, textbuf, + sizeof( textbuf ) ); + mods->sm_op = SLAP_MOD_SOFTDEL; + if (rc == LDAP_NO_SUCH_ATTRIBUTE) { + rc = LDAP_SUCCESS; + } + break; + + case SLAP_MOD_ADD_IF_NOT_PRESENT: + if ( attr_find( entry->e_attrs, mods->sm_desc ) ) { + rc = LDAP_SUCCESS; + break; + } + mods->sm_op = LDAP_MOD_ADD; + rc = modify_add_values(entry, mods, + get_permissiveModify(op), + &rs->sr_text, textbuf, + sizeof( textbuf ) ); + mods->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT; + break; } if(rc != LDAP_SUCCESS) break; } diff --git a/servers/slapd/back-ndb/modify.cpp b/servers/slapd/back-ndb/modify.cpp index 188826140cc3ae399f7eddad6276778b8f4daa51..76b0ce71f668dc278dba5efa0b61a33979db77d4 100644 --- a/servers/slapd/back-ndb/modify.cpp +++ b/servers/slapd/back-ndb/modify.cpp @@ -300,6 +300,49 @@ int ndb_modify_internal( } break; + case SLAP_MOD_SOFTDEL: + Debug(LDAP_DEBUG_ARGS, + "ndb_modify_internal: softdel %s\n", + mod->sm_desc->ad_cname.bv_val, 0, 0); + mod->sm_op = LDAP_MOD_DELETE; + + rc = modify_delete_values( NA->e, mod, get_permissiveModify(op), + text, textbuf, textlen ); + + mod->sm_op = SLAP_MOD_SOFTDEL; + + if ( rc == LDAP_NO_SUCH_ATTRIBUTE) { + rc = LDAP_SUCCESS; + } + + if( rc != LDAP_SUCCESS ) { + Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n", + rc, *text, 0); + } + break; + + case SLAP_MOD_ADD_IF_NOT_PRESENT: + Debug(LDAP_DEBUG_ARGS, + "ndb_modify_internal: add_if_not_present %s\n", + mod->sm_desc->ad_cname.bv_val, 0, 0); + if ( attr_find( NA->e->e_attrs, mod->sm_desc ) ) { + rc = LDAP_SUCCESS; + break; + } + + mod->sm_op = LDAP_MOD_ADD; + + rc = modify_add_values( NA->e, mod, get_permissiveModify(op), + text, textbuf, textlen ); + + mod->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT; + + if( rc != LDAP_SUCCESS ) { + Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n", + rc, *text, 0); + } + break; + default: Debug(LDAP_DEBUG_ANY, "ndb_modify_internal: invalid op %d\n", mod->sm_op, 0, 0); diff --git a/servers/slapd/back-sql/add.c b/servers/slapd/back-sql/add.c index 5e26cae2d4b0850a75e4d0eb0533e9b7c3d9ef31..af617000fb4c85743a7dbb9b53377ddd1f534dfe 100644 --- a/servers/slapd/back-sql/add.c +++ b/servers/slapd/back-sql/add.c @@ -389,6 +389,7 @@ del_all: */ case LDAP_MOD_ADD: /* case SLAP_MOD_SOFTADD: */ + /* case SLAP_MOD_ADD_IF_NOT_PRESENT: */ add_only:; if ( at->bam_add_proc == NULL ) { Debug( LDAP_DEBUG_TRACE, @@ -541,6 +542,7 @@ add_only:; break; case LDAP_MOD_DELETE: + /* case SLAP_MOD_SOFTDEL: */ if ( at->bam_delete_proc == NULL ) { Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c index 006647bf23f0ea76d5db4c4bc64b9098a9ee64c7..3a30d1471d2c9e7eb77072473dbeb67df0dc8bc5 100644 --- a/servers/slapd/bconfig.c +++ b/servers/slapd/bconfig.c @@ -5468,7 +5468,9 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, ct = config_find_table( colst, nocs, ml->sml_desc, ca ); switch (ml->sml_op) { case LDAP_MOD_DELETE: - case LDAP_MOD_REPLACE: { + case LDAP_MOD_REPLACE: + case SLAP_MOD_SOFTDEL: + { BerVarray vals = NULL, nvals = NULL; int *idx = NULL; if ( ct && ( ct->arg_type & ARG_NO_DELETE )) { @@ -5507,11 +5509,24 @@ config_modify_internal( CfEntryInfo *ce, Operation *op, SlapReply *rs, ml->sml_values = vals; ml->sml_nvalues = nvals; } + if ( rc == LDAP_NO_SUCH_ATTRIBUTE && ml->sml_op == SLAP_MOD_SOFTDEL ) + { + rc = LDAP_SUCCESS; + } + /* FIXME: check rc before fallthru? */ if ( !vals ) break; - } + } /* FALLTHRU: LDAP_MOD_REPLACE && vals */ + case SLAP_MOD_ADD_IF_NOT_PRESENT: + if ( ml->sml_op == SLAP_MOD_ADD_IF_NOT_PRESENT + && attr_find( e->e_attrs, ml->sml_desc ) ) + { + rc = LDAP_SUCCESS; + break; + } + case LDAP_MOD_ADD: case SLAP_MOD_SOFTADD: { int mop = ml->sml_op; diff --git a/servers/slapd/modify.c b/servers/slapd/modify.c index 32a39d97fb9be2b565c1e88bc8f2720881043374..14b6b37305ac2f5488f52ea352eeb33b4d50d678 100644 --- a/servers/slapd/modify.c +++ b/servers/slapd/modify.c @@ -879,6 +879,7 @@ void slap_mods_opattrs( for ( modtail = modsp; *modtail; modtail = &(*modtail)->sml_next ) { if ( (*modtail)->sml_op != LDAP_MOD_ADD && (*modtail)->sml_op != SLAP_MOD_SOFTADD && + (*modtail)->sml_op != SLAP_MOD_ADD_IF_NOT_PRESENT && (*modtail)->sml_op != LDAP_MOD_REPLACE ) { continue; diff --git a/servers/slapd/overlays/constraint.c b/servers/slapd/overlays/constraint.c index b3dbbae5c4d64b331c0f7ad3348a7647700fc403..fcb2830ee88cbf2e45d344ba3537fdfac10ee36e 100644 --- a/servers/slapd/overlays/constraint.c +++ b/servers/slapd/overlays/constraint.c @@ -1022,6 +1022,29 @@ constraint_update( Operation *op, SlapReply *rs ) } break; + case SLAP_MOD_SOFTDEL: + mod->sm_op = LDAP_MOD_ADD; + err = modify_delete_values( target_entry_copy, + mod, get_permissiveModify(op), + &text, textbuf, textlen ); + mod->sm_op = SLAP_MOD_SOFTDEL; + if ( err == LDAP_NO_SUCH_ATTRIBUTE ) { + err = LDAP_SUCCESS; + } + break; + + case SLAP_MOD_ADD_IF_NOT_PRESENT: + if ( attr_find( target_entry_copy->e_attrs, mod->sm_desc ) ) { + err = LDAP_SUCCESS; + break; + } + mod->sm_op = LDAP_MOD_ADD; + err = modify_add_values( target_entry_copy, + mod, get_permissiveModify(op), + &text, textbuf, textlen ); + mod->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT; + break; + default: err = LDAP_OTHER; break; diff --git a/servers/slapd/overlays/dds.c b/servers/slapd/overlays/dds.c index 6185ad8d52bd226e81642f634048ae565a5efa14..56d299fdb0142148d5c7df7895458bab568b3100 100644 --- a/servers/slapd/overlays/dds.c +++ b/servers/slapd/overlays/dds.c @@ -587,6 +587,7 @@ dds_op_modify( Operation *op, SlapReply *rs ) switch ( mod->sml_op ) { case LDAP_MOD_DELETE: + case SLAP_MOD_SOFTDEL: /* FIXME? */ if ( mod->sml_values != NULL ) { if ( BER_BVISEMPTY( &bv_entryTtl ) || !bvmatch( &bv_entryTtl, &mod->sml_values[ 0 ] ) ) @@ -611,8 +612,9 @@ dds_op_modify( Operation *op, SlapReply *rs ) entryTtl = -1; /* fallthru */ - case SLAP_MOD_SOFTADD: /* FIXME? */ case LDAP_MOD_ADD: + case SLAP_MOD_SOFTADD: /* FIXME? */ + case SLAP_MOD_ADD_IF_NOT_PRESENT: /* FIXME? */ assert( mod->sml_values != NULL ); assert( BER_BVISNULL( &mod->sml_values[ 1 ] ) ); diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 80509e11dfffa4b68d7fde969088ae71c094c2e1..745402aa1ccf544bf7dd8cfcb8e3272f359e7887 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -110,12 +110,25 @@ LDAP_BEGIN_DECL # define SLAP_STRING_UNKNOWN "unknown" #endif /* ! TCP Wrappers */ -/* LDAPMod.mod_op value ===> Must be kept in sync with ldap.h! - * This is a value used internally by the backends. It is needed to allow - * adding values that already exist without getting an error as required by - * modrdn when the new rdn was already an attribute value itself. +/* LDAPMod.mod_op value ===> Must be kept in sync with ldap.h! */ +/* These values are used internally by the backends. */ +/* SLAP_MOD_SOFTADD allows adding values that already exist without getting + * an error as required by modrdn when the new rdn was already an attribute + * value itself. + */ +#define SLAP_MOD_SOFTADD 0x1000 +/* SLAP_MOD_SOFTDEL allows deleting values if they exist without getting + * an error otherwise. + */ +#define SLAP_MOD_SOFTDEL 0x1001 +/* SLAP_MOD_ADD_IF_NOT_PRESENT allows adding values unless the attribute + * is already present without getting an error. + */ +#define SLAP_MOD_ADD_IF_NOT_PRESENT 0x1002 +/* SLAP_MOD_DEL_IF_PRESENT allows deleting values if the attribute + * is present, without getting an error otherwise. + * The semantics can be obtained using SLAP_MOD_SOFTDEL with NULL values. */ -#define SLAP_MOD_SOFTADD 0x1000 #define MAXREMATCHES (100)