#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(
BackendDB *be,
Connection *conn,
Operation *op,
struct berval *dn,
struct berval *ndn,
struct berval *newrdn,
struct berval *nnewrdn,
int deleteoldrdn,
struct berval *newSuperior,
struct berval *nnewSuperior
)
{
struct dsinfo *di = (struct dsinfo *)be->be_private;
dsstatus status;
u_int32_t dsid, newParentId, oldParentId, index;
dsrecord *child, *parent;
dsdata *rdnValue, *rdnKey;
LDAPRDN *new_rdn;
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", dn->bv_val, newrdn->bv_val,
(newSuperior != NULL) ? newSuperior->bv_val : "(null)"));
#else
Debug(LDAP_DEBUG_TRACE, "==> netinfo_back_modrdn dn=%s newrdn=%s newsuperior=%s\n",
dn->bv_val, newrdn->bv_val, newSuperior ? newSuperior->bv_val : "(null)");
#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 = netinfo_back_access_allowed(be, conn, op, dsid, slap_schema.si_ad_entry, NULL, ACL_WRITE);
if (status != DSStatusOK)
{
ENGINE_UNLOCK(di);
return netinfo_back_op_result(be, conn, op, status);
}
status = dsengine_fetch(di->engine, dsid, &child);
dsengine_flush_cache(di->engine);
if (status != DSStatusOK)
{
ENGINE_UNLOCK(di);
return netinfo_back_op_result(be, conn, op, status);
}
if (ldap_str2rdn(newrdn->bv_val, &new_rdn, &p, LDAP_DN_FORMAT_LDAP) != LDAP_SUCCESS)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
send_ldap_result(conn, op, LDAP_OPERATIONS_ERROR, NULL,
"Could not parse new RDN", NULL, NULL);
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_result(conn, op, rc, NULL,
text, NULL, NULL);
return -1;
}
status = schemamap_x500_to_ni_at(be, SUPER(child), ad, &map);
if (status != DSStatusOK)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
ldap_rdnfree(new_rdn);
send_ldap_result(conn, op, LDAP_OPERATIONS_ERROR, NULL,
"Could not parse new RDN type", NULL, NULL);
return -1;
}
if (map.selector == SELECT_META_ATTRIBUTE)
{
schemamap_atmap_release(&map);
dsrecord_release(child);
ENGINE_UNLOCK(di);
ldap_rdnfree(new_rdn);
send_ldap_result(conn, op, LDAP_NAMING_VIOLATION, NULL,
"Meta-attributes cannot name entries", NULL, NULL);
return -1;
}
status = (map.x500ToNiTransform)(be, &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_result(conn, op, LDAP_OPERATIONS_ERROR, NULL,
"Could not transform RDN value", NULL, NULL);
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 (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 (newSuperior != NULL)
{
status = netinfo_back_dn_pathmatch(be, nnewSuperior, &newParentId);
if (status != DSStatusOK)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
return netinfo_back_op_result(be, conn, op, status);
}
status = netinfo_back_access_allowed(be, conn, op, newParentId,
slap_schema.si_ad_children, NULL, ACL_WRITE);
if (status != DSStatusOK)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
return netinfo_back_op_result(be, conn, op, status);
}
oldParentId = child->super;
if (oldParentId != newParentId)
{
Entry *ent;
status = netinfo_back_access_allowed(be, conn, op, oldParentId,
slap_schema.si_ad_children, NULL, ACL_WRITE);
if (status != DSStatusOK)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
return netinfo_back_op_result(be, conn, op, status);
}
status = dsrecord_to_entry(be, child, &ent);
if (status != DSStatusOK)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
return netinfo_back_op_result(be, conn, op, status);
}
status = schemamap_validate_objectclasses(be, newParentId, ent);
if (status != DSStatusOK)
{
dsrecord_release(child);
netinfo_back_entry_free(ent);
ENGINE_UNLOCK(di);
return netinfo_back_op_result(be, conn, op, 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(be, conn, op, status);
}
if (newSuperior != NULL && oldParentId != newParentId)
{
parent = dsstore_fetch(di->engine->store, oldParentId);
if (parent == NULL)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
return netinfo_back_op_result(be, conn, op, 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(be, conn, op, status);
}
parent = dsstore_fetch(di->engine->store, newParentId);
if (parent == NULL)
{
dsrecord_release(child);
ENGINE_UNLOCK(di);
return netinfo_back_op_result(be, conn, op, 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(be, conn, op, status);
}