1*cf1d77f7Schristos /* $NetBSD: addpartial-overlay.c,v 1.3 2021/08/14 16:14:50 christos Exp $ */
24e6df137Slukem
34e6df137Slukem /* addpartial-overlay.c */
433197c6aStron /* $OpenLDAP$ */
54e6df137Slukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
62de962bdSlukem *
7*cf1d77f7Schristos * Copyright 2004-2021 The OpenLDAP Foundation.
84e6df137Slukem * Portions Copyright (C) 2004 Virginia Tech, David Hawes.
92de962bdSlukem * All rights reserved.
102de962bdSlukem *
112de962bdSlukem * Redistribution and use in source and binary forms, with or without
122de962bdSlukem * modification, are permitted only as authorized by the OpenLDAP
132de962bdSlukem * Public License.
142de962bdSlukem *
152de962bdSlukem * A copy of this license is available in file LICENSE in the
162de962bdSlukem * top-level directory of the distribution or, alternatively, at
172de962bdSlukem * http://www.OpenLDAP.org/license.html.
184e6df137Slukem */
194e6df137Slukem /* ACKNOLEDGEDMENTS:
204e6df137Slukem * This work was initially developed by David Hawes of Virginia Tech
214e6df137Slukem * for inclusion in OpenLDAP Software.
224e6df137Slukem */
234e6df137Slukem /* addpartial-overlay
242de962bdSlukem *
252de962bdSlukem * This is an OpenLDAP overlay that intercepts ADD requests, determines if a
262de962bdSlukem * change has actually taken place for that record, and then performs a modify
272de962bdSlukem * request for those values that have changed (modified, added, deleted). If
282de962bdSlukem * the record has not changed in any way, it is ignored. If the record does not
292de962bdSlukem * exist, the record falls through to the normal add mechanism. This overlay is
302de962bdSlukem * useful for replicating from sources that are not LDAPs where it is easier to
312de962bdSlukem * build entire records than to determine the changes (i.e. a database).
322de962bdSlukem */
332de962bdSlukem
348bd9f7cdSchristos #include <sys/cdefs.h>
35*cf1d77f7Schristos __RCSID("$NetBSD: addpartial-overlay.c,v 1.3 2021/08/14 16:14:50 christos Exp $");
368bd9f7cdSchristos
372de962bdSlukem #include "portable.h"
382de962bdSlukem #include "slap.h"
392de962bdSlukem
402de962bdSlukem static int collect_error_msg_cb( Operation *op, SlapReply *rs);
412de962bdSlukem
422de962bdSlukem static slap_overinst addpartial;
432de962bdSlukem
442de962bdSlukem /**
452de962bdSlukem * The meat of the overlay. Search for the record, determine changes, take
462de962bdSlukem * action or fall through.
472de962bdSlukem */
addpartial_add(Operation * op,SlapReply * rs)482de962bdSlukem static int addpartial_add( Operation *op, SlapReply *rs)
492de962bdSlukem {
502de962bdSlukem Operation nop = *op;
512de962bdSlukem Entry *toAdd = NULL;
524e6df137Slukem Entry *found = NULL;
532de962bdSlukem slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
542de962bdSlukem int rc;
552de962bdSlukem
562de962bdSlukem toAdd = op->oq_add.rs_e;
572de962bdSlukem
582de962bdSlukem Debug(LDAP_DEBUG_TRACE, "%s: toAdd->e_nname.bv_val: %s\n",
59*cf1d77f7Schristos addpartial.on_bi.bi_type, toAdd->e_nname.bv_val );
602de962bdSlukem
612de962bdSlukem /* if the user doesn't have access, fall through to the normal ADD */
622de962bdSlukem if(!access_allowed(op, toAdd, slap_schema.si_ad_entry,
632de962bdSlukem NULL, ACL_WRITE, NULL))
642de962bdSlukem {
652de962bdSlukem return SLAP_CB_CONTINUE;
662de962bdSlukem }
672de962bdSlukem
684e6df137Slukem rc = overlay_entry_get_ov(&nop, &nop.o_req_ndn, NULL, NULL, 0, &found, on);
692de962bdSlukem
702de962bdSlukem if(rc != LDAP_SUCCESS)
714e6df137Slukem {
724e6df137Slukem Debug(LDAP_DEBUG_TRACE,
734e6df137Slukem "%s: no entry found, falling through to normal add\n",
74*cf1d77f7Schristos addpartial.on_bi.bi_type );
752de962bdSlukem return SLAP_CB_CONTINUE;
764e6df137Slukem }
772de962bdSlukem else
782de962bdSlukem {
79*cf1d77f7Schristos Debug(LDAP_DEBUG_TRACE, "%s: found the dn\n", addpartial.on_bi.bi_type );
802de962bdSlukem
812de962bdSlukem if(found)
822de962bdSlukem {
832de962bdSlukem Attribute *attr = NULL;
842de962bdSlukem Attribute *at = NULL;
852de962bdSlukem int ret;
862de962bdSlukem Modifications *mods = NULL;
872de962bdSlukem Modifications **modtail = &mods;
882de962bdSlukem Modifications *mod = NULL;
892de962bdSlukem
902de962bdSlukem Debug(LDAP_DEBUG_TRACE, "%s: have an entry!\n",
91*cf1d77f7Schristos addpartial.on_bi.bi_type );
922de962bdSlukem
932de962bdSlukem /* determine if the changes are in the found entry */
942de962bdSlukem for(attr = toAdd->e_attrs; attr; attr = attr->a_next)
952de962bdSlukem {
962de962bdSlukem if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
972de962bdSlukem
982de962bdSlukem at = attr_find(found->e_attrs, attr->a_desc);
992de962bdSlukem if(!at)
1002de962bdSlukem {
1012de962bdSlukem Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s not found!\n",
1022de962bdSlukem addpartial.on_bi.bi_type,
103*cf1d77f7Schristos attr->a_desc->ad_cname.bv_val );
1042de962bdSlukem mod = (Modifications *) ch_malloc(sizeof(
1052de962bdSlukem Modifications));
1062de962bdSlukem mod->sml_flags = 0;
1072de962bdSlukem mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
1082de962bdSlukem mod->sml_op &= LDAP_MOD_OP;
1092de962bdSlukem mod->sml_next = NULL;
1102de962bdSlukem mod->sml_desc = attr->a_desc;
1114e6df137Slukem mod->sml_type = attr->a_desc->ad_cname;
1122de962bdSlukem mod->sml_values = attr->a_vals;
1132de962bdSlukem mod->sml_nvalues = attr->a_nvals;
1142de962bdSlukem mod->sml_numvals = attr->a_numvals;
1152de962bdSlukem *modtail = mod;
1162de962bdSlukem modtail = &mod->sml_next;
1172de962bdSlukem }
1182de962bdSlukem else
1192de962bdSlukem {
1202de962bdSlukem MatchingRule *mr = attr->a_desc->ad_type->sat_equality;
1212de962bdSlukem struct berval *bv;
1222de962bdSlukem const char *text;
1232de962bdSlukem int acount , bcount;
1242de962bdSlukem Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s found\n",
1252de962bdSlukem addpartial.on_bi.bi_type,
126*cf1d77f7Schristos attr->a_desc->ad_cname.bv_val );
1272de962bdSlukem
1282de962bdSlukem for(bv = attr->a_vals, acount = 0; bv->bv_val != NULL;
1292de962bdSlukem bv++, acount++)
1302de962bdSlukem {
1312de962bdSlukem /* count num values for attr */
1322de962bdSlukem }
1332de962bdSlukem for(bv = at->a_vals, bcount = 0; bv->bv_val != NULL;
1342de962bdSlukem bv++, bcount++)
1352de962bdSlukem {
1362de962bdSlukem /* count num values for attr */
1372de962bdSlukem }
1382de962bdSlukem if(acount != bcount)
1392de962bdSlukem {
1402de962bdSlukem Debug(LDAP_DEBUG_TRACE, "%s: acount != bcount, %s\n",
1412de962bdSlukem addpartial.on_bi.bi_type,
142*cf1d77f7Schristos "replace all" );
1432de962bdSlukem mod = (Modifications *) ch_malloc(sizeof(
1442de962bdSlukem Modifications));
1452de962bdSlukem mod->sml_flags = 0;
1462de962bdSlukem mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
1472de962bdSlukem mod->sml_op &= LDAP_MOD_OP;
1482de962bdSlukem mod->sml_next = NULL;
1492de962bdSlukem mod->sml_desc = attr->a_desc;
1504e6df137Slukem mod->sml_type = attr->a_desc->ad_cname;
1512de962bdSlukem mod->sml_values = attr->a_vals;
1522de962bdSlukem mod->sml_nvalues = attr->a_nvals;
1532de962bdSlukem mod->sml_numvals = attr->a_numvals;
1542de962bdSlukem *modtail = mod;
1552de962bdSlukem modtail = &mod->sml_next;
1562de962bdSlukem continue;
1572de962bdSlukem }
1582de962bdSlukem
1592de962bdSlukem for(bv = attr->a_vals; bv->bv_val != NULL; bv++)
1602de962bdSlukem {
1612de962bdSlukem struct berval *v;
1622de962bdSlukem ret = -1;
1632de962bdSlukem
1642de962bdSlukem for(v = at->a_vals; v->bv_val != NULL; v++)
1652de962bdSlukem {
1662de962bdSlukem int r;
1672de962bdSlukem if(mr && ((r = value_match(&ret, attr->a_desc, mr,
1682de962bdSlukem SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
1692de962bdSlukem bv, v, &text)) == 0))
1702de962bdSlukem {
1712de962bdSlukem if(ret == 0)
1722de962bdSlukem break;
1732de962bdSlukem }
1742de962bdSlukem else
1752de962bdSlukem {
1762de962bdSlukem Debug(LDAP_DEBUG_TRACE,
1772de962bdSlukem "%s: \tvalue DNE, r: %d \n",
1782de962bdSlukem addpartial.on_bi.bi_type,
179*cf1d77f7Schristos r );
1802de962bdSlukem ret = strcmp(bv->bv_val, v->bv_val);
1812de962bdSlukem if(ret == 0)
1822de962bdSlukem break;
1832de962bdSlukem }
1842de962bdSlukem }
1852de962bdSlukem
1862de962bdSlukem if(ret == 0)
1872de962bdSlukem {
1882de962bdSlukem Debug(LDAP_DEBUG_TRACE,
1892de962bdSlukem "%s: \tvalue %s exists, ret: %d\n",
1902de962bdSlukem addpartial.on_bi.bi_type, bv->bv_val, ret);
1912de962bdSlukem }
1922de962bdSlukem else
1932de962bdSlukem {
1942de962bdSlukem Debug(LDAP_DEBUG_TRACE,
1952de962bdSlukem "%s: \tvalue %s DNE, ret: %d\n",
1962de962bdSlukem addpartial.on_bi.bi_type, bv->bv_val, ret);
1972de962bdSlukem mod = (Modifications *) ch_malloc(sizeof(
1982de962bdSlukem Modifications));
1992de962bdSlukem mod->sml_flags = 0;
2002de962bdSlukem mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
2012de962bdSlukem mod->sml_op &= LDAP_MOD_OP;
2022de962bdSlukem mod->sml_next = NULL;
2032de962bdSlukem mod->sml_desc = attr->a_desc;
2044e6df137Slukem mod->sml_type = attr->a_desc->ad_cname;
2052de962bdSlukem mod->sml_values = attr->a_vals;
2062de962bdSlukem mod->sml_nvalues = attr->a_nvals;
2072de962bdSlukem mod->sml_numvals = attr->a_numvals;
2082de962bdSlukem *modtail = mod;
2092de962bdSlukem modtail = &mod->sml_next;
2102de962bdSlukem break;
2112de962bdSlukem }
2122de962bdSlukem }
2132de962bdSlukem }
2142de962bdSlukem }
2152de962bdSlukem
2162de962bdSlukem /* determine if any attributes were deleted */
2172de962bdSlukem for(attr = found->e_attrs; attr; attr = attr->a_next)
2182de962bdSlukem {
2192de962bdSlukem if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue;
2202de962bdSlukem
2212de962bdSlukem at = NULL;
2222de962bdSlukem at = attr_find(toAdd->e_attrs, attr->a_desc);
2232de962bdSlukem if(!at)
2242de962bdSlukem {
2252de962bdSlukem Debug(LDAP_DEBUG_TRACE,
2262de962bdSlukem "%s: Attribute %s not found in new entry!!!\n",
2272de962bdSlukem addpartial.on_bi.bi_type,
228*cf1d77f7Schristos attr->a_desc->ad_cname.bv_val );
2292de962bdSlukem mod = (Modifications *) ch_malloc(sizeof(
2302de962bdSlukem Modifications));
2312de962bdSlukem mod->sml_flags = 0;
2322de962bdSlukem mod->sml_op = LDAP_MOD_REPLACE;
2332de962bdSlukem mod->sml_next = NULL;
2342de962bdSlukem mod->sml_desc = attr->a_desc;
2354e6df137Slukem mod->sml_type = attr->a_desc->ad_cname;
2362de962bdSlukem mod->sml_values = NULL;
2372de962bdSlukem mod->sml_nvalues = NULL;
2382de962bdSlukem mod->sml_numvals = 0;
2392de962bdSlukem *modtail = mod;
2402de962bdSlukem modtail = &mod->sml_next;
2412de962bdSlukem }
2422de962bdSlukem else
2432de962bdSlukem {
2442de962bdSlukem Debug(LDAP_DEBUG_TRACE,
2452de962bdSlukem "%s: Attribute %s found in new entry\n",
2462de962bdSlukem addpartial.on_bi.bi_type,
247*cf1d77f7Schristos at->a_desc->ad_cname.bv_val );
2482de962bdSlukem }
2492de962bdSlukem }
2502de962bdSlukem
2514e6df137Slukem overlay_entry_release_ov(&nop, found, 0, on);
2524e6df137Slukem
2532de962bdSlukem if(mods)
2542de962bdSlukem {
2552de962bdSlukem Modifications *m = NULL;
2564e6df137Slukem Modifications *toDel;
2572de962bdSlukem int modcount;
2582de962bdSlukem slap_callback nullcb = { NULL, collect_error_msg_cb,
2592de962bdSlukem NULL, NULL };
2604e6df137Slukem
2614e6df137Slukem Debug(LDAP_DEBUG_TRACE, "%s: mods to do...\n",
262*cf1d77f7Schristos addpartial.on_bi.bi_type );
2632de962bdSlukem
2642de962bdSlukem nop.o_tag = LDAP_REQ_MODIFY;
2652de962bdSlukem nop.orm_modlist = mods;
2664e6df137Slukem nop.orm_no_opattrs = 0;
2672de962bdSlukem nop.o_callback = &nullcb;
2682de962bdSlukem nop.o_bd->bd_info = (BackendInfo *) on->on_info;
2692de962bdSlukem
2702de962bdSlukem for(m = mods, modcount = 0; m; m = m->sml_next,
2712de962bdSlukem modcount++)
2722de962bdSlukem {
2732de962bdSlukem /* count number of mods */
2742de962bdSlukem }
2752de962bdSlukem
2762de962bdSlukem Debug(LDAP_DEBUG_TRACE, "%s: number of mods: %d\n",
277*cf1d77f7Schristos addpartial.on_bi.bi_type, modcount );
2782de962bdSlukem
2794e6df137Slukem if(nop.o_bd->be_modify)
2804e6df137Slukem {
28133197c6aStron SlapReply nrs = { REP_RESULT };
2822de962bdSlukem rc = (nop.o_bd->be_modify)(&nop, &nrs);
2834e6df137Slukem }
2842de962bdSlukem
2852de962bdSlukem if(rc == LDAP_SUCCESS)
2862de962bdSlukem {
2872de962bdSlukem Debug(LDAP_DEBUG_TRACE,
2882de962bdSlukem "%s: modify successful\n",
289*cf1d77f7Schristos addpartial.on_bi.bi_type );
2902de962bdSlukem }
2912de962bdSlukem else
2922de962bdSlukem {
2932de962bdSlukem Debug(LDAP_DEBUG_TRACE, "%s: modify unsuccessful: %d\n",
294*cf1d77f7Schristos addpartial.on_bi.bi_type, rc );
2952de962bdSlukem rs->sr_err = rc;
2964e6df137Slukem if(nullcb.sc_private)
2972de962bdSlukem {
2982de962bdSlukem rs->sr_text = nullcb.sc_private;
2992de962bdSlukem }
3002de962bdSlukem }
3012de962bdSlukem
3022de962bdSlukem Debug(LDAP_DEBUG_TRACE, "%s: freeing mods...\n",
303*cf1d77f7Schristos addpartial.on_bi.bi_type );
3042de962bdSlukem
3052de962bdSlukem for(toDel = mods; toDel; toDel = mods)
3062de962bdSlukem {
3072de962bdSlukem mods = mods->sml_next;
3082de962bdSlukem ch_free(toDel);
3092de962bdSlukem }
3102de962bdSlukem }
3112de962bdSlukem else
3122de962bdSlukem {
3132de962bdSlukem Debug(LDAP_DEBUG_TRACE, "%s: no mods to process\n",
314*cf1d77f7Schristos addpartial.on_bi.bi_type );
3152de962bdSlukem }
3162de962bdSlukem }
3172de962bdSlukem else
3182de962bdSlukem {
3192de962bdSlukem Debug(LDAP_DEBUG_TRACE, "%s: no entry!\n",
320*cf1d77f7Schristos addpartial.on_bi.bi_type );
3212de962bdSlukem }
3222de962bdSlukem
3232de962bdSlukem op->o_callback = NULL;
3242de962bdSlukem send_ldap_result( op, rs );
3252de962bdSlukem ch_free((void *)rs->sr_text);
3262de962bdSlukem rs->sr_text = NULL;
3272de962bdSlukem
3282de962bdSlukem return LDAP_SUCCESS;
3292de962bdSlukem }
3302de962bdSlukem }
3312de962bdSlukem
collect_error_msg_cb(Operation * op,SlapReply * rs)3322de962bdSlukem static int collect_error_msg_cb( Operation *op, SlapReply *rs)
3332de962bdSlukem {
3342de962bdSlukem if(rs->sr_text)
3352de962bdSlukem {
3362de962bdSlukem op->o_callback->sc_private = (void *) ch_strdup(rs->sr_text);
3372de962bdSlukem }
3382de962bdSlukem
3392de962bdSlukem return LDAP_SUCCESS;
3402de962bdSlukem }
3412de962bdSlukem
addpartial_init()3422de962bdSlukem int addpartial_init()
3432de962bdSlukem {
3442de962bdSlukem addpartial.on_bi.bi_type = "addpartial";
345*cf1d77f7Schristos addpartial.on_bi.bi_flags = SLAPO_BFLAG_SINGLE;
3462de962bdSlukem addpartial.on_bi.bi_op_add = addpartial_add;
3472de962bdSlukem
3482de962bdSlukem return (overlay_register(&addpartial));
3492de962bdSlukem }
3502de962bdSlukem
init_module(int argc,char * argv[])3512de962bdSlukem int init_module(int argc, char *argv[])
3522de962bdSlukem {
3532de962bdSlukem return addpartial_init();
3542de962bdSlukem }
355