1 /* $OpenLDAP: pkg/ldap/servers/slapd/back-sql/delete.c,v 1.35.2.8 2008/02/11 23:26:48 kurt Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1999-2008 The OpenLDAP Foundation.
5 * Portions Copyright 1999 Dmitry Kovalev.
6 * Portions Copyright 2002 Pierangelo Masarati.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
18 * This work was initially developed by Dmitry Kovalev for inclusion
19 * by OpenLDAP Software. Additional significant contributors include
20 * Pierangelo Masarati.
26 #include <sys/types.h>
27 #include "ac/string.h"
30 #include "proto-sql.h"
32 typedef struct backsql_delete_attr_t
{
36 backsql_entryID
*e_id
;
37 } backsql_delete_attr_t
;
40 backsql_delete_attr_f( void *v_at
, void *v_bda
)
42 backsql_at_map_rec
*at
= (backsql_at_map_rec
*)v_at
;
43 backsql_delete_attr_t
*bda
= (backsql_delete_attr_t
*)v_bda
;
46 rc
= backsql_modify_delete_all_values( bda
->op
,
47 bda
->rs
, bda
->dbh
, bda
->e_id
, at
);
49 if ( rc
!= LDAP_SUCCESS
) {
50 return BACKSQL_AVL_STOP
;
53 return BACKSQL_AVL_CONTINUE
;
57 backsql_delete_all_attrs(
61 backsql_entryID
*eid
)
63 backsql_delete_attr_t bda
;
71 rc
= avl_apply( eid
->eid_oc
->bom_attrs
, backsql_delete_attr_f
, &bda
,
72 BACKSQL_AVL_STOP
, AVL_INORDER
);
73 if ( rc
== BACKSQL_AVL_STOP
) {
89 backsql_info
*bi
= (backsql_info
*)op
->o_bd
->be_private
;
90 SQLHSTMT sth
= SQL_NULL_HSTMT
;
92 int prc
= LDAP_SUCCESS
;
93 /* first parameter no */
99 rs
->sr_err
= backsql_delete_all_attrs( op
, rs
, dbh
, eid
);
100 if ( rs
->sr_err
!= LDAP_SUCCESS
) {
104 rc
= backsql_Prepare( dbh
, &sth
, eid
->eid_oc
->bom_delete_proc
, 0 );
105 if ( rc
!= SQL_SUCCESS
) {
106 Debug( LDAP_DEBUG_TRACE
,
107 " backsql_delete(): "
108 "error preparing delete query\n",
110 backsql_PrintErrors( bi
->sql_db_env
, dbh
, sth
, rc
);
112 rs
->sr_err
= LDAP_OTHER
;
113 rs
->sr_text
= "SQL-backend error";
118 if ( BACKSQL_IS_DEL( eid
->eid_oc
->bom_expect_return
) ) {
120 rc
= backsql_BindParamInt( sth
, 1, SQL_PARAM_OUTPUT
, &prc
);
121 if ( rc
!= SQL_SUCCESS
) {
122 Debug( LDAP_DEBUG_TRACE
,
123 " backsql_delete(): "
124 "error binding output parameter for objectClass %s\n",
125 eid
->eid_oc
->bom_oc
->soc_cname
.bv_val
, 0, 0 );
126 backsql_PrintErrors( bi
->sql_db_env
, dbh
,
128 SQLFreeStmt( sth
, SQL_DROP
);
130 rs
->sr_text
= "SQL-backend error";
131 rs
->sr_err
= LDAP_OTHER
;
137 rc
= backsql_BindParamID( sth
, pno
+ 1, SQL_PARAM_INPUT
, &eid
->eid_keyval
);
138 if ( rc
!= SQL_SUCCESS
) {
139 Debug( LDAP_DEBUG_TRACE
,
140 " backsql_delete(): "
141 "error binding keyval parameter for objectClass %s\n",
142 eid
->eid_oc
->bom_oc
->soc_cname
.bv_val
, 0, 0 );
143 backsql_PrintErrors( bi
->sql_db_env
, dbh
,
145 SQLFreeStmt( sth
, SQL_DROP
);
147 rs
->sr_text
= "SQL-backend error";
148 rs
->sr_err
= LDAP_OTHER
;
153 rc
= SQLExecute( sth
);
154 if ( rc
== SQL_SUCCESS
&& prc
== LDAP_SUCCESS
) {
155 rs
->sr_err
= LDAP_SUCCESS
;
158 Debug( LDAP_DEBUG_TRACE
, " backsql_delete(): "
159 "delete_proc execution failed (rc=%d, prc=%d)\n",
163 if ( prc
!= LDAP_SUCCESS
) {
164 /* SQL procedure executed fine
165 * but returned an error */
166 rs
->sr_err
= BACKSQL_SANITIZE_ERROR( prc
);
169 backsql_PrintErrors( bi
->sql_db_env
, dbh
,
171 rs
->sr_err
= LDAP_OTHER
;
173 SQLFreeStmt( sth
, SQL_DROP
);
176 SQLFreeStmt( sth
, SQL_DROP
);
178 /* delete "auxiliary" objectClasses, if any... */
179 rc
= backsql_Prepare( dbh
, &sth
, bi
->sql_delobjclasses_stmt
, 0 );
180 if ( rc
!= SQL_SUCCESS
) {
181 Debug( LDAP_DEBUG_TRACE
,
182 " backsql_delete(): "
183 "error preparing ldap_entry_objclasses delete query\n",
185 backsql_PrintErrors( bi
->sql_db_env
, dbh
, sth
, rc
);
187 rs
->sr_err
= LDAP_OTHER
;
188 rs
->sr_text
= "SQL-backend error";
193 rc
= backsql_BindParamID( sth
, 1, SQL_PARAM_INPUT
, &eid
->eid_id
);
194 if ( rc
!= SQL_SUCCESS
) {
195 Debug( LDAP_DEBUG_TRACE
,
196 " backsql_delete(): "
197 "error binding auxiliary objectClasses "
198 "entry ID parameter for objectClass %s\n",
199 eid
->eid_oc
->bom_oc
->soc_cname
.bv_val
, 0, 0 );
200 backsql_PrintErrors( bi
->sql_db_env
, dbh
,
202 SQLFreeStmt( sth
, SQL_DROP
);
204 rs
->sr_text
= "SQL-backend error";
205 rs
->sr_err
= LDAP_OTHER
;
210 rc
= SQLExecute( sth
);
213 /* apparently there were no "auxiliary" objectClasses
214 * for this entry... */
219 Debug( LDAP_DEBUG_TRACE
, " backsql_delete(): "
220 "failed to delete record from ldap_entry_objclasses\n",
222 backsql_PrintErrors( bi
->sql_db_env
, dbh
, sth
, rc
);
223 SQLFreeStmt( sth
, SQL_DROP
);
224 rs
->sr_err
= LDAP_OTHER
;
225 rs
->sr_text
= "SQL-backend error";
229 SQLFreeStmt( sth
, SQL_DROP
);
231 /* delete entry... */
232 rc
= backsql_Prepare( dbh
, &sth
, bi
->sql_delentry_stmt
, 0 );
233 if ( rc
!= SQL_SUCCESS
) {
234 Debug( LDAP_DEBUG_TRACE
,
235 " backsql_delete(): "
236 "error preparing ldap_entries delete query\n",
238 backsql_PrintErrors( bi
->sql_db_env
, dbh
, sth
, rc
);
240 rs
->sr_err
= LDAP_OTHER
;
241 rs
->sr_text
= "SQL-backend error";
246 rc
= backsql_BindParamID( sth
, 1, SQL_PARAM_INPUT
, &eid
->eid_id
);
247 if ( rc
!= SQL_SUCCESS
) {
248 Debug( LDAP_DEBUG_TRACE
,
249 " backsql_delete(): "
250 "error binding entry ID parameter "
251 "for objectClass %s\n",
252 eid
->eid_oc
->bom_oc
->soc_cname
.bv_val
, 0, 0 );
253 backsql_PrintErrors( bi
->sql_db_env
, dbh
,
255 SQLFreeStmt( sth
, SQL_DROP
);
257 rs
->sr_text
= "SQL-backend error";
258 rs
->sr_err
= LDAP_OTHER
;
263 rc
= SQLExecute( sth
);
264 if ( rc
!= SQL_SUCCESS
) {
265 Debug( LDAP_DEBUG_TRACE
, " backsql_delete(): "
266 "failed to delete record from ldap_entries\n",
268 backsql_PrintErrors( bi
->sql_db_env
, dbh
, sth
, rc
);
269 SQLFreeStmt( sth
, SQL_DROP
);
270 rs
->sr_err
= LDAP_OTHER
;
271 rs
->sr_text
= "SQL-backend error";
275 SQLFreeStmt( sth
, SQL_DROP
);
277 rs
->sr_err
= LDAP_SUCCESS
;
286 typedef struct backsql_tree_delete_t
{
289 backsql_entryID
*btd_eid
;
290 } backsql_tree_delete_t
;
293 backsql_tree_delete_search_cb( Operation
*op
, SlapReply
*rs
)
295 if ( rs
->sr_type
== REP_SEARCH
) {
296 backsql_tree_delete_t
*btd
;
297 backsql_entryID
*eid
;
299 btd
= (backsql_tree_delete_t
*)op
->o_callback
->sc_private
;
301 if ( !access_allowed( btd
->btd_op
, rs
->sr_entry
,
302 slap_schema
.si_ad_entry
, NULL
, ACL_WDEL
, NULL
)
303 || !access_allowed( btd
->btd_op
, rs
->sr_entry
,
304 slap_schema
.si_ad_children
, NULL
, ACL_WDEL
, NULL
) )
306 btd
->btd_rc
= LDAP_INSUFFICIENT_ACCESS
;
307 return rs
->sr_err
= LDAP_UNAVAILABLE
;
310 assert( rs
->sr_entry
!= NULL
);
311 assert( rs
->sr_entry
->e_private
!= NULL
);
313 eid
= (backsql_entryID
*)rs
->sr_entry
->e_private
;
314 assert( eid
->eid_oc
!= NULL
);
315 if ( eid
->eid_oc
== NULL
|| eid
->eid_oc
->bom_delete_proc
== NULL
) {
316 btd
->btd_rc
= LDAP_UNWILLING_TO_PERFORM
;
317 return rs
->sr_err
= LDAP_UNAVAILABLE
;
320 eid
= backsql_entryID_dup( eid
, op
->o_tmpmemctx
);
321 eid
->eid_next
= btd
->btd_eid
;
336 slap_callback sc
= { 0 };
337 SlapReply rs2
= { 0 };
338 backsql_tree_delete_t btd
= { 0 };
343 * - perform an internal subtree search as the rootdn
346 * - check objectClass and delete method(s)
349 * - if successful, commit
352 op2
.o_tag
= LDAP_REQ_SEARCH
;
353 op2
.o_protocol
= LDAP_VERSION3
;
356 sc
.sc_private
= &btd
;
357 sc
.sc_response
= backsql_tree_delete_search_cb
;
358 op2
.o_callback
= &sc
;
360 op2
.o_dn
= op
->o_bd
->be_rootdn
;
361 op2
.o_ndn
= op
->o_bd
->be_rootndn
;
363 op2
.o_managedsait
= SLAP_CONTROL_CRITICAL
;
365 op2
.ors_scope
= LDAP_SCOPE_SUBTREE
;
366 op2
.ors_deref
= LDAP_DEREF_NEVER
;
367 op2
.ors_slimit
= SLAP_NO_LIMIT
;
368 op2
.ors_tlimit
= SLAP_NO_LIMIT
;
369 op2
.ors_filter
= (Filter
*)slap_filter_objectClass_pres
;
370 op2
.ors_filterstr
= *slap_filterstr_objectClass_pres
;
371 op2
.ors_attrs
= slap_anlist_all_attributes
;
372 op2
.ors_attrsonly
= 0;
374 rc
= op
->o_bd
->be_search( &op2
, &rs2
);
375 if ( rc
!= LDAP_SUCCESS
) {
376 rc
= rs
->sr_err
= btd
.btd_rc
;
377 rs
->sr_text
= "subtree delete not possible";
378 send_ldap_result( op
, rs
);
382 for ( ; btd
.btd_eid
!= NULL
;
383 btd
.btd_eid
= backsql_free_entryID( btd
.btd_eid
,
384 1, op
->o_tmpmemctx
) )
386 Entry
*e
= (void *)0xbad;
387 rc
= backsql_delete_int( op
, rs
, dbh
, sthp
, btd
.btd_eid
, &e
);
388 if ( rc
!= LDAP_SUCCESS
) {
394 for ( ; btd
.btd_eid
!= NULL
;
395 btd
.btd_eid
= backsql_free_entryID( btd
.btd_eid
,
396 1, op
->o_tmpmemctx
) )
403 backsql_delete( Operation
*op
, SlapReply
*rs
)
405 SQLHDBC dbh
= SQL_NULL_HDBC
;
406 SQLHSTMT sth
= SQL_NULL_HSTMT
;
407 backsql_oc_map_rec
*oc
= NULL
;
408 backsql_srch_info bsi
= { 0 };
409 backsql_entryID e_id
= { 0 };
410 Entry d
= { 0 }, p
= { 0 }, *e
= NULL
;
411 struct berval pdn
= BER_BVNULL
;
412 int manageDSAit
= get_manageDSAit( op
);
414 Debug( LDAP_DEBUG_TRACE
, "==>backsql_delete(): deleting entry \"%s\"\n",
415 op
->o_req_ndn
.bv_val
, 0, 0 );
417 rs
->sr_err
= backsql_get_db_conn( op
, &dbh
);
418 if ( rs
->sr_err
!= LDAP_SUCCESS
) {
419 Debug( LDAP_DEBUG_TRACE
, " backsql_delete(): "
420 "could not get connection handle - exiting\n",
422 rs
->sr_text
= ( rs
->sr_err
== LDAP_OTHER
)
423 ? "SQL-backend error" : NULL
;
432 rs
->sr_err
= backsql_init_search( &bsi
, &op
->o_req_ndn
,
434 (time_t)(-1), NULL
, dbh
, op
, rs
, slap_anlist_no_attrs
,
435 ( BACKSQL_ISF_MATCHED
| BACKSQL_ISF_GET_ENTRY
| BACKSQL_ISF_GET_OC
) );
436 switch ( rs
->sr_err
) {
441 if ( manageDSAit
&& !BER_BVISNULL( &bsi
.bsi_e
->e_nname
) &&
442 dn_match( &op
->o_req_ndn
, &bsi
.bsi_e
->e_nname
) )
444 rs
->sr_err
= LDAP_SUCCESS
;
446 rs
->sr_matched
= NULL
;
448 ber_bvarray_free( rs
->sr_ref
);
457 Debug( LDAP_DEBUG_TRACE
, "backsql_delete(): "
458 "could not retrieve deleteDN ID - no such entry\n",
460 if ( !BER_BVISNULL( &d
.e_nname
) ) {
461 /* FIXME: should always be true! */
470 if ( get_assert( op
) &&
471 ( test_filter( op
, &d
, get_assertion( op
) )
472 != LDAP_COMPARE_TRUE
) )
474 rs
->sr_err
= LDAP_ASSERTION_FAILED
;
479 if ( !access_allowed( op
, &d
, slap_schema
.si_ad_entry
,
480 NULL
, ACL_WDEL
, NULL
) )
482 Debug( LDAP_DEBUG_TRACE
, " backsql_delete(): "
483 "no write access to entry\n",
485 rs
->sr_err
= LDAP_INSUFFICIENT_ACCESS
;
490 rs
->sr_err
= backsql_has_children( op
, dbh
, &op
->o_req_ndn
);
491 switch ( rs
->sr_err
) {
492 case LDAP_COMPARE_FALSE
:
493 rs
->sr_err
= LDAP_SUCCESS
;
496 case LDAP_COMPARE_TRUE
:
497 #ifdef SLAP_CONTROL_X_TREE_DELETE
498 if ( get_treeDelete( op
) ) {
499 rs
->sr_err
= LDAP_SUCCESS
;
502 #endif /* SLAP_CONTROL_X_TREE_DELETE */
504 Debug( LDAP_DEBUG_TRACE
, " backsql_delete(): "
505 "entry \"%s\" has children\n",
506 op
->o_req_dn
.bv_val
, 0, 0 );
507 rs
->sr_err
= LDAP_NOT_ALLOWED_ON_NONLEAF
;
508 rs
->sr_text
= "subordinate objects must be deleted first";
516 assert( bsi
.bsi_base_id
.eid_oc
!= NULL
);
517 oc
= bsi
.bsi_base_id
.eid_oc
;
518 if ( oc
->bom_delete_proc
== NULL
) {
519 Debug( LDAP_DEBUG_TRACE
, " backsql_delete(): "
520 "delete procedure is not defined "
521 "for this objectclass - aborting\n", 0, 0, 0 );
522 rs
->sr_err
= LDAP_UNWILLING_TO_PERFORM
;
523 rs
->sr_text
= "operation not permitted within namingContext";
531 e_id
= bsi
.bsi_base_id
;
532 memset( &bsi
.bsi_base_id
, 0, sizeof( bsi
.bsi_base_id
) );
533 if ( !be_issuffix( op
->o_bd
, &op
->o_req_ndn
) ) {
534 dnParent( &op
->o_req_ndn
, &pdn
);
536 rs
->sr_err
= backsql_init_search( &bsi
, &pdn
,
538 (time_t)(-1), NULL
, dbh
, op
, rs
,
539 slap_anlist_no_attrs
,
540 BACKSQL_ISF_GET_ENTRY
);
541 if ( rs
->sr_err
!= LDAP_SUCCESS
) {
542 Debug( LDAP_DEBUG_TRACE
, "backsql_delete(): "
543 "could not retrieve deleteDN ID "
550 (void)backsql_free_entryID( &bsi
.bsi_base_id
, 0, op
->o_tmpmemctx
);
552 /* check parent for "children" acl */
553 if ( !access_allowed( op
, &p
, slap_schema
.si_ad_children
,
554 NULL
, ACL_WDEL
, NULL
) )
556 Debug( LDAP_DEBUG_TRACE
, " backsql_delete(): "
557 "no write access to parent\n",
559 rs
->sr_err
= LDAP_INSUFFICIENT_ACCESS
;
567 #ifdef SLAP_CONTROL_X_TREE_DELETE
568 if ( get_treeDelete( op
) ) {
569 backsql_tree_delete( op
, rs
, dbh
, &sth
);
570 if ( rs
->sr_err
== LDAP_OTHER
|| rs
->sr_err
== LDAP_SUCCESS
)
576 #endif /* SLAP_CONTROL_X_TREE_DELETE */
578 backsql_delete_int( op
, rs
, dbh
, &sth
, &e_id
, &e
);
582 * Commit only if all operations succeed
584 if ( sth
!= SQL_NULL_HSTMT
) {
585 SQLUSMALLINT CompletionType
= SQL_ROLLBACK
;
587 if ( rs
->sr_err
== LDAP_SUCCESS
&& !op
->o_noop
) {
589 CompletionType
= SQL_COMMIT
;
592 SQLTransact( SQL_NULL_HENV
, dbh
, CompletionType
);
597 if ( !access_allowed( op
, e
, slap_schema
.si_ad_entry
, NULL
,
598 ACL_DISCLOSE
, NULL
) )
600 rs
->sr_err
= LDAP_NO_SUCH_OBJECT
;
602 rs
->sr_matched
= NULL
;
604 ber_bvarray_free( rs
->sr_ref
);
610 if ( op
->o_noop
&& rs
->sr_err
== LDAP_SUCCESS
) {
611 rs
->sr_err
= LDAP_X_NO_OPERATION
;
614 send_ldap_result( op
, rs
);
616 Debug( LDAP_DEBUG_TRACE
, "<==backsql_delete()\n", 0, 0, 0 );
618 if ( !BER_BVISNULL( &e_id
.eid_ndn
) ) {
619 (void)backsql_free_entryID( &e_id
, 0, op
->o_tmpmemctx
);
622 if ( !BER_BVISNULL( &d
.e_nname
) ) {
623 backsql_entry_clean( op
, &d
);
626 if ( !BER_BVISNULL( &p
.e_nname
) ) {
627 backsql_entry_clean( op
, &p
);
631 ber_bvarray_free( rs
->sr_ref
);