summaryrefslogtreecommitdiffstats
path: root/ldap/servers/slapd/delete.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldap/servers/slapd/delete.c')
-rw-r--r--ldap/servers/slapd/delete.c324
1 files changed, 324 insertions, 0 deletions
diff --git a/ldap/servers/slapd/delete.c b/ldap/servers/slapd/delete.c
new file mode 100644
index 00000000..6e009709
--- /dev/null
+++ b/ldap/servers/slapd/delete.c
@@ -0,0 +1,324 @@
+/** 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 delete_internal_pb (Slapi_PBlock *pb);
+static void op_shared_delete (Slapi_PBlock *pb);
+
+/* This function is called to process operation that come over external connections */
+void
+do_delete( Slapi_PBlock *pb )
+{
+ Slapi_Operation *operation;
+ BerElement *ber;
+ char *dn;
+ int err;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "do_delete\n", 0, 0, 0 );
+
+ slapi_pblock_get( pb, SLAPI_OPERATION, &operation);
+ ber = operation->o_ber;
+
+ /* count the delete request */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsRemoveEntryOps);
+
+ /*
+ * Parse the delete request. It looks like this:
+ *
+ * DelRequest := DistinguishedName
+ */
+
+ if ( ber_scanf( pb->pb_op->o_ber, "a", &dn ) == LBER_ERROR ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ber_scanf failed (op=Delete; params=DN)\n", 0, 0, 0 );
+ op_shared_log_error_access (pb, "DEL", "???", "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0,
+ NULL );
+ 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, "DEL", dn, "decoding error");
+ send_ldap_result( pb, err, NULL, NULL, 0, NULL );
+ goto free_and_return;
+ }
+
+ LDAPDebug( LDAP_DEBUG_ARGS, "do_delete: dn (%s)\n", dn, 0, 0 );
+
+ slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &pb->pb_op->o_isroot );
+ slapi_pblock_set( pb, SLAPI_ORIGINAL_TARGET, dn);
+
+ op_shared_delete (pb);
+
+free_and_return:;
+ slapi_ch_free ((void**)&dn);
+}
+
+/* This function is used to issue internal delete 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_delete_internal_pb instead */
+Slapi_PBlock *
+slapi_delete_internal(const char *idn, LDAPControl **controls, int dummy)
+{
+ Slapi_PBlock pb;
+ Slapi_PBlock *result_pb;
+ int opresult;
+
+ pblock_init (&pb);
+
+ slapi_delete_internal_set_pb (&pb, idn, controls, NULL, plugin_get_default_component_id(), 0);
+
+ delete_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 delete operation.
+ pblock should contain the following data (can be set via call to slapi_delete_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_CONTROLS_ARG set to request controls if present
+
+ For dn based search:
+ SLAPI_TARGET_DN set to the entry dn
+ SLAPI_CONTROLS_ARG set to request controls if present
+ */
+int slapi_delete_internal_pb (Slapi_PBlock *pb)
+{
+ if (pb == NULL)
+ return -1;
+
+ if (!allow_operation (pb))
+ {
+ slapi_send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "This plugin is not configured to access operation target data", 0, NULL );
+ return 0;
+ }
+
+ return delete_internal_pb (pb);
+}
+
+/* Initialize a pblock for a call to slapi_delete_internal_pb() */
+void slapi_delete_internal_set_pb (Slapi_PBlock *pb, const char *dn, LDAPControl **controls, const char *uniqueid,
+ Slapi_ComponentId *plugin_identity, int operation_flags)
+{
+ Operation *op;
+ PR_ASSERT (pb != NULL);
+ if (pb == NULL || dn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "slapi_delete_internal_set_pb: NULL parameter\n");
+ return;
+ }
+
+ op = internal_operation_new(SLAPI_OPERATION_DELETE,operation_flags);
+ slapi_pblock_set(pb, SLAPI_OPERATION, op);
+ slapi_pblock_set(pb, SLAPI_ORIGINAL_TARGET, (void*)dn);
+ slapi_pblock_set(pb, SLAPI_CONTROLS_ARG, controls);
+ if (uniqueid)
+ {
+ slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, (void*)uniqueid);
+ }
+ slapi_pblock_set(pb, SLAPI_PLUGIN_IDENTITY, plugin_identity);
+}
+
+/* Helper functions */
+
+static int delete_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_OPERATION, op);
+ 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);
+
+ /* perform delete operation */
+ op_shared_delete (pb);
+
+ slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+
+ return 0;
+}
+
+static void op_shared_delete (Slapi_PBlock *pb)
+{
+ char *dn;
+ Slapi_Backend *be = NULL;
+ char ebuf[ BUFSIZ ];
+ int internal_op;
+ Slapi_DN sdn;
+ Slapi_Operation *operation;
+ Slapi_Entry *referral;
+ Slapi_Entry *ecopy = NULL;
+ char errorbuf[BUFSIZ];
+ int err;
+
+ slapi_pblock_get(pb, SLAPI_ORIGINAL_TARGET, &dn);
+ slapi_pblock_get(pb, SLAPI_OPERATION, &operation);
+ internal_op= operation_is_flag_set(operation, OP_FLAG_INTERNAL);
+
+ slapi_sdn_init_dn_byref(&sdn,dn);
+ slapi_pblock_set(pb, SLAPI_DELETE_TARGET, (void*)slapi_sdn_get_ndn (&sdn));
+
+ /* target spec is used to decide which plugins are applicable for the operation */
+ operation_set_target_spec (operation, &sdn);
+
+ if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_ACCESS))
+ {
+ if (!internal_op )
+ {
+ slapi_log_access(LDAP_DEBUG_STATS, "conn=%d op=%d DEL dn=\"%s\"\n",
+ pb->pb_conn->c_connid,
+ pb->pb_op->o_opid,
+ escape_string(dn, ebuf));
+ }
+ else
+ {
+ slapi_log_access(LDAP_DEBUG_ARGS, "conn=%s op=%d DEL dn=\"%s\"\n",
+ LOG_INTERNAL_OP_CON_ID,
+ LOG_INTERNAL_OP_OP_ID,
+ escape_string(dn, ebuf));
+ }
+ }
+
+ /*
+ * We could be serving multiple database backends. Select the
+ * appropriate one.
+ */
+ if ((err = slapi_mapping_tree_select(pb, &be, &referral, errorbuf)) != LDAP_SUCCESS) {
+ send_ldap_result(pb, err, NULL, errorbuf, 0, NULL);
+ be = NULL;
+ goto free_and_return;
+ }
+
+ if (referral)
+ {
+ int managedsait;
+
+ slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
+ if (managedsait)
+ {
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "cannot delete 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);
+
+ /*
+ * call the pre-delete plugins. if they succeed, call
+ * the backend delete function. then call the
+ * post-delete plugins.
+ */
+ if (plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_PRE_DELETE_FN :
+ SLAPI_PLUGIN_PRE_DELETE_FN) == 0)
+ {
+ int rc;
+
+ slapi_pblock_set(pb, SLAPI_PLUGIN, be->be_database);
+ set_db_default_result_handlers(pb);
+ if (be->be_delete != NULL)
+ {
+ if ((rc = (*be->be_delete)(pb)) == 0)
+ {
+ /* 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_DELETE);
+
+ 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_PRE_OP, &ecopy);
+ do_ps_service(ecopy, NULL, LDAP_CHANGETYPE_DELETE, 0UL);
+ }
+ else
+ {
+ if (rc == SLAPI_FAIL_DISKFULL)
+ {
+ operation_out_of_disk_space();
+ goto free_and_return;
+ }
+ }
+ }
+
+ slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &rc);
+ plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN :
+ SLAPI_PLUGIN_POST_DELETE_FN);
+ }
+
+free_and_return:
+ if (be)
+ slapi_be_Unlock(be);
+ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &ecopy);
+ slapi_entry_free(ecopy);
+ slapi_pblock_get ( pb, SLAPI_DELETE_GLUE_PARENT_ENTRY, &ecopy );
+ if (ecopy)
+ {
+ slapi_entry_free (ecopy);
+ slapi_pblock_set (pb, SLAPI_DELETE_GLUE_PARENT_ENTRY, NULL);
+ }
+ slapi_pblock_get(pb, SLAPI_URP_NAMING_COLLISION_DN, &dn);
+ slapi_ch_free((void **)&dn);
+ slapi_sdn_done(&sdn);
+}