int mdb_modify_internal( Operation *op, MDB_txn *tid, Modifications *modlist, Entry *e, const char **text, char *textbuf, size_t textlen ) { int rc, err; Modification *mod; Modifications *ml; Attribute *save_attrs; Attribute *ap; int glue_attr_delete = 0; int got_delete; Debug( LDAP_DEBUG_TRACE, "mdb_modify_internal: 0x%08lx: %s\n", e->e_id, e->e_dn, 0); if ( !acl_check_modlist( op, e, modlist )) { return LDAP_INSUFFICIENT_ACCESS; } /* save_attrs will be disposed of by caller */ save_attrs = e->e_attrs; e->e_attrs = attrs_dup( e->e_attrs ); for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { int match; mod = &ml->sml_mod; switch( mod->sm_op ) { case LDAP_MOD_ADD: case LDAP_MOD_REPLACE: if ( mod->sm_desc == slap_schema.si_ad_structuralObjectClass ) { value_match( &match, slap_schema.si_ad_structuralObjectClass, slap_schema.si_ad_structuralObjectClass-> ad_type->sat_equality, SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, &mod->sm_values[0], &scbva[0], text ); if ( !match ) glue_attr_delete = 1; } } if ( glue_attr_delete ) break; } if ( glue_attr_delete ) { Attribute **app = &e->e_attrs; while ( *app != NULL ) { if ( !is_at_operational( (*app)->a_desc->ad_type )) { Attribute *save = *app; *app = (*app)->a_next; attr_free( save ); continue; } app = &(*app)->a_next; } } for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { mod = &ml->sml_mod; got_delete = 0; switch ( mod->sm_op ) { case LDAP_MOD_ADD: Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: add %s\n", mod->sm_desc->ad_cname.bv_val, 0, 0); err = modify_add_values( e, mod, get_permissiveModify(op), text, textbuf, textlen ); if( err != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", err, *text, 0); } break; case LDAP_MOD_DELETE: if ( glue_attr_delete ) { err = LDAP_SUCCESS; break; } Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: delete %s\n", mod->sm_desc->ad_cname.bv_val, 0, 0); err = modify_delete_values( e, mod, get_permissiveModify(op), text, textbuf, textlen ); if( err != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", err, *text, 0); } else { got_delete = 1; } break; case LDAP_MOD_REPLACE: Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: replace %s\n", mod->sm_desc->ad_cname.bv_val, 0, 0); err = modify_replace_values( e, mod, get_permissiveModify(op), text, textbuf, textlen ); if( err != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", err, *text, 0); } else { got_delete = 1; } break; case LDAP_MOD_INCREMENT: Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: increment %s\n", mod->sm_desc->ad_cname.bv_val, 0, 0); err = modify_increment_values( e, mod, get_permissiveModify(op), text, textbuf, textlen ); if( err != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", err, *text, 0); } else { got_delete = 1; } break; case SLAP_MOD_SOFTADD: Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: softadd %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_SOFTADD; if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) { err = LDAP_SUCCESS; } if( err != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", err, *text, 0); } break; case SLAP_MOD_SOFTDEL: Debug(LDAP_DEBUG_ARGS, "mdb_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_NO_SUCH_ATTRIBUTE ) { err = LDAP_SUCCESS; } if( err != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_ARGS, "mdb_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, "mdb_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, "mdb_modify_internal: %d %s\n", err, *text, 0); } break; default: Debug(LDAP_DEBUG_ANY, "mdb_modify_internal: invalid op %d\n", mod->sm_op, 0, 0); *text = "Invalid modify operation"; err = LDAP_OTHER; Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n", err, *text, 0); } if ( err != LDAP_SUCCESS ) { attrs_free( e->e_attrs ); e->e_attrs = save_attrs; /* unlock entry, delete from cache */ return err; } /* If objectClass was modified, reset the flags */ if ( mod->sm_desc == slap_schema.si_ad_objectClass ) { e->e_ocflags = 0; } if ( glue_attr_delete ) e->e_ocflags = 0; /* check if modified attribute was indexed * but not in case of NOOP... */ if ( !op->o_noop ) { mdb_modify_idxflags( op, mod->sm_desc, got_delete, e->e_attrs, save_attrs ); } } /* check that the entry still obeys the schema */ ap = NULL; rc = entry_schema_check( op, e, save_attrs, get_relax(op), 0, &ap, text, textbuf, textlen ); if ( rc != LDAP_SUCCESS || op->o_noop ) { attrs_free( e->e_attrs ); /* clear the indexing flags */ for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) { ap->a_flags &= ~(SLAP_ATTR_IXADD|SLAP_ATTR_IXDEL); } e->e_attrs = save_attrs; if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "entry failed schema check: %s\n", *text, 0, 0 ); } /* if NOOP then silently revert to saved attrs */ return rc; } /* structuralObjectClass modified! */ if ( ap ) { assert( ap->a_desc == slap_schema.si_ad_structuralObjectClass ); if ( !op->o_noop ) { mdb_modify_idxflags( op, slap_schema.si_ad_structuralObjectClass, 1, e->e_attrs, save_attrs ); } } /* update the indices of the modified attributes */ /* start with deleting the old index entries */ for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) { if ( ap->a_flags & SLAP_ATTR_IXDEL ) { struct berval *vals; Attribute *a2; ap->a_flags &= ~SLAP_ATTR_IXDEL; a2 = attr_find( e->e_attrs, ap->a_desc ); if ( a2 ) { /* need to detect which values were deleted */ int i, j; vals = op->o_tmpalloc( (ap->a_numvals + 1) * sizeof(struct berval), op->o_tmpmemctx ); j = 0; for ( i=0; i < ap->a_numvals; i++ ) { rc = attr_valfind( a2, SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, &ap->a_nvals[i], NULL, op->o_tmpmemctx ); /* Save deleted values */ if ( rc == LDAP_NO_SUCH_ATTRIBUTE ) vals[j++] = ap->a_nvals[i]; } BER_BVZERO(vals+j); } else { /* attribute was completely deleted */ vals = ap->a_nvals; } rc = 0; if ( !BER_BVISNULL( vals )) { rc = mdb_index_values( op, tid, ap->a_desc, vals, e->e_id, SLAP_INDEX_DELETE_OP ); if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "%s: attribute \"%s\" index delete failure\n", op->o_log_prefix, ap->a_desc->ad_cname.bv_val, 0 ); attrs_free( e->e_attrs ); e->e_attrs = save_attrs; } } if ( vals != ap->a_nvals ) op->o_tmpfree( vals, op->o_tmpmemctx ); if ( rc ) return rc; } } /* add the new index entries */ for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) { if (ap->a_flags & SLAP_ATTR_IXADD) { ap->a_flags &= ~SLAP_ATTR_IXADD; rc = mdb_index_values( op, tid, ap->a_desc, ap->a_nvals, e->e_id, SLAP_INDEX_ADD_OP ); if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "%s: attribute \"%s\" index add failure\n", op->o_log_prefix, ap->a_desc->ad_cname.bv_val, 0 ); attrs_free( e->e_attrs ); e->e_attrs = save_attrs; return rc; } } } return rc; }
int ndb_modify_internal( Operation *op, NdbArgs *NA, const char **text, char *textbuf, size_t textlen ) { struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private; Modification *mod; Modifications *ml; Modifications *modlist = op->orm_modlist; NdbAttrInfo **modai, *atmp; const NdbDictionary::Dictionary *myDict; const NdbDictionary::Table *myTable; int got_oc = 0, nmods = 0, nai = 0, i, j; int rc, indexed = 0; Attribute *old = NULL; Debug( LDAP_DEBUG_TRACE, "ndb_modify_internal: 0x%08lx: %s\n", NA->e->e_id, NA->e->e_dn, 0); if ( !acl_check_modlist( op, NA->e, modlist )) { return LDAP_INSUFFICIENT_ACCESS; } old = attrs_dup( NA->e->e_attrs ); for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { mod = &ml->sml_mod; nmods++; switch ( mod->sm_op ) { case LDAP_MOD_ADD: Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: add %s\n", mod->sm_desc->ad_cname.bv_val, 0, 0); rc = modify_add_values( NA->e, mod, get_permissiveModify(op), text, textbuf, textlen ); if( rc != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n", rc, *text, 0); } break; case LDAP_MOD_DELETE: Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: delete %s\n", mod->sm_desc->ad_cname.bv_val, 0, 0); rc = ndb_modify_delete( NA->e, mod, get_permissiveModify(op), text, textbuf, textlen, NULL ); assert( rc != LDAP_TYPE_OR_VALUE_EXISTS ); if( rc != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n", rc, *text, 0); } break; case LDAP_MOD_REPLACE: Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: replace %s\n", mod->sm_desc->ad_cname.bv_val, 0, 0); rc = modify_replace_values( NA->e, mod, get_permissiveModify(op), text, textbuf, textlen ); if( rc != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n", rc, *text, 0); } break; case LDAP_MOD_INCREMENT: Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: increment %s\n", mod->sm_desc->ad_cname.bv_val, 0, 0); rc = modify_increment_values( NA->e, mod, get_permissiveModify(op), text, textbuf, textlen ); if( rc != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n", rc, *text, 0); } break; case SLAP_MOD_SOFTADD: Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: softadd %s\n", mod->sm_desc->ad_cname.bv_val, 0, 0); mod->sm_op = LDAP_MOD_ADD; rc = modify_add_values( NA->e, mod, get_permissiveModify(op), text, textbuf, textlen ); mod->sm_op = SLAP_MOD_SOFTADD; if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) { rc = LDAP_SUCCESS; } if( rc != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n", rc, *text, 0); } 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); *text = "Invalid modify operation"; rc = LDAP_OTHER; Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n", rc, *text, 0); } if ( rc != LDAP_SUCCESS ) { attrs_free( old ); return rc; } /* If objectClass was modified, reset the flags */ if ( mod->sm_desc == slap_schema.si_ad_objectClass ) { NA->e->e_ocflags = 0; got_oc = 1; } } /* check that the entry still obeys the schema */ rc = entry_schema_check( op, NA->e, NULL, get_relax(op), 0, NULL, text, textbuf, textlen ); if ( rc != LDAP_SUCCESS || op->o_noop ) { if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "entry failed schema check: %s\n", *text, 0, 0 ); } attrs_free( old ); return rc; } if ( got_oc ) { rc = ndb_entry_put_info( op->o_bd, NA, 1 ); if ( rc ) { attrs_free( old ); return rc; } } /* apply modifications to DB */ modai = (NdbAttrInfo **)op->o_tmpalloc( nmods * sizeof(NdbAttrInfo*), op->o_tmpmemctx ); /* Get the unique list of modified attributes */ ldap_pvt_thread_rdwr_rlock( &ni->ni_ai_rwlock ); for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { /* Already took care of objectclass */ if ( ml->sml_desc == slap_schema.si_ad_objectClass ) continue; for ( i=0; i<nai; i++ ) { if ( ml->sml_desc->ad_type == modai[i]->na_attr ) break; } /* This attr was already updated */ if ( i < nai ) continue; modai[nai] = ndb_ai_find( ni, ml->sml_desc->ad_type ); if ( modai[nai]->na_flag & NDB_INFO_INDEX ) indexed++; nai++; } ldap_pvt_thread_rdwr_runlock( &ni->ni_ai_rwlock ); /* If got_oc, this was already done above */ if ( indexed && !got_oc) { rc = ndb_entry_put_info( op->o_bd, NA, 1 ); if ( rc ) { attrs_free( old ); return rc; } } myDict = NA->ndb->getDictionary(); /* sort modai so that OcInfo's are contiguous */ { int j, k; for ( i=0; i<nai; i++ ) { for ( j=i+1; j<nai; j++ ) { if ( modai[i]->na_oi == modai[j]->na_oi ) continue; for ( k=j+1; k<nai; k++ ) { if ( modai[i]->na_oi == modai[k]->na_oi ) { atmp = modai[j]; modai[j] = modai[k]; modai[k] = atmp; break; } } /* there are no more na_oi's that match modai[i] */ if ( k == nai ) { i = j; } } } } /* One call per table... */ for ( i=0; i<nai; i += j ) { atmp = modai[i]; for ( j=i+1; j<nai; j++ ) if ( atmp->na_oi != modai[j]->na_oi ) break; j -= i; myTable = myDict->getTable( atmp->na_oi->no_table.bv_val ); if ( !myTable ) continue; rc = ndb_oc_attrs( NA->txn, myTable, NA->e, atmp->na_oi, &modai[i], j, old ); if ( rc ) break; } attrs_free( old ); return rc; }
static int constraint_update( Operation *op, SlapReply *rs ) { slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; Backend *be = op->o_bd; constraint *c = on->on_bi.bi_private, *cp; Entry *target_entry = NULL, *target_entry_copy = NULL; Modifications *modlist, *m; BerVarray b = NULL; int i; struct berval rsv = BER_BVC("modify breaks constraint"); int rc; char *msg = NULL; if (get_relax(op)) { return SLAP_CB_CONTINUE; } switch ( op->o_tag ) { case LDAP_REQ_MODIFY: modlist = op->orm_modlist; break; case LDAP_REQ_MODRDN: modlist = op->orr_modlist; break; default: /* impossible! assert? */ return LDAP_OTHER; } Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "constraint_update()\n", 0,0,0); if ((m = modlist) == NULL) { op->o_bd->bd_info = (BackendInfo *)(on->on_info); send_ldap_error(op, rs, LDAP_INVALID_SYNTAX, "constraint_update() got null modlist"); return(rs->sr_err); } /* Do we need to count attributes? */ for(cp = c; cp; cp = cp->ap_next) { if (cp->count != 0 || cp->set || cp->restrict_lud != 0) { op->o_bd = on->on_info->oi_origdb; rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &target_entry ); op->o_bd = be; if (rc != 0 || target_entry == NULL) { Debug(LDAP_DEBUG_TRACE, "==> constraint_update rc = %d DN=\"%s\"%s\n", rc, op->o_req_ndn.bv_val, target_entry ? "" : " not found" ); if ( rc == 0 ) rc = LDAP_CONSTRAINT_VIOLATION; goto mod_violation; } break; } } rc = LDAP_CONSTRAINT_VIOLATION; for(;m; m = m->sml_next) { unsigned ce = 0; if (is_at_operational( m->sml_desc->ad_type )) continue; if ((( m->sml_op & LDAP_MOD_OP ) != LDAP_MOD_ADD) && (( m->sml_op & LDAP_MOD_OP ) != LDAP_MOD_REPLACE) && (( m->sml_op & LDAP_MOD_OP ) != LDAP_MOD_DELETE)) continue; /* we only care about ADD and REPLACE modifications */ /* and DELETE are used to track attribute count */ if ((( b = m->sml_values ) == NULL ) || (b[0].bv_val == NULL)) continue; /* Get this attribute count, if needed */ if (target_entry) ce = constraint_count_attr(target_entry, m->sml_desc); for(cp = c; cp; cp = cp->ap_next) { int j; for (j = 0; cp->ap[j]; j++) { if (cp->ap[j] == m->sml_desc) { break; } } if (cp->ap[j] == NULL) continue; if (cp->restrict_lud != NULL && constraint_check_restrict(op, cp, target_entry) == 0) { continue; } if (cp->count != 0) { unsigned ca; if (m->sml_op == LDAP_MOD_DELETE) ce = 0; for (ca = 0; b[ca].bv_val; ++ca); Debug(LDAP_DEBUG_TRACE, "==> constraint_update ce = %u, " "ca = %u, cp->count = %lu\n", ce, ca, (unsigned long) cp->count); if (m->sml_op == LDAP_MOD_ADD) { if (ca + ce > cp->count) { rc = LDAP_CONSTRAINT_VIOLATION; goto mod_violation; } } if (m->sml_op == LDAP_MOD_REPLACE) { if (ca > cp->count) { rc = LDAP_CONSTRAINT_VIOLATION; goto mod_violation; } ce = ca; } } /* DELETE are to be ignored beyond this point */ if (( m->sml_op & LDAP_MOD_OP ) == LDAP_MOD_DELETE) continue; for ( i = 0; b[i].bv_val; i++ ) { rc = constraint_violation( cp, &b[i], op, rs ); if ( rc ) { goto mod_violation; } } if (cp->set && target_entry) { if (target_entry_copy == NULL) { Modifications *ml; target_entry_copy = entry_dup(target_entry); /* if rename, set the new entry's name * (in normalized form only) */ if ( op->o_tag == LDAP_REQ_MODRDN ) { struct berval pdn, ndn = BER_BVNULL; if ( op->orr_nnewSup ) { pdn = *op->orr_nnewSup; } else { dnParent( &target_entry_copy->e_nname, &pdn ); } build_new_dn( &ndn, &pdn, &op->orr_nnewrdn, NULL ); ber_memfree( target_entry_copy->e_nname.bv_val ); target_entry_copy->e_nname = ndn; ber_bvreplace( &target_entry_copy->e_name, &ndn ); } /* apply modifications, in an attempt * to estimate what the entry would * look like in case all modifications * pass */ for ( ml = modlist; ml; ml = ml->sml_next ) { Modification *mod = &ml->sml_mod; const char *text; char textbuf[SLAP_TEXT_BUFLEN]; size_t textlen = sizeof(textbuf); int err; switch ( mod->sm_op ) { case LDAP_MOD_ADD: err = modify_add_values( target_entry_copy, mod, get_permissiveModify(op), &text, textbuf, textlen ); break; case LDAP_MOD_DELETE: err = modify_delete_values( target_entry_copy, mod, get_permissiveModify(op), &text, textbuf, textlen ); break; case LDAP_MOD_REPLACE: err = modify_replace_values( target_entry_copy, mod, get_permissiveModify(op), &text, textbuf, textlen ); break; case LDAP_MOD_INCREMENT: err = modify_increment_values( target_entry_copy, mod, get_permissiveModify(op), &text, textbuf, textlen ); break; case SLAP_MOD_SOFTADD: 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_SOFTADD; if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) { err = LDAP_SUCCESS; } 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; } if ( err != LDAP_SUCCESS ) { rc = err; goto mod_violation; } } } if ( acl_match_set(&cp->val, op, target_entry_copy, NULL) == 0) { rc = LDAP_CONSTRAINT_VIOLATION; goto mod_violation; } } } } if (target_entry) { op->o_bd = on->on_info->oi_origdb; be_entry_release_r(op, target_entry); op->o_bd = be; } if (target_entry_copy) { entry_free(target_entry_copy); } return SLAP_CB_CONTINUE; mod_violation: /* violation */ if (target_entry) { op->o_bd = on->on_info->oi_origdb; be_entry_release_r(op, target_entry); op->o_bd = be; } if (target_entry_copy) { entry_free(target_entry_copy); } op->o_bd->bd_info = (BackendInfo *)(on->on_info); if ( rc == LDAP_CONSTRAINT_VIOLATION ) { msg = print_message( &rsv, m->sml_desc ); } send_ldap_error( op, rs, LDAP_CONSTRAINT_VIOLATION, msg ); ch_free(msg); return (rs->sr_err); }