summaryrefslogtreecommitdiffstats
path: root/contrib/slapd-modules/addpartial/addpartial-overlay.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/slapd-modules/addpartial/addpartial-overlay.c')
-rw-r--r--contrib/slapd-modules/addpartial/addpartial-overlay.c349
1 files changed, 349 insertions, 0 deletions
diff --git a/contrib/slapd-modules/addpartial/addpartial-overlay.c b/contrib/slapd-modules/addpartial/addpartial-overlay.c
new file mode 100644
index 0000000..b1d637b
--- /dev/null
+++ b/contrib/slapd-modules/addpartial/addpartial-overlay.c
@@ -0,0 +1,349 @@
+/* addpartial-overlay.c */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2004-2022 The OpenLDAP Foundation.
+ * Portions Copyright (C) 2004 Virginia Tech, David Hawes.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * http://www.OpenLDAP.org/license.html.
+ */
+/* ACKNOLEDGEDMENTS:
+ * This work was initially developed by David Hawes of Virginia Tech
+ * for inclusion in OpenLDAP Software.
+ */
+/* addpartial-overlay
+ *
+ * This is an OpenLDAP overlay that intercepts ADD requests, determines if a
+ * change has actually taken place for that record, and then performs a modify
+ * request for those values that have changed (modified, added, deleted). If
+ * the record has not changed in any way, it is ignored. If the record does not
+ * exist, the record falls through to the normal add mechanism. This overlay is
+ * useful for replicating from sources that are not LDAPs where it is easier to
+ * build entire records than to determine the changes (i.e. a database).
+ */
+
+#include "portable.h"
+#include "slap.h"
+
+static int collect_error_msg_cb( Operation *op, SlapReply *rs);
+
+static slap_overinst addpartial;
+
+/**
+ * The meat of the overlay. Search for the record, determine changes, take
+ * action or fall through.
+ */
+static int addpartial_add( Operation *op, SlapReply *rs)
+{
+ Operation nop = *op;
+ Entry *toAdd = NULL;
+ Entry *found = NULL;
+ slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+ int rc;
+
+ toAdd = op->oq_add.rs_e;
+
+ Debug(LDAP_DEBUG_TRACE, "%s: toAdd->e_nname.bv_val: %s\n",
+ addpartial.on_bi.bi_type, toAdd->e_nname.bv_val );
+
+ /* if the user doesn't have access, fall through to the normal ADD */
+ if(!access_allowed(op, toAdd, slap_schema.si_ad_entry,
+ NULL, ACL_WRITE, NULL))
+ {
+ return SLAP_CB_CONTINUE;
+ }
+
+ rc = overlay_entry_get_ov(&nop, &nop.o_req_ndn, NULL, NULL, 0, &found, on);
+
+ if(rc != LDAP_SUCCESS)
+ {
+ Debug(LDAP_DEBUG_TRACE,
+ "%s: no entry found, falling through to normal add\n",
+ addpartial.on_bi.bi_type );
+ return SLAP_CB_CONTINUE;
+ }
+ else
+ {
+ Debug(LDAP_DEBUG_TRACE, "%s: found the dn\n", addpartial.on_bi.bi_type );
+
+ if(found)
+ {
+ Attribute *attr = NULL;
+ Attribute *at = NULL;
+ int ret;
+ Modifications *mods = NULL;
+ Modifications **modtail = &mods;
+ Modifications *mod = NULL;
+
+ Debug(LDAP_DEBUG_TRACE, "%s: have an entry!\n",
+ addpartial.on_bi.bi_type );
+
+ /* determine if the changes are in the found entry */
+ for(attr = toAdd->e_attrs; attr; attr = attr->a_next)
+ {
+ if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
+
+ at = attr_find(found->e_attrs, attr->a_desc);
+ if(!at)
+ {
+ Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s not found!\n",
+ addpartial.on_bi.bi_type,
+ attr->a_desc->ad_cname.bv_val );
+ mod = (Modifications *) ch_malloc(sizeof(
+ Modifications));
+ mod->sml_flags = 0;
+ mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
+ mod->sml_op &= LDAP_MOD_OP;
+ mod->sml_next = NULL;
+ mod->sml_desc = attr->a_desc;
+ mod->sml_type = attr->a_desc->ad_cname;
+ mod->sml_values = attr->a_vals;
+ mod->sml_nvalues = attr->a_nvals;
+ mod->sml_numvals = attr->a_numvals;
+ *modtail = mod;
+ modtail = &mod->sml_next;
+ }
+ else
+ {
+ MatchingRule *mr = attr->a_desc->ad_type->sat_equality;
+ struct berval *bv;
+ const char *text;
+ int acount , bcount;
+ Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s found\n",
+ addpartial.on_bi.bi_type,
+ attr->a_desc->ad_cname.bv_val );
+
+ for(bv = attr->a_vals, acount = 0; bv->bv_val != NULL;
+ bv++, acount++)
+ {
+ /* count num values for attr */
+ }
+ for(bv = at->a_vals, bcount = 0; bv->bv_val != NULL;
+ bv++, bcount++)
+ {
+ /* count num values for attr */
+ }
+ if(acount != bcount)
+ {
+ Debug(LDAP_DEBUG_TRACE, "%s: acount != bcount, %s\n",
+ addpartial.on_bi.bi_type,
+ "replace all" );
+ mod = (Modifications *) ch_malloc(sizeof(
+ Modifications));
+ mod->sml_flags = 0;
+ mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
+ mod->sml_op &= LDAP_MOD_OP;
+ mod->sml_next = NULL;
+ mod->sml_desc = attr->a_desc;
+ mod->sml_type = attr->a_desc->ad_cname;
+ mod->sml_values = attr->a_vals;
+ mod->sml_nvalues = attr->a_nvals;
+ mod->sml_numvals = attr->a_numvals;
+ *modtail = mod;
+ modtail = &mod->sml_next;
+ continue;
+ }
+
+ for(bv = attr->a_vals; bv->bv_val != NULL; bv++)
+ {
+ struct berval *v;
+ ret = -1;
+
+ for(v = at->a_vals; v->bv_val != NULL; v++)
+ {
+ int r;
+ if(mr && ((r = value_match(&ret, attr->a_desc, mr,
+ SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
+ bv, v, &text)) == 0))
+ {
+ if(ret == 0)
+ break;
+ }
+ else
+ {
+ Debug(LDAP_DEBUG_TRACE,
+ "%s: \tvalue DNE, r: %d \n",
+ addpartial.on_bi.bi_type,
+ r );
+ ret = strcmp(bv->bv_val, v->bv_val);
+ if(ret == 0)
+ break;
+ }
+ }
+
+ if(ret == 0)
+ {
+ Debug(LDAP_DEBUG_TRACE,
+ "%s: \tvalue %s exists, ret: %d\n",
+ addpartial.on_bi.bi_type, bv->bv_val, ret);
+ }
+ else
+ {
+ Debug(LDAP_DEBUG_TRACE,
+ "%s: \tvalue %s DNE, ret: %d\n",
+ addpartial.on_bi.bi_type, bv->bv_val, ret);
+ mod = (Modifications *) ch_malloc(sizeof(
+ Modifications));
+ mod->sml_flags = 0;
+ mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
+ mod->sml_op &= LDAP_MOD_OP;
+ mod->sml_next = NULL;
+ mod->sml_desc = attr->a_desc;
+ mod->sml_type = attr->a_desc->ad_cname;
+ mod->sml_values = attr->a_vals;
+ mod->sml_nvalues = attr->a_nvals;
+ mod->sml_numvals = attr->a_numvals;
+ *modtail = mod;
+ modtail = &mod->sml_next;
+ break;
+ }
+ }
+ }
+ }
+
+ /* determine if any attributes were deleted */
+ for(attr = found->e_attrs; attr; attr = attr->a_next)
+ {
+ if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
+
+ at = NULL;
+ at = attr_find(toAdd->e_attrs, attr->a_desc);
+ if(!at)
+ {
+ Debug(LDAP_DEBUG_TRACE,
+ "%s: Attribute %s not found in new entry!!!\n",
+ addpartial.on_bi.bi_type,
+ attr->a_desc->ad_cname.bv_val );
+ mod = (Modifications *) ch_malloc(sizeof(
+ Modifications));
+ mod->sml_flags = 0;
+ mod->sml_op = LDAP_MOD_REPLACE;
+ mod->sml_next = NULL;
+ mod->sml_desc = attr->a_desc;
+ mod->sml_type = attr->a_desc->ad_cname;
+ mod->sml_values = NULL;
+ mod->sml_nvalues = NULL;
+ mod->sml_numvals = 0;
+ *modtail = mod;
+ modtail = &mod->sml_next;
+ }
+ else
+ {
+ Debug(LDAP_DEBUG_TRACE,
+ "%s: Attribute %s found in new entry\n",
+ addpartial.on_bi.bi_type,
+ at->a_desc->ad_cname.bv_val );
+ }
+ }
+
+ overlay_entry_release_ov(&nop, found, 0, on);
+
+ if(mods)
+ {
+ Modifications *m = NULL;
+ Modifications *toDel;
+ int modcount;
+ slap_callback nullcb = { NULL, collect_error_msg_cb,
+ NULL, NULL };
+
+ Debug(LDAP_DEBUG_TRACE, "%s: mods to do...\n",
+ addpartial.on_bi.bi_type );
+
+ nop.o_tag = LDAP_REQ_MODIFY;
+ nop.orm_modlist = mods;
+ nop.orm_no_opattrs = 0;
+ nop.o_callback = &nullcb;
+ nop.o_bd->bd_info = (BackendInfo *) on->on_info;
+
+ for(m = mods, modcount = 0; m; m = m->sml_next,
+ modcount++)
+ {
+ /* count number of mods */
+ }
+
+ Debug(LDAP_DEBUG_TRACE, "%s: number of mods: %d\n",
+ addpartial.on_bi.bi_type, modcount );
+
+ if(nop.o_bd->be_modify)
+ {
+ SlapReply nrs = { REP_RESULT };
+ rc = (nop.o_bd->be_modify)(&nop, &nrs);
+ }
+
+ if(rc == LDAP_SUCCESS)
+ {
+ Debug(LDAP_DEBUG_TRACE,
+ "%s: modify successful\n",
+ addpartial.on_bi.bi_type );
+ }
+ else
+ {
+ Debug(LDAP_DEBUG_TRACE, "%s: modify unsuccessful: %d\n",
+ addpartial.on_bi.bi_type, rc );
+ rs->sr_err = rc;
+ if(nullcb.sc_private)
+ {
+ rs->sr_text = nullcb.sc_private;
+ }
+ }
+
+ Debug(LDAP_DEBUG_TRACE, "%s: freeing mods...\n",
+ addpartial.on_bi.bi_type );
+
+ for(toDel = mods; toDel; toDel = mods)
+ {
+ mods = mods->sml_next;
+ ch_free(toDel);
+ }
+ }
+ else
+ {
+ Debug(LDAP_DEBUG_TRACE, "%s: no mods to process\n",
+ addpartial.on_bi.bi_type );
+ }
+ }
+ else
+ {
+ Debug(LDAP_DEBUG_TRACE, "%s: no entry!\n",
+ addpartial.on_bi.bi_type );
+ }
+
+ op->o_callback = NULL;
+ send_ldap_result( op, rs );
+ ch_free((void *)rs->sr_text);
+ rs->sr_text = NULL;
+
+ return LDAP_SUCCESS;
+ }
+}
+
+static int collect_error_msg_cb( Operation *op, SlapReply *rs)
+{
+ if(rs->sr_text)
+ {
+ op->o_callback->sc_private = (void *) ch_strdup(rs->sr_text);
+ }
+
+ return LDAP_SUCCESS;
+}
+
+int addpartial_init()
+{
+ addpartial.on_bi.bi_type = "addpartial";
+ addpartial.on_bi.bi_flags = SLAPO_BFLAG_SINGLE;
+ addpartial.on_bi.bi_op_add = addpartial_add;
+
+ return (overlay_register(&addpartial));
+}
+
+int init_module(int argc, char *argv[])
+{
+ return addpartial_init();
+}