openldap/contrib/slapd-modules/nops/nops.c
Kurt Zeilenga a5abeb92ec Update contrib notices to reflect that they are distributed as part of
OpenLDAP Software (though they may not necessarily be supported by the
OpenLDAP Project).  Assistance in updating ACKNOWLEDGEMENTS welcomed.
2009-08-16 22:55:23 +00:00

177 lines
3.9 KiB
C

/* nops.c - Overlay to filter idempotent operations */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2008-2009 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
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work was originally developed by the Emmanuel Dreyfus for
* inclusion in OpenLDAP Software.
*/
#include "portable.h"
#ifdef SLAPD_OVER_NOPS
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "lutil.h"
#include "slap.h"
#include "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%s%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_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) */