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