X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-bdb%2Fmodrdn.c;h=2e3824a2ac0a7d15b74a8a91f6a5b2661fb6be7f;hb=190f161d741fb87417d743b64d0100dd6e2c0855;hp=dde788b392728da9114fa2c98788269849fd3e7a;hpb=838643d5ad3d9555a15b4c800ff19f4f1405513c;p=openldap diff --git a/servers/slapd/back-bdb/modrdn.c b/servers/slapd/back-bdb/modrdn.c index dde788b392..2e3824a2ac 100644 --- a/servers/slapd/back-bdb/modrdn.c +++ b/servers/slapd/back-bdb/modrdn.c @@ -1,7 +1,7 @@ /* modrdn.c - bdb backend modrdn routine */ /* $OpenLDAP$ */ /* - * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved. * COPYING RESTRICTIONS APPLY, see COPYRIGHT file */ @@ -14,37 +14,27 @@ #include "external.h" int -bdb_modrdn( - Backend *be, - Connection *conn, - Operation *op, - struct berval *dn, - struct berval *ndn, - struct berval *newrdn, - struct berval *nnewrdn, - int deleteoldrdn, - struct berval *newSuperior, - struct berval *nnewSuperior ) +bdb_modrdn( Operation *op, SlapReply *rs ) { - struct bdb_info *bdb = (struct bdb_info *) be->be_private; + struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; AttributeDescription *children = slap_schema.si_ad_children; + AttributeDescription *entry = slap_schema.si_ad_entry; struct berval p_dn, p_ndn; struct berval new_dn = {0, NULL}, new_ndn = {0, NULL}; int isroot = -1; Entry *e = NULL; Entry *p = NULL; - Entry *matched; - int rc; - const char *text; + EntryInfo *ei = NULL, *eip = NULL, *nei = NULL, *neip = NULL; + /* LDAP v2 supporting correct attribute handling. */ + LDAPRDN new_rdn = NULL; + LDAPRDN old_rdn = NULL; char textbuf[SLAP_TEXT_BUFLEN]; size_t textlen = sizeof textbuf; - DB_TXN * ltid = NULL; + DB_TXN *ltid = NULL, *lt2; struct bdb_op_info opinfo; + Entry dummy, *save; ID id; - int a_cnt, d_cnt; - LDAPRDN *new_rdn = NULL; - LDAPRDN *old_rdn = NULL; Entry *np = NULL; /* newSuperior Entry */ struct berval *np_dn = NULL; /* newSuperior dn */ @@ -56,84 +46,101 @@ bdb_modrdn( int manageDSAit = get_manageDSAit( op ); - u_int32_t locker; - DB_LOCK lock; + u_int32_t locker = 0; + DB_LOCK lock, plock, nplock; + + int noop = 0; + +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) + Operation *ps_list; + struct psid_entry *pm_list, *pm_prev; +#endif #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, ENTRY, "==>bdb_modrdn(%s,%s,%s)\n", - dn->bv_val,newrdn->bv_val, newSuperior ? newSuperior->bv_val : "NULL" ); + op->o_req_dn.bv_val,op->oq_modrdn.rs_newrdn.bv_val, + op->oq_modrdn.rs_newSup ? op->oq_modrdn.rs_newSup->bv_val : "NULL" ); #else Debug( LDAP_DEBUG_TRACE, "==>bdb_modrdn(%s,%s,%s)\n", - dn->bv_val, newrdn->bv_val, - newSuperior ? newSuperior->bv_val : "NULL" ); -#endif - -#if 0 - if( newSuperior != NULL ) { - rc = LDAP_UNWILLING_TO_PERFORM; - text = "newSuperior not implemented (yet)"; - goto return_results; - } + op->o_req_dn.bv_val,op->oq_modrdn.rs_newrdn.bv_val, + op->oq_modrdn.rs_newSup ? op->oq_modrdn.rs_newSup->bv_val : "NULL" ); #endif if( 0 ) { retry: /* transaction retry */ if (e != NULL) { - bdb_cache_delete_entry(&bdb->bi_cache, e); bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e); + e = NULL; } if (p != NULL) { bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p); + p = NULL; } if (np != NULL) { bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np); + np = NULL; } #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, DETAIL1, "==>bdb_modrdn: retrying...\n", 0, 0, 0); #else Debug( LDAP_DEBUG_TRACE, "==>bdb_modrdn: retrying...\n", 0, 0, 0 ); #endif - rc = TXN_ABORT( ltid ); + +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) + pm_list = LDAP_LIST_FIRST(&op->o_pm_list); + while ( pm_list != NULL ) { + LDAP_LIST_REMOVE ( pm_list, ps_link ); + pm_prev = pm_list; + pm_list = LDAP_LIST_NEXT ( pm_list, ps_link ); + ch_free( pm_prev ); + } +#endif + + rs->sr_err = TXN_ABORT( ltid ); ltid = NULL; op->o_private = NULL; - if( rc != 0 ) { - rc = LDAP_OTHER; - text = "internal error"; + op->o_do_not_cache = opinfo.boi_acl_cache; + if( rs->sr_err != 0 ) { + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; goto return_results; } ldap_pvt_thread_yield(); } /* begin transaction */ - rc = TXN_BEGIN( bdb->bi_dbenv, NULL, <id, + rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, NULL, <id, bdb->bi_db_opflags ); - text = NULL; - if( rc != 0 ) { + rs->sr_text = NULL; + if( rs->sr_err != 0 ) { #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, ERR, "==>bdb_modrdn: txn_begin failed: %s (%d)\n", - db_strerror(rc), rc, 0 ); + db_strerror(rs->sr_err), rs->sr_err, 0 ); #else Debug( LDAP_DEBUG_TRACE, "bdb_delete: txn_begin failed: %s (%d)\n", - db_strerror(rc), rc, 0 ); + db_strerror(rs->sr_err), rs->sr_err, 0 ); #endif - rc = LDAP_OTHER; - text = "internal error"; + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; goto return_results; } locker = TXN_ID ( ltid ); - opinfo.boi_bdb = be; + opinfo.boi_bdb = op->o_bd; opinfo.boi_txn = ltid; + opinfo.boi_locker = locker; opinfo.boi_err = 0; + opinfo.boi_acl_cache = op->o_do_not_cache; op->o_private = &opinfo; /* get entry */ - rc = bdb_dn2entry_w( be, ltid, ndn, &e, &matched, DB_RMW, locker, &lock ); + rs->sr_err = bdb_dn2entry( op->o_bd, ltid, &op->o_req_ndn, &ei, 1, + locker, &lock, op->o_tmpmemctx ); - switch( rc ) { + switch( rs->sr_err ) { case 0: case DB_NOTFOUND: break; @@ -141,45 +148,101 @@ retry: /* transaction retry */ case DB_LOCK_NOTGRANTED: goto retry; case LDAP_BUSY: - text = "ldap server busy"; + rs->sr_text = "ldap server busy"; goto return_results; default: - rc = LDAP_OTHER; - text = "internal error"; + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; goto return_results; } - if ( e == NULL ) { - char* matched_dn = NULL; - BerVarray refs; - - if( matched != NULL ) { - matched_dn = ch_strdup( matched->e_dn ); - refs = is_entry_referral( matched ) - ? get_entry_referrals( be, conn, op, matched ) + e = ei->bei_e; + if ( rs->sr_err == DB_NOTFOUND ) { + if( e != NULL ) { + rs->sr_matched = ch_strdup( e->e_dn ); + rs->sr_ref = is_entry_referral( e ) + ? get_entry_referrals( op, e ) : NULL; - bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, matched); - matched = NULL; + bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, e); + e = NULL; } else { - refs = referral_rewrite( default_referral, - NULL, dn, LDAP_SCOPE_DEFAULT ); + rs->sr_ref = referral_rewrite( default_referral, + NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); } - send_ldap_result( conn, op, rc = LDAP_REFERRAL, - matched_dn, NULL, refs, NULL ); + rs->sr_err = LDAP_REFERRAL; + send_ldap_result( op, rs ); - ber_bvarray_free( refs ); - free( matched_dn ); + ber_bvarray_free( rs->sr_ref ); + free( (char *)rs->sr_matched ); + rs->sr_ref = NULL; + rs->sr_matched = NULL; goto done; } + /* check write on old entry */ + rs->sr_err = access_allowed( op, e, entry, NULL, ACL_WRITE, NULL ); + + if ( ! rs->sr_err ) { + switch( opinfo.boi_err ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + } + +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, + "==>bdb_modrdn: no access to entry\n", 0, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0, + 0, 0 ); +#endif + rs->sr_text = "no write access to old entry"; + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + +#ifndef BDB_HIER + rs->sr_err = bdb_cache_children( op, ltid, e ); + if ( rs->sr_err != DB_NOTFOUND ) { + switch( rs->sr_err ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + case 0: +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, + "<=- bdb_modrdn: non-leaf %s\n", op->o_req_dn.bv_val, 0, 0 ); +#else + Debug(LDAP_DEBUG_ARGS, + "<=- bdb_modrdn: non-leaf %s\n", + op->o_req_dn.bv_val, 0, 0); +#endif + rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; + rs->sr_text = "subtree rename not supported"; + break; + default: +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, + "<=- bdb_modrdn: has_children failed %s (%d)\n", + db_strerror(rs->sr_err), rs->sr_err, 0 ); +#else + Debug(LDAP_DEBUG_ARGS, + "<=- bdb_modrdn: has_children failed: %s (%d)\n", + db_strerror(rs->sr_err), rs->sr_err, 0 ); +#endif + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; + } + goto return_results; + } + ei->bei_state |= CACHE_ENTRY_NO_KIDS; +#endif if (!manageDSAit && is_entry_referral( e ) ) { /* parent is a referral, don't allow add */ - /* parent is an alias, don't allow add */ - BerVarray refs = get_entry_referrals( be, - conn, op, e ); + rs->sr_ref = get_entry_referrals( op, e ); #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, DETAIL1, @@ -189,14 +252,17 @@ retry: /* transaction retry */ e->e_dn, 0, 0 ); #endif - send_ldap_result( conn, op, rc = LDAP_REFERRAL, - e->e_dn, NULL, refs, NULL ); + rs->sr_err = LDAP_REFERRAL, + rs->sr_matched = e->e_name.bv_val; + send_ldap_result( op, rs ); - ber_bvarray_free( refs ); + ber_bvarray_free( rs->sr_ref ); + rs->sr_ref = NULL; + rs->sr_matched = NULL; goto done; } - if ( be_issuffix( be, &e->e_nname ) ) { + if ( be_issuffix( op->o_bd, &e->e_nname ) ) { p_ndn = slap_empty_bv; } else { dnParent( &e->e_nname, &p_ndn ); @@ -206,9 +272,11 @@ retry: /* transaction retry */ /* Make sure parent entry exist and we can write its * children. */ - rc = bdb_dn2entry_r( be, ltid, &p_ndn, &p, NULL, 0, locker, &lock ); + eip = ei->bei_parent; + rs->sr_err = bdb_cache_find_id( op->o_bd, ltid, + eip->bei_id, &eip, 0, locker, &plock, op->o_tmpmemctx ); - switch( rc ) { + switch( rs->sr_err ) { case 0: case DB_NOTFOUND: break; @@ -216,14 +284,15 @@ retry: /* transaction retry */ case DB_LOCK_NOTGRANTED: goto retry; case LDAP_BUSY: - text = "ldap server busy"; + rs->sr_text = "ldap server busy"; goto return_results; default: - rc = LDAP_OTHER; - text = "internal error"; + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; goto return_results; } + p = eip->bei_e; if( p == NULL) { #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, ERR, @@ -232,14 +301,23 @@ retry: /* transaction retry */ Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: parent does not exist\n", 0, 0, 0); #endif - rc = LDAP_OTHER; + rs->sr_err = LDAP_OTHER; + rs->sr_text = "old entry's parent does not exist"; goto return_results; } /* check parent for "children" acl */ - if ( ! access_allowed( be, conn, op, p, - children, NULL, ACL_WRITE, NULL ) ) - { + rs->sr_err = access_allowed( op, p, + children, NULL, ACL_WRITE, NULL ); + + if ( ! rs->sr_err ) { + switch( opinfo.boi_err ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + } + + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, ERR, "==>bdb_modrdn: no access to parent\n", 0, 0, 0 ); @@ -247,8 +325,7 @@ retry: /* transaction retry */ Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0, 0, 0 ); #endif - send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, - NULL, NULL, NULL, NULL ); + rs->sr_text = "no write access to old parent's children"; goto return_results; } @@ -278,21 +355,27 @@ retry: /* transaction retry */ } else { /* no parent, modrdn entry directly under root */ - isroot = be_isroot( be, &op->o_ndn ); + isroot = be_isroot( op->o_bd, &op->o_ndn ); if ( ! isroot ) { - if ( be_issuffix( be, (struct berval *)&slap_empty_bv ) - || be_isupdate( be, &op->o_ndn ) ) { + if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv ) + || be_isupdate( op->o_bd, &op->o_ndn ) ) { p = (Entry *)&slap_entry_root; /* check parent for "children" acl */ - rc = access_allowed( be, conn, op, p, + rs->sr_err = access_allowed( op, p, children, NULL, ACL_WRITE, NULL ); p = NULL; - if ( ! rc ) - { + if ( ! rs->sr_err ) { + switch( opinfo.boi_err ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + } + + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, ERR, "==>bdb_modrdn: no access to parent\n", 0, 0, 0 ); @@ -301,9 +384,7 @@ retry: /* transaction retry */ "no access to parent\n", 0, 0, 0 ); #endif - send_ldap_result( conn, op, - LDAP_INSUFFICIENT_ACCESS, - NULL, NULL, NULL, NULL ); + rs->sr_text = "no write access to old parent"; goto return_results; } @@ -340,7 +421,8 @@ retry: /* transaction retry */ "& \"\" is not suffix\n", 0, 0, 0); #endif - rc = LDAP_INSUFFICIENT_ACCESS; + rs->sr_text = "no write access to old parent"; + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; goto return_results; } } @@ -348,40 +430,57 @@ retry: /* transaction retry */ new_parent_dn = &p_dn; /* New Parent unless newSuperior given */ - if ( newSuperior != NULL ) { + if ( op->oq_modrdn.rs_newSup != NULL ) { #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, DETAIL1, "==>bdb_modrdn: new parent \"%s\" requested...\n", - newSuperior->bv_val, 0, 0 ); + op->oq_modrdn.rs_newSup->bv_val, 0, 0 ); #else Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: new parent \"%s\" requested...\n", - newSuperior->bv_val, 0, 0 ); + op->oq_modrdn.rs_newSup->bv_val, 0, 0 ); #endif - if ( newSuperior->bv_len ) { - np_dn = newSuperior; - np_ndn = nnewSuperior; + /* newSuperior == oldParent? */ + if( dn_match( &p_ndn, op->oq_modrdn.rs_nnewSup ) ) { +#ifdef NEW_LOGGING + LDAP_LOG( BACK_BDB, INFO, "bdb_back_modrdn: " + "new parent \"%s\" same as the old parent \"%s\"\n", + op->oq_modrdn.rs_newSup->bv_val, p_dn.bv_val, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, "bdb_back_modrdn: " + "new parent \"%s\" same as the old parent \"%s\"\n", + op->oq_modrdn.rs_newSup->bv_val, p_dn.bv_val, 0 ); +#endif + op->oq_modrdn.rs_newSup = NULL; /* ignore newSuperior */ + } + } + + if ( op->oq_modrdn.rs_newSup != NULL ) { + if ( op->oq_modrdn.rs_newSup->bv_len ) { + np_dn = op->oq_modrdn.rs_newSup; + np_ndn = op->oq_modrdn.rs_nnewSup; /* newSuperior == oldParent?, if so ==> ERROR */ /* newSuperior == entry being moved?, if so ==> ERROR */ /* Get Entry with dn=newSuperior. Does newSuperior exist? */ - rc = bdb_dn2entry_r( be, ltid, nnewSuperior, &np, NULL, 0, locker, &lock ); + rs->sr_err = bdb_dn2entry( op->o_bd, ltid, np_ndn, + &neip, 0, locker, &nplock, op->o_tmpmemctx ); - switch( rc ) { - case 0: + switch( rs->sr_err ) { + case 0: np = neip->bei_e; case DB_NOTFOUND: break; case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; case LDAP_BUSY: - text = "ldap server busy"; + rs->sr_text = "ldap server busy"; goto return_results; default: - rc = LDAP_OTHER; - text = "internal error"; + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; goto return_results; } @@ -395,22 +494,32 @@ retry: /* transaction retry */ "bdb_modrdn: newSup(ndn=%s) not here!\n", np_ndn->bv_val, 0, 0); #endif - rc = LDAP_OTHER; + rs->sr_text = "new superior not found"; + rs->sr_err = LDAP_OTHER; goto return_results; } #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, DETAIL1, "==>bdb_modrdn: wr to new parent OK np=%p, id=%ld\n", - np, (long) np->e_id, 0 ); + (void *) np, (long) np->e_id, 0 ); #else Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: wr to new parent OK np=%p, id=%ld\n", - np, (long) np->e_id, 0 ); + (void *) np, (long) np->e_id, 0 ); #endif /* check newSuperior for "children" acl */ - if ( !access_allowed( be, conn, op, np, children, NULL, ACL_WRITE, NULL ) ) { + rs->sr_err = access_allowed( op, np, children, + NULL, ACL_WRITE, NULL ); + + if( ! rs->sr_err ) { + switch( opinfo.boi_err ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + } + #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, DETAIL1, "==>bdb_modrdn: no wr to newSup children\n", 0, 0, 0 ); @@ -419,7 +528,8 @@ retry: /* transaction retry */ "bdb_modrdn: no wr to newSup children\n", 0, 0, 0 ); #endif - rc = LDAP_INSUFFICIENT_ACCESS; + rs->sr_text = "no write access to new superior's children"; + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; goto return_results; } @@ -433,8 +543,8 @@ retry: /* transaction retry */ Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is alias\n", 0, 0, 0 ); #endif - - rc = LDAP_ALIAS_PROBLEM; + rs->sr_text = "new superior is an alias"; + rs->sr_err = LDAP_ALIAS_PROBLEM; goto return_results; } #endif @@ -448,32 +558,38 @@ retry: /* transaction retry */ Debug( LDAP_DEBUG_TRACE, "bdb_modrdn: entry is referral\n", 0, 0, 0 ); #endif - - rc = LDAP_OTHER; + rs->sr_text = "new superior is a referral"; + rs->sr_err = LDAP_OTHER; goto return_results; } } else { if ( isroot == -1 ) { - isroot = be_isroot( be, &op->o_ndn ); + isroot = be_isroot( op->o_bd, &op->o_ndn ); } np_dn = NULL; /* no parent, modrdn entry directly under root */ if ( ! isroot ) { - if ( be_issuffix( be, (struct berval *)&slap_empty_bv ) - || be_isupdate( be, &op->o_ndn ) ) { + if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv ) + || be_isupdate( op->o_bd, &op->o_ndn ) ) { np = (Entry *)&slap_entry_root; /* check parent for "children" acl */ - rc = access_allowed( be, conn, op, np, + rs->sr_err = access_allowed( op, np, children, NULL, ACL_WRITE, NULL ); np = NULL; - if ( ! rc ) - { + if ( ! rs->sr_err ) { + switch( opinfo.boi_err ) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto retry; + } + + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, ERR, "==>bdb_modrdn: no access to superior\n", 0, 0, 0 ); @@ -482,9 +598,7 @@ retry: /* transaction retry */ "no access to new superior\n", 0, 0, 0 ); #endif - send_ldap_result( conn, op, - LDAP_INSUFFICIENT_ACCESS, - NULL, NULL, NULL, NULL ); + rs->sr_text = "no write access to new superior's children"; goto return_results; } @@ -508,7 +622,8 @@ retry: /* transaction retry */ "& \"\" is not suffix\n", 0, 0, 0); #endif - rc = LDAP_INSUFFICIENT_ACCESS; + rs->sr_text = "no write access to new superior's children"; + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; goto return_results; } } @@ -534,11 +649,15 @@ retry: /* transaction retry */ new_parent_dn = np_dn; } - + /* Build target dn and make sure target entry doesn't exist already. */ - build_new_dn( &new_dn, new_parent_dn, newrdn ); + if (!new_dn.bv_val) build_new_dn( &new_dn, new_parent_dn, &op->oq_modrdn.rs_newrdn ); - dnNormalize2( NULL, &new_dn, &new_ndn ); + if (!new_ndn.bv_val) { + struct berval bv = {0, NULL}; + dnNormalize( 0, NULL, NULL, &new_dn, &bv, op->o_tmpmemctx ); + ber_dupbv( &new_ndn, &bv ); + } #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, RESULTS, @@ -548,257 +667,208 @@ retry: /* transaction retry */ new_ndn.bv_val, 0, 0 ); #endif - rc = bdb_dn2id ( be, ltid, &new_ndn, &id, 0 ); - switch( rc ) { + /* Shortcut the search */ + nei = neip ? neip : eip; + rs->sr_err = bdb_cache_find_ndn ( op->o_bd, ltid, &new_ndn, + &nei, locker, op->o_tmpmemctx ); + if ( nei ) bdb_cache_entryinfo_unlock( nei ); + switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; case DB_NOTFOUND: break; case 0: - rc = LDAP_ALREADY_EXISTS; + rs->sr_err = LDAP_ALREADY_EXISTS; goto return_results; default: - rc = LDAP_OTHER; - text = "internal error"; + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; goto return_results; } -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, ERR, - "bdb_modrdn: new ndn=%s does not exist\n", new_ndn.bv_val, 0, 0 ); -#else - Debug( LDAP_DEBUG_TRACE, - "bdb_modrdn: new ndn=%s does not exist\n", - new_ndn.bv_val, 0, 0 ); -#endif - /* Get attribute type and attribute value of our new rdn, we will * need to add that to our new entry */ - if ( ldap_bv2rdn( newrdn, &new_rdn, (char **)&text, - LDAP_DN_FORMAT_LDAP ) ) + if ( !new_rdn && ldap_bv2rdn_x( &op->oq_modrdn.rs_newrdn, &new_rdn, (char **)&rs->sr_text, + LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) ) { #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, ERR, - "bdb_modrdn: can't figure out type(s)/values(s) of newrdn\n", + "bdb_modrdn: can't figure out " + "type(s)/values(s) of newrdn\n", 0, 0, 0 ); #else Debug( LDAP_DEBUG_TRACE, - "bdb_modrdn: can't figure out type(s)/values(s) " - "of newrdn\n", 0, 0, 0 ); + "bdb_modrdn: can't figure out " + "type(s)/values(s) of newrdn\n", + 0, 0, 0 ); #endif - rc = LDAP_INVALID_DN_SYNTAX; - text = "unknown type(s) used in RDN"; - goto return_results; + rs->sr_err = LDAP_INVALID_DN_SYNTAX; + rs->sr_text = "unknown type(s) used in RDN"; + goto return_results; } #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, RESULTS, - "bdb_modrdn: new_rdn_type=\"%s\", new_rdn_val=\"%s\"\n", - new_rdn[0][0]->la_attr.bv_val, new_rdn[0][0]->la_value.bv_val, 0 ); + "bdb_modrdn: new_rdn_type=\"%s\", " + "new_rdn_val=\"%s\"\n", + new_rdn[ 0 ]->la_attr.bv_val, + new_rdn[ 0 ]->la_value.bv_val, 0 ); #else Debug( LDAP_DEBUG_TRACE, - "bdb_modrdn: new_rdn_type=\"%s\", new_rdn_val=\"%s\"\n", - new_rdn[0][0]->la_attr.bv_val, new_rdn[0][0]->la_value.bv_val, 0 ); -#endif - - if ( ldap_bv2rdn( dn, &old_rdn, (char **)&text, - LDAP_DN_FORMAT_LDAP ) ) - { -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, ERR, - "bdb_modrdn: can't figure out type(s)/values(s) of old_rdn\n", - 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_TRACE, - "bdb_back_modrdn: can't figure out the old_rdn " - "type(s)/value(s)\n", 0, 0, 0 ); -#endif - rc = LDAP_OTHER; - text = "cannot parse RDN from old DN"; - goto return_results; - } - -#if 0 - if ( newSuperior == NULL - && charray_strcasecmp( ( const char ** )old_rdn_types, - ( const char ** )new_rdn_types ) != 0 ) { - /* Not a big deal but we may say something */ -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, ERR, - "bdb_modrdn: old_rdn_type(s)=%s, new_rdn_type(s)=%s do not match\n", - old_rdn_types[ 0 ], new_rdn_types[ 0 ], 0 ); -#else - Debug( LDAP_DEBUG_TRACE, - "bdb_modrdn: old_rdn_type(s)=%s, new_rdn_type(s)=%s " - "do not match\n", - old_rdn_types[ 0 ], new_rdn_types[ 0 ], 0 ); -#endif - } + "bdb_modrdn: new_rdn_type=\"%s\", " + "new_rdn_val=\"%s\"\n", + new_rdn[ 0 ]->la_attr.bv_val, + new_rdn[ 0 ]->la_value.bv_val, 0 ); #endif - /* Add new attribute values to the entry */ - for ( a_cnt = 0; new_rdn[0][ a_cnt ]; a_cnt++ ) { - int rc; - AttributeDescription *desc = NULL; - Modifications *mod_tmp; - - rc = slap_bv2ad( &new_rdn[0][ a_cnt ]->la_attr, &desc, &text ); - - if ( rc != LDAP_SUCCESS ) { + if ( op->oq_modrdn.rs_deleteoldrdn ) { + if ( !old_rdn && ldap_bv2rdn_x( &op->o_req_dn, &old_rdn, (char **)&rs->sr_text, + LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ) ) + { #ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, ERR, "bdb_modrdn: %s: %s (new)\n", - text, new_rdn[0][a_cnt]->la_attr.bv_val, 0 ); + LDAP_LOG ( OPERATION, ERR, + "bdb_modrdn: can't figure out " + "type(s)/values(s) of old_rdn\n", + 0, 0, 0 ); #else Debug( LDAP_DEBUG_TRACE, - "bdb_modrdn: %s: %s (new)\n", - text, new_rdn[0][ a_cnt ]->la_attr.bv_val, 0 ); + "bdb_modrdn: can't figure out " + "the old_rdn type(s)/value(s)\n", + 0, 0, 0 ); #endif + rs->sr_err = LDAP_OTHER; + rs->sr_text = "cannot parse RDN from old DN"; goto return_results; } + } - /* ACL check of newly added attrs */ - if ( !access_allowed( be, conn, op, e, desc, - &new_rdn[0][ a_cnt ]->la_value, ACL_WRITE, NULL ) ) { -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, ERR, - "bdb_modrdn: access to attr \"%s\" (new) not allowed\n", - new_rdn[0][a_cnt]->la_attr.bv_val, 0, 0 ); -#else - Debug( LDAP_DEBUG_TRACE, - "bdb_modrdn: access to attr \"%s\" " - "(new) not allowed\n", - new_rdn[0][ a_cnt ]->la_attr.bv_val, 0, 0 ); -#endif - rc = LDAP_INSUFFICIENT_ACCESS; + /* prepare modlist of modifications from old/new rdn */ + if (!mod) { + rs->sr_err = slap_modrdn2mods( op, rs, e, old_rdn, new_rdn, &mod ); + if ( rs->sr_err != LDAP_SUCCESS ) { goto return_results; } - - /* Apply modification */ - mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications ) - + 2 * sizeof( struct berval ) ); - mod_tmp->sml_desc = desc; - mod_tmp->sml_bvalues = ( BerVarray )( mod_tmp + 1 ); - mod_tmp->sml_bvalues[ 0 ] = new_rdn[0][ a_cnt ]->la_value; - mod_tmp->sml_bvalues[ 1 ].bv_val = NULL; - mod_tmp->sml_op = SLAP_MOD_SOFTADD; - mod_tmp->sml_next = mod; - mod = mod_tmp; } - /* Remove old rdn value if required */ - if ( deleteoldrdn ) { - /* Get value of old rdn */ - if ( old_rdn == NULL) { + /* nested transaction */ + rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, <2, + bdb->bi_db_opflags ); + rs->sr_text = NULL; + if( rs->sr_err != 0 ) { #ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, ERR, - "bdb_modrdn: can't figure out old RDN values(s) " - "from old RDN\n", 0, 0, 0 ); + LDAP_LOG ( OPERATION, ERR, + "bdb_modrdn: txn_begin(2) failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 ); #else - Debug( LDAP_DEBUG_TRACE, - "bdb_modrdn: can't figure out old RDN value(s) " - "from old RDN\n", 0, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, + "bdb_modrdn: txn_begin(2) failed: %s (%d)\n", + db_strerror(rs->sr_err), rs->sr_err, 0 ); #endif - rc = LDAP_OTHER; - text = "could not parse value(s) from old RDN"; - goto return_results; - } - - for ( d_cnt = 0; old_rdn[0][ d_cnt ]; d_cnt++ ) { - int rc; - AttributeDescription *desc = NULL; - Modifications *mod_tmp; + rs->sr_err = LDAP_OTHER; + rs->sr_text = "internal error"; + goto return_results; + } - rc = slap_bv2ad( &old_rdn[0][ d_cnt ]->la_attr, - &desc, &text ); + dummy = *e; + save = e; + e = &dummy; - if ( rc != LDAP_SUCCESS ) { -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, ERR, "bdb_modrdn: %s: %s (old)\n", - text, old_rdn[0][d_cnt]->la_attr.bv_val, 0 ); -#else - Debug( LDAP_DEBUG_TRACE, - "bdb_modrdn: %s: %s (old)\n", - text, old_rdn[0][ d_cnt ]->la_attr.bv_val, 0 ); -#endif - goto return_results; - } - - /* ACL check of newly added attrs */ - if ( !access_allowed( be, conn, op, e, desc, - &old_rdn[0][d_cnt]->la_value, ACL_WRITE, NULL ) ) { + /* delete old one */ + rs->sr_err = bdb_dn2id_delete( op->o_bd, lt2, eip, e, + op->o_tmpmemctx ); + if ( rs->sr_err != 0 ) { #ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, ERR, - "bdb_modrdn: access to attr \"%s\" (old) not allowed\n", - old_rdn[0][d_cnt]->la_attr.bv_val, 0, 0 ); + LDAP_LOG ( OPERATION, ERR, + "<=- bdb_modrdn: dn2id del failed: %s (%d)\n", + db_strerror(rs->sr_err), rs->sr_err, 0 ); #else - Debug( LDAP_DEBUG_TRACE, - "bdb_modrdn: access to attr \"%s\" " - "(old) not allowed\n", - old_rdn[0][ d_cnt ]->la_attr.bv_val, 0, 0 ); + Debug(LDAP_DEBUG_TRACE, + "<=- bdb_modrdn: dn2id del failed: %s (%d)\n", + db_strerror(rs->sr_err), rs->sr_err, 0 ); #endif - rc = LDAP_INSUFFICIENT_ACCESS; - goto return_results; - } - - /* Apply modification */ - mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications ) - + 2 * sizeof ( struct berval ) ); - mod_tmp->sml_desc = desc; - mod_tmp->sml_bvalues = ( BerVarray )(mod_tmp+1); - mod_tmp->sml_bvalues[ 0 ] = old_rdn[0][ d_cnt ]->la_value; - mod_tmp->sml_bvalues[ 1 ].bv_val = NULL; - mod_tmp->sml_op = LDAP_MOD_DELETE; - mod_tmp->sml_next = mod; - mod = mod_tmp; - } - } - - /* delete old one */ - rc = bdb_dn2id_delete( be, ltid, p_ndn.bv_val, e ); - if ( rc != 0 ) { - switch( rc ) { + switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; } - rc = LDAP_OTHER; - text = "DN index delete fail"; + rs->sr_err = LDAP_OTHER; + rs->sr_text = "DN index delete fail"; goto return_results; } - (void) bdb_cache_delete_entry(&bdb->bi_cache, e); - /* Binary format uses a single contiguous block, cannot - * free individual fields. Leave new_dn/new_ndn set so - * they can be individually freed later. + * free individual fields. But if a previous modrdn has + * already happened, must free the names. The frees are + * done in bdb_cache_modrdn(). */ +#ifdef BDB_HIER + e->e_name.bv_val = ch_malloc(new_dn.bv_len + new_ndn.bv_len + 2); + e->e_name.bv_len = new_dn.bv_len; + e->e_nname.bv_val = e->e_name.bv_val + new_dn.bv_len + 1; + e->e_nname.bv_len = new_ndn.bv_len; + strcpy(e->e_name.bv_val, new_dn.bv_val); + strcpy(e->e_nname.bv_val, new_ndn.bv_val); +#else + if( e->e_nname.bv_val < e->e_bv.bv_val || e->e_nname.bv_val > + e->e_bv.bv_val + e->e_bv.bv_len ) { + e->e_name.bv_val = NULL; + e->e_nname.bv_val = NULL; + } e->e_name = new_dn; e->e_nname = new_ndn; - new_dn.bv_val = NULL; new_ndn.bv_val = NULL; - +#endif /* add new one */ - rc = bdb_dn2id_add( be, ltid, np_ndn, e ); - if ( rc != 0 ) { - switch( rc ) { + rs->sr_err = bdb_dn2id_add( op->o_bd, lt2, neip ? neip : eip, e, + op->o_tmpmemctx ); + if ( rs->sr_err != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, + "<=- bdb_modrdn: dn2id add failed: %s (%d)\n", + db_strerror(rs->sr_err), rs->sr_err, 0 ); +#else + Debug(LDAP_DEBUG_TRACE, + "<=- bdb_modrdn: dn2id add failed: %s (%d)\n", + db_strerror(rs->sr_err), rs->sr_err, 0 ); +#endif + switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; } - rc = LDAP_OTHER; - text = "DN index add failed"; + rs->sr_err = LDAP_OTHER; + rs->sr_text = "DN index add failed"; goto return_results; } +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) + if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { + LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) { + bdb_psearch( op, rs, ps_list, e, LDAP_PSEARCH_BY_PREMODIFY ); + } + } +#endif + /* modify entry */ - rc = bdb_modify_internal( be, conn, op, ltid, &mod[0], e, - &text, textbuf, textlen ); + rs->sr_err = bdb_modify_internal( op, lt2, &mod[0], e, + &rs->sr_text, textbuf, textlen ); - if( rc != LDAP_SUCCESS ) { - switch( rc ) { + if( rs->sr_err != LDAP_SUCCESS ) { +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, + "<=- bdb_modrdn: modify failed: %s (%d)\n", + db_strerror(rs->sr_err), rs->sr_err, 0 ); +#else + Debug(LDAP_DEBUG_TRACE, + "<=- bdb_modrdn: modify failed: %s (%d)\n", + db_strerror(rs->sr_err), rs->sr_err, 0 ); +#endif + if ( ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) && opinfo.boi_err ) { + rs->sr_err = opinfo.boi_err; + } + switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; @@ -807,23 +877,38 @@ retry: /* transaction retry */ } /* id2entry index */ - rc = bdb_id2entry_update( be, ltid, e ); - if ( rc != 0 ) { - switch( rc ) { + rs->sr_err = bdb_id2entry_update( op->o_bd, lt2, e ); + if ( rs->sr_err != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, + "<=- bdb_modrdn: id2entry failed: %s (%d)\n", + db_strerror(rs->sr_err), rs->sr_err, 0 ); +#else + Debug(LDAP_DEBUG_TRACE, + "<=- bdb_modrdn: id2entry failed: %s (%d)\n", + db_strerror(rs->sr_err), rs->sr_err, 0 ); +#endif + switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; } - rc = LDAP_OTHER; - text = "entry update failed"; + rs->sr_err = LDAP_OTHER; + rs->sr_text = "entry update failed"; + goto return_results; + } + if ( TXN_COMMIT( lt2, 0 ) != 0 ) { + rs->sr_err = LDAP_OTHER; + rs->sr_text = "txn_commit(2) failed"; goto return_results; } if( op->o_noop ) { - if(( rc=TXN_ABORT( ltid )) != 0 ) { - text = "txn_abort (no-op) failed"; + if(( rs->sr_err=TXN_ABORT( ltid )) != 0 ) { + rs->sr_text = "txn_abort (no-op) failed"; } else { - rc = LDAP_SUCCESS; + noop = 1; + rs->sr_err = LDAP_SUCCESS; } } else { @@ -832,23 +917,15 @@ retry: /* transaction retry */ snprintf( gid, sizeof( gid ), "%s-%08lx-%08lx", bdb_uuid.bv_val, (long) op->o_connid, (long) op->o_opid ); - if(( rc=TXN_PREPARE( ltid, gid )) != 0 ) { - text = "txn_prepare failed"; + if(( rs->sr_err=TXN_PREPARE( ltid, gid )) != 0 ) { + rs->sr_text = "txn_prepare failed"; } else { - if( bdb_cache_update_entry(&bdb->bi_cache, e) == -1 ) { - if(( rc=TXN_ABORT( ltid )) != 0 ) { - text ="cache update & txn_abort failed"; - } else { - rc = LDAP_OTHER; - text = "cache update failed"; - } - + bdb_cache_modrdn( save, &op->orr_nnewrdn, e, neip, + bdb->bi_dbenv, locker, &lock ); + if(( rs->sr_err=TXN_COMMIT( ltid, 0 )) != 0 ) { + rs->sr_text = "txn_commit failed"; } else { - if(( rc=TXN_COMMIT( ltid, 0 )) != 0 ) { - text = "txn_commit failed"; - } else { - rc = LDAP_SUCCESS; - } + rs->sr_err = LDAP_SUCCESS; } } } @@ -856,7 +933,7 @@ retry: /* transaction retry */ ltid = NULL; op->o_private = NULL; - if( rc == LDAP_SUCCESS ) { + if( rs->sr_err == LDAP_SUCCESS ) { #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, RESULTS, "bdb_modrdn: rdn modified%s id=%08lx dn=\"%s\"\n", @@ -866,25 +943,40 @@ retry: /* transaction retry */ "bdb_modrdn: rdn modified%s id=%08lx dn=\"%s\"\n", op->o_noop ? " (no-op)" : "", e->e_id, e->e_dn ); #endif - text = NULL; - bdb_cache_entry_commit( e ); - + rs->sr_text = NULL; } else { #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, RESULTS, "bdb_modrdn: %s : %s (%d)\n", - text, db_strerror(rc), rc ); + rs->sr_text, db_strerror(rs->sr_err), rs->sr_err ); #else Debug( LDAP_DEBUG_TRACE, "bdb_add: %s : %s (%d)\n", - text, db_strerror(rc), rc ); + rs->sr_text, db_strerror(rs->sr_err), rs->sr_err ); #endif - rc = LDAP_OTHER; + rs->sr_err = LDAP_OTHER; } return_results: - send_ldap_result( conn, op, rc, - NULL, text, NULL, NULL ); + send_ldap_result( op, rs ); + +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) + if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { + /* Loop through in-scope entries for each psearch spec */ + LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) { + bdb_psearch( op, rs, ps_list, e, LDAP_PSEARCH_BY_MODIFY ); + } + pm_list = LDAP_LIST_FIRST(&op->o_pm_list); + while ( pm_list != NULL ) { + bdb_psearch(op, rs, pm_list->ps_op, + e, LDAP_PSEARCH_BY_SCOPEOUT); + pm_prev = pm_list; + LDAP_LIST_REMOVE ( pm_list, ps_link ); + pm_list = LDAP_LIST_NEXT ( pm_list, ps_link ); + ch_free( pm_prev ); + } + } +#endif - if( rc == LDAP_SUCCESS && bdb->bi_txn_cp ) { + if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp ) { ldap_pvt_thread_yield(); TXN_CHECKPOINT( bdb->bi_dbenv, bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 ); @@ -895,12 +987,17 @@ done: if( new_ndn.bv_val != NULL ) free( new_ndn.bv_val ); /* LDAP v2 supporting correct attribute handling. */ - if( new_rdn != NULL ) ldap_rdnfree( new_rdn ); - if( old_rdn != NULL ) ldap_rdnfree( old_rdn ); + if ( new_rdn != NULL ) { + ldap_rdnfree_x( new_rdn, op->o_tmpmemctx ); + } + if ( old_rdn != NULL ) { + ldap_rdnfree_x( old_rdn, op->o_tmpmemctx ); + } if( mod != NULL ) { Modifications *tmp; for (; mod; mod=tmp ) { tmp = mod->sml_next; + if ( mod->sml_nvalues ) free( mod->sml_nvalues[0].bv_val ); free( mod ); } } @@ -922,9 +1019,18 @@ done: } if( ltid != NULL ) { +#if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) + pm_list = LDAP_LIST_FIRST(&op->o_pm_list); + while ( pm_list != NULL ) { + LDAP_LIST_REMOVE ( pm_list, ps_link ); + pm_prev = pm_list; + pm_list = LDAP_LIST_NEXT ( pm_list, ps_link ); + ch_free( pm_prev ); + } +#endif TXN_ABORT( ltid ); op->o_private = NULL; } - return rc; + return ( ( rs->sr_err == LDAP_SUCCESS ) ? noop : rs->sr_err ); }