]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/add.c
misc cleanup
[openldap] / servers / slapd / back-bdb / add.c
1 /* add.c - ldap BerkeleyDB back-end add routine */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2003 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(Operation *op, SlapReply *rs )
18 {
19         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
20         struct berval   pdn;
21         Entry           *p;
22         EntryInfo       *ei;
23         char textbuf[SLAP_TEXT_BUFLEN];
24         size_t textlen = sizeof textbuf;
25         AttributeDescription *children = slap_schema.si_ad_children;
26         AttributeDescription *entry = slap_schema.si_ad_entry;
27         DB_TXN          *ltid = NULL, *lt2;
28         struct bdb_op_info opinfo;
29 #ifdef BDB_SUBENTRIES
30         int subentry;
31 #endif
32         u_int32_t       locker = 0;
33         DB_LOCK         lock;
34         int             noop = 0;
35
36         int             num_retries = 0;
37
38 #ifdef LDAP_SYNC
39         Operation* ps_list;
40         int             rc;
41         EntryInfo       *suffix_ei;
42         Entry           *ctxcsn_e;
43         int                     ctxcsn_added = 0;
44 #endif
45
46 #ifdef NEW_LOGGING
47         LDAP_LOG ( OPERATION, ARGS, "==> bdb_add: %s\n", op->oq_add.rs_e->e_name.bv_val, 0, 0 );
48 #else
49         Debug(LDAP_DEBUG_ARGS, "==> bdb_add: %s\n", op->oq_add.rs_e->e_name.bv_val, 0, 0);
50 #endif
51
52         /* check entry's schema */
53         rs->sr_err = entry_schema_check( op->o_bd, op->oq_add.rs_e, NULL, &rs->sr_text, textbuf, textlen );
54         if ( rs->sr_err != LDAP_SUCCESS ) {
55 #ifdef NEW_LOGGING
56         LDAP_LOG ( OPERATION, ERR, 
57                 "bdb_add: entry failed schema check: %s (%d)\n", rs->sr_text, rs->sr_err, 0 );
58 #else
59                 Debug( LDAP_DEBUG_TRACE,
60                         "bdb_add: entry failed schema check: %s (%d)\n",
61                         rs->sr_text, rs->sr_err, 0 );
62 #endif
63                 goto return_results;
64         }
65
66 #ifdef BDB_SUBENTRIES
67         subentry = is_entry_subentry( op->oq_add.rs_e );
68 #endif
69
70         /*
71          * acquire an ID outside of the operation transaction
72          * to avoid serializing adds.
73          */
74         rs->sr_err = bdb_next_id( op->o_bd, NULL, &op->oq_add.rs_e->e_id );
75         if( rs->sr_err != 0 ) {
76 #ifdef NEW_LOGGING
77                 LDAP_LOG ( OPERATION, ERR, 
78                         "bdb_add: next_id failed (%d)\n", rs->sr_err, 0, 0 );
79 #else
80                 Debug( LDAP_DEBUG_TRACE,
81                         "bdb_add: next_id failed (%d)\n", rs->sr_err, 0, 0 );
82 #endif
83                 rs->sr_err = LDAP_OTHER;
84                 rs->sr_text = "internal error";
85                 goto return_results;
86         }
87
88         if( 0 ) {
89 retry:  /* transaction retry */
90                 if( p ) {
91                         /* free parent and reader lock */
92                         bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, p );
93                         p = NULL;
94                 }
95                 rs->sr_err = TXN_ABORT( ltid );
96                 ltid = NULL;
97                 op->o_private = NULL;
98                 op->o_do_not_cache = opinfo.boi_acl_cache;
99                 if( rs->sr_err != 0 ) {
100                         rs->sr_err = LDAP_OTHER;
101                         rs->sr_text = "internal error";
102                         goto return_results;
103                 }
104                 bdb_trans_backoff( ++num_retries );
105                 ldap_pvt_thread_yield();
106         }
107
108         /* begin transaction */
109         rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid, 
110                 bdb->bi_db_opflags );
111         rs->sr_text = NULL;
112         if( rs->sr_err != 0 ) {
113 #ifdef NEW_LOGGING
114                 LDAP_LOG ( OPERATION, ERR, 
115                         "bdb_add: txn_begin failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
116 #else
117                 Debug( LDAP_DEBUG_TRACE,
118                         "bdb_add: txn_begin failed: %s (%d)\n",
119                         db_strerror(rs->sr_err), rs->sr_err, 0 );
120 #endif
121                 rs->sr_err = LDAP_OTHER;
122                 rs->sr_text = "internal error";
123                 goto return_results;
124         }
125
126         locker = TXN_ID ( ltid );
127
128         opinfo.boi_bdb = op->o_bd;
129         opinfo.boi_txn = ltid;
130         opinfo.boi_locker = locker;
131         opinfo.boi_err = 0;
132         opinfo.boi_acl_cache = op->o_do_not_cache;
133         op->o_private = &opinfo;
134         
135         /*
136          * Get the parent dn and see if the corresponding entry exists.
137          * If the parent does not exist, only allow the "root" user to
138          * add the entry.
139          */
140         if ( be_issuffix( op->o_bd, &op->oq_add.rs_e->e_nname ) ) {
141                 pdn = slap_empty_bv;
142         } else {
143                 dnParent( &op->oq_add.rs_e->e_nname, &pdn );
144         }
145
146         /* get entry or parent */
147         rs->sr_err = bdb_dn2entry( op, ltid, &op->ora_e->e_nname, &ei,
148                 1, locker, &lock );
149         switch( rs->sr_err ) {
150         case 0:
151                 rs->sr_err = LDAP_ALREADY_EXISTS;
152                 goto return_results;
153         case DB_NOTFOUND:
154                 break;
155         case DB_LOCK_DEADLOCK:
156         case DB_LOCK_NOTGRANTED:
157                 goto retry;
158         case LDAP_BUSY:
159                 rs->sr_text = "ldap server busy";
160                 goto return_results;
161         default:
162                 rs->sr_err = LDAP_OTHER;
163                 rs->sr_text = "internal error";
164                 goto return_results;
165         }
166
167         p = ei->bei_e;
168         if ( p ) {
169                 if ( !bvmatch( &pdn, &p->e_nname ) ) {
170                         rs->sr_matched = ber_strdup_x( p->e_name.bv_val,
171                                 op->o_tmpmemctx );
172                         rs->sr_ref = is_entry_referral( p )
173                                 ? get_entry_referrals( op, p )
174                                 : NULL;
175                         bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, p );
176                         p = NULL;
177 #ifdef NEW_LOGGING
178                         LDAP_LOG ( OPERATION, DETAIL1, 
179                                 "bdb_add: parent does not exist\n", 0, 0, 0 );
180 #else
181                         Debug( LDAP_DEBUG_TRACE, "bdb_add: parent does not exist\n",
182                                 0, 0, 0 );
183 #endif
184
185                         rs->sr_err = LDAP_REFERRAL;
186                         send_ldap_result( op, rs );
187
188                         ber_bvarray_free( rs->sr_ref );
189                         op->o_tmpfree( (char *)rs->sr_matched, op->o_tmpmemctx );
190                         rs->sr_ref = NULL;
191                         rs->sr_matched = NULL;
192
193                         goto done;
194                 }
195
196                 rs->sr_err = access_allowed( op, p,
197                         children, NULL, ACL_WRITE, NULL );
198
199                 if ( ! rs->sr_err ) {
200                         switch( opinfo.boi_err ) {
201                         case DB_LOCK_DEADLOCK:
202                         case DB_LOCK_NOTGRANTED:
203                                 goto retry;
204                         }
205
206 #ifdef NEW_LOGGING
207                         LDAP_LOG ( OPERATION, DETAIL1, 
208                                 "bdb_add: no write access to parent\n", 0, 0, 0 );
209 #else
210                         Debug( LDAP_DEBUG_TRACE, "bdb_add: no write access to parent\n",
211                                 0, 0, 0 );
212 #endif
213                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
214                         rs->sr_text = "no write access to parent";
215                         goto return_results;;
216                 }
217
218 #ifdef BDB_SUBENTRIES
219                 if ( is_entry_subentry( p ) ) {
220                         /* parent is a subentry, don't allow add */
221 #ifdef NEW_LOGGING
222                         LDAP_LOG ( OPERATION, DETAIL1, 
223                                 "bdb_add: parent is subentry\n", 0, 0, 0 );
224 #else
225                         Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is subentry\n",
226                                 0, 0, 0 );
227 #endif
228                         rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
229                         rs->sr_text = "parent is a subentry";
230                         goto return_results;;
231                 }
232 #endif
233 #ifdef BDB_ALIASES
234                 if ( is_entry_alias( p ) ) {
235                         /* parent is an alias, don't allow add */
236 #ifdef NEW_LOGGING
237                         LDAP_LOG ( OPERATION, DETAIL1, 
238                                 "bdb_add: parent is alias\n", 0, 0, 0 );
239 #else
240                         Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is alias\n",
241                                 0, 0, 0 );
242 #endif
243                         rs->sr_err = LDAP_ALIAS_PROBLEM;
244                         rs->sr_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                         rs->sr_matched = p->e_name.bv_val;
252                         rs->sr_ref = get_entry_referrals( op, p );
253
254 #ifdef NEW_LOGGING
255                         LDAP_LOG ( OPERATION, DETAIL1, 
256                                 "bdb_add: parent is referral\n", 0, 0, 0 );
257 #else
258                         Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is referral\n",
259                                 0, 0, 0 );
260 #endif
261
262                         rs->sr_err = LDAP_REFERRAL;
263                         send_ldap_result( op, rs );
264
265                         ber_bvarray_free( rs->sr_ref );
266                         bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, p );
267                         rs->sr_ref = NULL;
268                         rs->sr_matched = NULL;
269                         p = NULL;
270                         goto done;
271                 }
272
273 #ifdef BDB_SUBENTRIES
274                 if ( subentry ) {
275                         /* FIXME: */
276                         /* parent must be an administrative point of the required kind */
277                 }
278 #endif
279
280                 /* free parent and reader lock */
281                 bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, p );
282                 p = NULL;
283
284         } else {
285                 /*
286                  * no parent!
287                  *      must be adding entry at suffix or with parent ""
288                  */
289                 if ( !be_isroot( op->o_bd, &op->o_ndn )) {
290                         if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
291                                 || be_isupdate( op->o_bd, &op->o_ndn ) )
292                         {
293                                 p = (Entry *)&slap_entry_root;
294
295                                 /* check parent for "children" acl */
296                                 rs->sr_err = access_allowed( op, p,
297                                         children, NULL, ACL_WRITE, NULL );
298
299                                 p = NULL;
300
301                                 if ( ! rs->sr_err ) {
302                                         switch( opinfo.boi_err ) {
303                                         case DB_LOCK_DEADLOCK:
304                                         case DB_LOCK_NOTGRANTED:
305                                                 goto retry;
306                                         }
307
308 #ifdef NEW_LOGGING
309                                         LDAP_LOG ( OPERATION, DETAIL1, 
310                                                 "bdb_add: no write access to parent\n", 0, 0, 0 );
311 #else
312                                         Debug( LDAP_DEBUG_TRACE,
313                                                 "bdb_add: no write access to parent\n",
314                                                 0, 0, 0 );
315 #endif
316                                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
317                                         rs->sr_text = "no write access to parent";
318                                         goto return_results;
319                                 }
320 #ifdef LDAP_SYNCREPL
321                         } else if ( !is_entry_glue( op->oq_add.rs_e )) {
322 #else
323                         } else {
324 #endif
325 #ifdef NEW_LOGGING
326                                 LDAP_LOG ( OPERATION, DETAIL1, "bdb_add: %s denied\n", 
327                                         pdn.bv_len == 0 ? "suffix" : "entry at root", 0, 0 );
328 #else
329                                 Debug( LDAP_DEBUG_TRACE, "bdb_add: %s denied\n",
330                                         pdn.bv_len == 0 ? "suffix" : "entry at root",
331                                         0, 0 );
332 #endif
333                                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
334                                 goto return_results;
335                         }
336                 }
337
338 #ifdef BDB_SUBENTRIES
339                 if( subentry ) {
340 #ifdef NEW_LOGGING
341                         LDAP_LOG ( OPERATION, DETAIL1, 
342                                 "bdb_add: no parent, cannot add subentry\n", 0, 0, 0 );
343 #else
344                         Debug( LDAP_DEBUG_TRACE,
345                                 "bdb_add: no parent, cannot add subentry\n",
346                                 0, 0, 0 );
347 #endif
348                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
349                         rs->sr_text = "no parent, cannot add subentry";
350                         goto return_results;
351                 }
352 #endif
353         }
354
355         if ( get_assert( op ) &&
356                 ( test_filter( op, op->oq_add.rs_e, get_assertion( op ))
357                         != LDAP_COMPARE_TRUE ))
358         {
359                 rs->sr_err = LDAP_ASSERTION_FAILED;
360                 goto return_results;
361         }
362
363         rs->sr_err = access_allowed( op, op->oq_add.rs_e,
364                 entry, NULL, ACL_WRITE, NULL );
365
366         if ( ! rs->sr_err ) {
367                 switch( opinfo.boi_err ) {
368                 case DB_LOCK_DEADLOCK:
369                 case DB_LOCK_NOTGRANTED:
370                         goto retry;
371                 }
372
373 #ifdef NEW_LOGGING
374                 LDAP_LOG ( OPERATION, DETAIL1, 
375                         "bdb_add: no write access to entry\n", 0, 0, 0 );
376 #else
377                 Debug( LDAP_DEBUG_TRACE, "bdb_add: no write access to entry\n",
378                         0, 0, 0 );
379 #endif
380                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
381                 rs->sr_text = "no write access to entry";
382                 goto return_results;;
383         }
384
385         /* nested transaction */
386         rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, &lt2, 
387                 bdb->bi_db_opflags );
388         rs->sr_text = NULL;
389         if( rs->sr_err != 0 ) {
390 #ifdef NEW_LOGGING
391                 LDAP_LOG ( OPERATION, ERR, 
392                         "bdb_add: txn_begin(2) failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
393 #else
394                 Debug( LDAP_DEBUG_TRACE,
395                         "bdb_add: txn_begin(2) failed: %s (%d)\n",
396                         db_strerror(rs->sr_err), rs->sr_err, 0 );
397 #endif
398                 rs->sr_err = LDAP_OTHER;
399                 rs->sr_text = "internal error";
400                 goto return_results;
401         }
402
403         /* dn2id index */
404         rs->sr_err = bdb_dn2id_add( op, lt2, ei, op->oq_add.rs_e );
405         if ( rs->sr_err != 0 ) {
406 #ifdef NEW_LOGGING
407                 LDAP_LOG ( OPERATION, ERR, 
408                         "bdb_add: dn2id_add failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
409 #else
410                 Debug( LDAP_DEBUG_TRACE, "bdb_add: dn2id_add failed: %s (%d)\n",
411                         db_strerror(rs->sr_err), rs->sr_err, 0 );
412 #endif
413
414                 switch( rs->sr_err ) {
415                 case DB_LOCK_DEADLOCK:
416                 case DB_LOCK_NOTGRANTED:
417                         goto retry;
418                 case DB_KEYEXIST:
419                         rs->sr_err = LDAP_ALREADY_EXISTS;
420                         break;
421                 default:
422                         rs->sr_err = LDAP_OTHER;
423                 }
424                 goto return_results;
425         }
426
427         /* id2entry index */
428         rs->sr_err = bdb_id2entry_add( op->o_bd, lt2, op->oq_add.rs_e );
429         if ( rs->sr_err != 0 ) {
430 #ifdef NEW_LOGGING
431                 LDAP_LOG ( OPERATION, ERR, "bdb_add: id2entry_add failed\n", 0, 0, 0 );
432 #else
433                 Debug( LDAP_DEBUG_TRACE, "bdb_add: id2entry_add failed\n",
434                         0, 0, 0 );
435 #endif
436                 switch( rs->sr_err ) {
437                 case DB_LOCK_DEADLOCK:
438                 case DB_LOCK_NOTGRANTED:
439                         goto retry;
440                 default:
441                         rs->sr_err = LDAP_OTHER;
442                 }
443                 rs->sr_text = "entry store failed";
444                 goto return_results;
445         }
446
447         /* attribute indexes */
448         rs->sr_err = bdb_index_entry_add( op, lt2, op->oq_add.rs_e );
449         if ( rs->sr_err != LDAP_SUCCESS ) {
450 #ifdef NEW_LOGGING
451                 LDAP_LOG ( OPERATION, ERR, 
452                         "bdb_add: index_entry_add failed\n", 0, 0, 0 );
453 #else
454                 Debug( LDAP_DEBUG_TRACE, "bdb_add: index_entry_add failed\n",
455                         0, 0, 0 );
456 #endif
457                 switch( rs->sr_err ) {
458                 case DB_LOCK_DEADLOCK:
459                 case DB_LOCK_NOTGRANTED:
460                         goto retry;
461                 default:
462                         rs->sr_err = LDAP_OTHER;
463                 }
464                 rs->sr_text = "index generation failed";
465                 goto return_results;
466         }
467         if ( TXN_COMMIT( lt2, 0 ) != 0 ) {
468                 rs->sr_err = LDAP_OTHER;
469                 rs->sr_text = "txn_commit(2) failed";
470                 goto return_results;
471         }
472
473 #ifdef LDAP_SYNC
474         rc = bdb_csn_commit( op, rs, ltid, ei, &suffix_ei, &ctxcsn_e, &ctxcsn_added, locker );
475         switch ( rc ) {
476         case BDB_CSN_ABORT :
477                 goto return_results;
478         case BDB_CSN_RETRY :
479                 goto retry;
480         }
481 #endif
482
483         if ( op->o_noop ) {
484                 if (( rs->sr_err=TXN_ABORT( ltid )) != 0 ) {
485                         rs->sr_text = "txn_abort (no-op) failed";
486                 } else {
487                         noop = 1;
488                         rs->sr_err = LDAP_SUCCESS;
489                 }
490
491         } else {
492                 char gid[DB_XIDDATASIZE];
493
494                 snprintf( gid, sizeof( gid ), "%s-%08lx-%08lx",
495                         bdb_uuid.bv_val, (long) op->o_connid, (long) op->o_opid );
496
497                 if (( rs->sr_err=TXN_PREPARE( ltid, gid )) != 0 ) {
498                         rs->sr_text = "txn_prepare failed";
499
500                 } else {
501                         struct berval nrdn;
502 #ifdef LDAP_SYNC
503                         struct berval ctx_nrdn;
504 #endif
505
506                         if (pdn.bv_len) {
507                                 nrdn.bv_val = op->ora_e->e_nname.bv_val;
508                                 nrdn.bv_len = pdn.bv_val - nrdn.bv_val - 1;
509                         } else {
510                                 nrdn = op->ora_e->e_nname;
511                         }
512
513                         bdb_cache_add( bdb, ei, op->oq_add.rs_e, &nrdn, locker );
514
515 #ifdef LDAP_SYNC
516                         if ( ctxcsn_added ) {
517                                 ctx_nrdn.bv_val = "cn=ldapsync";
518                                 ctx_nrdn.bv_len = strlen( ctx_nrdn.bv_val );
519                                 bdb_cache_add( bdb, suffix_ei, ctxcsn_e, &ctx_nrdn, locker );
520                         }
521 #endif
522
523                         if(( rs->sr_err=TXN_COMMIT( ltid, 0 )) != 0 ) {
524                                 rs->sr_text = "txn_commit failed";
525                         } else {
526                                 rs->sr_err = LDAP_SUCCESS;
527                         }
528                 }
529         }
530
531         ltid = NULL;
532         op->o_private = NULL;
533
534         if (rs->sr_err == LDAP_SUCCESS) {
535 #ifdef NEW_LOGGING
536                 LDAP_LOG ( OPERATION, RESULTS, 
537                         "bdb_add: added%s id=%08lx dn=\"%s\"\n", 
538                         op->o_noop ? " (no-op)" : "", op->oq_add.rs_e->e_id, op->oq_add.rs_e->e_dn );
539 #else
540                 Debug(LDAP_DEBUG_TRACE, "bdb_add: added%s id=%08lx dn=\"%s\"\n",
541                         op->o_noop ? " (no-op)" : "", op->oq_add.rs_e->e_id, op->oq_add.rs_e->e_dn );
542 #endif
543                 rs->sr_text = NULL;
544         }
545         else {
546 #ifdef NEW_LOGGING
547                 LDAP_LOG ( OPERATION, ERR, 
548                         "bdb_add: %s : %s (%d)\n",  rs->sr_text, db_strerror(rs->sr_err), rs->sr_err );
549 #else
550                 Debug( LDAP_DEBUG_TRACE, "bdb_add: %s : %s (%d)\n",
551                         rs->sr_text, db_strerror(rs->sr_err), rs->sr_err );
552 #endif
553                 rs->sr_err = LDAP_OTHER;
554         }
555
556 return_results:
557         send_ldap_result( op, rs );
558
559 #ifdef LDAP_SYNC
560         if ( rs->sr_err == LDAP_SUCCESS && !noop ) {
561                 LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) {
562                         bdb_psearch( op, rs, ps_list, op->oq_add.rs_e, LDAP_PSEARCH_BY_ADD );
563                 }
564         }
565 #endif
566
567         if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp ) {
568                 ldap_pvt_thread_yield();
569                 TXN_CHECKPOINT( bdb->bi_dbenv,
570                         bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
571         }
572
573 done:
574
575         if( ltid != NULL ) {
576                 TXN_ABORT( ltid );
577                 op->o_private = NULL;
578         }
579
580         return ( ( rs->sr_err == LDAP_SUCCESS ) ? noop : rs->sr_err );
581 }