]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/delete.c
ITS#3796 fix IDL cache lock setup/teardown
[openldap] / servers / slapd / back-sql / delete.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2005 The OpenLDAP Foundation.
5  * Portions Copyright 1999 Dmitry Kovalev.
6  * Portions Copyright 2002 Pierangelo Masarati.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
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>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Dmitry Kovalev for inclusion
19  * by OpenLDAP Software.  Additional significant contributors include
20  * Pierangelo Masarati.
21  */
22
23 #include "portable.h"
24
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include "ac/string.h"
28
29 #include "slap.h"
30 #include "proto-sql.h"
31
32 typedef struct backsql_delete_attr_t {
33         Operation               *op;
34         SlapReply               *rs;
35         SQLHDBC                 dbh; 
36         backsql_entryID         *e_id;
37 } backsql_delete_attr_t;
38
39 static int
40 backsql_delete_attr_f( void *v_at, void *v_bda )
41 {
42         backsql_at_map_rec      *at = (backsql_at_map_rec *)v_at;
43         backsql_delete_attr_t   *bda = (backsql_delete_attr_t *)v_bda;
44         int                     rc;
45
46         rc = backsql_modify_delete_all_values( bda->op,
47                         bda->rs, bda->dbh, bda->e_id, at );
48
49         if ( rc != LDAP_SUCCESS ) {
50                 return BACKSQL_AVL_STOP;
51         }
52
53         return BACKSQL_AVL_CONTINUE;
54 }
55
56 static int
57 backsql_delete_all_attrs(
58         Operation               *op,
59         SlapReply               *rs,
60         SQLHDBC                 dbh, 
61         backsql_entryID         *e_id,
62         backsql_oc_map_rec      *oc )
63 {
64         backsql_delete_attr_t   bda;
65         int                     rc;
66
67         bda.op = op;
68         bda.rs = rs;
69         bda.dbh = dbh;
70         bda.e_id = e_id;
71         
72         rc = avl_apply( oc->bom_attrs, backsql_delete_attr_f, &bda,
73                         BACKSQL_AVL_STOP, AVL_INORDER );
74         if ( rc == BACKSQL_AVL_STOP ) {
75                 return rs->sr_err;
76         }
77
78         return LDAP_SUCCESS;
79 }
80
81 int
82 backsql_delete( Operation *op, SlapReply *rs )
83 {
84         backsql_info            *bi = (backsql_info*)op->o_bd->be_private;
85         SQLHDBC                 dbh = SQL_NULL_HDBC;
86         SQLHSTMT                sth = SQL_NULL_HSTMT;
87         RETCODE                 rc;
88         int                     prc = LDAP_SUCCESS;
89         backsql_oc_map_rec      *oc = NULL;
90         backsql_srch_info       bsi = { 0 };
91         backsql_entryID         e_id = { 0 };
92         Entry                   d = { 0 }, p = { 0 }, *e = NULL;
93         struct berval           pdn = BER_BVNULL;
94         int                     manageDSAit = get_manageDSAit( op );
95         /* first parameter no */
96         SQLUSMALLINT            pno;
97
98         Debug( LDAP_DEBUG_TRACE, "==>backsql_delete(): deleting entry \"%s\"\n",
99                         op->o_req_ndn.bv_val, 0, 0 );
100
101         rs->sr_err = backsql_get_db_conn( op, &dbh );
102         if ( rs->sr_err != LDAP_SUCCESS ) {
103                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
104                         "could not get connection handle - exiting\n", 
105                         0, 0, 0 );
106                 rs->sr_text = ( rs->sr_err == LDAP_OTHER )
107                         ? "SQL-backend error" : NULL;
108                 e = NULL;
109                 goto done;
110         }
111         
112         /*
113          * Get the entry
114          */
115         bsi.bsi_e = &d;
116         rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn,
117                         LDAP_SCOPE_BASE, 
118                         SLAP_NO_LIMIT, SLAP_NO_LIMIT,
119                         (time_t)(-1), NULL, dbh, op, rs, slap_anlist_no_attrs,
120                         ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) );
121         switch ( rs->sr_err ) {
122         case LDAP_SUCCESS:
123                 break;
124
125         case LDAP_REFERRAL:
126                 if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) &&
127                                 dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) )
128                 {
129                         rs->sr_err = LDAP_SUCCESS;
130                         rs->sr_text = NULL;
131                         rs->sr_matched = NULL;
132                         if ( rs->sr_ref ) {
133                                 ber_bvarray_free( rs->sr_ref );
134                                 rs->sr_ref = NULL;
135                         }
136                         break;
137                 }
138                 e = &d;
139                 /* fallthru */
140
141         default:
142                 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
143                         "could not retrieve deleteDN ID - no such entry\n", 
144                         0, 0, 0 );
145                 if ( !BER_BVISNULL( &d.e_nname ) ) {
146                         /* FIXME: should always be true! */
147                         e = &d;
148
149                 } else {
150                         e = NULL;
151                 }
152                 goto done;
153         }
154
155         if ( get_assert( op ) &&
156                         ( test_filter( op, &d, get_assertion( op ) )
157                           != LDAP_COMPARE_TRUE ) )
158         {
159                 rs->sr_err = LDAP_ASSERTION_FAILED;
160                 e = &d;
161                 goto done;
162         }
163
164         if ( !access_allowed( op, &d, slap_schema.si_ad_entry, 
165                         NULL, ACL_WDEL, NULL ) )
166         {
167                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
168                         "no write access to entry\n", 
169                         0, 0, 0 );
170                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
171                 e = &d;
172                 goto done;
173         }
174
175         rs->sr_err = backsql_has_children( bi, dbh, &op->o_req_ndn );
176         switch ( rs->sr_err ) {
177         case LDAP_COMPARE_FALSE:
178                 rs->sr_err = LDAP_SUCCESS;
179                 break;
180
181         case LDAP_COMPARE_TRUE:
182                 if ( get_treeDelete( op ) ) {
183                         /* not supported yet */ ;
184                 }
185                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
186                         "entry \"%s\" has children\n",
187                         op->o_req_dn.bv_val, 0, 0 );
188                 rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
189                 rs->sr_text = "subordinate objects must be deleted first";
190                 /* fallthru */
191
192         default:
193                 e = &d;
194                 goto done;
195         }
196
197         oc = backsql_id2oc( bi, bsi.bsi_base_id.eid_oc_id );
198         if ( oc == NULL ) {
199                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
200                         "cannot determine objectclass of entry -- aborting\n",
201                         0, 0, 0 );
202                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
203                 rs->sr_text = "operation not permitted within namingContext";
204                 e = NULL;
205                 goto done;
206         }
207
208         if ( oc->bom_delete_proc == NULL ) {
209                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
210                         "delete procedure is not defined "
211                         "for this objectclass - aborting\n", 0, 0, 0 );
212                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
213                 rs->sr_text = "operation not permitted within namingContext";
214                 e = NULL;
215                 goto done;
216         }
217
218         /*
219          * Get the parent
220          */
221         dnParent( &op->o_req_ndn, &pdn );
222         bsi.bsi_e = &p;
223         e_id = bsi.bsi_base_id;
224         rs->sr_err = backsql_init_search( &bsi, &pdn,
225                         LDAP_SCOPE_BASE, 
226                         SLAP_NO_LIMIT, SLAP_NO_LIMIT,
227                         (time_t)(-1), NULL, dbh, op, rs, slap_anlist_no_attrs,
228                         BACKSQL_ISF_GET_ENTRY );
229         if ( rs->sr_err != LDAP_SUCCESS ) {
230                 Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
231                         "could not retrieve deleteDN ID - no such entry\n", 
232                         0, 0, 0 );
233                 e = &p;
234                 goto done;
235         }
236
237         (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 );
238
239         /* check parent for "children" acl */
240         if ( !access_allowed( op, &p, slap_schema.si_ad_children, 
241                         NULL, ACL_WDEL, NULL ) )
242         {
243                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
244                         "no write access to parent\n", 
245                         0, 0, 0 );
246                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
247                 e = &p;
248                 goto done;
249
250         }
251
252         /* avl_apply ... */
253         rs->sr_err = backsql_delete_all_attrs( op, rs, dbh, &e_id, oc );
254         if ( rs->sr_err != LDAP_SUCCESS ) {
255                 e = &d;
256                 goto done;
257         }
258
259         rc = backsql_Prepare( dbh, &sth, oc->bom_delete_proc, 0 );
260         if ( rc != SQL_SUCCESS ) {
261                 Debug( LDAP_DEBUG_TRACE,
262                         "   backsql_delete(): "
263                         "error preparing delete query\n", 
264                         0, 0, 0 );
265                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
266
267                 rs->sr_err = LDAP_OTHER;
268                 rs->sr_text = "SQL-backend error";
269                 e = NULL;
270                 goto done;
271         }
272
273         if ( BACKSQL_IS_DEL( oc->bom_expect_return ) ) {
274                 pno = 1;
275                 rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &prc );
276                 if ( rc != SQL_SUCCESS ) {
277                         Debug( LDAP_DEBUG_TRACE,
278                                 "   backsql_delete(): "
279                                 "error binding output parameter for objectClass %s\n",
280                                 oc->bom_oc->soc_cname.bv_val, 0, 0 );
281                         backsql_PrintErrors( bi->sql_db_env, dbh, 
282                                 sth, rc );
283                         SQLFreeStmt( sth, SQL_DROP );
284
285                         rs->sr_text = "SQL-backend error";
286                         rs->sr_err = LDAP_OTHER;
287                         e = NULL;
288                         goto done;
289                 }
290
291         } else {
292                 pno = 0;
293         }
294
295         rc = backsql_BindParamID( sth, pno + 1, SQL_PARAM_INPUT, &e_id.eid_keyval );
296         if ( rc != SQL_SUCCESS ) {
297                 Debug( LDAP_DEBUG_TRACE,
298                         "   backsql_delete(): "
299                         "error binding keyval parameter for objectClass %s\n",
300                         oc->bom_oc->soc_cname.bv_val, 0, 0 );
301                 backsql_PrintErrors( bi->sql_db_env, dbh, 
302                         sth, rc );
303                 SQLFreeStmt( sth, SQL_DROP );
304
305                 rs->sr_text = "SQL-backend error";
306                 rs->sr_err = LDAP_OTHER;
307                 e = NULL;
308                 goto done;
309         }
310
311         rc = SQLExecute( sth );
312         if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) {
313                 rs->sr_err = LDAP_SUCCESS;
314
315         } else {
316                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
317                         "delete_proc execution failed (rc=%d, prc=%d)\n",
318                         rc, prc, 0 );
319
320
321                 if ( prc != LDAP_SUCCESS ) {
322                         /* SQL procedure executed fine 
323                          * but returned an error */
324                         rs->sr_err = BACKSQL_SANITIZE_ERROR( prc );
325
326                 } else {
327                         backsql_PrintErrors( bi->sql_db_env, dbh,
328                                         sth, rc );
329                         rs->sr_err = LDAP_OTHER;
330                 }
331                 SQLFreeStmt( sth, SQL_DROP );
332                 e = &d;
333                 goto done;
334         }
335         SQLFreeStmt( sth, SQL_DROP );
336
337         /* delete "auxiliary" objectClasses, if any... */
338         rc = backsql_Prepare( dbh, &sth, bi->sql_delobjclasses_stmt, 0 );
339         if ( rc != SQL_SUCCESS ) {
340                 Debug( LDAP_DEBUG_TRACE,
341                         "   backsql_delete(): "
342                         "error preparing ldap_entry_objclasses delete query\n", 
343                         0, 0, 0 );
344                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
345
346                 rs->sr_err = LDAP_OTHER;
347                 rs->sr_text = "SQL-backend error";
348                 e = NULL;
349                 goto done;
350         }
351
352         rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &e_id.eid_id );
353         if ( rc != SQL_SUCCESS ) {
354                 Debug( LDAP_DEBUG_TRACE,
355                         "   backsql_delete(): "
356                         "error binding auxiliary objectClasses "
357                         "entry ID parameter for objectClass %s\n",
358                         oc->bom_oc->soc_cname.bv_val, 0, 0 );
359                 backsql_PrintErrors( bi->sql_db_env, dbh, 
360                         sth, rc );
361                 SQLFreeStmt( sth, SQL_DROP );
362
363                 rs->sr_text = "SQL-backend error";
364                 rs->sr_err = LDAP_OTHER;
365                 e = NULL;
366                 goto done;
367         }
368
369         rc = SQLExecute( sth );
370         switch ( rc ) {
371         case SQL_NO_DATA:
372                 /* apparently there were no "auxiliary" objectClasses
373                  * for this entry... */
374         case SQL_SUCCESS:
375                 break;
376
377         default:
378                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
379                         "failed to delete record from ldap_entry_objclasses\n", 
380                         0, 0, 0 );
381                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
382                 SQLFreeStmt( sth, SQL_DROP );
383                 rs->sr_err = LDAP_OTHER;
384                 rs->sr_text = "SQL-backend error";
385                 e = NULL;
386                 goto done;
387         }
388         SQLFreeStmt( sth, SQL_DROP );
389
390         /* delete entry... */
391         rc = backsql_Prepare( dbh, &sth, bi->sql_delentry_stmt, 0 );
392         if ( rc != SQL_SUCCESS ) {
393                 Debug( LDAP_DEBUG_TRACE,
394                         "   backsql_delete(): "
395                         "error preparing ldap_entries delete query\n", 
396                         0, 0, 0 );
397                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
398
399                 rs->sr_err = LDAP_OTHER;
400                 rs->sr_text = "SQL-backend error";
401                 e = NULL;
402                 goto done;
403         }
404
405         rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT, &e_id.eid_id );
406         if ( rc != SQL_SUCCESS ) {
407                 Debug( LDAP_DEBUG_TRACE,
408                         "   backsql_delete(): "
409                         "error binding entry ID parameter "
410                         "for objectClass %s\n",
411                         oc->bom_oc->soc_cname.bv_val, 0, 0 );
412                 backsql_PrintErrors( bi->sql_db_env, dbh, 
413                         sth, rc );
414                 SQLFreeStmt( sth, SQL_DROP );
415
416                 rs->sr_text = "SQL-backend error";
417                 rs->sr_err = LDAP_OTHER;
418                 e = NULL;
419                 goto done;
420         }
421
422         rc = SQLExecute( sth );
423         if ( rc != SQL_SUCCESS ) {
424                 Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
425                         "failed to delete record from ldap_entries\n", 
426                         0, 0, 0 );
427                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
428                 SQLFreeStmt( sth, SQL_DROP );
429                 rs->sr_err = LDAP_OTHER;
430                 rs->sr_text = "SQL-backend error";
431                 e = NULL;
432                 goto done;
433         }
434         SQLFreeStmt( sth, SQL_DROP );
435
436         rs->sr_err = LDAP_SUCCESS;
437
438         /*
439          * Commit only if all operations succeed
440          */
441         if ( sth != SQL_NULL_HSTMT ) {
442                 SQLUSMALLINT    CompletionType = SQL_ROLLBACK;
443         
444                 if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
445                         CompletionType = SQL_COMMIT;
446                 }
447
448                 SQLTransact( SQL_NULL_HENV, dbh, CompletionType );
449         }
450
451 done:;
452 #ifdef SLAP_ACL_HONOR_DISCLOSE
453         if ( e != NULL ) {
454                 if ( !access_allowed( op, e, slap_schema.si_ad_entry, NULL,
455                                         ACL_DISCLOSE, NULL ) )
456                 {
457                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
458                         rs->sr_text = NULL;
459                         rs->sr_matched = NULL;
460                         if ( rs->sr_ref ) {
461                                 ber_bvarray_free( rs->sr_ref );
462                                 rs->sr_ref = NULL;
463                         }
464                 }
465         }
466 #endif /* SLAP_ACL_HONOR_DISCLOSE */
467
468         send_ldap_result( op, rs );
469
470         Debug( LDAP_DEBUG_TRACE, "<==backsql_delete()\n", 0, 0, 0 );
471
472         if ( !BER_BVISNULL( &e_id.eid_ndn ) ) {
473                 (void)backsql_free_entryID( op, &e_id, 0 );
474         }
475
476         if ( !BER_BVISNULL( &d.e_nname ) ) {
477                 backsql_entry_clean( op, &d );
478         }
479
480         if ( !BER_BVISNULL( &p.e_nname ) ) {
481                 backsql_entry_clean( op, &p );
482         }
483
484         return rs->sr_err;
485 }
486