/** * $Id: addpartial-overlay.c 6588 2007-11-07 18:29:25Z dhawes $ * * 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. * * SEE LICENSE FOR MORE INFORMATION * * Author: David H. Hawes, Jr. * Email: dhawes@vt.edu * Version: $Revision: 6588 $ * Updated: $Date: 2007-11-07 13:29:25 -0500 (Wed, 07 Nov 2007) $ * * 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 addpartial_search_cb( Operation *op, SlapReply *rs); 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; SlapReply nrs = { REP_RESULT }; Filter *filter = NULL; Entry *toAdd = NULL; struct berval fstr = BER_BVNULL; slap_callback cb = { NULL, addpartial_search_cb, NULL, 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,0); /* 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; } rs->sr_text = NULL; nop.o_callback = &cb; op->o_bd->bd_info = (BackendInfo *) on->on_info; nop.o_tag = LDAP_REQ_SEARCH; nop.o_ctrls = NULL; filter = str2filter("(objectclass=*)"); filter2bv(filter, &fstr); nop.ors_scope = LDAP_SCOPE_BASE; nop.ors_deref = LDAP_DEREF_NEVER; nop.ors_slimit = -1;//SLAP_NO_LIMIT; nop.ors_tlimit = -1;//SLAP_NO_LIMIT; nop.ors_attrsonly = 0; nop.ors_attrs = slap_anlist_no_attrs; nop.ors_filter = filter; nop.ors_filterstr = fstr; memset(&nrs, 0, sizeof(nrs)); nrs.sr_type = REP_RESULT; nrs.sr_err = LDAP_SUCCESS; nrs.sr_entry = NULL; nrs.sr_flags |= REP_ENTRY_MUSTBEFREED; nrs.sr_text = NULL; Debug(LDAP_DEBUG_TRACE, "%s: performing search\n", addpartial.on_bi.bi_type, 0,0); if(nop.o_bd->be_search) { rc = nop.o_bd->be_search(&nop, &nrs); Debug(LDAP_DEBUG_TRACE, "%s: search performed\n", addpartial.on_bi.bi_type,0,0); } else { Debug(LDAP_DEBUG_TRACE, "%s: backend missing search function\n", addpartial.on_bi.bi_type,0,0); } if(filter) filter_free(filter); if(fstr.bv_val) ch_free(fstr.bv_val); if(rc != LDAP_SUCCESS) return SLAP_CB_CONTINUE; else { Entry *found = NULL; Debug(LDAP_DEBUG_TRACE, "%s: found the dn\n", addpartial.on_bi.bi_type, 0,0); found = (Entry *) cb.sc_private; 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,0,0); /* 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,0); 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.bv_val = attr->a_desc->ad_cname.bv_val; mod->sml_type.bv_len = strlen(mod->sml_type.bv_val); 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,0); 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",0); 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.bv_val = attr->a_desc->ad_cname.bv_val; mod->sml_type.bv_len = strlen(mod->sml_type.bv_val); 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,0); 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.bv_val = attr->a_desc->ad_cname.bv_val; mod->sml_type.bv_len = strlen(mod->sml_type.bv_val); 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, 0); 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.bv_val = attr->a_desc->ad_cname.bv_val; mod->sml_type.bv_len = strlen(mod->sml_type.bv_val); 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, 0); } } if(mods) { Debug(LDAP_DEBUG_TRACE, "%s: mods to do...\n", addpartial.on_bi.bi_type, 0, 0); if(nop.o_bd->be_modify) { Modifications *m = NULL; int modcount; slap_callback nullcb = { NULL, collect_error_msg_cb, NULL, NULL }; char textbuf[SLAP_TEXT_BUFLEN]; size_t textlen = sizeof textbuf; memset(&nrs, 0, sizeof(nrs)); nrs.sr_type = REP_RESULT; nrs.sr_err = LDAP_SUCCESS; nrs.sr_entry = NULL; nrs.sr_text = NULL; nop.o_tag = LDAP_REQ_MODIFY; nop.orm_modlist = mods; 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, 0); 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, 0, 0); } else { Debug(LDAP_DEBUG_TRACE, "%s: modify unsuccessful: %d\n", addpartial.on_bi.bi_type, rc, 0); rs->sr_err = rc; if(nrs.sr_text) { rs->sr_text = nullcb.sc_private; } } Debug(LDAP_DEBUG_TRACE, "%s: freeing mods...\n", addpartial.on_bi.bi_type, 0, 0); if(mods != NULL) { Modifications *toDel; 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, 0, 0); } if(found != NULL) entry_free(found); } else { Debug(LDAP_DEBUG_TRACE, "%s: no entry!\n", addpartial.on_bi.bi_type, 0, 0); } op->o_callback = NULL; send_ldap_result( op, rs ); ch_free((void *)rs->sr_text); rs->sr_text = NULL; return LDAP_SUCCESS; } } static int addpartial_search_cb( Operation *op, SlapReply *rs) { Entry *entry = NULL; if(rs->sr_type != REP_SEARCH) return 0; Debug(LDAP_DEBUG_TRACE, "%s: addpartial_search_cb\n", addpartial.on_bi.bi_type, 0, 0); if(rs->sr_entry) { Debug(LDAP_DEBUG_TRACE, "%s: dn found: %s\n", addpartial.on_bi.bi_type, rs->sr_entry->e_nname.bv_val, 0); entry = rs->sr_entry; op->o_callback->sc_private = (void *) entry_dup(entry); } return 0; } 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_op_add = addpartial_add; return (overlay_register(&addpartial)); } int init_module(int argc, char *argv[]) { return addpartial_init(); }