]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/add.c
Delete extranous assert()
[openldap] / servers / slapd / back-bdb / add.c
1 /* add.c - ldap BerkeleyDB back-end add routine */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2002 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_add(
18         BackendDB       *be,
19         Connection      *conn,
20         Operation       *op,
21         Entry   *e )
22 {
23         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
24         struct berval   pdn;
25         Entry           *p = NULL;
26         int                     rc; 
27         const char      *text;
28         char textbuf[SLAP_TEXT_BUFLEN];
29         size_t textlen = sizeof textbuf;
30         AttributeDescription *children = slap_schema.si_ad_children;
31         DB_TXN          *ltid = NULL;
32         struct bdb_op_info opinfo;
33 #ifdef BDB_SUBENTRIES
34         int subentry;
35 #endif
36 #if 0
37         u_int32_t       lockid;
38         DB_LOCK         lock;
39 #endif
40
41 #ifdef NEW_LOGGING
42         LDAP_LOG (( "add", LDAP_LEVEL_ARGS, "==> bdb_add: %s\n", e->e_dn ));
43 #else
44         Debug(LDAP_DEBUG_ARGS, "==> bdb_add: %s\n", e->e_dn, 0, 0);
45 #endif
46
47         /* check entry's schema */
48         rc = entry_schema_check( be, e, NULL, &text, textbuf, textlen );
49         if ( rc != LDAP_SUCCESS ) {
50 #ifdef NEW_LOGGING
51         LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: entry failed schema check: %s (%d)\n", text, rc ));
52 #else
53                 Debug( LDAP_DEBUG_TRACE,
54                         "bdb_add: entry failed schema check: %s (%d)\n",
55                         text, rc, 0 );
56 #endif
57                 goto return_results;
58         }
59
60 #ifdef BDB_SUBENTRIES
61         subentry = is_entry_subentry( e );
62 #endif
63
64         /*
65          * acquire an ID outside of the operation transaction
66          * to avoid serializing adds.
67          */
68         rc = bdb_next_id( be, NULL, &e->e_id );
69         if( rc != 0 ) {
70 #ifdef NEW_LOGGING
71                 LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: next_id failed (%d)\n", rc ));
72 #else
73                 Debug( LDAP_DEBUG_TRACE,
74                         "bdb_add: next_id failed (%d)\n",
75                         rc, 0, 0 );
76 #endif
77                 rc = LDAP_OTHER;
78                 text = "internal error";
79                 goto return_results;
80         }
81
82         if( 0 ) {
83 retry:  /* transaction retry */
84                 rc = TXN_ABORT( ltid );
85                 ltid = NULL;
86                 op->o_private = NULL;
87                 if( rc != 0 ) {
88                         rc = LDAP_OTHER;
89                         text = "internal error";
90                         goto return_results;
91                 }
92                 ldap_pvt_thread_yield();
93         }
94
95         /* begin transaction */
96         rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid, 
97                 bdb->bi_db_opflags );
98         text = NULL;
99         if( rc != 0 ) {
100 #ifdef NEW_LOGGING
101                 LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: txn_begin failed: %s (%d)\n", db_strerror(rc), rc ));
102 #else
103                 Debug( LDAP_DEBUG_TRACE,
104                         "bdb_add: txn_begin failed: %s (%d)\n",
105                         db_strerror(rc), rc, 0 );
106 #endif
107                 rc = LDAP_OTHER;
108                 text = "internal error";
109                 goto return_results;
110         }
111 #if 0
112         lockid = TXN_ID( ltid );
113 #endif
114
115         opinfo.boi_bdb = be;
116         opinfo.boi_txn = ltid;
117         opinfo.boi_err = 0;
118         op->o_private = &opinfo;
119         
120         /*
121          * Get the parent dn and see if the corresponding entry exists.
122          * If the parent does not exist, only allow the "root" user to
123          * add the entry.
124          */
125         if ( be_issuffix( be, &e->e_nname ) ) {
126                 pdn = slap_empty_bv;
127         } else {
128                 dnParent( &e->e_nname, &pdn );
129         }
130
131         if( pdn.bv_len != 0 ) {
132                 Entry *matched = NULL;
133
134 #if 0
135                 if ( ltid ) {
136                         DBT obj;
137                         obj.data = pdn.bv_val-1;
138                         obj.size = pdn.bv_len+1;
139                         rc = LOCK_GET( bdb->bi_dbenv, lockid, 0, &obj,
140                                 DB_LOCK_WRITE, &lock);
141                 }
142 #endif
143
144                 /* get parent */
145                 rc = bdb_dn2entry_r( be, ltid, &pdn, &p, &matched, 0 );
146
147                 switch( rc ) {
148                 case 0:
149                 case DB_NOTFOUND:
150                         break;
151                 case DB_LOCK_DEADLOCK:
152                 case DB_LOCK_NOTGRANTED:
153                         goto retry;
154                 case LDAP_BUSY:
155                         text = "ldap server busy";
156                         goto return_results;
157                 default:
158                         rc = LDAP_OTHER;
159                         text = "internal error";
160                         goto return_results;
161                 }
162
163                 if ( p == NULL ) {
164                         char *matched_dn = NULL;
165                         BerVarray refs;
166
167                         if ( matched != NULL ) {
168                                 matched_dn = ch_strdup( matched->e_dn );
169                                 refs = is_entry_referral( matched )
170                                         ? get_entry_referrals( be, conn, op, matched )
171                                         : NULL;
172                                 bdb_cache_return_entry_r(&bdb->bi_cache, matched);
173                                 matched = NULL;
174
175                         } else {
176                                 refs = referral_rewrite( default_referral,
177                                         NULL, &e->e_name, LDAP_SCOPE_DEFAULT );
178                         }
179
180 #ifdef NEW_LOGGING
181                         LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: parent does not exist\n" ));
182 #else
183                         Debug( LDAP_DEBUG_TRACE, "bdb_add: parent does not exist\n",
184                                 0, 0, 0 );
185 #endif
186
187                         send_ldap_result( conn, op, rc = LDAP_REFERRAL,
188                                 matched_dn, NULL, refs, NULL );
189
190                         ber_bvarray_free( refs );
191                         ch_free( matched_dn );
192
193                         goto done;
194                 }
195
196                 rc = access_allowed( be, conn, op, p,
197                         children, NULL, ACL_WRITE, NULL );
198
199                 switch( opinfo.boi_err ) {
200                 case DB_LOCK_DEADLOCK:
201                 case DB_LOCK_NOTGRANTED:
202                         /* free parent and reader lock */
203                         bdb_cache_return_entry_r( &bdb->bi_cache, p );
204                         p = NULL;
205                         goto retry;
206                 }
207
208                 if ( ! rc ) {
209 #ifdef NEW_LOGGING
210                         LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: no write access to parent\n" ));
211 #else
212                         Debug( LDAP_DEBUG_TRACE, "bdb_add: no write access to parent\n",
213                                 0, 0, 0 );
214 #endif
215                         rc = LDAP_INSUFFICIENT_ACCESS;
216                         text = "no write access to parent";
217                         goto return_results;;
218                 }
219
220 #ifdef BDB_SUBENTRIES
221                 if ( is_entry_subentry( p ) ) {
222                         /* parent is a subentry, don't allow add */
223 #ifdef NEW_LOGGING
224                         LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: parent is subentry\n" ));
225 #else
226                         Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is subentry\n",
227                                 0, 0, 0 );
228 #endif
229                         rc = LDAP_OBJECT_CLASS_VIOLATION;
230                         text = "parent is a subentry";
231                         goto return_results;;
232                 }
233 #endif
234 #ifdef BDB_ALIASES
235                 if ( is_entry_alias( p ) ) {
236                         /* parent is an alias, don't allow add */
237 #ifdef NEW_LOGGING
238                         LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: parent is alias\n" ));
239 #else
240                         Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is alias\n",
241                                 0, 0, 0 );
242 #endif
243                         rc = LDAP_ALIAS_PROBLEM;
244                         text = "parent is an alias";
245                         goto return_results;;
246                 }
247 #endif
248
249                 if ( is_entry_referral( p ) ) {
250                         /* parent is a referral, don't allow add */
251                         char *matched_dn = p->e_dn;
252                         BerVarray refs = get_entry_referrals( be, conn, op, p );
253
254 #ifdef NEW_LOGGING
255                         LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: parent is referral\n" ));
256 #else
257                         Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is referral\n",
258                                 0, 0, 0 );
259 #endif
260
261                         send_ldap_result( conn, op, rc = LDAP_REFERRAL,
262                                 matched_dn, NULL, refs, NULL );
263
264                         ber_bvarray_free( refs );
265                         bdb_cache_return_entry_r( &bdb->bi_cache, p );
266                         p = NULL;
267                         goto done;
268                 }
269
270 #ifdef BDB_SUBENTRIES
271                 if ( subentry ) {
272                         /* FIXME: */
273                         /* parent must be an administrative point of the required kind */
274                 }
275 #endif
276
277                 /* free parent and reader lock */
278                 bdb_cache_return_entry_r( &bdb->bi_cache, p );
279                 p = NULL;
280
281         } else {
282                 /*
283                  * no parent!
284                  *      must be adding entry at suffix or with parent ""
285                  */
286                 if ( !be_isroot( be, &op->o_ndn )) {
287                         if ( be_issuffix( be, (struct berval *)&slap_empty_bv )
288                                 || be_isupdate( be, &op->o_ndn ) ) {
289                                 p = (Entry *)&slap_entry_root;
290
291                                 /* check parent for "children" acl */
292                                 rc = access_allowed( be, conn, op, p,
293                                         children, NULL, ACL_WRITE, NULL );
294                                 p = NULL;
295
296                                 switch( opinfo.boi_err ) {
297                                 case DB_LOCK_DEADLOCK:
298                                 case DB_LOCK_NOTGRANTED:
299                                         goto retry;
300                                 }
301
302                                 if ( ! rc ) {
303 #ifdef NEW_LOGGING
304                                         LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: no write access to parent\n" ));
305 #else
306                                         Debug( LDAP_DEBUG_TRACE,
307                                                 "bdb_add: no write access to parent\n",
308                                                 0, 0, 0 );
309 #endif
310                                         rc = LDAP_INSUFFICIENT_ACCESS;
311                                         text = "no write access to parent";
312                                         goto return_results;;
313                                 }
314
315                         } else {
316 #ifdef NEW_LOGGING
317                                 LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: %s denied\n", pdn.bv_len == 0 ? "suffix" : "entry at root" ));
318 #else
319                                 Debug( LDAP_DEBUG_TRACE, "bdb_add: %s denied\n",
320                                         pdn.bv_len == 0 ? "suffix" : "entry at root",
321                                         0, 0 );
322 #endif
323                                 rc = LDAP_INSUFFICIENT_ACCESS;
324                                 goto return_results;
325                         }
326                 }
327
328 #ifdef BDB_SUBENTRIES
329                 if( subentry ) {
330 #ifdef NEW_LOGGING
331                         LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: no parent, cannot add subentry\n" ));
332 #else
333                         Debug( LDAP_DEBUG_TRACE,
334                                 "bdb_add: no parent, cannot add subentry\n",
335                                 0, 0, 0 );
336 #endif
337                         rc = LDAP_INSUFFICIENT_ACCESS;
338                         text = "no parent, cannot add subentry";
339                         goto return_results;;
340                 }
341 #endif
342 #if 0
343                 if ( ltid ) {
344                         DBT obj;
345                         obj.data = ",";
346                         obj.size = 1;
347                         rc = LOCK_GET( bdb->bi_dbenv, lockid, 0, &obj,
348                                 DB_LOCK_WRITE, &lock);
349                 }
350 #endif
351         }
352
353         /* dn2id index */
354         rc = bdb_dn2id_add( be, ltid, &pdn, e );
355         if ( rc != 0 ) {
356 #ifdef NEW_LOGGING
357                 LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: dn2id_add failed: %s (%d)\n", db_strerror(rc), rc ));
358 #else
359                 Debug( LDAP_DEBUG_TRACE, "bdb_add: dn2id_add failed: %s (%d)\n",
360                         db_strerror(rc), rc, 0 );
361 #endif
362
363                 switch( rc ) {
364                 case DB_LOCK_DEADLOCK:
365                 case DB_LOCK_NOTGRANTED:
366                         goto retry;
367                 case DB_KEYEXIST:
368                         rc = LDAP_ALREADY_EXISTS;
369                         break;
370                 default:
371                         rc = LDAP_OTHER;
372                 }
373                 goto return_results;
374         }
375
376         /* id2entry index */
377         rc = bdb_id2entry_add( be, ltid, e );
378         if ( rc != 0 ) {
379 #ifdef NEW_LOGGING
380                 LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: id2entry_add failed\n" ));
381 #else
382                 Debug( LDAP_DEBUG_TRACE, "bdb_add: id2entry_add failed\n",
383                         0, 0, 0 );
384 #endif
385                 switch( rc ) {
386                 case DB_LOCK_DEADLOCK:
387                 case DB_LOCK_NOTGRANTED:
388                         goto retry;
389                 default:
390                         rc = LDAP_OTHER;
391                 }
392                 text = "entry store failed";
393                 goto return_results;
394         }
395
396         /* attribute indexes */
397         rc = bdb_index_entry_add( be, ltid, e, e->e_attrs );
398         if ( rc != LDAP_SUCCESS ) {
399 #ifdef NEW_LOGGING
400                 LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: index_entry_add failed\n" ));
401 #else
402                 Debug( LDAP_DEBUG_TRACE, "bdb_add: index_entry_add failed\n",
403                         0, 0, 0 );
404 #endif
405                 switch( rc ) {
406                 case DB_LOCK_DEADLOCK:
407                 case DB_LOCK_NOTGRANTED:
408                         goto retry;
409                 default:
410                         rc = LDAP_OTHER;
411                 }
412                 text = "index generation failed";
413                 goto return_results;
414         }
415
416         if( op->o_noop ) {
417                 if (( rc=TXN_ABORT( ltid )) != 0 ) {
418                         text = "txn_abort (no-op) failed";
419                 } else {
420                         rc = LDAP_SUCCESS;
421                 }
422
423         } else {
424                 char gid[DB_XIDDATASIZE];
425
426                 snprintf( gid, sizeof( gid ), "%s-%08lx-%08lx",
427                         bdb_uuid.bv_val, (long) op->o_connid, (long) op->o_opid );
428
429                 if (( rc=TXN_PREPARE( ltid, gid )) != 0 ) {
430                         text = "txn_prepare failed";
431
432                 } else {
433                         if ( bdb_cache_add_entry_rw(&bdb->bi_cache,
434                                 e, CACHE_WRITE_LOCK) != 0 )
435                         {
436                                 if(( rc=TXN_ABORT( ltid )) != 0 ) {
437                                         text = "cache add & txn_abort failed";
438                                 } else {
439                                         rc = LDAP_OTHER;
440                                         text = "cache add failed";
441                                 }
442                         } else {
443                                 if(( rc=TXN_COMMIT( ltid, 0 )) != 0 ) {
444                                         text = "txn_commit failed";
445                                 } else {
446                                         rc = LDAP_SUCCESS;
447                                 }
448                         }
449                 }
450         }
451
452         ltid = NULL;
453         op->o_private = NULL;
454
455         if (rc == LDAP_SUCCESS) {
456 #ifdef NEW_LOGGING
457                 LDAP_LOG (( "add", LDAP_LEVEL_RESULTS, "bdb_add: added%s id=%08lx dn=\"%s\"\n", op->o_noop ? " (no-op)" : "", e->e_id, e->e_dn ));
458 #else
459                 Debug(LDAP_DEBUG_TRACE, "bdb_add: added%s id=%08lx dn=\"%s\"\n",
460                         op->o_noop ? " (no-op)" : "", e->e_id, e->e_dn );
461 #endif
462                 text = NULL;
463                 bdb_cache_entry_commit( e );
464         }
465         else {
466 #ifdef NEW_LOGGING
467                 LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: %s : %s (%d)\n", text, db_strerror(rc), rc ));
468 #else
469                 Debug( LDAP_DEBUG_TRACE, "bdb_add: %s : %s (%d)\n",
470                         text, db_strerror(rc), rc );
471 #endif
472                 rc = LDAP_OTHER;
473         }
474
475 return_results:
476         send_ldap_result( conn, op, rc,
477                 NULL, text, NULL, NULL );
478
479         if( rc == LDAP_SUCCESS && bdb->bi_txn_cp ) {
480                 ldap_pvt_thread_yield();
481                 TXN_CHECKPOINT( bdb->bi_dbenv,
482                         bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
483         }
484
485 done:
486
487         if( ltid != NULL ) {
488                 TXN_ABORT( ltid );
489                 op->o_private = NULL;
490         }
491
492         return rc;
493 }