1 /* add.c - ldap BerkeleyDB back-end add routine */
4 * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
5 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
11 #include <ac/string.h>
23 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
28 char textbuf[SLAP_TEXT_BUFLEN];
29 size_t textlen = sizeof textbuf;
30 AttributeDescription *children = slap_schema.si_ad_children;
32 struct bdb_op_info opinfo;
42 LDAP_LOG (( "add", LDAP_LEVEL_ARGS, "==> bdb_add: %s\n", e->e_dn ));
44 Debug(LDAP_DEBUG_ARGS, "==> bdb_add: %s\n", e->e_dn, 0, 0);
47 /* check entry's schema */
48 rc = entry_schema_check( be, e, NULL, &text, textbuf, textlen );
49 if ( rc != LDAP_SUCCESS ) {
51 LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: entry failed schema check: %s (%d)\n", text, rc ));
53 Debug( LDAP_DEBUG_TRACE,
54 "bdb_add: entry failed schema check: %s (%d)\n",
61 subentry = is_entry_subentry( e );
65 * acquire an ID outside of the operation transaction
66 * to avoid serializing adds.
68 rc = bdb_next_id( be, NULL, &e->e_id );
71 LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: next_id failed (%d)\n", rc ));
73 Debug( LDAP_DEBUG_TRACE,
74 "bdb_add: next_id failed (%d)\n",
78 text = "internal error";
83 retry: /* transaction retry */
84 rc = TXN_ABORT( ltid );
89 text = "internal error";
92 ldap_pvt_thread_yield();
95 /* begin transaction */
96 rc = TXN_BEGIN( bdb->bi_dbenv, NULL, <id,
101 LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: txn_begin failed: %s (%d)\n", db_strerror(rc), rc ));
103 Debug( LDAP_DEBUG_TRACE,
104 "bdb_add: txn_begin failed: %s (%d)\n",
105 db_strerror(rc), rc, 0 );
108 text = "internal error";
112 lockid = TXN_ID( ltid );
116 opinfo.boi_txn = ltid;
118 op->o_private = &opinfo;
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
125 if ( be_issuffix( be, &e->e_nname ) ) {
128 dnParent( &e->e_nname, &pdn );
131 if( pdn.bv_len != 0 ) {
132 Entry *matched = NULL;
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);
145 rc = bdb_dn2entry_r( be, ltid, &pdn, &p, &matched, 0 );
151 case DB_LOCK_DEADLOCK:
152 case DB_LOCK_NOTGRANTED:
155 text = "ldap server busy";
159 text = "internal error";
164 char *matched_dn = NULL;
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 )
172 bdb_cache_return_entry_r(&bdb->bi_cache, matched);
176 refs = referral_rewrite( default_referral,
177 NULL, &e->e_name, LDAP_SCOPE_DEFAULT );
181 LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: parent does not exist\n" ));
183 Debug( LDAP_DEBUG_TRACE, "bdb_add: parent does not exist\n",
187 send_ldap_result( conn, op, rc = LDAP_REFERRAL,
188 matched_dn, NULL, refs, NULL );
190 ber_bvarray_free( refs );
191 ch_free( matched_dn );
196 rc = access_allowed( be, conn, op, p,
197 children, NULL, ACL_WRITE, NULL );
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 );
210 LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: no write access to parent\n" ));
212 Debug( LDAP_DEBUG_TRACE, "bdb_add: no write access to parent\n",
215 rc = LDAP_INSUFFICIENT_ACCESS;
216 text = "no write access to parent";
217 goto return_results;;
220 #ifdef BDB_SUBENTRIES
221 if ( is_entry_subentry( p ) ) {
222 /* parent is a subentry, don't allow add */
224 LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: parent is subentry\n" ));
226 Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is subentry\n",
229 rc = LDAP_OBJECT_CLASS_VIOLATION;
230 text = "parent is a subentry";
231 goto return_results;;
235 if ( is_entry_alias( p ) ) {
236 /* parent is an alias, don't allow add */
238 LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: parent is alias\n" ));
240 Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is alias\n",
243 rc = LDAP_ALIAS_PROBLEM;
244 text = "parent is an alias";
245 goto return_results;;
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 );
255 LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: parent is referral\n" ));
257 Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is referral\n",
261 send_ldap_result( conn, op, rc = LDAP_REFERRAL,
262 matched_dn, NULL, refs, NULL );
264 ber_bvarray_free( refs );
265 bdb_cache_return_entry_r( &bdb->bi_cache, p );
270 #ifdef BDB_SUBENTRIES
273 /* parent must be an administrative point of the required kind */
277 /* free parent and reader lock */
278 bdb_cache_return_entry_r( &bdb->bi_cache, p );
284 * must be adding entry at suffix or with parent ""
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;
291 /* check parent for "children" acl */
292 rc = access_allowed( be, conn, op, p,
293 children, NULL, ACL_WRITE, NULL );
296 switch( opinfo.boi_err ) {
297 case DB_LOCK_DEADLOCK:
298 case DB_LOCK_NOTGRANTED:
304 LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: no write access to parent\n" ));
306 Debug( LDAP_DEBUG_TRACE,
307 "bdb_add: no write access to parent\n",
310 rc = LDAP_INSUFFICIENT_ACCESS;
311 text = "no write access to parent";
312 goto return_results;;
317 LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: %s denied\n", pdn.bv_len == 0 ? "suffix" : "entry at root" ));
319 Debug( LDAP_DEBUG_TRACE, "bdb_add: %s denied\n",
320 pdn.bv_len == 0 ? "suffix" : "entry at root",
323 rc = LDAP_INSUFFICIENT_ACCESS;
328 #ifdef BDB_SUBENTRIES
331 LDAP_LOG (( "add", LDAP_LEVEL_DETAIL1, "bdb_add: no parent, cannot add subentry\n" ));
333 Debug( LDAP_DEBUG_TRACE,
334 "bdb_add: no parent, cannot add subentry\n",
337 rc = LDAP_INSUFFICIENT_ACCESS;
338 text = "no parent, cannot add subentry";
339 goto return_results;;
347 rc = LOCK_GET( bdb->bi_dbenv, lockid, 0, &obj,
348 DB_LOCK_WRITE, &lock);
354 rc = bdb_dn2id_add( be, ltid, &pdn, e );
357 LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: dn2id_add failed: %s (%d)\n", db_strerror(rc), rc ));
359 Debug( LDAP_DEBUG_TRACE, "bdb_add: dn2id_add failed: %s (%d)\n",
360 db_strerror(rc), rc, 0 );
364 case DB_LOCK_DEADLOCK:
365 case DB_LOCK_NOTGRANTED:
368 rc = LDAP_ALREADY_EXISTS;
377 rc = bdb_id2entry_add( be, ltid, e );
380 LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: id2entry_add failed\n" ));
382 Debug( LDAP_DEBUG_TRACE, "bdb_add: id2entry_add failed\n",
386 case DB_LOCK_DEADLOCK:
387 case DB_LOCK_NOTGRANTED:
392 text = "entry store failed";
396 /* attribute indexes */
397 rc = bdb_index_entry_add( be, ltid, e, e->e_attrs );
398 if ( rc != LDAP_SUCCESS ) {
400 LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: index_entry_add failed\n" ));
402 Debug( LDAP_DEBUG_TRACE, "bdb_add: index_entry_add failed\n",
406 case DB_LOCK_DEADLOCK:
407 case DB_LOCK_NOTGRANTED:
412 text = "index generation failed";
417 if (( rc=TXN_ABORT( ltid )) != 0 ) {
418 text = "txn_abort (no-op) failed";
424 char gid[DB_XIDDATASIZE];
426 snprintf( gid, sizeof( gid ), "%s-%08lx-%08lx",
427 bdb_uuid.bv_val, (long) op->o_connid, (long) op->o_opid );
429 if (( rc=TXN_PREPARE( ltid, gid )) != 0 ) {
430 text = "txn_prepare failed";
433 if ( bdb_cache_add_entry_rw(&bdb->bi_cache,
434 e, CACHE_WRITE_LOCK) != 0 )
436 if(( rc=TXN_ABORT( ltid )) != 0 ) {
437 text = "cache add & txn_abort failed";
440 text = "cache add failed";
443 if(( rc=TXN_COMMIT( ltid, 0 )) != 0 ) {
444 text = "txn_commit failed";
453 op->o_private = NULL;
455 if (rc == LDAP_SUCCESS) {
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 ));
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 );
463 bdb_cache_entry_commit( e );
467 LDAP_LOG (( "add", LDAP_LEVEL_ERR, "bdb_add: %s : %s (%d)\n", text, db_strerror(rc), rc ));
469 Debug( LDAP_DEBUG_TRACE, "bdb_add: %s : %s (%d)\n",
470 text, db_strerror(rc), rc );
476 send_ldap_result( conn, op, rc,
477 NULL, text, NULL, NULL );
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 );
489 op->o_private = NULL;