#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include <ac/string.h>
#include "slap.h"
#include "back-netinfo.h"
int
netinfo_back_modrdn(
struct slap_op *op,
struct slap_rep *rs
)
{
struct dsinfo *di = (struct dsinfo *)op->o_bd->be_private;
dsstatus status;
u_int32_t dsid, newParentId, oldParentId, index;
dsrecord *child, *parent;
dsdata *rdnValue, *rdnKey;
LDAPRDN *new_rdn = NULL;
dsattribute *a;
char *p;
AttributeDescription *ad = NULL;
const char *text;
int rc;
struct atmap map;
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, ARGS, "netinfo_back_modrdn DN %s "
"new RDN %s new superior DN %s\n", op->o_req_dn.bv_val, op->orr_newrdn.bv_val,
(op->orr_newSup != NULL) ? op->orr_newSup->bv_val : "(null)"));
#else
Debug(LDAP_DEBUG_TRACE, "==> netinfo_back_modrdn dn=%s newrdn=%s newsuperior=%s\n",
op->o_req_dn.bv_val, op->orr_newrdn.bv_val, op->orr_newSup ? op->orr_newSup->bv_val : "(null)");
#endif
if (netinfo_back_send_referrals(op, rs, &op->o_req_ndn) == DSStatusOK)
{
return 1;
}
ENGINE_LOCK(di);
status = netinfo_back_dn_pathmatch(op->o_bd, &op->o_req_ndn, &dsid);
if (status != DSStatusOK)
{
ENGINE_UNLOCK(di);
return netinfo_back_op_result(op, rs, status);
}
status = netinfo_back_access_allowed(op, dsid, slap_schema.si_ad_entry, NULL, ACL_WRITE);
if (status != DSStatusOK)
{
ENGINE_UNLOCK(di);
return netinfo_back_op_result(op, rs, status);
}
status = dsengine_fetch(di->engine, dsid, &child);
dsengine_flush_cache(di->engine);
if (status != DSStatusOK)
{
ENGINE_UNLOCK(di);
return netinfo_back_op_result(op, rs, status);
}
if (ldap_str2rdn(op->orr_newrdn.bv_val, new_rdn, &p, LDAP_DN_FORMAT_LDAP) != LDAP_SUCCESS)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
send_ldap_error(op, rs, LDAP_OPERATIONS_ERROR,
"Could not parse new RDN");
return -1;
}
rc = slap_bv2ad(&new_rdn[0][0]->la_attr, &ad, &text);
if (rc != LDAP_SUCCESS)
{
ldap_rdnfree(*new_rdn);
dsrecord_release(child);
ENGINE_UNLOCK(di);
send_ldap_error(op, rs, rc, text);
return -1;
}
status = schemamap_x500_to_ni_at(op->o_bd, SUPER(child), ad, &map);
if (status != DSStatusOK)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
ldap_rdnfree(*new_rdn);
send_ldap_error(op, rs, LDAP_OPERATIONS_ERROR,
"Could not parse new RDN type");
return -1;
}
if (map.selector == SELECT_META_ATTRIBUTE)
{
schemamap_atmap_release(&map);
dsrecord_release(child);
ENGINE_UNLOCK(di);
ldap_rdnfree(*new_rdn);
send_ldap_error(op, rs, LDAP_NAMING_VIOLATION,
"Meta-attributes cannot name entries");
return -1;
}
status = (map.x500ToNiTransform)(op->o_bd, &rdnValue, &new_rdn[0][0]->la_value,
map.type, map.x500ToNiArg);
if (status != DSStatusOK)
{
schemamap_atmap_release(&map);
dsrecord_release(child);
ENGINE_UNLOCK(di);
ldap_rdnfree(*new_rdn);
send_ldap_error(op, rs, LDAP_OPERATIONS_ERROR,
"Could not transform RDN value");
return -1;
}
ldap_rdnfree(*new_rdn);
rdnKey = dsdata_copy((dsdata *)&netinfo_back_name_rdn);
dsrecord_remove_key(child, rdnKey, SELECT_META_ATTRIBUTE);
if (dsdata_equal(map.ni_key, (dsdata *)&netinfo_back_name_name) == 0)
{
a = dsattribute_new(rdnKey);
assert(a != NULL);
dsrecord_append_attribute(child, a, SELECT_META_ATTRIBUTE);
dsattribute_insert(a, map.ni_key, 0);
dsattribute_release(a);
}
dsdata_release(rdnKey);
a = dsrecord_attribute(child, map.ni_key, SELECT_ATTRIBUTE);
if (a == NULL)
{
a = dsattribute_new(map.ni_key);
assert(a != NULL);
dsrecord_append_attribute(child, a, SELECT_ATTRIBUTE);
}
else
{
if (op->orr_deleteoldrdn)
{
dsattribute_remove(a, 0);
}
index = dsattribute_index(a, rdnValue);
if (index != IndexNull)
dsattribute_remove(a, index);
}
dsattribute_insert(a, rdnValue, 0);
schemamap_atmap_release(&map);
dsdata_release(rdnValue);
dsattribute_release(a);
if (op->o_abandon)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
return SLAPD_ABANDON;
}
if (op->orr_newSup != NULL)
{
status = netinfo_back_dn_pathmatch(op->o_bd, op->orr_nnewSup, &newParentId);
if (status != DSStatusOK)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
return netinfo_back_op_result(op, rs, status);
}
status = netinfo_back_access_allowed(op, newParentId,
slap_schema.si_ad_children, NULL, ACL_WRITE);
if (status != DSStatusOK)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
return netinfo_back_op_result(op, rs, status);
}
oldParentId = child->super;
if (oldParentId != newParentId)
{
Entry *ent;
status = netinfo_back_access_allowed(op, oldParentId,
slap_schema.si_ad_children, NULL, ACL_WRITE);
if (status != DSStatusOK)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
return netinfo_back_op_result(op, rs, status);
}
status = dsrecord_to_entry(op->o_bd, child, &ent);
if (status != DSStatusOK)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
return netinfo_back_op_result(op, rs, status);
}
status = schemamap_validate_objectclasses(op->o_bd, newParentId, ent);
if (status != DSStatusOK)
{
dsrecord_release(child);
netinfo_back_entry_free(ent);
ENGINE_UNLOCK(di);
return netinfo_back_op_result(op, rs, status);
}
netinfo_back_entry_free(ent);
child->super = newParentId;
}
}
else
{
oldParentId = newParentId;
}
if (op->o_abandon)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
return SLAPD_ABANDON;
}
status = dsstore_save(di->engine->store, child);
if (status != DSStatusOK)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
return netinfo_back_op_result(op, rs, status);
}
if (op->orr_newSup != NULL && oldParentId != newParentId)
{
parent = dsstore_fetch(di->engine->store, oldParentId);
if (parent == NULL)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
return netinfo_back_op_result(op, rs, DSStatusInvalidPath);
}
dsrecord_remove_sub(parent, dsid);
dsindex_delete_dsid(parent->index, dsid);
status = dsstore_save(di->engine->store, parent);
dsrecord_release(parent);
if (status != DSStatusOK)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
return netinfo_back_op_result(op, rs, status);
}
parent = dsstore_fetch(di->engine->store, newParentId);
if (parent == NULL)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
return netinfo_back_op_result(op, rs, DSStatusInvalidPath);
}
dsrecord_append_sub(parent, dsid);
dsindex_insert_record(parent->index, child);
status = dsstore_save(di->engine->store, parent);
dsrecord_release(parent);
}
dsrecord_release(child);
ENGINE_UNLOCK(di);
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, INFO, "netinfo_back_modrdn: done\n"));
#else
Debug(LDAP_DEBUG_TRACE, "<== netinfo_back_modrdn \n", 0, 0, 0);
#endif
return netinfo_back_op_result(op, rs, status);
}