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: 8385 $
20 * Updated: $Date: 2008-11-04 12:19:52 -0500 (Tue, 04 Nov 2008) $
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 collect_error_msg_cb( Operation *op, SlapReply *rs);
38 static slap_overinst addpartial;
41 * The meat of the overlay. Search for the record, determine changes, take
42 * action or fall through.
44 static int addpartial_add( Operation *op, SlapReply *rs)
47 SlapReply nrs = { REP_RESULT };
50 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
53 toAdd = op->oq_add.rs_e;
55 Debug(LDAP_DEBUG_TRACE, "%s: toAdd->e_nname.bv_val: %s\n",
56 addpartial.on_bi.bi_type, toAdd->e_nname.bv_val,0);
58 /* if the user doesn't have access, fall through to the normal ADD */
59 if(!access_allowed(op, toAdd, slap_schema.si_ad_entry,
60 NULL, ACL_WRITE, NULL))
62 return SLAP_CB_CONTINUE;
65 rc = overlay_entry_get_ov(&nop, &nop.o_req_ndn, NULL, NULL, 0, &found, on);
67 if(rc != LDAP_SUCCESS)
69 Debug(LDAP_DEBUG_TRACE,
70 "%s: no entry found, falling through to normal add\n",
71 addpartial.on_bi.bi_type, 0, 0);
72 return SLAP_CB_CONTINUE;
76 Debug(LDAP_DEBUG_TRACE, "%s: found the dn\n", addpartial.on_bi.bi_type,
81 Attribute *attr = NULL;
84 Modifications *mods = NULL;
85 Modifications **modtail = &mods;
86 Modifications *mod = NULL;
88 Debug(LDAP_DEBUG_TRACE, "%s: have an entry!\n",
89 addpartial.on_bi.bi_type,0,0);
91 /* determine if the changes are in the found entry */
92 for(attr = toAdd->e_attrs; attr; attr = attr->a_next)
94 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
96 at = attr_find(found->e_attrs, attr->a_desc);
99 Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s not found!\n",
100 addpartial.on_bi.bi_type,
101 attr->a_desc->ad_cname.bv_val,0);
102 mod = (Modifications *) ch_malloc(sizeof(
105 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
106 mod->sml_op &= LDAP_MOD_OP;
107 mod->sml_next = NULL;
108 mod->sml_desc = attr->a_desc;
109 mod->sml_type = attr->a_desc->ad_cname;
110 mod->sml_values = attr->a_vals;
111 mod->sml_nvalues = attr->a_nvals;
112 mod->sml_numvals = attr->a_numvals;
114 modtail = &mod->sml_next;
118 MatchingRule *mr = attr->a_desc->ad_type->sat_equality;
122 Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s found\n",
123 addpartial.on_bi.bi_type,
124 attr->a_desc->ad_cname.bv_val,0);
126 for(bv = attr->a_vals, acount = 0; bv->bv_val != NULL;
129 /* count num values for attr */
131 for(bv = at->a_vals, bcount = 0; bv->bv_val != NULL;
134 /* count num values for attr */
138 Debug(LDAP_DEBUG_TRACE, "%s: acount != bcount, %s\n",
139 addpartial.on_bi.bi_type,
141 mod = (Modifications *) ch_malloc(sizeof(
144 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
145 mod->sml_op &= LDAP_MOD_OP;
146 mod->sml_next = NULL;
147 mod->sml_desc = attr->a_desc;
148 mod->sml_type = attr->a_desc->ad_cname;
149 mod->sml_values = attr->a_vals;
150 mod->sml_nvalues = attr->a_nvals;
151 mod->sml_numvals = attr->a_numvals;
153 modtail = &mod->sml_next;
157 for(bv = attr->a_vals; bv->bv_val != NULL; bv++)
162 for(v = at->a_vals; v->bv_val != NULL; v++)
165 if(mr && ((r = value_match(&ret, attr->a_desc, mr,
166 SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
167 bv, v, &text)) == 0))
174 Debug(LDAP_DEBUG_TRACE,
175 "%s: \tvalue DNE, r: %d \n",
176 addpartial.on_bi.bi_type,
178 ret = strcmp(bv->bv_val, v->bv_val);
186 Debug(LDAP_DEBUG_TRACE,
187 "%s: \tvalue %s exists, ret: %d\n",
188 addpartial.on_bi.bi_type, bv->bv_val, ret);
192 Debug(LDAP_DEBUG_TRACE,
193 "%s: \tvalue %s DNE, ret: %d\n",
194 addpartial.on_bi.bi_type, bv->bv_val, ret);
195 mod = (Modifications *) ch_malloc(sizeof(
198 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
199 mod->sml_op &= LDAP_MOD_OP;
200 mod->sml_next = NULL;
201 mod->sml_desc = attr->a_desc;
202 mod->sml_type = attr->a_desc->ad_cname;
203 mod->sml_values = attr->a_vals;
204 mod->sml_nvalues = attr->a_nvals;
205 mod->sml_numvals = attr->a_numvals;
207 modtail = &mod->sml_next;
214 /* determine if any attributes were deleted */
215 for(attr = found->e_attrs; attr; attr = attr->a_next)
217 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
220 at = attr_find(toAdd->e_attrs, attr->a_desc);
223 Debug(LDAP_DEBUG_TRACE,
224 "%s: Attribute %s not found in new entry!!!\n",
225 addpartial.on_bi.bi_type,
226 attr->a_desc->ad_cname.bv_val, 0);
227 mod = (Modifications *) ch_malloc(sizeof(
230 mod->sml_op = LDAP_MOD_REPLACE;
231 mod->sml_next = NULL;
232 mod->sml_desc = attr->a_desc;
233 mod->sml_type = attr->a_desc->ad_cname;
234 mod->sml_values = NULL;
235 mod->sml_nvalues = NULL;
236 mod->sml_numvals = 0;
238 modtail = &mod->sml_next;
242 Debug(LDAP_DEBUG_TRACE,
243 "%s: Attribute %s found in new entry\n",
244 addpartial.on_bi.bi_type,
245 at->a_desc->ad_cname.bv_val, 0);
249 overlay_entry_release_ov(&nop, found, 0, on);
253 Modifications *m = NULL;
254 Modifications *toDel;
256 slap_callback nullcb = { NULL, collect_error_msg_cb,
259 Debug(LDAP_DEBUG_TRACE, "%s: mods to do...\n",
260 addpartial.on_bi.bi_type, 0, 0);
262 memset(&nrs, 0, sizeof(nrs));
263 nrs.sr_type = REP_RESULT;
264 nrs.sr_err = LDAP_SUCCESS;
268 nop.o_tag = LDAP_REQ_MODIFY;
269 nop.orm_modlist = mods;
270 nop.orm_no_opattrs = 0;
271 nop.o_callback = &nullcb;
272 nop.o_bd->bd_info = (BackendInfo *) on->on_info;
274 for(m = mods, modcount = 0; m; m = m->sml_next,
277 /* count number of mods */
280 Debug(LDAP_DEBUG_TRACE, "%s: number of mods: %d\n",
281 addpartial.on_bi.bi_type, modcount, 0);
283 if(nop.o_bd->be_modify)
285 rc = (nop.o_bd->be_modify)(&nop, &nrs);
288 if(rc == LDAP_SUCCESS)
290 Debug(LDAP_DEBUG_TRACE,
291 "%s: modify successful\n",
292 addpartial.on_bi.bi_type, 0, 0);
296 Debug(LDAP_DEBUG_TRACE, "%s: modify unsuccessful: %d\n",
297 addpartial.on_bi.bi_type, rc, 0);
299 if(nullcb.sc_private)
301 rs->sr_text = nullcb.sc_private;
305 Debug(LDAP_DEBUG_TRACE, "%s: freeing mods...\n",
306 addpartial.on_bi.bi_type, 0, 0);
308 for(toDel = mods; toDel; toDel = mods)
310 mods = mods->sml_next;
316 Debug(LDAP_DEBUG_TRACE, "%s: no mods to process\n",
317 addpartial.on_bi.bi_type, 0, 0);
322 Debug(LDAP_DEBUG_TRACE, "%s: no entry!\n",
323 addpartial.on_bi.bi_type, 0, 0);
326 op->o_callback = NULL;
327 send_ldap_result( op, rs );
328 ch_free((void *)rs->sr_text);
335 static int collect_error_msg_cb( Operation *op, SlapReply *rs)
339 op->o_callback->sc_private = (void *) ch_strdup(rs->sr_text);
345 int addpartial_init()
347 addpartial.on_bi.bi_type = "addpartial";
348 addpartial.on_bi.bi_op_add = addpartial_add;
350 return (overlay_register(&addpartial));
353 int init_module(int argc, char *argv[])
355 return addpartial_init();