2 * $Id: addpartial-overlay.c 6588 2007-11-07 18:29:25Z dhawes $
4 * Copyright (C) 2004 Virginia Tech, David Hawes.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
11 * A copy of this license is available in file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * http://www.OpenLDAP.org/license.html.
15 * SEE LICENSE FOR MORE INFORMATION
17 * Author: David H. Hawes, Jr.
18 * Email: dhawes@vt.edu
19 * Version: $Revision: 6588 $
20 * Updated: $Date: 2007-11-07 13:29:25 -0500 (Wed, 07 Nov 2007) $
24 * This is an OpenLDAP overlay that intercepts ADD requests, determines if a
25 * change has actually taken place for that record, and then performs a modify
26 * request for those values that have changed (modified, added, deleted). If
27 * the record has not changed in any way, it is ignored. If the record does not
28 * exist, the record falls through to the normal add mechanism. This overlay is
29 * useful for replicating from sources that are not LDAPs where it is easier to
30 * build entire records than to determine the changes (i.e. a database).
36 static int addpartial_search_cb( Operation *op, SlapReply *rs);
37 static int collect_error_msg_cb( Operation *op, SlapReply *rs);
39 static slap_overinst addpartial;
42 * The meat of the overlay. Search for the record, determine changes, take
43 * action or fall through.
45 static int addpartial_add( Operation *op, SlapReply *rs)
48 SlapReply nrs = { REP_RESULT };
49 Filter *filter = NULL;
51 struct berval fstr = BER_BVNULL;
52 slap_callback cb = { NULL, addpartial_search_cb, NULL, NULL };
53 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
56 toAdd = op->oq_add.rs_e;
58 Debug(LDAP_DEBUG_TRACE, "%s: toAdd->e_nname.bv_val: %s\n",
59 addpartial.on_bi.bi_type, toAdd->e_nname.bv_val,0);
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))
65 return SLAP_CB_CONTINUE;
71 op->o_bd->bd_info = (BackendInfo *) on->on_info;
72 nop.o_tag = LDAP_REQ_SEARCH;
75 filter = str2filter("(objectclass=*)");
76 filter2bv(filter, &fstr);
78 nop.ors_scope = LDAP_SCOPE_BASE;
79 nop.ors_deref = LDAP_DEREF_NEVER;
80 nop.ors_slimit = -1;//SLAP_NO_LIMIT;
81 nop.ors_tlimit = -1;//SLAP_NO_LIMIT;
82 nop.ors_attrsonly = 0;
83 nop.ors_attrs = slap_anlist_no_attrs;
84 nop.ors_filter = filter;
85 nop.ors_filterstr = fstr;
87 memset(&nrs, 0, sizeof(nrs));
88 nrs.sr_type = REP_RESULT;
89 nrs.sr_err = LDAP_SUCCESS;
91 nrs.sr_flags |= REP_ENTRY_MUSTBEFREED;
94 Debug(LDAP_DEBUG_TRACE, "%s: performing search\n", addpartial.on_bi.bi_type,
97 if(nop.o_bd->be_search)
99 rc = nop.o_bd->be_search(&nop, &nrs);
100 Debug(LDAP_DEBUG_TRACE, "%s: search performed\n",
101 addpartial.on_bi.bi_type,0,0);
105 Debug(LDAP_DEBUG_TRACE, "%s: backend missing search function\n",
106 addpartial.on_bi.bi_type,0,0);
112 ch_free(fstr.bv_val);
114 if(rc != LDAP_SUCCESS)
115 return SLAP_CB_CONTINUE;
119 Debug(LDAP_DEBUG_TRACE, "%s: found the dn\n", addpartial.on_bi.bi_type,
121 found = (Entry *) cb.sc_private;
125 Attribute *attr = NULL;
126 Attribute *at = NULL;
128 Modifications *mods = NULL;
129 Modifications **modtail = &mods;
130 Modifications *mod = NULL;
132 Debug(LDAP_DEBUG_TRACE, "%s: have an entry!\n",
133 addpartial.on_bi.bi_type,0,0);
135 /* determine if the changes are in the found entry */
136 for(attr = toAdd->e_attrs; attr; attr = attr->a_next)
138 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
140 at = attr_find(found->e_attrs, attr->a_desc);
143 Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s not found!\n",
144 addpartial.on_bi.bi_type,
145 attr->a_desc->ad_cname.bv_val,0);
146 mod = (Modifications *) ch_malloc(sizeof(
149 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
150 mod->sml_op &= LDAP_MOD_OP;
151 mod->sml_next = NULL;
152 mod->sml_desc = attr->a_desc;
153 mod->sml_type.bv_val = attr->a_desc->ad_cname.bv_val;
154 mod->sml_type.bv_len = strlen(mod->sml_type.bv_val);
155 mod->sml_values = attr->a_vals;
156 mod->sml_nvalues = attr->a_nvals;
157 mod->sml_numvals = attr->a_numvals;
159 modtail = &mod->sml_next;
163 MatchingRule *mr = attr->a_desc->ad_type->sat_equality;
167 Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s found\n",
168 addpartial.on_bi.bi_type,
169 attr->a_desc->ad_cname.bv_val,0);
171 for(bv = attr->a_vals, acount = 0; bv->bv_val != NULL;
174 /* count num values for attr */
176 for(bv = at->a_vals, bcount = 0; bv->bv_val != NULL;
179 /* count num values for attr */
183 Debug(LDAP_DEBUG_TRACE, "%s: acount != bcount, %s\n",
184 addpartial.on_bi.bi_type,
186 mod = (Modifications *) ch_malloc(sizeof(
189 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
190 mod->sml_op &= LDAP_MOD_OP;
191 mod->sml_next = NULL;
192 mod->sml_desc = attr->a_desc;
193 mod->sml_type.bv_val = attr->a_desc->ad_cname.bv_val;
194 mod->sml_type.bv_len = strlen(mod->sml_type.bv_val);
195 mod->sml_values = attr->a_vals;
196 mod->sml_nvalues = attr->a_nvals;
197 mod->sml_numvals = attr->a_numvals;
199 modtail = &mod->sml_next;
203 for(bv = attr->a_vals; bv->bv_val != NULL; bv++)
208 for(v = at->a_vals; v->bv_val != NULL; v++)
211 if(mr && ((r = value_match(&ret, attr->a_desc, mr,
212 SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
213 bv, v, &text)) == 0))
220 Debug(LDAP_DEBUG_TRACE,
221 "%s: \tvalue DNE, r: %d \n",
222 addpartial.on_bi.bi_type,
224 ret = strcmp(bv->bv_val, v->bv_val);
232 Debug(LDAP_DEBUG_TRACE,
233 "%s: \tvalue %s exists, ret: %d\n",
234 addpartial.on_bi.bi_type, bv->bv_val, ret);
238 Debug(LDAP_DEBUG_TRACE,
239 "%s: \tvalue %s DNE, ret: %d\n",
240 addpartial.on_bi.bi_type, bv->bv_val, ret);
241 mod = (Modifications *) ch_malloc(sizeof(
244 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
245 mod->sml_op &= LDAP_MOD_OP;
246 mod->sml_next = NULL;
247 mod->sml_desc = attr->a_desc;
248 mod->sml_type.bv_val =
249 attr->a_desc->ad_cname.bv_val;
250 mod->sml_type.bv_len = strlen(mod->sml_type.bv_val);
251 mod->sml_values = attr->a_vals;
252 mod->sml_nvalues = attr->a_nvals;
253 mod->sml_numvals = attr->a_numvals;
255 modtail = &mod->sml_next;
262 /* determine if any attributes were deleted */
263 for(attr = found->e_attrs; attr; attr = attr->a_next)
265 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
268 at = attr_find(toAdd->e_attrs, attr->a_desc);
271 Debug(LDAP_DEBUG_TRACE,
272 "%s: Attribute %s not found in new entry!!!\n",
273 addpartial.on_bi.bi_type,
274 attr->a_desc->ad_cname.bv_val, 0);
275 mod = (Modifications *) ch_malloc(sizeof(
278 mod->sml_op = LDAP_MOD_REPLACE;
279 mod->sml_next = NULL;
280 mod->sml_desc = attr->a_desc;
281 mod->sml_type.bv_val =
282 attr->a_desc->ad_cname.bv_val;
283 mod->sml_type.bv_len = strlen(mod->sml_type.bv_val);
284 mod->sml_values = NULL;
285 mod->sml_nvalues = NULL;
286 mod->sml_numvals = 0;
288 modtail = &mod->sml_next;
292 Debug(LDAP_DEBUG_TRACE,
293 "%s: Attribute %s found in new entry\n",
294 addpartial.on_bi.bi_type,
295 at->a_desc->ad_cname.bv_val, 0);
301 Debug(LDAP_DEBUG_TRACE, "%s: mods to do...\n",
302 addpartial.on_bi.bi_type, 0, 0);
303 if(nop.o_bd->be_modify)
305 Modifications *m = NULL;
307 slap_callback nullcb = { NULL, collect_error_msg_cb,
309 char textbuf[SLAP_TEXT_BUFLEN];
310 size_t textlen = sizeof textbuf;
312 memset(&nrs, 0, sizeof(nrs));
313 nrs.sr_type = REP_RESULT;
314 nrs.sr_err = LDAP_SUCCESS;
318 nop.o_tag = LDAP_REQ_MODIFY;
319 nop.orm_modlist = mods;
320 nop.o_callback = &nullcb;
321 nop.o_bd->bd_info = (BackendInfo *) on->on_info;
323 for(m = mods, modcount = 0; m; m = m->sml_next,
326 /* count number of mods */
329 Debug(LDAP_DEBUG_TRACE, "%s: number of mods: %d\n",
330 addpartial.on_bi.bi_type, modcount, 0);
332 rc = (nop.o_bd->be_modify)(&nop, &nrs);
334 if(rc == LDAP_SUCCESS)
336 Debug(LDAP_DEBUG_TRACE,
337 "%s: modify successful\n",
338 addpartial.on_bi.bi_type, 0, 0);
342 Debug(LDAP_DEBUG_TRACE, "%s: modify unsuccessful: %d\n",
343 addpartial.on_bi.bi_type, rc, 0);
347 rs->sr_text = nullcb.sc_private;
351 Debug(LDAP_DEBUG_TRACE, "%s: freeing mods...\n",
352 addpartial.on_bi.bi_type, 0, 0);
356 Modifications *toDel;
358 for(toDel = mods; toDel; toDel = mods)
360 mods = mods->sml_next;
368 Debug(LDAP_DEBUG_TRACE, "%s: no mods to process\n",
369 addpartial.on_bi.bi_type, 0, 0);
377 Debug(LDAP_DEBUG_TRACE, "%s: no entry!\n",
378 addpartial.on_bi.bi_type, 0, 0);
381 op->o_callback = NULL;
382 send_ldap_result( op, rs );
383 ch_free((void *)rs->sr_text);
390 static int addpartial_search_cb( Operation *op, SlapReply *rs)
394 if(rs->sr_type != REP_SEARCH) return 0;
396 Debug(LDAP_DEBUG_TRACE, "%s: addpartial_search_cb\n",
397 addpartial.on_bi.bi_type, 0, 0);
401 Debug(LDAP_DEBUG_TRACE, "%s: dn found: %s\n",
402 addpartial.on_bi.bi_type, rs->sr_entry->e_nname.bv_val, 0);
403 entry = rs->sr_entry;
404 op->o_callback->sc_private = (void *) entry_dup(entry);
410 static int collect_error_msg_cb( Operation *op, SlapReply *rs)
414 op->o_callback->sc_private = (void *) ch_strdup(rs->sr_text);
420 int addpartial_init()
422 addpartial.on_bi.bi_type = "addpartial";
423 addpartial.on_bi.bi_op_add = addpartial_add;
425 return (overlay_register(&addpartial));
428 int init_module(int argc, char *argv[])
430 return addpartial_init();