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