summaryrefslogtreecommitdiffstats
path: root/ldap/servers/slapd/modrdn.c
diff options
context:
space:
mode:
authorcvsadm <cvsadm>2005-01-21 00:44:34 +0000
committercvsadm <cvsadm>2005-01-21 00:44:34 +0000
commitb2093e3016027d6b5cf06b3f91f30769bfc099e2 (patch)
treecf58939393a9032182c4fbc4441164a9456e82f8 /ldap/servers/slapd/modrdn.c
downloadds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.tar.gz
ds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.tar.xz
ds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.zip
Moving NSCP Directory Server from DirectoryBranch to TRUNK, initial drop. (foxworth)ldapserver7x
Diffstat (limited to 'ldap/servers/slapd/modrdn.c')
-rw-r--r--ldap/servers/slapd/modrdn.c501
1 files changed, 501 insertions, 0 deletions
diff --git a/ldap/servers/slapd/modrdn.c b/ldap/servers/slapd/modrdn.c
new file mode 100644
index 00000000..3e6c4bf6
--- /dev/null
+++ b/ldap/servers/slapd/modrdn.c
@@ -0,0 +1,501 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#include "slap.h"
+#include "pratom.h"
+
+/* Forward declarations */
+static int rename_internal_pb (Slapi_PBlock *pb);
+static void op_shared_rename (Slapi_PBlock *pb, int passin_args );
+
+/* This function is called to process operation that come over external connections */
+void
+do_modrdn( Slapi_PBlock *pb )
+{
+ Slapi_Operation *operation;
+ BerElement *ber;
+ char *dn, *newsuperior = NULL;
+ char *newrdn = NULL;
+ int err, deloldrdn;
+ unsigned long len;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "do_modrdn\n", 0, 0, 0 );
+
+ /* count the modrdn request */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsModifyRDNOps);
+
+ slapi_pblock_get( pb, SLAPI_OPERATION, &operation);
+ ber = operation->o_ber;
+
+ /*
+ * Parse the modrdn request. It looks like this:
+ *
+ * ModifyRDNRequest := SEQUENCE {
+ * entry DistinguishedName,
+ * newrdn RelativeDistinguishedName,
+ * deleteoldrdn BOOLEAN,
+ * newSuperior [0] LDAPDN OPTIONAL -- v3 only
+ * }
+ */
+
+ if ( ber_scanf( ber, "{aab", &dn, &newrdn, &deloldrdn )
+ == LBER_ERROR ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ber_scanf failed (op=ModRDN; params=DN,newRDN,deleteOldRDN)\n",
+ 0, 0, 0 );
+ op_shared_log_error_access (pb, "MODRDN", "???", "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "unable to decode DN, newRDN, or deleteOldRDN parameters",
+ 0, NULL );
+ return;
+ }
+
+ if ( ber_peek_tag( ber, &len ) == LDAP_TAG_NEWSUPERIOR ) {
+ if ( pb->pb_conn->c_ldapversion < LDAP_VERSION3 ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "got newSuperior in LDAPv2 modrdn op\n", 0, 0, 0 );
+ op_shared_log_error_access (pb, "MODRDN", dn, "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "received newSuperior in LDAPv2 modrdn", 0, NULL );
+ goto free_and_return;
+ }
+ if ( ber_scanf( ber, "a", &newsuperior ) == LBER_ERROR ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ber_scanf failed (op=ModRDN; params=newSuperior)\n",
+ 0, 0, 0 );
+ op_shared_log_error_access (pb, "MODRDN", dn, "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "unable to decode newSuperior parameter", 0, NULL );
+ goto free_and_return;
+ }
+ }
+
+ /*
+ * in LDAPv3 there can be optional control extensions on
+ * the end of an LDAPMessage. we need to read them in and
+ * pass them to the backend.
+ */
+ if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) {
+ op_shared_log_error_access (pb, "MODRDN", dn, "failed to decode LDAP controls");
+ send_ldap_result( pb, err, NULL, NULL, 0, NULL );
+ goto free_and_return;
+ }
+
+ LDAPDebug( LDAP_DEBUG_ARGS,
+ "do_moddn: dn (%s) newrdn (%s) deloldrdn (%d)\n", dn, newrdn,
+ deloldrdn );
+
+ slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &pb->pb_op->o_isroot );
+ slapi_pblock_set( pb, SLAPI_ORIGINAL_TARGET, dn );
+ slapi_pblock_set( pb, SLAPI_MODRDN_NEWRDN, newrdn );
+ slapi_pblock_set( pb, SLAPI_MODRDN_NEWSUPERIOR, newsuperior );
+ slapi_pblock_set( pb, SLAPI_MODRDN_DELOLDRDN, &deloldrdn );
+
+ op_shared_rename(pb, 1 /* pass in ownership of string arguments */ );
+ return;
+
+free_and_return:;
+ slapi_ch_free((void **) &dn );
+ slapi_ch_free((void **) &newrdn );
+ slapi_ch_free((void **) &newsuperior );
+}
+
+/* This function is used to issue internal modrdn operation
+ This is an old style API. Its use is discoraged because it is not extendable and
+ because it does not allow to check whether plugin has right to access part of the
+ tree it is trying to modify. Use slapi_modrdn_internal_pb instead */
+Slapi_PBlock *
+slapi_modrdn_internal(const char *iodn, const char *inewrdn, int deloldrdn, LDAPControl **controls, int dummy)
+{
+ return slapi_rename_internal(iodn, inewrdn, NULL, deloldrdn, controls, dummy);
+}
+
+Slapi_PBlock *
+slapi_rename_internal(const char *iodn, const char *inewrdn, const char *inewsuperior, int deloldrdn, LDAPControl **controls, int dummy)
+{
+ Slapi_PBlock pb;
+ Slapi_PBlock *result_pb = NULL;
+ int opresult= 0;
+
+ pblock_init (&pb);
+
+ slapi_rename_internal_set_pb (&pb, iodn, inewrdn, inewsuperior, deloldrdn,
+ controls, NULL, plugin_get_default_component_id(), 0);
+ rename_internal_pb (&pb);
+
+ result_pb = slapi_pblock_new();
+ if (result_pb)
+ {
+ slapi_pblock_get(&pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ slapi_pblock_set(result_pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ }
+ pblock_done(&pb);
+
+ return result_pb;
+}
+
+/* This is new style API to issue internal add operation.
+ pblock should contain the following data (can be set via call to slapi_rename_internal_set_pb):
+ For uniqueid based operation:
+ SLAPI_TARGET_DN set to dn that allows to select right backend, can be stale
+ SLAPI_TARGET_UNIQUEID set to the uniqueid of the entry we are looking for
+ SLAPI_MODRDN_NEWRDN set to new rdn of the entry
+ SLAPI_MODRDN_DELOLDRDN tells whether old rdn should be kept in the entry
+ LAPI_CONTROLS_ARG set to request controls if present
+
+ For dn based search:
+ SLAPI_TARGET_DN set to the entry dn
+ SLAPI_MODRDN_NEWRDN set to new rdn of the entry
+ SLAPI_MODRDN_DELOLDRDN tells whether old rdn should be kept in the entry
+ SLAPI_CONTROLS_ARG set to request controls if present
+ */
+int slapi_modrdn_internal_pb (Slapi_PBlock *pb)
+{
+ if (pb == NULL)
+ return -1;
+
+ return rename_internal_pb (pb);
+}
+
+/* Initialize a pblock for a call to slapi_modrdn_internal_pb() */
+void slapi_rename_internal_set_pb (Slapi_PBlock *pb, const char *olddn, const char *newrdn, const char *newsuperior, int deloldrdn,
+ LDAPControl **controls, const char *uniqueid, Slapi_ComponentId *plugin_identity, int operation_flags)
+{
+ Operation *op;
+ PR_ASSERT (pb != NULL);
+ if (pb == NULL || olddn == NULL || newrdn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "slapi_rename_internal_set_pb: NULL parameter\n");
+ return;
+ }
+
+ op= internal_operation_new(SLAPI_OPERATION_MODRDN,operation_flags);
+ slapi_pblock_set(pb, SLAPI_OPERATION, op);
+ slapi_pblock_set(pb, SLAPI_ORIGINAL_TARGET, (void*)olddn);
+ slapi_pblock_set(pb, SLAPI_MODRDN_NEWRDN, (void*)newrdn);
+ slapi_pblock_set(pb, SLAPI_MODRDN_NEWSUPERIOR, (void*)newsuperior);
+ slapi_pblock_set(pb, SLAPI_MODRDN_DELOLDRDN, &deloldrdn);
+ slapi_pblock_set(pb, SLAPI_CONTROLS_ARG, controls);
+ slapi_pblock_set(pb, SLAPI_MODIFY_MODS, NULL);
+ if (uniqueid)
+ {
+ slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, (void*)uniqueid);
+ }
+ slapi_pblock_set(pb, SLAPI_PLUGIN_IDENTITY, plugin_identity);
+}
+
+/* Helper functions */
+
+static int rename_internal_pb (Slapi_PBlock *pb)
+{
+ LDAPControl **controls;
+ Operation *op;
+ int opresult = 0;
+
+ PR_ASSERT (pb != NULL);
+
+ slapi_pblock_get(pb, SLAPI_CONTROLS_ARG, &controls);
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ op->o_handler_data = &opresult;
+ op->o_result_handler = internal_getresult_callback;
+
+ slapi_pblock_set(pb, SLAPI_REQCONTROLS, controls);
+
+ /* set parameters common for all internal operations */
+ set_common_params (pb);
+
+ /* set actions taken to process the operation */
+ set_config_params (pb);
+
+ op_shared_rename (pb, 0 /* not passing ownership of args */ );
+
+ slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+
+ return 0;
+}
+
+
+/*
+ * op_shared_rename() -- common frontend code for modDN operations.
+ *
+ * Beware: this function resets the following pblock elements that were
+ * set by the caller:
+ *
+ * SLAPI_MODRDN_TARGET
+ * SLAPI_MODRDN_NEWRDN
+ * SLAPI_MODRDN_NEWSUPERIOR
+ */
+static void
+op_shared_rename(Slapi_PBlock *pb, int passin_args)
+{
+ char *dn, *newsuperior, *newrdn, *newdn = NULL;
+ char **rdns;
+ int deloldrdn;
+ Slapi_Backend *be = NULL;
+ Slapi_DN sdn;
+ Slapi_Mods smods;
+ char dnbuf[BUFSIZ];
+ char newrdnbuf[BUFSIZ];
+ char newsuperiorbuf[BUFSIZ];
+ int internal_op, repl_op, lastmod;
+ Slapi_Operation *operation;
+ Slapi_Entry *referral;
+ char errorbuf[BUFSIZ];
+ int err;
+
+ slapi_pblock_get(pb, SLAPI_ORIGINAL_TARGET, &dn);
+ slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &newrdn);
+ slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR, &newsuperior);
+ slapi_pblock_get(pb, SLAPI_MODRDN_DELOLDRDN, &deloldrdn);
+ slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op);
+ slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
+ internal_op= operation_is_flag_set(operation, OP_FLAG_INTERNAL);
+
+ /*
+ * If ownership has not been passed to this function, we replace the
+ * string input fields within the pblock with strdup'd copies. Why?
+ * Because some pre- and post-op plugins may change them, and the
+ * convention is that plugins should place a malloc'd string in the
+ * pblock. Therefore, we need to be able to retrieve and free them
+ * later. But the callers of the internal modrdn calls are promised
+ * that we will not free these parameters... so if passin_args is
+ * zero, we need to make copies.
+ *
+ * In the case of SLAPI_MODRDN_TARGET and SLAPI_MODRDN_NEWSUPERIOR, we
+ * replace the existing values with normalized values (because plugins
+ * expect these DNs to be normalized).
+ */
+ if ( passin_args ) {
+ slapi_sdn_init_dn_passin(&sdn,dn); /* freed by slapi_sdn_done() */
+ } else {
+ slapi_sdn_init_dn_byref(&sdn,dn);
+ }
+ if ( !passin_args ) {
+ newrdn = slapi_ch_strdup( newrdn );
+ newsuperior = slapi_ch_strdup( newsuperior );
+ }
+ if ( NULL != newsuperior ) {
+ slapi_dn_normalize_case( newsuperior ); /* normalize in place */
+ }
+ slapi_pblock_set (pb, SLAPI_MODRDN_TARGET,
+ (void*)slapi_ch_strdup(slapi_sdn_get_ndn (&sdn)));
+ slapi_pblock_set(pb, SLAPI_MODRDN_NEWRDN, (void *)newrdn );
+ slapi_pblock_set(pb, SLAPI_MODRDN_NEWSUPERIOR, (void *)newsuperior);
+
+ /*
+ * first, log the operation to the access log,
+ * then check rdn and newsuperior,
+ * and - if applicable - log reason of any error to the errors log
+ */
+ if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_ACCESS))
+ {
+ if ( !internal_op )
+ {
+ slapi_log_access(LDAP_DEBUG_STATS,
+ "conn=%d op=%d MODRDN dn=\"%s\" newrdn=\"%s\" newsuperior=\"%s\"\n",
+ pb->pb_conn->c_connid,
+ pb->pb_op->o_opid,
+ escape_string(dn, dnbuf),
+ (NULL == newrdn) ? "(null)" : escape_string(newrdn, newrdnbuf),
+ (NULL == newsuperior) ? "(null)" : escape_string(newsuperior, newsuperiorbuf));
+ }
+ else
+ {
+ slapi_log_access(LDAP_DEBUG_ARGS,
+ "conn=%s op=%d MODRDN dn=\"%s\" newrdn=\"%s\" newsuperior=\"%s\"\n",
+ LOG_INTERNAL_OP_CON_ID,
+ LOG_INTERNAL_OP_OP_ID,
+ escape_string(dn, dnbuf),
+ (NULL == newrdn) ? "(null)" : escape_string(newrdn, newrdnbuf),
+ (NULL == newsuperior) ? "(null)" : escape_string(newsuperior, newsuperiorbuf));
+ }
+ }
+
+ /* check that the rdn is formatted correctly */
+ if ((rdns = ldap_explode_rdn(newrdn, 0)) == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "conn=%d op=%d MODRDN invalid new RDN (\"%s\")\n",
+ pb->pb_conn->c_connid,
+ pb->pb_op->o_opid,
+ (NULL == newrdn) ? "(null)" : newrdn);
+ send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL, "invalid RDN", 0, NULL);
+ goto free_and_return_nolock;
+ }
+ else
+ {
+ ldap_value_free(rdns);
+ }
+
+ /* check that the dn is formatted correctly */
+ if ((rdns = ldap_explode_dn(newsuperior, 0)) == NULL)
+ {
+ LDAPDebug(LDAP_DEBUG_ARGS, "ldap_explode_dn of newSuperior failed\n", 0, 0, 0);
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "conn=%d op=%d MODRDN invalid new superior (\"%s\")",
+ pb->pb_conn->c_connid,
+ pb->pb_op->o_opid,
+ (NULL == newsuperior) ? "(null)" : newsuperiorbuf);
+ send_ldap_result(pb, LDAP_PROTOCOL_ERROR, NULL,
+ "newSuperior does not look like a DN", 0, NULL);
+ goto free_and_return_nolock;
+ }
+ else
+ {
+ ldap_value_free(rdns);
+ }
+
+ if (newsuperior != NULL)
+ {
+ LDAPDebug(LDAP_DEBUG_ARGS, "do_moddn: newsuperior (%s)\n", newsuperior, 0, 0);
+ }
+
+ /* target spec is used to decide which plugins are applicable for the operation */
+ operation_set_target_spec (pb->pb_op, &sdn);
+
+ /*
+ * Construct the new DN (code copied from backend
+ * and modified to handle newsuperior)
+ */
+ newdn = slapi_moddn_get_newdn(&sdn,newrdn,newsuperior);
+
+ /*
+ * We could be serving multiple database backends. Select the
+ * appropriate one, or send a referral to our "referral server"
+ * if we don't hold it.
+ */
+ if ((err = slapi_mapping_tree_select_and_check(pb, newdn, &be, &referral, errorbuf)) != LDAP_SUCCESS)
+ {
+ send_ldap_result(pb, err, NULL, errorbuf, 0, NULL);
+ goto free_and_return_nolock;
+ }
+
+ if (referral)
+ {
+ int managedsait;
+
+ slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
+ if (managedsait)
+ {
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "cannot update referral", 0, NULL);
+ slapi_entry_free(referral);
+ goto free_and_return;
+ }
+
+ send_referrals_from_entry(pb,referral);
+ slapi_entry_free(referral);
+ goto free_and_return;
+ }
+
+ slapi_pblock_set(pb, SLAPI_BACKEND, be);
+
+ /* can get lastmod only after backend is selected */
+ slapi_pblock_get(pb, SLAPI_BE_LASTMOD, &lastmod);
+
+ /* if it is a replicated operation - leave lastmod attributes alone */
+ slapi_mods_init (&smods, 2);
+ if (!repl_op && lastmod)
+ {
+ modify_update_last_modified_attr(pb, &smods);
+ slapi_pblock_set(pb, SLAPI_MODIFY_MODS, (void*)slapi_mods_get_ldapmods_passout(&smods));
+ }
+ else {
+ slapi_mods_done (&smods);
+ }
+
+ /*
+ * call the pre-modrdn plugins. if they succeed, call
+ * the backend modrdn function. then call the
+ * post-modrdn plugins.
+ */
+ if (plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_PRE_MODRDN_FN :
+ SLAPI_PLUGIN_PRE_MODRDN_FN) == 0)
+ {
+ int rc= LDAP_OPERATIONS_ERROR;
+ slapi_pblock_set(pb, SLAPI_PLUGIN, be->be_database);
+ set_db_default_result_handlers(pb);
+ if (be->be_modrdn != NULL)
+ {
+ if ((rc = (*be->be_modrdn)(pb)) == 0)
+ {
+ Slapi_Entry *pse;
+ Slapi_Entry *ecopy;
+ /* we don't perform acl check for internal operations */
+ /* dont update aci store for remote acis */
+ if ((!internal_op) &&
+ (!slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA)))
+ plugin_call_acl_mods_update (pb, SLAPI_OPERATION_MODRDN);
+
+ if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_AUDIT))
+ write_audit_log_entry(pb); /* Record the operation in the audit log */
+
+ slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &pse);
+ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &ecopy);
+ /* GGOODREPL persistent search system needs the changenumber, oops. */
+ do_ps_service(pse, ecopy, LDAP_CHANGETYPE_MODDN, 0UL);
+ }
+ }
+ else
+ {
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Function not implemented", 0, NULL);
+ }
+
+ slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &rc);
+ plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN :
+ SLAPI_PLUGIN_POST_MODRDN_FN);
+ }
+
+free_and_return:
+ if (be)
+ slapi_be_Unlock(be);
+free_and_return_nolock:
+ {
+ /* Free up everything left in the PBlock */
+ Slapi_Entry *pse;
+ Slapi_Entry *ecopy;
+ LDAPMod **mods;
+ char *s;
+
+ slapi_ch_free((void **) &newdn);
+ slapi_sdn_done(&sdn);
+ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &ecopy);
+ slapi_entry_free(ecopy);
+ slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &pse);
+ slapi_entry_free(pse);
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+ ldap_mods_free( mods, 1 );
+
+ /* retrieve these in case a pre- or post-op plugin has changed them */
+ slapi_pblock_get(pb, SLAPI_MODRDN_TARGET, &s);
+ slapi_ch_free((void **)&s);
+ slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &s);
+ slapi_ch_free((void **)&s);
+ slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR, &s);
+ slapi_ch_free((void **)&s);
+ slapi_pblock_get(pb, SLAPI_URP_NAMING_COLLISION_DN, &s);
+ slapi_ch_free((void **)&s);
+ }
+}