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-2021 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 "slap-config.h"
33 
34 static ConfigDriver nops_cf_gen;
35 
nops_cf_gen(ConfigArgs * c)36 static int nops_cf_gen( ConfigArgs *c ) { return 0; }
37 
38 static void
nops_rm_mod(Modifications ** mods,Modifications * mod)39 nops_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 
62 static int
nops_modify(Operation * op,SlapReply * rs)63 nops_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",
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 
158 static slap_overinst nops_ovl;
159 
160 #if SLAPD_OVER_NOPS == SLAPD_MOD_DYNAMIC
161 static
162 #endif
163 int
nops_initialize(void)164 nops_initialize( void ) {
165 	nops_ovl.on_bi.bi_type = "nops";
166 	nops_ovl.on_bi.bi_flags = SLAPO_BFLAG_SINGLE;
167 	nops_ovl.on_bi.bi_op_modify = nops_modify;
168 	return overlay_register( &nops_ovl );
169 }
170 
171 #if SLAPD_OVER_NOPS == SLAPD_MOD_DYNAMIC
init_module(int argc,char * argv[])172 int init_module(int argc, char *argv[]) {
173 	return nops_initialize();
174 }
175 #endif
176 
177 #endif /* defined(SLAPD_OVER_NOPS) */
178 
179