Back to index

openldap  2.4.31
modrdn.c
Go to the documentation of this file.
00001 /* modrdn.c - bdb backend modrdn routine */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2000-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 
00017 #include "portable.h"
00018 
00019 #include <stdio.h>
00020 #include <ac/string.h>
00021 
00022 #include "back-bdb.h"
00023 
00024 int
00025 bdb_modrdn( Operation       *op, SlapReply *rs )
00026 {
00027        struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
00028        AttributeDescription *children = slap_schema.si_ad_children;
00029        AttributeDescription *entry = slap_schema.si_ad_entry;
00030        struct berval p_dn, p_ndn;
00031        struct berval new_dn = {0, NULL}, new_ndn = {0, NULL};
00032        Entry         *e = NULL;
00033        Entry         *p = NULL;
00034        EntryInfo     *ei = NULL, *eip = NULL, *nei = NULL, *neip = NULL;
00035        /* LDAP v2 supporting correct attribute handling. */
00036        char textbuf[SLAP_TEXT_BUFLEN];
00037        size_t textlen = sizeof textbuf;
00038        DB_TXN        *ltid = NULL, *lt2;
00039        struct bdb_op_info opinfo = {{{ 0 }}};
00040        Entry dummy = {0};
00041 
00042        Entry         *np = NULL;                 /* newSuperior Entry */
00043        struct berval *np_dn = NULL;                     /* newSuperior dn */
00044        struct berval *np_ndn = NULL;                    /* newSuperior ndn */
00045        struct berval *new_parent_dn = NULL;      /* np_dn, p_dn, or NULL */
00046 
00047        int           manageDSAit = get_manageDSAit( op );
00048 
00049        DB_LOCK              lock, plock, nplock;
00050 
00051        int           num_retries = 0;
00052 
00053        LDAPControl **preread_ctrl = NULL;
00054        LDAPControl **postread_ctrl = NULL;
00055        LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
00056        int num_ctrls = 0;
00057 
00058        int    rc;
00059 
00060        int parent_is_glue = 0;
00061        int parent_is_leaf = 0;
00062 
00063 #ifdef LDAP_X_TXN
00064        int settle = 0;
00065 #endif
00066 
00067        Debug( LDAP_DEBUG_TRACE, "==>" LDAP_XSTRING(bdb_modrdn) "(%s,%s,%s)\n",
00068               op->o_req_dn.bv_val,op->oq_modrdn.rs_newrdn.bv_val,
00069               op->oq_modrdn.rs_newSup ? op->oq_modrdn.rs_newSup->bv_val : "NULL" );
00070 
00071 #ifdef LDAP_X_TXN
00072        if( op->o_txnSpec ) {
00073               /* acquire connection lock */
00074               ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
00075               if( op->o_conn->c_txn == CONN_TXN_INACTIVE ) {
00076                      rs->sr_text = "invalid transaction identifier";
00077                      rs->sr_err = LDAP_X_TXN_ID_INVALID;
00078                      goto txnReturn;
00079               } else if( op->o_conn->c_txn == CONN_TXN_SETTLE ) {
00080                      settle=1;
00081                      goto txnReturn;
00082               }
00083 
00084               if( op->o_conn->c_txn_backend == NULL ) {
00085                      op->o_conn->c_txn_backend = op->o_bd;
00086 
00087               } else if( op->o_conn->c_txn_backend != op->o_bd ) {
00088                      rs->sr_text = "transaction cannot span multiple database contexts";
00089                      rs->sr_err = LDAP_AFFECTS_MULTIPLE_DSAS;
00090                      goto txnReturn;
00091               }
00092 
00093               /* insert operation into transaction */
00094 
00095               rs->sr_text = "transaction specified";
00096               rs->sr_err = LDAP_X_TXN_SPECIFY_OKAY;
00097 
00098 txnReturn:
00099               /* release connection lock */
00100               ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
00101 
00102               if( !settle ) {
00103                      send_ldap_result( op, rs );
00104                      return rs->sr_err;
00105               }
00106        }
00107 #endif
00108 
00109        ctrls[num_ctrls] = NULL;
00110 
00111        slap_mods_opattrs( op, &op->orr_modlist, 1 );
00112 
00113        if( 0 ) {
00114 retry: /* transaction retry */
00115               if ( dummy.e_attrs ) {
00116                      attrs_free( dummy.e_attrs );
00117                      dummy.e_attrs = NULL;
00118               }
00119               if (e != NULL) {
00120                      bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
00121                      e = NULL;
00122               }
00123               if (p != NULL) {
00124                      bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
00125                      p = NULL;
00126               }
00127               if (np != NULL) {
00128                      bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np);
00129                      np = NULL;
00130               }
00131               Debug( LDAP_DEBUG_TRACE, "==>" LDAP_XSTRING(bdb_modrdn)
00132                             ": retrying...\n", 0, 0, 0 );
00133 
00134               rs->sr_err = TXN_ABORT( ltid );
00135               ltid = NULL;
00136               LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
00137               opinfo.boi_oe.oe_key = NULL;
00138               op->o_do_not_cache = opinfo.boi_acl_cache;
00139               if( rs->sr_err != 0 ) {
00140                      rs->sr_err = LDAP_OTHER;
00141                      rs->sr_text = "internal error";
00142                      goto return_results;
00143               }
00144               if ( op->o_abandon ) {
00145                      rs->sr_err = SLAPD_ABANDON;
00146                      goto return_results;
00147               }
00148               parent_is_glue = 0;
00149               parent_is_leaf = 0;
00150               bdb_trans_backoff( ++num_retries );
00151        }
00152 
00153        /* begin transaction */
00154        rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid, 
00155               bdb->bi_db_opflags );
00156        rs->sr_text = NULL;
00157        if( rs->sr_err != 0 ) {
00158               Debug( LDAP_DEBUG_TRACE,
00159                      LDAP_XSTRING(bdb_modrdn) ": txn_begin failed: "
00160                      "%s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
00161               rs->sr_err = LDAP_OTHER;
00162               rs->sr_text = "internal error";
00163               goto return_results;
00164        }
00165 
00166        opinfo.boi_oe.oe_key = bdb;
00167        opinfo.boi_txn = ltid;
00168        opinfo.boi_err = 0;
00169        opinfo.boi_acl_cache = op->o_do_not_cache;
00170        LDAP_SLIST_INSERT_HEAD( &op->o_extra, &opinfo.boi_oe, oe_next );
00171 
00172        /* get entry */
00173        rs->sr_err = bdb_dn2entry( op, ltid, &op->o_req_ndn, &ei, 1,
00174               &lock );
00175 
00176        switch( rs->sr_err ) {
00177        case 0:
00178        case DB_NOTFOUND:
00179               break;
00180        case DB_LOCK_DEADLOCK:
00181        case DB_LOCK_NOTGRANTED:
00182               goto retry;
00183        case LDAP_BUSY:
00184               rs->sr_text = "ldap server busy";
00185               goto return_results;
00186        default:
00187               rs->sr_err = LDAP_OTHER;
00188               rs->sr_text = "internal error";
00189               goto return_results;
00190        }
00191 
00192        e = ei->bei_e;
00193        /* FIXME: dn2entry() should return non-glue entry */
00194        if (( rs->sr_err == DB_NOTFOUND ) ||
00195               ( !manageDSAit && e && is_entry_glue( e )))
00196        {
00197               if( e != NULL ) {
00198                      rs->sr_matched = ch_strdup( e->e_dn );
00199                      rs->sr_ref = is_entry_referral( e )
00200                             ? get_entry_referrals( op, e )
00201                             : NULL;
00202                      bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, e);
00203                      e = NULL;
00204 
00205               } else {
00206                      rs->sr_ref = referral_rewrite( default_referral, NULL,
00207                                    &op->o_req_dn, LDAP_SCOPE_DEFAULT );
00208               }
00209 
00210               rs->sr_err = LDAP_REFERRAL;
00211               send_ldap_result( op, rs );
00212 
00213               ber_bvarray_free( rs->sr_ref );
00214               free( (char *)rs->sr_matched );
00215               rs->sr_ref = NULL;
00216               rs->sr_matched = NULL;
00217 
00218               goto done;
00219        }
00220 
00221        if ( get_assert( op ) &&
00222               ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
00223        {
00224               rs->sr_err = LDAP_ASSERTION_FAILED;
00225               goto return_results;
00226        }
00227 
00228        /* check write on old entry */
00229        rs->sr_err = access_allowed( op, e, entry, NULL, ACL_WRITE, NULL );
00230        if ( ! rs->sr_err ) {
00231               switch( opinfo.boi_err ) {
00232               case DB_LOCK_DEADLOCK:
00233               case DB_LOCK_NOTGRANTED:
00234                      goto retry;
00235               }
00236 
00237               Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
00238                      0, 0 );
00239               rs->sr_text = "no write access to old entry";
00240               rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00241               goto return_results;
00242        }
00243 
00244 #ifndef BDB_HIER
00245        rs->sr_err = bdb_cache_children( op, ltid, e );
00246        if ( rs->sr_err != DB_NOTFOUND ) {
00247               switch( rs->sr_err ) {
00248               case DB_LOCK_DEADLOCK:
00249               case DB_LOCK_NOTGRANTED:
00250                      goto retry;
00251               case 0:
00252                      Debug(LDAP_DEBUG_ARGS,
00253                             "<=- " LDAP_XSTRING(bdb_modrdn)
00254                             ": non-leaf %s\n",
00255                             op->o_req_dn.bv_val, 0, 0);
00256                      rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
00257                      rs->sr_text = "subtree rename not supported";
00258                      break;
00259               default:
00260                      Debug(LDAP_DEBUG_ARGS,
00261                             "<=- " LDAP_XSTRING(bdb_modrdn)
00262                             ": has_children failed: %s (%d)\n",
00263                             db_strerror(rs->sr_err), rs->sr_err, 0 );
00264                      rs->sr_err = LDAP_OTHER;
00265                      rs->sr_text = "internal error";
00266               }
00267               goto return_results;
00268        }
00269        ei->bei_state |= CACHE_ENTRY_NO_KIDS;
00270 #endif
00271 
00272        if (!manageDSAit && is_entry_referral( e ) ) {
00273               /* parent is a referral, don't allow add */
00274               rs->sr_ref = get_entry_referrals( op, e );
00275 
00276               Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn)
00277                      ": entry %s is referral\n", e->e_dn, 0, 0 );
00278 
00279               rs->sr_err = LDAP_REFERRAL,
00280               rs->sr_matched = e->e_name.bv_val;
00281               send_ldap_result( op, rs );
00282 
00283               ber_bvarray_free( rs->sr_ref );
00284               rs->sr_ref = NULL;
00285               rs->sr_matched = NULL;
00286               goto done;
00287        }
00288 
00289        if ( be_issuffix( op->o_bd, &e->e_nname ) ) {
00290 #ifdef BDB_MULTIPLE_SUFFIXES
00291               /* Allow renaming one suffix entry to another */
00292               p_ndn = slap_empty_bv;
00293 #else
00294               /* There can only be one suffix entry */
00295               rs->sr_err = LDAP_NAMING_VIOLATION;
00296               rs->sr_text = "cannot rename suffix entry";
00297               goto return_results;
00298 #endif
00299        } else {
00300               dnParent( &e->e_nname, &p_ndn );
00301        }
00302        np_ndn = &p_ndn;
00303        eip = ei->bei_parent;
00304        if ( eip && eip->bei_id ) {
00305               /* Make sure parent entry exist and we can write its 
00306                * children.
00307                */
00308               rs->sr_err = bdb_cache_find_id( op, ltid,
00309                      eip->bei_id, &eip, 0, &plock );
00310 
00311               switch( rs->sr_err ) {
00312               case 0:
00313               case DB_NOTFOUND:
00314                      break;
00315               case DB_LOCK_DEADLOCK:
00316               case DB_LOCK_NOTGRANTED:
00317                      goto retry;
00318               case LDAP_BUSY:
00319                      rs->sr_text = "ldap server busy";
00320                      goto return_results;
00321               default:
00322                      rs->sr_err = LDAP_OTHER;
00323                      rs->sr_text = "internal error";
00324                      goto return_results;
00325               }
00326 
00327               p = eip->bei_e;
00328               if( p == NULL) {
00329                      Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn)
00330                             ": parent does not exist\n", 0, 0, 0);
00331                      rs->sr_err = LDAP_OTHER;
00332                      rs->sr_text = "old entry's parent does not exist";
00333                      goto return_results;
00334               }
00335        } else {
00336               p = (Entry *)&slap_entry_root;
00337        }
00338 
00339        /* check parent for "children" acl */
00340        rs->sr_err = access_allowed( op, p,
00341               children, NULL,
00342               op->oq_modrdn.rs_newSup == NULL ?
00343                      ACL_WRITE : ACL_WDEL,
00344               NULL );
00345 
00346        if ( !p_ndn.bv_len )
00347               p = NULL;
00348 
00349        if ( ! rs->sr_err ) {
00350               switch( opinfo.boi_err ) {
00351               case DB_LOCK_DEADLOCK:
00352               case DB_LOCK_NOTGRANTED:
00353                      goto retry;
00354               }
00355 
00356               rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00357               Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
00358                      0, 0 );
00359               rs->sr_text = "no write access to old parent's children";
00360               goto return_results;
00361        }
00362 
00363        Debug( LDAP_DEBUG_TRACE,
00364               LDAP_XSTRING(bdb_modrdn) ": wr to children "
00365               "of entry %s OK\n", p_ndn.bv_val, 0, 0 );
00366        
00367        if ( p_ndn.bv_val == slap_empty_bv.bv_val ) {
00368               p_dn = slap_empty_bv;
00369        } else {
00370               dnParent( &e->e_name, &p_dn );
00371        }
00372 
00373        Debug( LDAP_DEBUG_TRACE,
00374               LDAP_XSTRING(bdb_modrdn) ": parent dn=%s\n",
00375               p_dn.bv_val, 0, 0 );
00376 
00377        new_parent_dn = &p_dn;      /* New Parent unless newSuperior given */
00378 
00379        if ( op->oq_modrdn.rs_newSup != NULL ) {
00380               Debug( LDAP_DEBUG_TRACE, 
00381                      LDAP_XSTRING(bdb_modrdn)
00382                      ": new parent \"%s\" requested...\n",
00383                      op->oq_modrdn.rs_newSup->bv_val, 0, 0 );
00384 
00385               /*  newSuperior == oldParent? */
00386               if( dn_match( &p_ndn, op->oq_modrdn.rs_nnewSup ) ) {
00387                      Debug( LDAP_DEBUG_TRACE, "bdb_back_modrdn: "
00388                             "new parent \"%s\" same as the old parent \"%s\"\n",
00389                             op->oq_modrdn.rs_newSup->bv_val, p_dn.bv_val, 0 );
00390                      op->oq_modrdn.rs_newSup = NULL; /* ignore newSuperior */
00391               }
00392        }
00393 
00394        /* There's a BDB_MULTIPLE_SUFFIXES case here that this code doesn't
00395         * support. E.g., two suffixes dc=foo,dc=com and dc=bar,dc=net.
00396         * We do not allow modDN
00397         *   dc=foo,dc=com
00398         *    newrdn dc=bar
00399         *    newsup dc=net
00400         * and we probably should. But since MULTIPLE_SUFFIXES is deprecated
00401         * I'm ignoring this problem for now.
00402         */
00403        if ( op->oq_modrdn.rs_newSup != NULL ) {
00404               if ( op->oq_modrdn.rs_newSup->bv_len ) {
00405                      np_dn = op->oq_modrdn.rs_newSup;
00406                      np_ndn = op->oq_modrdn.rs_nnewSup;
00407 
00408                      /* newSuperior == oldParent? - checked above */
00409                      /* newSuperior == entry being moved?, if so ==> ERROR */
00410                      if ( dnIsSuffix( np_ndn, &e->e_nname )) {
00411                             rs->sr_err = LDAP_NO_SUCH_OBJECT;
00412                             rs->sr_text = "new superior not found";
00413                             goto return_results;
00414                      }
00415                      /* Get Entry with dn=newSuperior. Does newSuperior exist? */
00416 
00417                      rs->sr_err = bdb_dn2entry( op, ltid, np_ndn,
00418                             &neip, 0, &nplock );
00419 
00420                      switch( rs->sr_err ) {
00421                      case 0: np = neip->bei_e;
00422                      case DB_NOTFOUND:
00423                             break;
00424                      case DB_LOCK_DEADLOCK:
00425                      case DB_LOCK_NOTGRANTED:
00426                             goto retry;
00427                      case LDAP_BUSY:
00428                             rs->sr_text = "ldap server busy";
00429                             goto return_results;
00430                      default:
00431                             rs->sr_err = LDAP_OTHER;
00432                             rs->sr_text = "internal error";
00433                             goto return_results;
00434                      }
00435 
00436                      if( np == NULL) {
00437                             Debug( LDAP_DEBUG_TRACE,
00438                                    LDAP_XSTRING(bdb_modrdn)
00439                                    ": newSup(ndn=%s) not here!\n",
00440                                    np_ndn->bv_val, 0, 0);
00441                             rs->sr_text = "new superior not found";
00442                             rs->sr_err = LDAP_NO_SUCH_OBJECT;
00443                             goto return_results;
00444                      }
00445 
00446                      Debug( LDAP_DEBUG_TRACE,
00447                             LDAP_XSTRING(bdb_modrdn)
00448                             ": wr to new parent OK np=%p, id=%ld\n",
00449                             (void *) np, (long) np->e_id, 0 );
00450 
00451                      /* check newSuperior for "children" acl */
00452                      rs->sr_err = access_allowed( op, np, children,
00453                             NULL, ACL_WADD, NULL );
00454 
00455                      if( ! rs->sr_err ) {
00456                             switch( opinfo.boi_err ) {
00457                             case DB_LOCK_DEADLOCK:
00458                             case DB_LOCK_NOTGRANTED:
00459                                    goto retry;
00460                             }
00461 
00462                             Debug( LDAP_DEBUG_TRACE,
00463                                    LDAP_XSTRING(bdb_modrdn)
00464                                    ": no wr to newSup children\n",
00465                                    0, 0, 0 );
00466                             rs->sr_text = "no write access to new superior's children";
00467                             rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00468                             goto return_results;
00469                      }
00470 
00471                      if ( is_entry_alias( np ) ) {
00472                             /* parent is an alias, don't allow add */
00473                             Debug( LDAP_DEBUG_TRACE,
00474                                    LDAP_XSTRING(bdb_modrdn)
00475                                    ": entry is alias\n",
00476                                    0, 0, 0 );
00477                             rs->sr_text = "new superior is an alias";
00478                             rs->sr_err = LDAP_ALIAS_PROBLEM;
00479                             goto return_results;
00480                      }
00481 
00482                      if ( is_entry_referral( np ) ) {
00483                             /* parent is a referral, don't allow add */
00484                             Debug( LDAP_DEBUG_TRACE,
00485                                    LDAP_XSTRING(bdb_modrdn)
00486                                    ": entry is referral\n",
00487                                    0, 0, 0 );
00488                             rs->sr_text = "new superior is a referral";
00489                             rs->sr_err = LDAP_OTHER;
00490                             goto return_results;
00491                      }
00492 
00493               } else {
00494                      np_dn = NULL;
00495 
00496                      /* no parent, modrdn entry directly under root */
00497                      if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
00498                             || be_isupdate( op ) ) {
00499                             np = (Entry *)&slap_entry_root;
00500 
00501                             /* check parent for "children" acl */
00502                             rs->sr_err = access_allowed( op, np,
00503                                    children, NULL, ACL_WADD, NULL );
00504 
00505                             np = NULL;
00506 
00507                             if ( ! rs->sr_err ) {
00508                                    switch( opinfo.boi_err ) {
00509                                    case DB_LOCK_DEADLOCK:
00510                                    case DB_LOCK_NOTGRANTED:
00511                                           goto retry;
00512                                    }
00513 
00514                                    rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
00515                                    Debug( LDAP_DEBUG_TRACE, 
00516                                           "no access to new superior\n", 
00517                                           0, 0, 0 );
00518                                    rs->sr_text =
00519                                           "no write access to new superior's children";
00520                                    goto return_results;
00521                             }
00522                      }
00523               }
00524 
00525               Debug( LDAP_DEBUG_TRACE,
00526                      LDAP_XSTRING(bdb_modrdn)
00527                      ": wr to new parent's children OK\n",
00528                      0, 0, 0 );
00529 
00530               new_parent_dn = np_dn;
00531        }
00532 
00533        /* Build target dn and make sure target entry doesn't exist already. */
00534        if (!new_dn.bv_val) {
00535               build_new_dn( &new_dn, new_parent_dn, &op->oq_modrdn.rs_newrdn, NULL ); 
00536        }
00537 
00538        if (!new_ndn.bv_val) {
00539               struct berval bv = {0, NULL};
00540               dnNormalize( 0, NULL, NULL, &new_dn, &bv, op->o_tmpmemctx );
00541               ber_dupbv( &new_ndn, &bv );
00542               /* FIXME: why not call dnNormalize() w/o ctx? */
00543               op->o_tmpfree( bv.bv_val, op->o_tmpmemctx );
00544        }
00545 
00546        Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_modrdn) ": new ndn=%s\n",
00547               new_ndn.bv_val, 0, 0 );
00548 
00549        /* Shortcut the search */
00550        nei = neip ? neip : eip;
00551        rs->sr_err = bdb_cache_find_ndn ( op, ltid, &new_ndn, &nei );
00552        if ( nei ) bdb_cache_entryinfo_unlock( nei );
00553        switch( rs->sr_err ) {
00554        case DB_LOCK_DEADLOCK:
00555        case DB_LOCK_NOTGRANTED:
00556               goto retry;
00557        case DB_NOTFOUND:
00558               break;
00559        case 0:
00560               /* Allow rename to same DN */
00561               if ( nei == ei )
00562                      break;
00563               rs->sr_err = LDAP_ALREADY_EXISTS;
00564               goto return_results;
00565        default:
00566               rs->sr_err = LDAP_OTHER;
00567               rs->sr_text = "internal error";
00568               goto return_results;
00569        }
00570 
00571        assert( op->orr_modlist != NULL );
00572 
00573        if( op->o_preread ) {
00574               if( preread_ctrl == NULL ) {
00575                      preread_ctrl = &ctrls[num_ctrls++];
00576                      ctrls[num_ctrls] = NULL;
00577               }
00578               if( slap_read_controls( op, rs, e,
00579                      &slap_pre_read_bv, preread_ctrl ) )
00580               {
00581                      Debug( LDAP_DEBUG_TRACE,        
00582                             "<=- " LDAP_XSTRING(bdb_modrdn)
00583                             ": pre-read failed!\n", 0, 0, 0 );
00584                      if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
00585                             /* FIXME: is it correct to abort
00586                              * operation if control fails? */
00587                             goto return_results;
00588                      }
00589               }                   
00590        }
00591 
00592        /* nested transaction */
00593        rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, &lt2, bdb->bi_db_opflags );
00594        rs->sr_text = NULL;
00595        if( rs->sr_err != 0 ) {
00596               Debug( LDAP_DEBUG_TRACE,
00597                      LDAP_XSTRING(bdb_modrdn)
00598                      ": txn_begin(2) failed: %s (%d)\n",
00599                      db_strerror(rs->sr_err), rs->sr_err, 0 );
00600               rs->sr_err = LDAP_OTHER;
00601               rs->sr_text = "internal error";
00602               goto return_results;
00603        }
00604 
00605        /* delete old DN */
00606        rs->sr_err = bdb_dn2id_delete( op, lt2, eip, e );
00607        if ( rs->sr_err != 0 ) {
00608               Debug(LDAP_DEBUG_TRACE,
00609                      "<=- " LDAP_XSTRING(bdb_modrdn)
00610                      ": dn2id del failed: %s (%d)\n",
00611                      db_strerror(rs->sr_err), rs->sr_err, 0 );
00612               switch( rs->sr_err ) {
00613               case DB_LOCK_DEADLOCK:
00614               case DB_LOCK_NOTGRANTED:
00615                      goto retry;
00616               }
00617               rs->sr_err = LDAP_OTHER;
00618               rs->sr_text = "DN index delete fail";
00619               goto return_results;
00620        }
00621 
00622        /* copy the entry, then override some fields */
00623        dummy = *e;
00624        dummy.e_name = new_dn;
00625        dummy.e_nname = new_ndn;
00626        dummy.e_attrs = NULL;
00627 
00628        /* add new DN */
00629        rs->sr_err = bdb_dn2id_add( op, lt2, neip ? neip : eip, &dummy );
00630        if ( rs->sr_err != 0 ) {
00631               Debug(LDAP_DEBUG_TRACE,
00632                      "<=- " LDAP_XSTRING(bdb_modrdn)
00633                      ": dn2id add failed: %s (%d)\n",
00634                      db_strerror(rs->sr_err), rs->sr_err, 0 );
00635               switch( rs->sr_err ) {
00636               case DB_LOCK_DEADLOCK:
00637               case DB_LOCK_NOTGRANTED:
00638                      goto retry;
00639               }
00640               rs->sr_err = LDAP_OTHER;
00641               rs->sr_text = "DN index add failed";
00642               goto return_results;
00643        }
00644 
00645        dummy.e_attrs = e->e_attrs;
00646 
00647        /* modify entry */
00648        rs->sr_err = bdb_modify_internal( op, lt2, op->orr_modlist, &dummy,
00649               &rs->sr_text, textbuf, textlen );
00650        if( rs->sr_err != LDAP_SUCCESS ) {
00651               Debug(LDAP_DEBUG_TRACE,
00652                      "<=- " LDAP_XSTRING(bdb_modrdn)
00653                      ": modify failed: %s (%d)\n",
00654                      db_strerror(rs->sr_err), rs->sr_err, 0 );
00655               if ( ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) && opinfo.boi_err ) {
00656                      rs->sr_err = opinfo.boi_err;
00657               }
00658               if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
00659               switch( rs->sr_err ) {
00660               case DB_LOCK_DEADLOCK:
00661               case DB_LOCK_NOTGRANTED:
00662                      goto retry;
00663               }
00664               goto return_results;
00665        }
00666 
00667        /* id2entry index */
00668        rs->sr_err = bdb_id2entry_update( op->o_bd, lt2, &dummy );
00669        if ( rs->sr_err != 0 ) {
00670               Debug(LDAP_DEBUG_TRACE,
00671                      "<=- " LDAP_XSTRING(bdb_modrdn)
00672                      ": id2entry failed: %s (%d)\n",
00673                      db_strerror(rs->sr_err), rs->sr_err, 0 );
00674               switch( rs->sr_err ) {
00675               case DB_LOCK_DEADLOCK:
00676               case DB_LOCK_NOTGRANTED:
00677                      goto retry;
00678               }
00679               rs->sr_err = LDAP_OTHER;
00680               rs->sr_text = "entry update failed";
00681               goto return_results;
00682        }
00683 
00684        if ( p_ndn.bv_len != 0 ) {
00685               parent_is_glue = is_entry_glue(p);
00686               rs->sr_err = bdb_cache_children( op, lt2, p );
00687               if ( rs->sr_err != DB_NOTFOUND ) {
00688                      switch( rs->sr_err ) {
00689                      case DB_LOCK_DEADLOCK:
00690                      case DB_LOCK_NOTGRANTED:
00691                             goto retry;
00692                      case 0:
00693                             break;
00694                      default:
00695                             Debug(LDAP_DEBUG_ARGS,
00696                                    "<=- " LDAP_XSTRING(bdb_modrdn)
00697                                    ": has_children failed: %s (%d)\n",
00698                                    db_strerror(rs->sr_err), rs->sr_err, 0 );
00699                             rs->sr_err = LDAP_OTHER;
00700                             rs->sr_text = "internal error";
00701                             goto return_results;
00702                      }
00703                      parent_is_leaf = 1;
00704               }
00705               bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
00706               p = NULL;
00707        }
00708 
00709        if ( TXN_COMMIT( lt2, 0 ) != 0 ) {
00710               rs->sr_err = LDAP_OTHER;
00711               rs->sr_text = "txn_commit(2) failed";
00712               goto return_results;
00713        }
00714 
00715        if( op->o_postread ) {
00716               if( postread_ctrl == NULL ) {
00717                      postread_ctrl = &ctrls[num_ctrls++];
00718                      ctrls[num_ctrls] = NULL;
00719               }
00720               if( slap_read_controls( op, rs, &dummy,
00721                      &slap_post_read_bv, postread_ctrl ) )
00722               {
00723                      Debug( LDAP_DEBUG_TRACE,        
00724                             "<=- " LDAP_XSTRING(bdb_modrdn)
00725                             ": post-read failed!\n", 0, 0, 0 );
00726                      if ( op->o_postread & SLAP_CONTROL_CRITICAL ) {
00727                             /* FIXME: is it correct to abort
00728                              * operation if control fails? */
00729                             goto return_results;
00730                      }
00731               }                   
00732        }
00733 
00734        if( op->o_noop ) {
00735               if(( rs->sr_err=TXN_ABORT( ltid )) != 0 ) {
00736                      rs->sr_text = "txn_abort (no-op) failed";
00737               } else {
00738                      rs->sr_err = LDAP_X_NO_OPERATION;
00739                      ltid = NULL;
00740                      /* Only free attrs if they were dup'd.  */
00741                      if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL;
00742                      goto return_results;
00743               }
00744 
00745        } else {
00746               rc = bdb_cache_modrdn( bdb, e, &op->orr_nnewrdn, &dummy, neip,
00747                      ltid, &lock );
00748               switch( rc ) {
00749               case DB_LOCK_DEADLOCK:
00750               case DB_LOCK_NOTGRANTED:
00751                      goto retry;
00752               }
00753               dummy.e_attrs = NULL;
00754               new_dn.bv_val = NULL;
00755               new_ndn.bv_val = NULL;
00756 
00757               if(( rs->sr_err=TXN_COMMIT( ltid, 0 )) != 0 ) {
00758                      rs->sr_text = "txn_commit failed";
00759               } else {
00760                      rs->sr_err = LDAP_SUCCESS;
00761               }
00762        }
00763  
00764        ltid = NULL;
00765        LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
00766        opinfo.boi_oe.oe_key = NULL;
00767  
00768        if( rs->sr_err != LDAP_SUCCESS ) {
00769               Debug( LDAP_DEBUG_TRACE,
00770                      LDAP_XSTRING(bdb_modrdn) ": %s : %s (%d)\n",
00771                      rs->sr_text, db_strerror(rs->sr_err), rs->sr_err );
00772               rs->sr_err = LDAP_OTHER;
00773 
00774               goto return_results;
00775        }
00776 
00777        Debug(LDAP_DEBUG_TRACE,
00778               LDAP_XSTRING(bdb_modrdn)
00779               ": rdn modified%s id=%08lx dn=\"%s\"\n",
00780               op->o_noop ? " (no-op)" : "",
00781               dummy.e_id, op->o_req_dn.bv_val );
00782        rs->sr_text = NULL;
00783        if( num_ctrls ) rs->sr_ctrls = ctrls;
00784 
00785 return_results:
00786        if ( dummy.e_attrs ) {
00787               attrs_free( dummy.e_attrs );
00788        }
00789        send_ldap_result( op, rs );
00790 
00791        if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp_kbyte ) {
00792               TXN_CHECKPOINT( bdb->bi_dbenv,
00793                      bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
00794        }
00795        
00796        if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) {
00797               op->o_delete_glue_parent = 1;
00798        }
00799 
00800 done:
00801        slap_graduate_commit_csn( op );
00802 
00803        if( new_dn.bv_val != NULL ) free( new_dn.bv_val );
00804        if( new_ndn.bv_val != NULL ) free( new_ndn.bv_val );
00805 
00806        /* LDAP v3 Support */
00807        if( np != NULL ) {
00808               /* free new parent and reader lock */
00809               bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, np);
00810        }
00811 
00812        if( p != NULL ) {
00813               /* free parent and reader lock */
00814               bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
00815        }
00816 
00817        /* free entry */
00818        if( e != NULL ) {
00819               bdb_unlocked_cache_return_entry_w( &bdb->bi_cache, e);
00820        }
00821 
00822        if( ltid != NULL ) {
00823               TXN_ABORT( ltid );
00824        }
00825        if ( opinfo.boi_oe.oe_key ) {
00826               LDAP_SLIST_REMOVE( &op->o_extra, &opinfo.boi_oe, OpExtra, oe_next );
00827        }
00828 
00829        if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
00830               slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
00831               slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
00832        }
00833        if( postread_ctrl != NULL && (*postread_ctrl) != NULL ) {
00834               slap_sl_free( (*postread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
00835               slap_sl_free( *postread_ctrl, op->o_tmpmemctx );
00836        }
00837        return rs->sr_err;
00838 }