openldap/contrib/slapd-modules/addpartial/addpartial-overlay.c
2007-11-14 18:05:07 +00:00

432 lines
16 KiB
C

/**
* $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();
}