xref: /netbsd-src/external/bsd/openldap/dist/contrib/slapd-modules/nops/nops.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
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