1/* nops.c - Overlay to filter idempotent operations */
2/* $OpenLDAP$ */
3/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 2008-2011 The OpenLDAP Foundation.
6 * Copyright 2008 Emmanuel Dreyfus.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
11 * Public License.
12 *
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
16 */
17/* ACKNOWLEDGEMENTS:
18 * This work was originally developed by the Emmanuel Dreyfus for
19 * inclusion in OpenLDAP Software.
20 */
21#include "portable.h"
22
23#ifdef SLAPD_OVER_NOPS
24
25#include <stdio.h>
26
27#include <ac/string.h>
28#include <ac/socket.h>
29
30#include "lutil.h"
31#include "slap.h"
32#include "config.h"
33
34static ConfigDriver nops_cf_gen;
35
36static int nops_cf_gen( ConfigArgs *c ) { return 0; }
37
38static void
39nops_rm_mod( Modifications **mods, Modifications *mod ) {
40	Modifications *next, *m;
41
42	next = mod->sml_next;
43	if (*mods == mod) {
44		*mods = next;
45	} else {
46		Modifications *m;
47
48		for (m = *mods; m; m = m->sml_next) {
49			if (m->sml_next == mod) {
50				m->sml_next = next;
51				break;
52			}
53		}
54	}
55
56	mod->sml_next = NULL;
57	slap_mods_free(mod, 1);
58
59	return;
60}
61
62static int
63nops_modify( Operation *op, SlapReply *rs )
64{
65	slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
66	Backend *be = op->o_bd;
67	Entry *target_entry = NULL;
68	Modifications *m;
69	int rc;
70
71	if ((m = op->orm_modlist) == NULL) {
72		op->o_bd->bd_info = (BackendInfo *)(on->on_info);
73		send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
74				"nops() got null orm_modlist");
75		return(rs->sr_err);
76	}
77
78	op->o_bd = on->on_info->oi_origdb;
79	rc = be_entry_get_rw(op, &op->o_req_ndn, NULL, NULL, 0,  &target_entry);
80	op->o_bd = be;
81
82	if (rc != 0 || target_entry == NULL)
83		return 0;
84
85	/*
86	 * For each attribute modification, check if the
87	 * modification and the old entry are the same.
88	 */
89	while (m) {
90		int i, j;
91		int found;
92		Attribute *a;
93		BerVarray bm;
94		BerVarray bt;
95		Modifications *mc;
96
97		mc = m;
98		m = m->sml_next;
99
100		/* Check only replace sub-operations */
101		if ((mc->sml_op & LDAP_MOD_OP) != LDAP_MOD_REPLACE)
102			continue;
103
104		/* If there is no values, skip */
105		if (((bm = mc->sml_values ) == NULL ) || (bm[0].bv_val == NULL))
106			continue;
107
108		/* If the attribute does not exist in old entry, skip */
109		if ((a = attr_find(target_entry->e_attrs, mc->sml_desc)) == NULL)
110			continue;
111		if ((bt = a->a_vals) == NULL)
112			continue;
113
114		/* For each value replaced, do we find it in old entry? */
115		found = 0;
116		for (i = 0; bm[i].bv_val; i++) {
117			for (j = 0; bt[j].bv_val; j++) {
118				if (bm[i].bv_len != bt[j].bv_len)
119					continue;
120				if (memcmp(bm[i].bv_val, bt[j].bv_val, bt[j].bv_len) != 0)
121					continue;
122
123				found++;
124				break;
125			}
126		}
127
128		/* Did we find as many values as we had in old entry? */
129		if (i != a->a_numvals || found != a->a_numvals)
130			continue;
131
132		/* This is a nop, remove it */
133		Debug(LDAP_DEBUG_TRACE, "removing nop on %s%s%s",
134			a->a_desc->ad_cname.bv_val, "", "");
135
136		nops_rm_mod(&op->orm_modlist, mc);
137	}
138	if (target_entry) {
139		op->o_bd = on->on_info->oi_origdb;
140		be_entry_release_r(op, target_entry);
141		op->o_bd = be;
142	}
143
144	if ((m = op->orm_modlist) == NULL) {
145		slap_callback *cb = op->o_callback;
146
147		op->o_bd->bd_info = (BackendInfo *)(on->on_info);
148		op->o_callback = NULL;
149                send_ldap_error(op, rs, LDAP_SUCCESS, "");
150		op->o_callback = cb;
151
152		return (rs->sr_err);
153	}
154
155	return SLAP_CB_CONTINUE;
156}
157
158static slap_overinst nops_ovl;
159
160#if SLAPD_OVER_NOPS == SLAPD_MOD_DYNAMIC
161static
162#endif
163int
164nops_initialize( void ) {
165	nops_ovl.on_bi.bi_type = "nops";
166	nops_ovl.on_bi.bi_op_modify = nops_modify;
167	return overlay_register( &nops_ovl );
168}
169
170#if SLAPD_OVER_NOPS == SLAPD_MOD_DYNAMIC
171int init_module(int argc, char *argv[]) {
172	return nops_initialize();
173}
174#endif
175
176#endif /* defined(SLAPD_OVER_NOPS) */
177
178