/* nops.c - Overlay to filter idempotent operations */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software .
*
* Copyright 2008-2022 The OpenLDAP Foundation.
* Copyright 2008 Emmanuel Dreyfus.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* .
*/
/* ACKNOWLEDGEMENTS:
* This work was originally developed by the Emmanuel Dreyfus for
* inclusion in OpenLDAP Software.
*/
#include "portable.h"
#ifdef SLAPD_OVER_NOPS
#include
#include
#include
#include "lutil.h"
#include "slap.h"
#include "slap-config.h"
static ConfigDriver nops_cf_gen;
static int nops_cf_gen( ConfigArgs *c ) { return 0; }
static void
nops_rm_mod( Modifications **mods, Modifications *mod ) {
Modifications *next, *m;
next = mod->sml_next;
if (*mods == mod) {
*mods = next;
} else {
Modifications *m;
for (m = *mods; m; m = m->sml_next) {
if (m->sml_next == mod) {
m->sml_next = next;
break;
}
}
}
mod->sml_next = NULL;
slap_mods_free(mod, 1);
return;
}
static int
nops_modify( Operation *op, SlapReply *rs )
{
slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
Backend *be = op->o_bd;
Entry *target_entry = NULL;
Modifications *m;
int rc;
if ((m = op->orm_modlist) == NULL) {
op->o_bd->bd_info = (BackendInfo *)(on->on_info);
send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
"nops() got null orm_modlist");
return(rs->sr_err);
}
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)
return 0;
/*
* For each attribute modification, check if the
* modification and the old entry are the same.
*/
while (m) {
int i, j;
int found;
Attribute *a;
BerVarray bm;
BerVarray bt;
Modifications *mc;
mc = m;
m = m->sml_next;
/* Check only replace sub-operations */
if ((mc->sml_op & LDAP_MOD_OP) != LDAP_MOD_REPLACE)
continue;
/* If there is no values, skip */
if (((bm = mc->sml_values ) == NULL ) || (bm[0].bv_val == NULL))
continue;
/* If the attribute does not exist in old entry, skip */
if ((a = attr_find(target_entry->e_attrs, mc->sml_desc)) == NULL)
continue;
if ((bt = a->a_vals) == NULL)
continue;
/* For each value replaced, do we find it in old entry? */
found = 0;
for (i = 0; bm[i].bv_val; i++) {
for (j = 0; bt[j].bv_val; j++) {
if (bm[i].bv_len != bt[j].bv_len)
continue;
if (memcmp(bm[i].bv_val, bt[j].bv_val, bt[j].bv_len) != 0)
continue;
found++;
break;
}
}
/* Did we find as many values as we had in old entry? */
if (i != a->a_numvals || found != a->a_numvals)
continue;
/* This is a nop, remove it */
Debug(LDAP_DEBUG_TRACE, "removing nop on %s",
a->a_desc->ad_cname.bv_val );
nops_rm_mod(&op->orm_modlist, mc);
}
if (target_entry) {
op->o_bd = on->on_info->oi_origdb;
be_entry_release_r(op, target_entry);
op->o_bd = be;
}
if ((m = op->orm_modlist) == NULL) {
slap_callback *cb = op->o_callback;
op->o_bd->bd_info = (BackendInfo *)(on->on_info);
op->o_callback = NULL;
send_ldap_error(op, rs, LDAP_SUCCESS, "");
op->o_callback = cb;
return (rs->sr_err);
}
return SLAP_CB_CONTINUE;
}
static slap_overinst nops_ovl;
#if SLAPD_OVER_NOPS == SLAPD_MOD_DYNAMIC
static
#endif
int
nops_initialize( void ) {
nops_ovl.on_bi.bi_type = "nops";
nops_ovl.on_bi.bi_flags = SLAPO_BFLAG_SINGLE;
nops_ovl.on_bi.bi_op_modify = nops_modify;
return overlay_register( &nops_ovl );
}
#if SLAPD_OVER_NOPS == SLAPD_MOD_DYNAMIC
int init_module(int argc, char *argv[]) {
return nops_initialize();
}
#endif
#endif /* defined(SLAPD_OVER_NOPS) */