]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/delete.c
22e67f6f67a404367ea7560294c449cad40c0683
[openldap] / servers / slapd / back-bdb / delete.c
1 /* delete.c - bdb backend delete routine */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11 #include <ac/string.h>
12
13 #include "back-bdb.h"
14 #include "external.h"
15
16 int
17 bdb_delete(
18         BackendDB       *be,
19         Connection      *conn,
20         Operation       *op,
21         const char      *dn,
22         const char      *ndn
23 )
24 {
25         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
26         Entry   *matched;
27         char    *pdn = NULL;
28         Entry   *e, *p = NULL;
29         int     rc;
30         const char *text;
31         int             manageDSAit = get_manageDSAit( op );
32         AttributeDescription *children = slap_schema.si_ad_children;
33         DB_TXN          *ltid = NULL;
34         struct bdb_op_info opinfo;
35
36         Debug( LDAP_DEBUG_ARGS, "==> bdb_delete: %s\n", dn, 0, 0 );
37
38         if( 0 ) {
39 retry:  /* transaction retry */
40                 Debug( LDAP_DEBUG_TRACE, "==> bdb_delete: retrying...\n", 0, 0, 0 );
41                 rc = txn_abort( ltid );
42                 ltid = NULL;
43                 op->o_private = NULL;
44                 if( rc != 0 ) {
45                         rc = LDAP_OTHER;
46                         text = "internal error";
47                         goto return_results;
48                 }
49         }
50
51         if( bdb->bi_txn ) {
52                 /* begin transaction */
53                 rc = txn_begin( bdb->bi_dbenv, NULL, &ltid, 0 );
54                 text = NULL;
55                 if( rc != 0 ) {
56                         Debug( LDAP_DEBUG_TRACE,
57                                 "bdb_delete: txn_begin failed: %s (%d)\n",
58                                 db_strerror(rc), rc, 0 );
59                         rc = LDAP_OTHER;
60                         text = "internal error";
61                         goto return_results;
62                 }
63         }
64
65         opinfo.boi_bdb = be;
66         opinfo.boi_txn = ltid;
67         opinfo.boi_err = 0;
68         op->o_private = &opinfo;
69
70         /* get entry for read/modify/write */
71         rc = bdb_dn2entry( be, ltid, ndn, &e, &matched, DB_RMW );
72
73         switch( rc ) {
74         case 0:
75         case DB_NOTFOUND:
76                 break;
77         case DB_LOCK_DEADLOCK:
78         case DB_LOCK_NOTGRANTED:
79                 goto retry;
80         default:
81                 rc = LDAP_OTHER;
82                 text = "internal error";
83                 goto return_results;
84         }
85
86         if ( e == NULL ) {
87                 char *matched_dn = NULL;
88                 struct berval **refs;
89
90                 Debug( LDAP_DEBUG_ARGS,
91                         "<=- bdb_delete: no such object %s\n",
92                         dn, 0, 0);
93
94                 if ( matched != NULL ) {
95                         matched_dn = ch_strdup( matched->e_dn );
96                         refs = is_entry_referral( matched )
97                                 ? get_entry_referrals( be, conn, op, matched,
98                                         dn, LDAP_SCOPE_DEFAULT )
99                                 : NULL;
100                         bdb_entry_return( be, matched );
101                         matched = NULL;
102
103                 } else {
104                         refs = referral_rewrite( default_referral,
105                                 NULL, dn, LDAP_SCOPE_DEFAULT );
106                 }
107
108                 send_ldap_result( conn, op, LDAP_REFERRAL,
109                         matched_dn, NULL, refs, NULL );
110
111                 ber_bvecfree( refs );
112                 free( matched_dn );
113
114                 rc = -1;
115                 goto done;
116         }
117
118         pdn = dn_parent( be, ndn );
119
120         if( pdn != NULL && *pdn != '\0' ) {
121                 /* get parent */
122                 rc = bdb_dn2entry( be, ltid, pdn, &p, NULL, 0 );
123
124                 ch_free( pdn );
125
126                 switch( rc ) {
127                 case 0:
128                 case DB_NOTFOUND:
129                         break;
130                 case DB_LOCK_DEADLOCK:
131                 case DB_LOCK_NOTGRANTED:
132                         goto retry;
133                 default:
134                         rc = LDAP_OTHER;
135                         text = "internal error";
136                         goto return_results;
137                 }
138
139                 if( p == NULL) {
140                         Debug( LDAP_DEBUG_TRACE,
141                                 "<=- bdb_delete: parent does not exist\n",
142                                 0, 0, 0);
143                         rc = LDAP_OTHER;
144                         text = "could not locate parent of entry";
145                         goto return_results;
146                 }
147
148                 /* check parent for "children" acl */
149                 rc = access_allowed( be, conn, op, p,
150                         children, NULL, ACL_WRITE );
151
152                 bdb_entry_return( be, p );
153                 p = NULL;
154
155                 if ( !rc  ) {
156                         Debug( LDAP_DEBUG_TRACE,
157                                 "<=- bdb_delete: no access to parent\n",
158                                 0, 0, 0 );
159                         rc = LDAP_INSUFFICIENT_ACCESS;
160                         goto return_results;
161                 }
162
163         } else {
164                 ch_free( pdn );
165
166                 /* no parent, must be root to delete */
167                 if( ! be_isroot( be, op->o_ndn ) ) {
168                         if ( be_issuffix( be, "" ) || be_isupdate( be, op->o_ndn ) ) {
169                                 p = (Entry *)&slap_entry_root;
170
171                                 /* check parent for "children" acl */
172                                 rc = access_allowed( be, conn, op, p,
173                                         children, NULL, ACL_WRITE );
174                                 p = NULL;
175
176                                 if ( !rc  ) {
177                                         Debug( LDAP_DEBUG_TRACE,
178                                                 "<=- bdb_delete: no access "
179                                                 "to parent\n", 0, 0, 0 );
180                                         rc = LDAP_INSUFFICIENT_ACCESS;
181                                         goto return_results;
182                                 }
183
184                         } else {
185                                 Debug( LDAP_DEBUG_TRACE,
186                                         "<=- bdb_delete: no parent "
187                                         "and not root\n", 0, 0, 0);
188                                 rc = LDAP_INSUFFICIENT_ACCESS;
189                                 goto return_results;
190                         }
191                 }
192         }
193
194         if ( !manageDSAit && is_entry_referral( e ) ) {
195                 /* parent is a referral, don't allow add */
196                 /* parent is an alias, don't allow add */
197                 struct berval **refs = get_entry_referrals( be,
198                         conn, op, e, dn, LDAP_SCOPE_DEFAULT );
199
200                 Debug( LDAP_DEBUG_TRACE,
201                         "bdb_delete: entry is referral\n",
202                         0, 0, 0 );
203
204                 send_ldap_result( conn, op, LDAP_REFERRAL,
205                         e->e_dn, NULL, refs, NULL );
206
207                 ber_bvecfree( refs );
208
209                 rc = 1;
210                 goto done;
211         }
212
213         rc = bdb_dn2id_children( be, ltid, e->e_ndn );
214         if( rc != DB_NOTFOUND ) {
215                 switch( rc ) {
216                 case DB_LOCK_DEADLOCK:
217                 case DB_LOCK_NOTGRANTED:
218                         goto retry;
219                 case 0:
220                         Debug(LDAP_DEBUG_ARGS,
221                                 "<=- bdb_delete: non-leaf %s\n",
222                                 dn, 0, 0);
223                         rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
224                         text = "subtree delete not supported";
225                         break;
226                 default:
227                         Debug(LDAP_DEBUG_ARGS,
228                                 "<=- bdb_delete: has_children failed: %s (%d)\n",
229                                 db_strerror(rc), rc, 0 );
230                         rc = LDAP_OTHER;
231                         text = "internal error";
232                 }
233                 goto return_results;
234         }
235
236         /* delete from dn2id */
237         rc = bdb_dn2id_delete( be, ltid, e->e_ndn, e->e_id );
238         if ( rc != 0 ) {
239                 switch( rc ) {
240                 case DB_LOCK_DEADLOCK:
241                 case DB_LOCK_NOTGRANTED:
242                         goto retry;
243                 default:
244                         rc = LDAP_OTHER;
245                 }
246                 Debug(LDAP_DEBUG_ARGS,
247                         "<=- bdb_delete: dn2id failed: %s (%d)\n",
248                         db_strerror(rc), rc, 0 );
249                 text = "DN index delete failed";
250                 goto return_results;
251         }
252
253         /* delete indices for old attributes */
254         rc = bdb_index_entry_del( be, ltid, e, e->e_attrs );
255         if ( rc != LDAP_SUCCESS ) {
256                 switch( rc ) {
257                 case DB_LOCK_DEADLOCK:
258                 case DB_LOCK_NOTGRANTED:
259                         goto retry;
260                 default:
261                         rc = LDAP_OTHER;
262                 }
263                 Debug( LDAP_DEBUG_ANY, "entry index delete failed!\n",
264                         0, 0, 0 );
265                 text = "entry index delete failed";
266                 goto return_results;
267         }
268
269         /* delete from id2entry */
270         rc = bdb_id2entry_delete( be, ltid, e->e_id );
271         if ( rc != 0 ) {
272                 switch( rc ) {
273                 case DB_LOCK_DEADLOCK:
274                 case DB_LOCK_NOTGRANTED:
275                         goto retry;
276                 default:
277                         rc = LDAP_OTHER;
278                 }
279                 Debug(LDAP_DEBUG_ARGS,
280                         "<=- bdb_delete: id2entry failed: %s (%d)\n",
281                         db_strerror(rc), rc, 0 );
282                 text = "entry delete failed";
283                 goto return_results;
284         }
285
286         if( bdb->bi_txn ) {
287                 rc = txn_commit( ltid, 0 );
288         }
289         ltid = NULL;
290         op->o_private = NULL;
291
292         if( rc != 0 ) {
293                 Debug( LDAP_DEBUG_TRACE,
294                         "bdb_delete: txn_commit failed: %s (%d)\n",
295                         db_strerror(rc), rc, 0 );
296                 rc = LDAP_OTHER;
297                 text = "commit failed";
298
299         } else {
300                 Debug( LDAP_DEBUG_TRACE,
301                         "bdb_delete: deleted id=%08lx dn=\"%s\"\n",
302                         e->e_id, e->e_dn, 0 );
303                 rc = LDAP_SUCCESS;
304                 text = NULL;
305         }
306
307 return_results:
308         send_ldap_result( conn, op, LDAP_SUCCESS,
309                 NULL, text, NULL, NULL );
310
311         if(rc == LDAP_SUCCESS && bdb->bi_txn_cp ) {
312                 ldap_pvt_thread_yield();
313                 txn_checkpoint( bdb->bi_dbenv,
314                         bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
315         }
316
317 done:
318         /* free entry */
319         if( e != NULL ) {
320                 bdb_entry_return( be, e );
321         }
322
323         if( ltid != NULL ) {
324                 txn_abort( ltid );
325                 op->o_private = NULL;
326         }
327
328         return rc;
329 }