#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include <ac/string.h>
#include "slap.h"
#include "back-netinfo.h"
static dsstatus enqueue_modification LDAP_P((BackendDB *be, dsrecord *rec, Modification *mod));
static dsstatus enqueue_modification(
BackendDB *be,
dsrecord *rec,
Modification *mod)
{
struct atmap map;
dsattribute *a, *existing;
dsstatus status;
BerVarray bvp;
int i;
u_int32_t super;
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, ARGS, "enqueue_modification: attribute %s\n", mod->sm_desc->ad_cname.bv_val));
#else
Debug(LDAP_DEBUG_TRACE, "==> enqueue_modification %s\n", mod->sm_desc->ad_cname.bv_val, 0, 0);
#endif
super = SUPER(rec);
if (ad_cmp(mod->sm_desc, slap_schema.si_ad_objectClass) == 0)
{
dsstatus status;
status = schemamap_validate_objectclass_mods(be, super, mod);
if (status != DSStatusOK)
{
return status;
}
}
status = schemamap_x500_to_ni_at(be, super, mod->sm_desc, &map);
if (status != DSStatusOK)
{
return status;
}
a = dsattribute_new(map.ni_key);
if (a == NULL)
{
schemamap_atmap_release(&map);
return DSStatusFailed;
}
if (mod->sm_bvalues != NULL)
{
for (bvp = mod->sm_bvalues; bvp->bv_val != NULL; bvp++)
{
dsdata *d;
status = (map.x500ToNiTransform)(be, &d, bvp, map.type, map.x500ToNiArg);
if (status != DSStatusOK)
{
schemamap_atmap_release(&map);
dsattribute_release(a);
return status;
}
dsattribute_append(a, d);
dsdata_release(d);
}
}
switch (mod->sm_op & ~LDAP_MOD_BVALUES)
{
case LDAP_MOD_ADD:
dsrecord_merge_attribute(rec, a, map.selector);
break;
case LDAP_MOD_DELETE:
if (a->count == 0)
{
dsrecord_remove_key(rec, a->key, map.selector);
}
else
{
existing = dsrecord_attribute(rec, a->key, map.selector);
if (existing == NULL)
{
dsattribute_release(a);
schemamap_atmap_release(&map);
return DSStatusOK;
}
for (i = 0; i < a->count; i++)
{
u_int32_t index;
index = dsattribute_index(existing, a->value[i]);
if (index != IndexNull)
{
dsattribute_remove(existing, index);
}
}
dsattribute_release(existing);
}
break;
case LDAP_MOD_REPLACE:
default:
dsrecord_remove_key(rec, a->key, map.selector);
if (a->count)
{
dsrecord_append_attribute(rec, a, map.selector);
}
break;
}
dsattribute_release(a);
schemamap_atmap_release(&map);
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, INFO, "enqueue_modification: done\n"));
#else
Debug(LDAP_DEBUG_TRACE, "<== enqueue_modification\n", 0, 0, 0);
#endif
return DSStatusOK;
}
int netinfo_back_modify(
BackendDB *be,
Connection *conn,
Operation *op,
struct berval *dn,
struct berval *ndn,
Modifications *modlist)
{
struct dsinfo *di = (struct dsinfo *)be->be_private;
dsstatus status;
u_int32_t dsid;
dsrecord *rec;
Modifications *p;
Entry *ent;
int rc;
const char *text;
char textbuf[SLAP_TEXT_BUFLEN];
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, ARGS, "netinfo_back_modify: DN %s\n", dn->bv_val));
#else
Debug(LDAP_DEBUG_TRACE, "==> netinfo_back_modify dn=%s\n", dn->bv_val, 0, 0);
#endif
if (netinfo_back_send_referrals(be, conn, op, ndn) == DSStatusOK)
{
return -1;
}
ENGINE_LOCK(di);
status = netinfo_back_dn_pathmatch(be, ndn, &dsid);
if (status != DSStatusOK)
{
ENGINE_UNLOCK(di);
return netinfo_back_op_result(be, conn, op, status);
}
status = dsengine_fetch(di->engine, dsid, &rec);
dsengine_flush_cache(di->engine);
if (status != DSStatusOK)
{
ENGINE_UNLOCK(di);
return netinfo_back_op_result(be, conn, op, status);
}
for (p = modlist; p != NULL; p = p->sml_next)
{
status = netinfo_back_access_allowed(be, conn, op, dsid, p->sml_desc, NULL, ACL_WRITE);
if (status != DSStatusOK)
{
dsrecord_release(rec);
ENGINE_UNLOCK(di);
return netinfo_back_op_result(be, conn, op, status);
}
status = enqueue_modification(be, rec, &p->sml_mod);
if (status != DSStatusOK)
{
dsrecord_release(rec);
ENGINE_UNLOCK(di);
return netinfo_back_op_result(be, conn, op, status);
}
}
status = dsrecord_to_entry(be, rec, &ent);
if (status != DSStatusOK)
{
dsrecord_release(rec);
ENGINE_UNLOCK(di);
return netinfo_back_op_result(be, conn, op, status);
}
rc = entry_schema_check(be, ent, NULL, &text, textbuf, sizeof(textbuf));
if (rc != LDAP_SUCCESS)
{
if (rc == LDAP_NO_OBJECT_CLASS_MODS && rec->count > 0)
rc = LDAP_OBJECT_CLASS_VIOLATION;
dsrecord_release(rec);
netinfo_back_entry_free(ent);
ENGINE_UNLOCK(di);
send_ldap_result(conn, op, rc, NULL, text, NULL, NULL);
return rc;
}
netinfo_back_entry_free(ent);
if (op->o_abandon)
{
dsrecord_release(rec);
ENGINE_UNLOCK(di);
return SLAPD_ABANDON;
}
status = dsengine_save(di->engine, rec);
dsrecord_release(rec);
ENGINE_UNLOCK(di);
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, INFO, "netinfo_back_modify: done\n"));
#else
Debug(LDAP_DEBUG_TRACE, "<== netinfo_back_modify\n", 0, 0, 0);
#endif
return netinfo_back_op_result(be, conn, op, status);
}