1
/** BEGIN COPYRIGHT BLOCK
2
* This Program is free software; you can redistribute it and/or modify it under
3
* the terms of the GNU General Public License as published by the Free Software
4
* Foundation; version 2 of the License.
6
* This Program is distributed in the hope that it will be useful, but WITHOUT
7
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
10
* You should have received a copy of the GNU General Public License along with
11
* this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
12
* Place, Suite 330, Boston, MA 02111-1307 USA.
14
* In addition, as a special exception, Red Hat, Inc. gives You the additional
15
* right to link the code of this Program with code not covered under the GNU
16
* General Public License ("Non-GPL Code") and to distribute linked combinations
17
* including the two, subject to the limitations in this paragraph. Non-GPL Code
18
* permitted under this exception must only link to the code of this Program
19
* through those well defined interfaces identified in the file named EXCEPTION
20
* found in the source code files (the "Approved Interfaces"). The files of
21
* Non-GPL Code may instantiate templates or use macros or inline functions from
22
* the Approved Interfaces without causing the resulting work to be covered by
23
* the GNU General Public License. Only Red Hat, Inc. may make changes or
24
* additions to the list of Approved Interfaces. You must obey the GNU General
25
* Public License in all respects for all of the Program code and other code used
26
* in conjunction with the Program except the Non-GPL Code covered by this
27
* exception. If you modify this file, you may extend this exception to your
28
* version of the file, but you are not obligated to do so. If you do not wish to
29
* provide this exception without modification, you must delete this exception
30
* statement from your version and license this file solely under the GPL without
34
* Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
35
* Copyright (C) 2005 Red Hat, Inc.
36
* All rights reserved.
37
* END COPYRIGHT BLOCK **/
44
* Copyright (c) 1995 Regents of the University of Michigan.
45
* All rights reserved.
47
* Redistribution and use in source and binary forms are permitted
48
* provided that this notice is preserved and that due credit is given
49
* to the University of Michigan at Ann Arbor. The name of the University
50
* may not be used to endorse or promote products derived from this
51
* software without specific prior written permission. This software
52
* is provided ``as is'' without express or implied warranty.
57
#include <sys/types.h>
59
#include <sys/socket.h>
64
/* Forward declarations */
65
static int delete_internal_pb (Slapi_PBlock *pb);
66
static void op_shared_delete (Slapi_PBlock *pb);
68
/* This function is called to process operation that come over external connections */
70
do_delete( Slapi_PBlock *pb )
72
Slapi_Operation *operation;
77
LDAPDebug( LDAP_DEBUG_TRACE, "do_delete\n", 0, 0, 0 );
79
slapi_pblock_get( pb, SLAPI_OPERATION, &operation);
80
ber = operation->o_ber;
82
/* count the delete request */
83
slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsRemoveEntryOps);
86
* Parse the delete request. It looks like this:
88
* DelRequest := DistinguishedName
91
if ( ber_scanf( pb->pb_op->o_ber, "a", &rawdn ) == LBER_ERROR ) {
92
LDAPDebug( LDAP_DEBUG_ANY,
93
"ber_scanf failed (op=Delete; params=DN)\n", 0, 0, 0 );
94
op_shared_log_error_access (pb, "DEL", "???", "decoding error");
95
send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0,
99
/* Check if we should be performing strict validation. */
100
if (config_get_dn_validate_strict()) {
101
/* check that the dn is formatted correctly */
102
err = slapi_dn_syntax_check(pb, rawdn, 1);
103
if (err) { /* syntax check failed */
104
op_shared_log_error_access(pb, "DEL", rawdn?rawdn:"",
105
"strict: invalid dn");
106
send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX,
107
NULL, "invalid dn", 0, NULL);
108
goto free_and_return;
113
* in LDAPv3 there can be optional control extensions on
114
* the end of an LDAPMessage. we need to read them in and
115
* pass them to the backend.
117
if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) {
118
op_shared_log_error_access (pb, "DEL", rawdn, "decoding error");
119
send_ldap_result( pb, err, NULL, NULL, 0, NULL );
120
goto free_and_return;
123
LDAPDebug1Arg( LDAP_DEBUG_ARGS, "do_delete: dn (%s)\n", rawdn );
125
slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &pb->pb_op->o_isroot );
126
slapi_pblock_set( pb, SLAPI_ORIGINAL_TARGET, rawdn);
128
op_shared_delete (pb);
131
slapi_ch_free ((void**)&rawdn);
134
/* This function is used to issue internal delete operation
135
This is an old style API. Its use is discoraged because it is not extendable and
136
because it does not allow to check whether plugin has right to access part of the
137
tree it is trying to modify. Use slapi_delete_internal_pb instead */
139
slapi_delete_internal(const char *idn, LDAPControl **controls, int dummy)
142
Slapi_PBlock *result_pb;
147
slapi_delete_internal_set_pb (&pb, idn, controls, NULL, plugin_get_default_component_id(), 0);
149
delete_internal_pb (&pb);
151
result_pb = slapi_pblock_new();
154
slapi_pblock_get(&pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
155
slapi_pblock_set(result_pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
162
/* This is new style API to issue internal delete operation.
163
pblock should contain the following data (can be set via call to slapi_delete_internal_set_pb):
164
For uniqueid based operation:
165
SLAPI_TARGET_DN set to dn that allows to select right backend, can be stale
166
SLAPI_TARGET_UNIQUEID set to the uniqueid of the entry we are looking for
167
SLAPI_CONTROLS_ARG set to request controls if present
170
SLAPI_TARGET_DN set to the entry dn
171
SLAPI_CONTROLS_ARG set to request controls if present
173
int slapi_delete_internal_pb (Slapi_PBlock *pb)
178
if (!allow_operation (pb))
180
slapi_send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
181
"This plugin is not configured to access operation target data", 0, NULL );
185
return delete_internal_pb (pb);
188
/* Initialize a pblock for a call to slapi_delete_internal_pb() */
190
slapi_delete_internal_set_pb (Slapi_PBlock *pb,
192
LDAPControl **controls, const char *uniqueid,
193
Slapi_ComponentId *plugin_identity,
197
PR_ASSERT (pb != NULL);
198
if (pb == NULL || rawdn == NULL)
200
slapi_log_error(SLAPI_LOG_FATAL, NULL,
201
"slapi_delete_internal_set_pb: NULL parameter\n");
205
op = internal_operation_new(SLAPI_OPERATION_DELETE,operation_flags);
206
slapi_pblock_set(pb, SLAPI_OPERATION, op);
207
slapi_pblock_set(pb, SLAPI_ORIGINAL_TARGET, (void*)rawdn);
208
slapi_pblock_set(pb, SLAPI_CONTROLS_ARG, controls);
211
slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, (void*)uniqueid);
213
slapi_pblock_set(pb, SLAPI_PLUGIN_IDENTITY, plugin_identity);
216
/* Helper functions */
218
static int delete_internal_pb (Slapi_PBlock *pb)
220
LDAPControl **controls;
224
PR_ASSERT (pb != NULL);
226
slapi_pblock_get(pb, SLAPI_CONTROLS_ARG, &controls);
228
slapi_pblock_get(pb, SLAPI_OPERATION, &op);
229
op->o_handler_data = &opresult;
230
op->o_result_handler = internal_getresult_callback;
232
slapi_pblock_set(pb, SLAPI_OPERATION, op);
233
slapi_pblock_set(pb, SLAPI_REQCONTROLS, controls);
235
/* set parameters common for all internal operations */
236
set_common_params (pb);
238
/* set actions taken to process the operation */
239
set_config_params (pb);
241
/* perform delete operation */
242
op_shared_delete (pb);
244
slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
249
static void op_shared_delete (Slapi_PBlock *pb)
252
const char *dn = NULL;
253
Slapi_Backend *be = NULL;
255
Slapi_DN *sdn = NULL;
256
Slapi_Operation *operation;
257
Slapi_Entry *referral;
258
Slapi_Entry *ecopy = NULL;
259
char errorbuf[BUFSIZ];
261
char *proxydn = NULL;
262
char *proxystr = NULL;
263
int proxy_err = LDAP_SUCCESS;
264
char *errtext = NULL;
266
slapi_pblock_get(pb, SLAPI_ORIGINAL_TARGET, &rawdn);
267
slapi_pblock_get(pb, SLAPI_OPERATION, &operation);
268
internal_op= operation_is_flag_set(operation, OP_FLAG_INTERNAL);
270
sdn = slapi_sdn_new_dn_byval(rawdn);
271
dn = slapi_sdn_get_dn(sdn);
272
slapi_pblock_set(pb, SLAPI_DELETE_TARGET_SDN, (void*)sdn);
273
if (rawdn && (strlen(rawdn) > 0) && (NULL == dn)) {
274
/* normalization failed */
275
op_shared_log_error_access(pb, "DEL", rawdn, "invalid dn");
276
send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX,
277
NULL, "invalid dn", 0, NULL);
278
goto free_and_return;
281
/* target spec is used to decide which plugins are applicable for the operation */
282
operation_set_target_spec (operation, sdn);
284
/* get the proxy auth dn if the proxy auth control is present */
285
proxy_err = proxyauth_get_dn(pb, &proxydn, &errtext);
287
if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_ACCESS))
291
proxystr = slapi_ch_smprintf(" authzid=\"%s\"", proxydn);
296
slapi_log_access(LDAP_DEBUG_STATS, "conn=%" NSPRIu64 " op=%d DEL dn=\"%s\"%s\n",
297
pb->pb_conn->c_connid,
299
slapi_sdn_get_dn(sdn),
300
proxystr ? proxystr: "");
304
slapi_log_access(LDAP_DEBUG_ARGS, "conn=%s op=%d DEL dn=\"%s\"%s\n",
305
LOG_INTERNAL_OP_CON_ID,
306
LOG_INTERNAL_OP_OP_ID,
307
slapi_sdn_get_dn(sdn),
308
proxystr ? proxystr: "");
312
/* If we encountered an error parsing the proxy control, return an error
313
* to the client. We do this here to ensure that we log the operation first. */
314
if (proxy_err != LDAP_SUCCESS)
316
send_ldap_result(pb, proxy_err, NULL, errtext, 0, NULL);
317
goto free_and_return;
321
* We could be serving multiple database backends. Select the
324
if ((err = slapi_mapping_tree_select(pb, &be, &referral, errorbuf)) != LDAP_SUCCESS) {
325
send_ldap_result(pb, err, NULL, errorbuf, 0, NULL);
327
goto free_and_return;
334
slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
337
send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
338
"cannot delete referral", 0, NULL);
339
slapi_entry_free(referral);
340
goto free_and_return;
343
send_referrals_from_entry(pb,referral);
344
slapi_entry_free(referral);
345
goto free_and_return;
348
slapi_pblock_set(pb, SLAPI_BACKEND, be);
351
* call the pre-delete plugins. if they succeed, call
352
* the backend delete function. then call the
353
* post-delete plugins.
355
if (plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_PRE_DELETE_FN :
356
SLAPI_PLUGIN_PRE_DELETE_FN) == 0)
360
slapi_pblock_set(pb, SLAPI_PLUGIN, be->be_database);
361
set_db_default_result_handlers(pb);
362
if (be->be_delete != NULL)
364
if ((rc = (*be->be_delete)(pb)) == 0)
366
/* we don't perform acl check for internal operations */
367
/* Dont update aci store for remote acis */
368
if ((!internal_op) &&
369
(!slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA)))
370
plugin_call_acl_mods_update (pb, SLAPI_OPERATION_DELETE);
372
if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_AUDIT))
373
write_audit_log_entry(pb); /* Record the operation in the audit log */
375
slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &ecopy);
376
do_ps_service(ecopy, NULL, LDAP_CHANGETYPE_DELETE, 0);
380
if (rc == SLAPI_FAIL_DISKFULL)
382
operation_out_of_disk_space();
383
goto free_and_return;
388
slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &rc);
389
plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN :
390
SLAPI_PLUGIN_POST_DELETE_FN);
399
Slapi_Entry *epre = NULL, *eparent = NULL;
400
slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &epre);
401
slapi_pblock_get(pb, SLAPI_DELETE_GLUE_PARENT_ENTRY, &eparent);
402
slapi_pblock_set(pb, SLAPI_ENTRY_PRE_OP, NULL);
403
slapi_pblock_set(pb, SLAPI_DELETE_GLUE_PARENT_ENTRY, NULL);
404
if (epre == eparent) {
407
slapi_entry_free(epre);
408
slapi_entry_free(eparent);
409
slapi_pblock_get(pb, SLAPI_URP_NAMING_COLLISION_DN, &coldn);
410
slapi_ch_free_string(&coldn);
413
slapi_pblock_get(pb, SLAPI_DELETE_TARGET_SDN, &sdn);
414
slapi_sdn_free(&sdn);
415
slapi_ch_free_string(&proxydn);
416
slapi_ch_free_string(&proxystr);