]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/delete.c
a39930179805a53a1a53b9b49ac10ce887380be7
[openldap] / servers / slapd / back-bdb / delete.c
1 /* delete.c - ldbm 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
15 int
16 bdb_delete(
17     Backend     *be,
18     Connection  *conn,
19     Operation   *op,
20     const char  *dn,
21     const char  *ndn
22 )
23 {
24         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
25         Entry   *matched;
26         char    *pdn = NULL;
27         Entry   *e, *p = NULL;
28         int     rc;
29         const char *text = NULL;
30         int             manageDSAit = get_manageDSAit( op );
31         AttributeDescription *children = slap_schema.si_ad_children;
32         DB_TXN          *ltid = NULL;
33
34         Debug(LDAP_DEBUG_ARGS, "==> bdb_delete: %s\n", dn, 0, 0);
35
36         if (0) {
37 retry:  rc = txn_abort( ltid );
38                 ltid = NULL;
39                 op->o_private = NULL;
40                 if( rc != 0 ) {
41                         rc = LDAP_OTHER;
42                         text = "internal error";
43                         goto return_results;
44                 }
45         }
46
47         /* begin transaction */
48         rc = txn_begin( bdb->bi_dbenv, NULL, &ltid, 0 );
49         if( rc != 0 ) {
50                 Debug( LDAP_DEBUG_TRACE,
51                         "bdb_delete: txn_begin failed: %s (%d)\n",
52                         db_strerror(rc), rc, 0 );
53                 rc = LDAP_OTHER;
54                 text = "internal error";
55                 goto return_results;
56         }
57
58         op->o_private = ltid;
59
60         pdn = dn_parent( be, e->e_ndn );
61
62         if( pdn != NULL && *pdn != '\0' ) {
63                 /* get parent with reader lock */
64                 rc = dn2entry_r( be, ltid, pdn, &p, NULL );
65
66                 ch_free( pdn );
67
68                 switch( rc ) {
69                 case DB_LOCK_DEADLOCK:
70                 case DB_LOCK_NOTGRANTED:
71                         goto retry;
72                 default:
73                         rc = LDAP_OTHER;
74                         text = "internal error";
75                         goto return_results;
76                 }
77
78                 if( p == NULL) {
79                         Debug( LDAP_DEBUG_TRACE,
80                                 "<=- bdb_delete: parent does not exist\n",
81                                 0, 0, 0);
82                         rc = LDAP_OTHER;
83                         text = "could not locate parent of entry";
84                         goto return_results;
85                 }
86
87                 /* check parent for "children" acl */
88                 rc = access_allowed( be, conn, op, p,
89                         children, NULL, ACL_WRITE );
90
91                 bdb_entry_return( be, p );
92
93                 if ( !rc  ) {
94                         Debug( LDAP_DEBUG_TRACE,
95                                 "<=- bdb_delete: no access to parent\n",
96                                 0, 0, 0 );
97                         rc = LDAP_INSUFFICIENT_ACCESS;
98                         goto return_results;
99                 }
100
101         } else {
102                 ch_free( pdn );
103
104                 /* no parent, must be root to delete */
105                 if( ! be_isroot( be, op->o_ndn ) ) {
106                         Debug( LDAP_DEBUG_TRACE,
107                                 "<=- bdb_delete: no parent and not root\n",
108                                 0, 0, 0);
109                         rc = LDAP_INSUFFICIENT_ACCESS;
110                         goto return_results;
111                 }
112         }
113
114         /* get entry */
115         rc = dn2entry_w( be, ltid, ndn, &e, &matched );
116
117         switch( rc ) {
118         case DB_LOCK_DEADLOCK:
119         case DB_LOCK_NOTGRANTED:
120                 goto retry;
121         default:
122                 rc = LDAP_OTHER;
123                 text = "internal error";
124                 goto return_results;
125         }
126
127         if ( e == NULL ) {
128                 char *matched_dn = NULL;
129                 struct berval **refs = NULL;
130
131                 Debug( LDAP_DEBUG_ARGS,
132                         "<=- bdb_delete: no such object %s\n",
133                         dn, 0, 0);
134
135                 if ( matched != NULL ) {
136                         matched_dn = ch_strdup( matched->e_dn );
137                         refs = is_entry_referral( matched )
138                                 ? get_entry_referrals( be, conn, op, matched )
139                                 : NULL;
140                         bdb_entry_return( be, matched );
141                 } else {
142                         refs = default_referral;
143                 }
144
145                 send_ldap_result( conn, op, LDAP_REFERRAL,
146                         matched_dn, NULL, refs, NULL );
147
148                 if ( matched != NULL ) {
149                         ber_bvecfree( refs );
150                         free( matched_dn );
151                 }
152
153                 rc = -1;
154                 goto done;
155         }
156
157     if ( !manageDSAit && is_entry_referral( e ) ) {
158                 /* parent is a referral, don't allow add */
159                 /* parent is an alias, don't allow add */
160                 struct berval **refs = get_entry_referrals( be,
161                         conn, op, e );
162
163                 Debug( LDAP_DEBUG_TRACE,
164                         "bdb_delete: entry is referral\n",
165                         0, 0, 0 );
166
167                 send_ldap_result( conn, op, LDAP_REFERRAL,
168                     e->e_dn, NULL, refs, NULL );
169
170                 ber_bvecfree( refs );
171
172                 rc = 1;
173                 goto done;
174         }
175
176
177         if ( bdb_has_children( be, e ) ) {
178                 Debug(LDAP_DEBUG_ARGS,
179                         "<=- bdb_delete: non leaf %s\n",
180                         dn, 0, 0);
181                 rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
182                 text = "subtree delete not supported";
183                 goto return_results;
184         }
185
186         /* delete from dn2id mapping */
187         if ( bdb_dn2id_delete( be, e->e_ndn, e->e_id ) != 0 ) {
188                 Debug(LDAP_DEBUG_ARGS,
189                         "<=- ldbm_back_delete: operations error %s\n",
190                         dn, 0, 0);
191                 rc = LDAP_OTHER;
192                 text = "DN index delete failed";
193                 goto return_results;
194         }
195
196         /* delete from disk and cache */
197         if ( bdb_id2entry_delete( be, e ) != 0 ) {
198                 Debug(LDAP_DEBUG_ARGS,
199                         "<=- bdb_delete: operations error %s\n",
200                         dn, 0, 0);
201                 rc = LDAP_OTHER;
202                 text = "entry delete failed";
203                 goto return_results;
204         }
205
206         rc = txn_commit( ltid, 0 );
207         ltid = NULL;
208         op->o_private = NULL;
209
210         if( rc == 0 ) {
211                 Debug( LDAP_DEBUG_TRACE,
212                         "bdb_add: txn_commit failed: %s (%d)\n",
213                         db_strerror(rc), rc, 0 );
214                 rc = LDAP_OTHER;
215                 text = "commit failed";
216         } else {
217                 Debug( LDAP_DEBUG_TRACE,
218                         "bdb_add: added id=%08x dn=\"%s\"\n",
219                         e->e_id, e->e_dn, 0 );
220                 rc = LDAP_SUCCESS;
221                 text = NULL;
222         }
223
224 return_results:
225         send_ldap_result( conn, op, LDAP_SUCCESS,
226                 NULL, text, NULL, NULL );
227
228 done:
229         /* free entry and writer lock */
230         bdb_entry_return( be, e );
231
232         if( ltid != NULL ) {
233                 txn_abort( ltid );
234                 op->o_private = NULL;
235         }
236
237         return rc;
238 }