1 /* $NetBSD: addpartial-overlay.c,v 1.3 2021/08/14 16:14:50 christos Exp $ */
2
3 /* addpartial-overlay.c */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 2004-2021 The OpenLDAP Foundation.
8 * Portions Copyright (C) 2004 Virginia Tech, David Hawes.
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 file LICENSE in the
16 * top-level directory of the distribution or, alternatively, at
17 * http://www.OpenLDAP.org/license.html.
18 */
19 /* ACKNOLEDGEDMENTS:
20 * This work was initially developed by David Hawes of Virginia Tech
21 * for inclusion in OpenLDAP Software.
22 */
23 /* addpartial-overlay
24 *
25 * This is an OpenLDAP overlay that intercepts ADD requests, determines if a
26 * change has actually taken place for that record, and then performs a modify
27 * request for those values that have changed (modified, added, deleted). If
28 * the record has not changed in any way, it is ignored. If the record does not
29 * exist, the record falls through to the normal add mechanism. This overlay is
30 * useful for replicating from sources that are not LDAPs where it is easier to
31 * build entire records than to determine the changes (i.e. a database).
32 */
33
34 #include <sys/cdefs.h>
35 __RCSID("$NetBSD: addpartial-overlay.c,v 1.3 2021/08/14 16:14:50 christos Exp $");
36
37 #include "portable.h"
38 #include "slap.h"
39
40 static int collect_error_msg_cb( Operation *op, SlapReply *rs);
41
42 static slap_overinst addpartial;
43
44 /**
45 * The meat of the overlay. Search for the record, determine changes, take
46 * action or fall through.
47 */
addpartial_add(Operation * op,SlapReply * rs)48 static int addpartial_add( Operation *op, SlapReply *rs)
49 {
50 Operation nop = *op;
51 Entry *toAdd = NULL;
52 Entry *found = NULL;
53 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
54 int rc;
55
56 toAdd = op->oq_add.rs_e;
57
58 Debug(LDAP_DEBUG_TRACE, "%s: toAdd->e_nname.bv_val: %s\n",
59 addpartial.on_bi.bi_type, toAdd->e_nname.bv_val );
60
61 /* if the user doesn't have access, fall through to the normal ADD */
62 if(!access_allowed(op, toAdd, slap_schema.si_ad_entry,
63 NULL, ACL_WRITE, NULL))
64 {
65 return SLAP_CB_CONTINUE;
66 }
67
68 rc = overlay_entry_get_ov(&nop, &nop.o_req_ndn, NULL, NULL, 0, &found, on);
69
70 if(rc != LDAP_SUCCESS)
71 {
72 Debug(LDAP_DEBUG_TRACE,
73 "%s: no entry found, falling through to normal add\n",
74 addpartial.on_bi.bi_type );
75 return SLAP_CB_CONTINUE;
76 }
77 else
78 {
79 Debug(LDAP_DEBUG_TRACE, "%s: found the dn\n", addpartial.on_bi.bi_type );
80
81 if(found)
82 {
83 Attribute *attr = NULL;
84 Attribute *at = NULL;
85 int ret;
86 Modifications *mods = NULL;
87 Modifications **modtail = &mods;
88 Modifications *mod = NULL;
89
90 Debug(LDAP_DEBUG_TRACE, "%s: have an entry!\n",
91 addpartial.on_bi.bi_type );
92
93 /* determine if the changes are in the found entry */
94 for(attr = toAdd->e_attrs; attr; attr = attr->a_next)
95 {
96 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
97
98 at = attr_find(found->e_attrs, attr->a_desc);
99 if(!at)
100 {
101 Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s not found!\n",
102 addpartial.on_bi.bi_type,
103 attr->a_desc->ad_cname.bv_val );
104 mod = (Modifications *) ch_malloc(sizeof(
105 Modifications));
106 mod->sml_flags = 0;
107 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
108 mod->sml_op &= LDAP_MOD_OP;
109 mod->sml_next = NULL;
110 mod->sml_desc = attr->a_desc;
111 mod->sml_type = attr->a_desc->ad_cname;
112 mod->sml_values = attr->a_vals;
113 mod->sml_nvalues = attr->a_nvals;
114 mod->sml_numvals = attr->a_numvals;
115 *modtail = mod;
116 modtail = &mod->sml_next;
117 }
118 else
119 {
120 MatchingRule *mr = attr->a_desc->ad_type->sat_equality;
121 struct berval *bv;
122 const char *text;
123 int acount , bcount;
124 Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s found\n",
125 addpartial.on_bi.bi_type,
126 attr->a_desc->ad_cname.bv_val );
127
128 for(bv = attr->a_vals, acount = 0; bv->bv_val != NULL;
129 bv++, acount++)
130 {
131 /* count num values for attr */
132 }
133 for(bv = at->a_vals, bcount = 0; bv->bv_val != NULL;
134 bv++, bcount++)
135 {
136 /* count num values for attr */
137 }
138 if(acount != bcount)
139 {
140 Debug(LDAP_DEBUG_TRACE, "%s: acount != bcount, %s\n",
141 addpartial.on_bi.bi_type,
142 "replace all" );
143 mod = (Modifications *) ch_malloc(sizeof(
144 Modifications));
145 mod->sml_flags = 0;
146 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
147 mod->sml_op &= LDAP_MOD_OP;
148 mod->sml_next = NULL;
149 mod->sml_desc = attr->a_desc;
150 mod->sml_type = attr->a_desc->ad_cname;
151 mod->sml_values = attr->a_vals;
152 mod->sml_nvalues = attr->a_nvals;
153 mod->sml_numvals = attr->a_numvals;
154 *modtail = mod;
155 modtail = &mod->sml_next;
156 continue;
157 }
158
159 for(bv = attr->a_vals; bv->bv_val != NULL; bv++)
160 {
161 struct berval *v;
162 ret = -1;
163
164 for(v = at->a_vals; v->bv_val != NULL; v++)
165 {
166 int r;
167 if(mr && ((r = value_match(&ret, attr->a_desc, mr,
168 SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
169 bv, v, &text)) == 0))
170 {
171 if(ret == 0)
172 break;
173 }
174 else
175 {
176 Debug(LDAP_DEBUG_TRACE,
177 "%s: \tvalue DNE, r: %d \n",
178 addpartial.on_bi.bi_type,
179 r );
180 ret = strcmp(bv->bv_val, v->bv_val);
181 if(ret == 0)
182 break;
183 }
184 }
185
186 if(ret == 0)
187 {
188 Debug(LDAP_DEBUG_TRACE,
189 "%s: \tvalue %s exists, ret: %d\n",
190 addpartial.on_bi.bi_type, bv->bv_val, ret);
191 }
192 else
193 {
194 Debug(LDAP_DEBUG_TRACE,
195 "%s: \tvalue %s DNE, ret: %d\n",
196 addpartial.on_bi.bi_type, bv->bv_val, ret);
197 mod = (Modifications *) ch_malloc(sizeof(
198 Modifications));
199 mod->sml_flags = 0;
200 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
201 mod->sml_op &= LDAP_MOD_OP;
202 mod->sml_next = NULL;
203 mod->sml_desc = attr->a_desc;
204 mod->sml_type = attr->a_desc->ad_cname;
205 mod->sml_values = attr->a_vals;
206 mod->sml_nvalues = attr->a_nvals;
207 mod->sml_numvals = attr->a_numvals;
208 *modtail = mod;
209 modtail = &mod->sml_next;
210 break;
211 }
212 }
213 }
214 }
215
216 /* determine if any attributes were deleted */
217 for(attr = found->e_attrs; attr; attr = attr->a_next)
218 {
219 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
220
221 at = NULL;
222 at = attr_find(toAdd->e_attrs, attr->a_desc);
223 if(!at)
224 {
225 Debug(LDAP_DEBUG_TRACE,
226 "%s: Attribute %s not found in new entry!!!\n",
227 addpartial.on_bi.bi_type,
228 attr->a_desc->ad_cname.bv_val );
229 mod = (Modifications *) ch_malloc(sizeof(
230 Modifications));
231 mod->sml_flags = 0;
232 mod->sml_op = LDAP_MOD_REPLACE;
233 mod->sml_next = NULL;
234 mod->sml_desc = attr->a_desc;
235 mod->sml_type = attr->a_desc->ad_cname;
236 mod->sml_values = NULL;
237 mod->sml_nvalues = NULL;
238 mod->sml_numvals = 0;
239 *modtail = mod;
240 modtail = &mod->sml_next;
241 }
242 else
243 {
244 Debug(LDAP_DEBUG_TRACE,
245 "%s: Attribute %s found in new entry\n",
246 addpartial.on_bi.bi_type,
247 at->a_desc->ad_cname.bv_val );
248 }
249 }
250
251 overlay_entry_release_ov(&nop, found, 0, on);
252
253 if(mods)
254 {
255 Modifications *m = NULL;
256 Modifications *toDel;
257 int modcount;
258 slap_callback nullcb = { NULL, collect_error_msg_cb,
259 NULL, NULL };
260
261 Debug(LDAP_DEBUG_TRACE, "%s: mods to do...\n",
262 addpartial.on_bi.bi_type );
263
264 nop.o_tag = LDAP_REQ_MODIFY;
265 nop.orm_modlist = mods;
266 nop.orm_no_opattrs = 0;
267 nop.o_callback = &nullcb;
268 nop.o_bd->bd_info = (BackendInfo *) on->on_info;
269
270 for(m = mods, modcount = 0; m; m = m->sml_next,
271 modcount++)
272 {
273 /* count number of mods */
274 }
275
276 Debug(LDAP_DEBUG_TRACE, "%s: number of mods: %d\n",
277 addpartial.on_bi.bi_type, modcount );
278
279 if(nop.o_bd->be_modify)
280 {
281 SlapReply nrs = { REP_RESULT };
282 rc = (nop.o_bd->be_modify)(&nop, &nrs);
283 }
284
285 if(rc == LDAP_SUCCESS)
286 {
287 Debug(LDAP_DEBUG_TRACE,
288 "%s: modify successful\n",
289 addpartial.on_bi.bi_type );
290 }
291 else
292 {
293 Debug(LDAP_DEBUG_TRACE, "%s: modify unsuccessful: %d\n",
294 addpartial.on_bi.bi_type, rc );
295 rs->sr_err = rc;
296 if(nullcb.sc_private)
297 {
298 rs->sr_text = nullcb.sc_private;
299 }
300 }
301
302 Debug(LDAP_DEBUG_TRACE, "%s: freeing mods...\n",
303 addpartial.on_bi.bi_type );
304
305 for(toDel = mods; toDel; toDel = mods)
306 {
307 mods = mods->sml_next;
308 ch_free(toDel);
309 }
310 }
311 else
312 {
313 Debug(LDAP_DEBUG_TRACE, "%s: no mods to process\n",
314 addpartial.on_bi.bi_type );
315 }
316 }
317 else
318 {
319 Debug(LDAP_DEBUG_TRACE, "%s: no entry!\n",
320 addpartial.on_bi.bi_type );
321 }
322
323 op->o_callback = NULL;
324 send_ldap_result( op, rs );
325 ch_free((void *)rs->sr_text);
326 rs->sr_text = NULL;
327
328 return LDAP_SUCCESS;
329 }
330 }
331
collect_error_msg_cb(Operation * op,SlapReply * rs)332 static int collect_error_msg_cb( Operation *op, SlapReply *rs)
333 {
334 if(rs->sr_text)
335 {
336 op->o_callback->sc_private = (void *) ch_strdup(rs->sr_text);
337 }
338
339 return LDAP_SUCCESS;
340 }
341
addpartial_init()342 int addpartial_init()
343 {
344 addpartial.on_bi.bi_type = "addpartial";
345 addpartial.on_bi.bi_flags = SLAPO_BFLAG_SINGLE;
346 addpartial.on_bi.bi_op_add = addpartial_add;
347
348 return (overlay_register(&addpartial));
349 }
350
init_module(int argc,char * argv[])351 int init_module(int argc, char *argv[])
352 {
353 return addpartial_init();
354 }
355