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
39 static ConfigDriver nops_cf_gen;
40
nops_cf_gen(ConfigArgs * c)41 static int nops_cf_gen( ConfigArgs *c ) { return 0; }
42
43 static void
nops_rm_mod(Modifications ** mods,Modifications * mod)44 nops_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
67 static int
nops_modify(Operation * op,SlapReply * rs)68 nops_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
163 static slap_overinst nops_ovl;
164
165 #if SLAPD_OVER_NOPS == SLAPD_MOD_DYNAMIC
166 static
167 #endif
168 int
nops_initialize(void)169 nops_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
init_module(int argc,char * argv[])177 int init_module(int argc, char *argv[]) {
178 return nops_initialize();
179 }
180 #endif
181
182 #endif /* defined(SLAPD_OVER_NOPS) */
183
184