2 * $Id: addpartial-overlay.c 5376 2007-01-26 20:03:13Z 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: 5376 $
20 * Updated: $Date: 2007-01-26 15:03:13 -0500 (Fri, 26 Jan 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).
35 #include <ac/string.h>
36 #include <ac/socket.h>
41 static int addpartial_search_cb( Operation *op, SlapReply *rs);
42 static int collect_error_msg_cb( Operation *op, SlapReply *rs);
44 static slap_overinst addpartial;
47 * The meat of the overlay. Search for the record, determine changes, take
48 * action or fall through.
50 static int addpartial_add( Operation *op, SlapReply *rs)
53 SlapReply nrs = { REP_RESULT };
54 Filter *filter = NULL;
56 struct berval fstr = BER_BVNULL;
57 slap_callback cb = { NULL, addpartial_search_cb, NULL, NULL };
58 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
61 toAdd = op->oq_add.rs_e;
63 Debug(LDAP_DEBUG_TRACE, "%s: toAdd->e_nname.bv_val: %s\n",
64 addpartial.on_bi.bi_type, toAdd->e_nname.bv_val,0);
66 /* if the user doesn't have access, fall through to the normal ADD */
67 if(!access_allowed(op, toAdd, slap_schema.si_ad_entry,
68 NULL, ACL_WRITE, NULL))
70 return SLAP_CB_CONTINUE;
76 op->o_bd->bd_info = (BackendInfo *) on->on_info;
77 nop.o_tag = LDAP_REQ_SEARCH;
80 filter = str2filter("(objectclass=*)");
81 filter2bv(filter, &fstr);
83 nop.ors_scope = LDAP_SCOPE_BASE;
84 nop.ors_deref = LDAP_DEREF_NEVER;
85 nop.ors_slimit = -1;//SLAP_NO_LIMIT;
86 nop.ors_tlimit = -1;//SLAP_NO_LIMIT;
87 nop.ors_attrsonly = 0;
88 nop.ors_attrs = slap_anlist_no_attrs;
89 nop.ors_filter = filter;
90 nop.ors_filterstr = fstr;
92 memset(&nrs, 0, sizeof(nrs));
93 nrs.sr_type = REP_RESULT;
94 nrs.sr_err = LDAP_SUCCESS;
96 nrs.sr_flags |= REP_ENTRY_MUSTBEFREED;
99 Debug(LDAP_DEBUG_TRACE, "%s: performing search\n", addpartial.on_bi.bi_type,
102 if(nop.o_bd->be_search)
104 rc = nop.o_bd->be_search(&nop, &nrs);
105 Debug(LDAP_DEBUG_TRACE, "%s: search performed\n",
106 addpartial.on_bi.bi_type,0,0);
110 Debug(LDAP_DEBUG_TRACE, "%s: backend missing search function\n",
111 addpartial.on_bi.bi_type,0,0);
117 ch_free(fstr.bv_val);
119 if(rc != LDAP_SUCCESS)
120 return SLAP_CB_CONTINUE;
124 Debug(LDAP_DEBUG_TRACE, "%s: found the dn\n", addpartial.on_bi.bi_type,
126 found = (Entry *) cb.sc_private;
130 Attribute *attr = NULL;
131 Attribute *at = NULL;
133 Modifications *mods = NULL;
134 Modifications **modtail = &mods;
135 Modifications *mod = NULL;
137 Debug(LDAP_DEBUG_TRACE, "%s: have an entry!\n",
138 addpartial.on_bi.bi_type,0,0);
140 /* determine if the changes are in the found entry */
141 for(attr = toAdd->e_attrs; attr; attr = attr->a_next)
143 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
145 at = attr_find(found->e_attrs, attr->a_desc);
148 Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s not found!\n",
149 addpartial.on_bi.bi_type,
150 attr->a_desc->ad_cname.bv_val,0);
151 mod = (Modifications *) ch_malloc(sizeof(
154 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
155 mod->sml_op &= LDAP_MOD_OP;
156 mod->sml_next = NULL;
157 mod->sml_desc = attr->a_desc;
158 mod->sml_type.bv_val = attr->a_desc->ad_cname.bv_val;
159 mod->sml_type.bv_len = strlen(mod->sml_type.bv_val);
160 mod->sml_values = attr->a_vals;
161 mod->sml_nvalues = attr->a_nvals;
163 modtail = &mod->sml_next;
167 MatchingRule *mr = attr->a_desc->ad_type->sat_equality;
171 Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s found\n",
172 addpartial.on_bi.bi_type,
173 attr->a_desc->ad_cname.bv_val,0);
175 for(bv = attr->a_vals, acount = 0; bv->bv_val != NULL;
178 /* count num values for attr */
180 for(bv = at->a_vals, bcount = 0; bv->bv_val != NULL;
183 /* count num values for attr */
187 Debug(LDAP_DEBUG_TRACE, "%s: acount != bcount, %s\n",
188 addpartial.on_bi.bi_type,
190 mod = (Modifications *) ch_malloc(sizeof(
193 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
194 mod->sml_op &= LDAP_MOD_OP;
195 mod->sml_next = NULL;
196 mod->sml_desc = attr->a_desc;
197 mod->sml_type.bv_val = attr->a_desc->ad_cname.bv_val;
198 mod->sml_type.bv_len = strlen(mod->sml_type.bv_val);
199 mod->sml_values = attr->a_vals;
200 mod->sml_nvalues = attr->a_nvals;
202 modtail = &mod->sml_next;
206 for(bv = attr->a_vals; bv->bv_val != NULL; bv++)
211 for(v = at->a_vals; v->bv_val != NULL; v++)
214 if(mr && ((r = value_match(&ret, attr->a_desc, mr,
215 SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
216 bv, v, &text)) == 0))
223 Debug(LDAP_DEBUG_TRACE,
224 "%s: \tvalue DNE, r: %d \n",
225 addpartial.on_bi.bi_type,
227 ret = strcmp(bv->bv_val, v->bv_val);
235 Debug(LDAP_DEBUG_TRACE,
236 "%s: \tvalue %s exists, ret: %d\n",
237 addpartial.on_bi.bi_type, bv->bv_val, ret);
241 Debug(LDAP_DEBUG_TRACE,
242 "%s: \tvalue %s DNE, ret: %d\n",
243 addpartial.on_bi.bi_type, bv->bv_val, ret);
244 mod = (Modifications *) ch_malloc(sizeof(
247 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
248 mod->sml_op &= LDAP_MOD_OP;
249 mod->sml_next = NULL;
250 mod->sml_desc = attr->a_desc;
251 mod->sml_type.bv_val =
252 attr->a_desc->ad_cname.bv_val;
253 mod->sml_type.bv_len = strlen(mod->sml_type.bv_val);
254 mod->sml_values = attr->a_vals;
255 mod->sml_nvalues = attr->a_nvals;
257 modtail = &mod->sml_next;
264 /* determine if any attributes were deleted */
265 for(attr = found->e_attrs; attr; attr = attr->a_next)
267 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
270 at = attr_find(toAdd->e_attrs, attr->a_desc);
273 Debug(LDAP_DEBUG_TRACE,
274 "%s: Attribute %s not found in new entry!!!\n",
275 addpartial.on_bi.bi_type,
276 attr->a_desc->ad_cname.bv_val, 0);
277 mod = (Modifications *) ch_malloc(sizeof(
280 mod->sml_op = LDAP_MOD_REPLACE;
281 mod->sml_next = NULL;
282 mod->sml_desc = attr->a_desc;
283 mod->sml_type.bv_val =
284 attr->a_desc->ad_cname.bv_val;
285 mod->sml_type.bv_len = strlen(mod->sml_type.bv_val);
286 mod->sml_values = NULL;
287 mod->sml_nvalues = NULL;
289 modtail = &mod->sml_next;
293 Debug(LDAP_DEBUG_TRACE,
294 "%s: Attribute %s found in new entry\n",
295 addpartial.on_bi.bi_type,
296 at->a_desc->ad_cname.bv_val, 0);
302 Debug(LDAP_DEBUG_TRACE, "%s: mods to do...\n",
303 addpartial.on_bi.bi_type, 0, 0);
304 if(nop.o_bd->be_modify)
306 Modifications *m = NULL;
308 slap_callback cb2 = { NULL, slap_replog_cb, NULL, NULL };
309 slap_callback nullcb = { NULL, collect_error_msg_cb,
311 char textbuf[SLAP_TEXT_BUFLEN];
312 size_t textlen = sizeof textbuf;
314 memset(&nrs, 0, sizeof(nrs));
315 nrs.sr_type = REP_RESULT;
316 nrs.sr_err = LDAP_SUCCESS;
320 nop.o_tag = LDAP_REQ_MODIFY;
321 nop.orm_modlist = mods;
322 cb2.sc_next = &nullcb;
323 nop.o_callback = &cb2;
324 nop.o_bd->bd_info = (BackendInfo *) on->on_info;
326 for(m = mods, modcount = 0; m; m = m->sml_next,
329 /* count number of mods */
332 Debug(LDAP_DEBUG_TRACE, "%s: number of mods: %d\n",
333 addpartial.on_bi.bi_type, modcount, 0);
335 rc = (nop.o_bd->be_modify)(&nop, &nrs);
337 if(rc == LDAP_SUCCESS)
339 Debug(LDAP_DEBUG_TRACE,
340 "%s: modify successful\n",
341 addpartial.on_bi.bi_type, 0, 0);
345 Debug(LDAP_DEBUG_TRACE, "%s: modify unsuccessful: %d\n",
346 addpartial.on_bi.bi_type, rc, 0);
350 rs->sr_text = nullcb.sc_private;
354 Debug(LDAP_DEBUG_TRACE, "%s: freeing mods...\n",
355 addpartial.on_bi.bi_type, 0, 0);
359 Modifications *toDel;
361 for(toDel = mods; toDel; toDel = mods)
363 mods = mods->sml_next;
371 Debug(LDAP_DEBUG_TRACE, "%s: no mods to process\n",
372 addpartial.on_bi.bi_type, 0, 0);
380 Debug(LDAP_DEBUG_TRACE, "%s: no entry!\n",
381 addpartial.on_bi.bi_type, 0, 0);
384 op->o_callback = NULL;
385 send_ldap_result( op, rs );
386 ch_free((void *)rs->sr_text);
393 static int addpartial_search_cb( Operation *op, SlapReply *rs)
397 if(rs->sr_type != REP_SEARCH) return 0;
399 Debug(LDAP_DEBUG_TRACE, "%s: addpartial_search_cb\n",
400 addpartial.on_bi.bi_type, 0, 0);
404 Debug(LDAP_DEBUG_TRACE, "%s: dn found: %s\n",
405 addpartial.on_bi.bi_type, rs->sr_entry->e_nname.bv_val, 0);
406 entry = rs->sr_entry;
407 op->o_callback->sc_private = (void *) entry_dup(entry);
413 static int collect_error_msg_cb( Operation *op, SlapReply *rs)
417 op->o_callback->sc_private = (void *) ch_strdup(rs->sr_text);
423 int addpartial_init()
425 addpartial.on_bi.bi_type = "addpartial";
426 addpartial.on_bi.bi_op_add = addpartial_add;
428 return (overlay_register(&addpartial));
431 int init_module(int argc, char *argv[])
433 return addpartial_init();