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