]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb2/add.c
Backout the input exhaustion change, it loops. Still looking for
[openldap] / servers / slapd / back-bdb2 / add.c
1 /* add.c - ldap bdb2 back-end add routine */
2
3 #include "portable.h"
4
5 #include <stdio.h>
6
7 #include <ac/socket.h>
8 #include <ac/string.h>
9
10 #include "slap.h"
11 #include "back-bdb2.h"
12 #include "proto-back-bdb2.h"
13
14 static DB_LOCK         lock;
15
16
17 static int
18 bdb2i_back_add_internal(
19     BackendDB   *be,
20     Connection  *conn,
21     Operation   *op,
22     Entry       *e
23 )
24 {
25         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
26         char            *pdn;
27         Entry           *p = NULL;
28         int                     rc; 
29         struct timeval  time1;
30
31         Debug(LDAP_DEBUG_ARGS, "==> bdb2i_back_add: %s\n", e->e_dn, 0, 0);
32
33         if ( ( bdb2i_dn2id( be, e->e_ndn ) ) != NOID ) {
34                 entry_free( e );
35                 send_ldap_result( conn, op, LDAP_ALREADY_EXISTS,
36                         NULL, NULL, NULL, NULL );
37                 return( -1 );
38         }
39
40         if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
41                 Debug( LDAP_DEBUG_TRACE, "entry failed schema check\n",
42                         0, 0, 0 );
43
44                 entry_free( e );
45                 send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION,
46                         NULL, NULL, NULL, NULL );
47                 return( -1 );
48         }
49
50         /*
51          * Get the parent dn and see if the corresponding entry exists.
52          * If the parent does not exist, only allow the "root" user to
53          * add the entry.
54          */
55
56         pdn = dn_parent( be, e->e_ndn );
57
58         if( pdn != NULL && *pdn != '\0' && !be_issuffix(be, "") ) {
59                 Entry *matched = NULL;
60
61                 assert( *pdn != '\0' );
62
63                 /* get parent with writer lock */
64                 if ( (p = bdb2i_dn2entry_w( be, pdn, &matched )) == NULL ) {
65                         char *matched_dn;
66                         struct berval **refs;
67
68                         if( matched != NULL ) {
69                                 matched_dn = ch_strdup( matched->e_dn );
70                                 refs = is_entry_referral( matched )
71                                         ? get_entry_referrals( be, conn, op, matched )
72                                         : NULL;
73
74                                 bdb2i_cache_return_entry_w( &li->li_cache, matched ); 
75
76                         } else {
77                                 matched_dn = NULL;
78                                 refs = default_referral;
79                         }
80
81                         Debug( LDAP_DEBUG_TRACE, "parent does not exist\n",
82                                 0, 0, 0 );
83
84                         send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
85                             matched_dn, NULL, NULL, NULL );
86
87                         if ( matched != NULL ) {
88                                 ber_bvecfree( refs );
89                                 free( matched_dn );
90                         }
91
92                         entry_free( e );
93                         free( pdn );
94                         return -1;
95                 }
96
97                 free(pdn);
98
99                 if ( ! access_allowed( be, conn, op, p,
100                         "children", NULL, ACL_WRITE ) )
101                 {
102                         /* free parent and writer lock */
103                         bdb2i_cache_return_entry_w( &li->li_cache, p ); 
104
105                         Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
106                             0, 0 );
107                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
108                             NULL, NULL, NULL, NULL );
109
110                         entry_free( e );
111                         return -1;
112                 }
113
114
115                 if ( is_entry_alias( p ) ) {
116                         /* parent is an alias, don't allow add */
117
118                         /* free parent and writer lock */
119                         bdb2i_cache_return_entry_w( &li->li_cache, p ); 
120
121                         Debug( LDAP_DEBUG_TRACE, "parent is alias\n", 0,
122                             0, 0 );
123                         send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM,
124                             NULL, NULL, NULL, NULL );
125
126                         entry_free( e );
127                         return -1;
128                 }
129
130                 if ( is_entry_referral( p ) ) {
131                         /* parent is an referral, don't allow add */
132                         char *matched_dn = ch_strdup( matched->e_dn );
133                         struct berval **refs = is_entry_referral( matched )
134                                         ? get_entry_referrals( be, conn, op, matched )
135                                         : NULL;
136
137                         /* free parent and writer lock */
138                         bdb2i_cache_return_entry_w( &li->li_cache, p ); 
139
140                         Debug( LDAP_DEBUG_TRACE, "parent is referral\n", 0,
141                             0, 0 );
142                         send_ldap_result( conn, op, LDAP_REFERRAL,
143                             matched_dn, NULL, refs, NULL );
144
145                         ber_bvecfree( refs );
146                         free( matched_dn );
147                         entry_free( e );
148                         return -1;
149                 }
150
151         } else {
152                 if(pdn != NULL) {
153                         assert( *pdn == '\0' );
154                         free(pdn);
155                 }
156
157                 /* no parent, must be adding entry to root */
158                 if ( ! be_isroot( be, op->o_ndn ) ) {
159                         Debug( LDAP_DEBUG_TRACE, "%s add denied\n",
160                                 pdn == NULL ? "suffix" : "entry at root",
161                                 0, 0 );
162
163                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
164                             NULL, NULL, NULL, NULL );
165
166                         entry_free( e );
167                         return -1;
168                 }
169         }
170
171         e->e_id = bdb2i_next_id( be );
172
173         /*
174          * Try to add the entry to the cache, assign it a new dnid.
175          */
176         bdb2i_start_timing( be->bd_info, &time1 );
177
178         rc = bdb2i_cache_add_entry_rw( &li->li_cache, e, CACHE_WRITE_LOCK );
179
180         bdb2i_stop_timing( be->bd_info, time1, "ADD-CACHE", conn, op );
181
182         if ( rc != 0 ) {
183                 if( p != NULL) {
184                         /* free parent and writer lock */
185                         bdb2i_cache_return_entry_w( &li->li_cache, p ); 
186                 }
187
188                 Debug( LDAP_DEBUG_ANY, "cache_add_entry_lock failed\n", 0, 0,
189                     0 );
190
191                 /* return the id */
192                 bdb2i_next_id_return( be, e->e_id );
193                 
194                 /* free the entry */
195                 entry_free( e );
196
197                 send_ldap_result( conn, op,
198                         rc > 0 ? LDAP_ALREADY_EXISTS : LDAP_OPERATIONS_ERROR,
199                         NULL, NULL, NULL, NULL );
200
201                 return( -1 );
202         }
203
204         rc = -1;
205
206         /*
207          * add it to the id2children index for the parent
208          */
209
210         bdb2i_start_timing( be->bd_info, &time1 );
211
212         if ( bdb2i_id2children_add( be, p, e ) != 0 ) {
213                 Debug( LDAP_DEBUG_TRACE, "bdb2i_id2children_add failed\n", 0,
214                     0, 0 );
215                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
216                         NULL, NULL, NULL, NULL );
217
218                 bdb2i_stop_timing( be->bd_info, time1, "ADD-ID2CHILDREN", conn, op );
219
220                 goto return_results;
221         }
222
223         bdb2i_stop_timing( be->bd_info, time1, "ADD-ID2CHILDREN", conn, op );
224
225         /*
226          * Add the entry to the attribute indexes, then add it to
227          * the id2children index, dn2id index, and the id2entry index.
228          */
229
230         bdb2i_start_timing( be->bd_info, &time1 );
231
232         /* attribute indexes */
233         if ( bdb2i_index_add_entry( be, e ) != 0 ) {
234                 Debug( LDAP_DEBUG_TRACE, "bdb2i_index_add_entry failed\n", 0,
235                     0, 0 );
236                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
237                         NULL, NULL, NULL, NULL );
238
239                 bdb2i_stop_timing( be->bd_info, time1, "ADD-INDEX", conn, op );
240
241                 goto return_results;
242         }
243
244         bdb2i_stop_timing( be->bd_info, time1, "ADD-INDEX", conn, op );
245
246         bdb2i_start_timing( be->bd_info, &time1 );
247
248         /* dn2id index */
249         if ( bdb2i_dn2id_add( be, e->e_ndn, e->e_id ) != 0 ) {
250                 Debug( LDAP_DEBUG_TRACE, "bdb2i_dn2id_add failed\n", 0,
251                     0, 0 );
252                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
253                         NULL, NULL, NULL, NULL );
254
255                 bdb2i_stop_timing( be->bd_info, time1, "ADD-DN2ID", conn, op );
256
257                 goto return_results;
258         }
259
260         bdb2i_stop_timing( be->bd_info, time1, "ADD-DN2ID", conn, op );
261
262         bdb2i_start_timing( be->bd_info, &time1 );
263
264         /* id2entry index */
265         if ( bdb2i_id2entry_add( be, e ) != 0 ) {
266                 Debug( LDAP_DEBUG_TRACE, "bdb2i_id2entry_add failed\n", 0,
267                     0, 0 );
268                 (void) bdb2i_dn2id_delete( be, e->e_ndn );
269                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
270                         NULL, NULL, NULL, NULL );
271
272                 bdb2i_stop_timing( be->bd_info, time1, "ADD-ID2ENTRY", conn, op );
273
274                 goto return_results;
275         }
276
277         bdb2i_stop_timing( be->bd_info, time1, "ADD-ID2ENTRY", conn, op );
278
279         send_ldap_result( conn, op, LDAP_SUCCESS,
280                         NULL, NULL, NULL, NULL );
281         rc = 0;
282
283 return_results:;
284         if (p != NULL) {
285                 /* free parent and writer lock */
286                 bdb2i_cache_return_entry_w( &li->li_cache, p ); 
287         }
288
289         if ( rc ) {
290                 /* free entry and writer lock */
291                 bdb2i_cache_return_entry_w( &li->li_cache, e );
292         }
293
294         return( rc );
295 }
296
297
298 int
299 bdb2_back_add(
300     BackendDB   *be,
301     Connection  *conn,
302     Operation   *op,
303     Entry       *e
304 )
305 {
306         struct ldbminfo *li  = (struct ldbminfo *) be->be_private;
307         struct timeval  time1;
308         int             ret;
309
310         bdb2i_start_timing( be->bd_info, &time1 );
311
312         if ( bdb2i_enter_backend_w( &lock ) != 0 ) {
313                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
314                         NULL, NULL, NULL, NULL );
315                 return( -1 );
316         }
317
318         /*  check, if a new default attribute index will be created,
319                 in which case we have to open the index file BEFORE TP  */
320         switch ( slapMode ) {
321                 case SLAP_SERVER_MODE:
322                 case SLAP_TIMEDSERVER_MODE:
323                 case SLAP_TOOL_MODE:
324                 case SLAP_TOOLID_MODE:
325                         bdb2i_check_default_attr_index_add( li, e );
326                         break;
327         }
328
329         ret = bdb2i_back_add_internal( be, conn, op, e );
330
331         /*  if the operation was successful, we will delay the unlock  */
332         if ( ret )
333                 (void) bdb2i_leave_backend_w( lock );
334
335         bdb2i_stop_timing( be->bd_info, time1, "ADD", conn, op );
336
337         return( ret );
338 }
339
340
341 int
342 bdb2i_release_add_lock( void )
343 {
344         (void) bdb2i_leave_backend_w( lock );
345         return 0;
346 }
347
348