1 /* addpartial-overlay.c */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2004-2011 The OpenLDAP Foundation.
6 * Portions Copyright (C) 2004 Virginia Tech, David Hawes.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
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.
18 * This work was initially developed by David Hawes of Virginia Tech
19 * for inclusion in OpenLDAP Software.
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).
35 static int collect_error_msg_cb( Operation *op, SlapReply *rs);
37 static slap_overinst addpartial;
40 * The meat of the overlay. Search for the record, determine changes, take
41 * action or fall through.
43 static int addpartial_add( Operation *op, SlapReply *rs)
48 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
51 toAdd = op->oq_add.rs_e;
53 Debug(LDAP_DEBUG_TRACE, "%s: toAdd->e_nname.bv_val: %s\n",
54 addpartial.on_bi.bi_type, toAdd->e_nname.bv_val,0);
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))
60 return SLAP_CB_CONTINUE;
63 rc = overlay_entry_get_ov(&nop, &nop.o_req_ndn, NULL, NULL, 0, &found, on);
65 if(rc != LDAP_SUCCESS)
67 Debug(LDAP_DEBUG_TRACE,
68 "%s: no entry found, falling through to normal add\n",
69 addpartial.on_bi.bi_type, 0, 0);
70 return SLAP_CB_CONTINUE;
74 Debug(LDAP_DEBUG_TRACE, "%s: found the dn\n", addpartial.on_bi.bi_type,
79 Attribute *attr = NULL;
82 Modifications *mods = NULL;
83 Modifications **modtail = &mods;
84 Modifications *mod = NULL;
86 Debug(LDAP_DEBUG_TRACE, "%s: have an entry!\n",
87 addpartial.on_bi.bi_type,0,0);
89 /* determine if the changes are in the found entry */
90 for(attr = toAdd->e_attrs; attr; attr = attr->a_next)
92 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
94 at = attr_find(found->e_attrs, attr->a_desc);
97 Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s not found!\n",
98 addpartial.on_bi.bi_type,
99 attr->a_desc->ad_cname.bv_val,0);
100 mod = (Modifications *) ch_malloc(sizeof(
103 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
104 mod->sml_op &= LDAP_MOD_OP;
105 mod->sml_next = NULL;
106 mod->sml_desc = attr->a_desc;
107 mod->sml_type = attr->a_desc->ad_cname;
108 mod->sml_values = attr->a_vals;
109 mod->sml_nvalues = attr->a_nvals;
110 mod->sml_numvals = attr->a_numvals;
112 modtail = &mod->sml_next;
116 MatchingRule *mr = attr->a_desc->ad_type->sat_equality;
120 Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s found\n",
121 addpartial.on_bi.bi_type,
122 attr->a_desc->ad_cname.bv_val,0);
124 for(bv = attr->a_vals, acount = 0; bv->bv_val != NULL;
127 /* count num values for attr */
129 for(bv = at->a_vals, bcount = 0; bv->bv_val != NULL;
132 /* count num values for attr */
136 Debug(LDAP_DEBUG_TRACE, "%s: acount != bcount, %s\n",
137 addpartial.on_bi.bi_type,
139 mod = (Modifications *) ch_malloc(sizeof(
142 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
143 mod->sml_op &= LDAP_MOD_OP;
144 mod->sml_next = NULL;
145 mod->sml_desc = attr->a_desc;
146 mod->sml_type = attr->a_desc->ad_cname;
147 mod->sml_values = attr->a_vals;
148 mod->sml_nvalues = attr->a_nvals;
149 mod->sml_numvals = attr->a_numvals;
151 modtail = &mod->sml_next;
155 for(bv = attr->a_vals; bv->bv_val != NULL; bv++)
160 for(v = at->a_vals; v->bv_val != NULL; v++)
163 if(mr && ((r = value_match(&ret, attr->a_desc, mr,
164 SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
165 bv, v, &text)) == 0))
172 Debug(LDAP_DEBUG_TRACE,
173 "%s: \tvalue DNE, r: %d \n",
174 addpartial.on_bi.bi_type,
176 ret = strcmp(bv->bv_val, v->bv_val);
184 Debug(LDAP_DEBUG_TRACE,
185 "%s: \tvalue %s exists, ret: %d\n",
186 addpartial.on_bi.bi_type, bv->bv_val, ret);
190 Debug(LDAP_DEBUG_TRACE,
191 "%s: \tvalue %s DNE, ret: %d\n",
192 addpartial.on_bi.bi_type, bv->bv_val, ret);
193 mod = (Modifications *) ch_malloc(sizeof(
196 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
197 mod->sml_op &= LDAP_MOD_OP;
198 mod->sml_next = NULL;
199 mod->sml_desc = attr->a_desc;
200 mod->sml_type = attr->a_desc->ad_cname;
201 mod->sml_values = attr->a_vals;
202 mod->sml_nvalues = attr->a_nvals;
203 mod->sml_numvals = attr->a_numvals;
205 modtail = &mod->sml_next;
212 /* determine if any attributes were deleted */
213 for(attr = found->e_attrs; attr; attr = attr->a_next)
215 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
218 at = attr_find(toAdd->e_attrs, attr->a_desc);
221 Debug(LDAP_DEBUG_TRACE,
222 "%s: Attribute %s not found in new entry!!!\n",
223 addpartial.on_bi.bi_type,
224 attr->a_desc->ad_cname.bv_val, 0);
225 mod = (Modifications *) ch_malloc(sizeof(
228 mod->sml_op = LDAP_MOD_REPLACE;
229 mod->sml_next = NULL;
230 mod->sml_desc = attr->a_desc;
231 mod->sml_type = attr->a_desc->ad_cname;
232 mod->sml_values = NULL;
233 mod->sml_nvalues = NULL;
234 mod->sml_numvals = 0;
236 modtail = &mod->sml_next;
240 Debug(LDAP_DEBUG_TRACE,
241 "%s: Attribute %s found in new entry\n",
242 addpartial.on_bi.bi_type,
243 at->a_desc->ad_cname.bv_val, 0);
247 overlay_entry_release_ov(&nop, found, 0, on);
251 Modifications *m = NULL;
252 Modifications *toDel;
254 slap_callback nullcb = { NULL, collect_error_msg_cb,
257 Debug(LDAP_DEBUG_TRACE, "%s: mods to do...\n",
258 addpartial.on_bi.bi_type, 0, 0);
260 nop.o_tag = LDAP_REQ_MODIFY;
261 nop.orm_modlist = mods;
262 nop.orm_no_opattrs = 0;
263 nop.o_callback = &nullcb;
264 nop.o_bd->bd_info = (BackendInfo *) on->on_info;
266 for(m = mods, modcount = 0; m; m = m->sml_next,
269 /* count number of mods */
272 Debug(LDAP_DEBUG_TRACE, "%s: number of mods: %d\n",
273 addpartial.on_bi.bi_type, modcount, 0);
275 if(nop.o_bd->be_modify)
277 SlapReply nrs = { REP_RESULT };
278 rc = (nop.o_bd->be_modify)(&nop, &nrs);
281 if(rc == LDAP_SUCCESS)
283 Debug(LDAP_DEBUG_TRACE,
284 "%s: modify successful\n",
285 addpartial.on_bi.bi_type, 0, 0);
289 Debug(LDAP_DEBUG_TRACE, "%s: modify unsuccessful: %d\n",
290 addpartial.on_bi.bi_type, rc, 0);
292 if(nullcb.sc_private)
294 rs->sr_text = nullcb.sc_private;
298 Debug(LDAP_DEBUG_TRACE, "%s: freeing mods...\n",
299 addpartial.on_bi.bi_type, 0, 0);
301 for(toDel = mods; toDel; toDel = mods)
303 mods = mods->sml_next;
309 Debug(LDAP_DEBUG_TRACE, "%s: no mods to process\n",
310 addpartial.on_bi.bi_type, 0, 0);
315 Debug(LDAP_DEBUG_TRACE, "%s: no entry!\n",
316 addpartial.on_bi.bi_type, 0, 0);
319 op->o_callback = NULL;
320 send_ldap_result( op, rs );
321 ch_free((void *)rs->sr_text);
328 static int collect_error_msg_cb( Operation *op, SlapReply *rs)
332 op->o_callback->sc_private = (void *) ch_strdup(rs->sr_text);
338 int addpartial_init()
340 addpartial.on_bi.bi_type = "addpartial";
341 addpartial.on_bi.bi_op_add = addpartial_add;
343 return (overlay_register(&addpartial));
346 int init_module(int argc, char *argv[])
348 return addpartial_init();